1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.bluetoothmidiservice; 18 19 import android.media.midi.MidiReceiver; 20 import android.util.Log; 21 22 import java.io.IOException; 23 24 /** 25 * This is an abstract base class that decodes a packet buffer and passes it to a 26 * {@link android.media.midi.MidiReceiver} 27 */ 28 public class BluetoothPacketDecoder extends PacketDecoder { 29 30 private static final String TAG = "BluetoothPacketDecoder"; 31 32 private final byte[] mBuffer; 33 private MidiBtleTimeTracker mTimeTracker; 34 35 private final int TIMESTAMP_MASK_HIGH = 0x1F80; 36 private final int TIMESTAMP_MASK_LOW = 0x7F; 37 private final int HEADER_TIMESTAMP_MASK = 0x3F; 38 39 public BluetoothPacketDecoder(int maxPacketSize) { 40 mBuffer = new byte[maxPacketSize]; 41 } 42 43 @Override 44 public void decodePacket(byte[] buffer, MidiReceiver receiver) { 45 if (mTimeTracker == null) { 46 mTimeTracker = new MidiBtleTimeTracker(System.nanoTime()); 47 } 48 49 int length = buffer.length; 50 51 // NOTE his code allows running status across packets, 52 // although the specification does not allow that. 53 54 if (length < 1) { 55 Log.e(TAG, "empty packet"); 56 return; 57 } 58 byte header = buffer[0]; 59 if ((header & 0xC0) != 0x80) { 60 Log.e(TAG, "packet does not start with header"); 61 return; 62 } 63 64 // shift bits 0 - 5 to bits 7 - 12 65 int highTimestamp = (header & HEADER_TIMESTAMP_MASK) << 7; 66 boolean lastWasTimestamp = false; 67 int dataCount = 0; 68 int previousLowTimestamp = 0; 69 long nanoTimestamp = 0; 70 int currentTimestamp = 0; 71 72 // iterate through the rest of the packet, separating MIDI data from timestamps 73 for (int i = 1; i < buffer.length; i++) { 74 byte b = buffer[i]; 75 76 if ((b & 0x80) != 0 && !lastWasTimestamp) { 77 lastWasTimestamp = true; 78 int lowTimestamp = b & TIMESTAMP_MASK_LOW; 79 if (lowTimestamp < previousLowTimestamp) { 80 highTimestamp = (highTimestamp + 0x0080) & TIMESTAMP_MASK_HIGH; 81 } 82 previousLowTimestamp = lowTimestamp; 83 84 int newTimestamp = highTimestamp | lowTimestamp; 85 if (newTimestamp != currentTimestamp) { 86 if (dataCount > 0) { 87 // send previous message separately since it has a different timestamp 88 try { 89 receiver.send(mBuffer, 0, dataCount, nanoTimestamp); 90 } catch (IOException e) { 91 // ??? 92 } 93 dataCount = 0; 94 } 95 currentTimestamp = newTimestamp; 96 } 97 98 // calculate nanoTimestamp 99 long now = System.nanoTime(); 100 nanoTimestamp = mTimeTracker.convertTimestampToNanotime(currentTimestamp, now); 101 } else { 102 lastWasTimestamp = false; 103 mBuffer[dataCount++] = b; 104 } 105 } 106 107 if (dataCount > 0) { 108 try { 109 receiver.send(mBuffer, 0, dataCount, nanoTimestamp); 110 } catch (IOException e) { 111 // ??? 112 } 113 } 114 } 115 } 116