Merge "BLE-MIDI: fix timestamps for sysex data" into rvc-dev am: 2682bcf618 am: ec1e4705f7 am: e5545c3cf7

Change-Id: I1f9266a6a336e220cb280c944c597374f4ee5785
This commit is contained in:
TreeHugger Robot
2020-03-28 02:58:36 +00:00
committed by Automerger Merge Worker

View File

@@ -22,24 +22,41 @@ import android.util.Log;
import java.io.IOException; import java.io.IOException;
/** /**
* This is an abstract base class that decodes a packet buffer and passes it to a * This is an abstract base class that decodes a BLE-MIDI packet
* {@link android.media.midi.MidiReceiver} * buffer and passes it to a {@link android.media.midi.MidiReceiver}
*/ */
public class BluetoothPacketDecoder extends PacketDecoder { public class BluetoothPacketDecoder extends PacketDecoder {
private static final String TAG = "BluetoothPacketDecoder"; private static final String TAG = "BluetoothPacketDecoder";
private final byte[] mBuffer; private final byte[] mBuffer;
private int mBytesInBuffer;
private MidiBtleTimeTracker mTimeTracker; private MidiBtleTimeTracker mTimeTracker;
private final int TIMESTAMP_MASK_HIGH = 0x1F80; private int mLowTimestamp;
private final int TIMESTAMP_MASK_LOW = 0x7F; private long mNanoTimestamp;
private final int HEADER_TIMESTAMP_MASK = 0x3F;
private static final int TIMESTAMP_MASK_HIGH = 0x1F80; // top 7 bits
private static final int TIMESTAMP_MASK_LOW = 0x7F; // bottom 7 bits
private static final int HEADER_TIMESTAMP_MASK = 0x3F; // bottom 6 bits
public BluetoothPacketDecoder(int maxPacketSize) { public BluetoothPacketDecoder(int maxPacketSize) {
mBuffer = new byte[maxPacketSize]; mBuffer = new byte[maxPacketSize];
} }
private void flushOutput(MidiReceiver receiver) {
if (mBytesInBuffer > 0) {
try {
receiver.send(mBuffer, 0, mBytesInBuffer, mNanoTimestamp);
} catch (IOException e) {
// ???
}
mBytesInBuffer = 0;
}
}
// NOTE: this code allows running status across packets,
// although the specification does not allow that.
@Override @Override
public void decodePacket(byte[] buffer, MidiReceiver receiver) { public void decodePacket(byte[] buffer, MidiReceiver receiver) {
if (mTimeTracker == null) { if (mTimeTracker == null) {
@@ -47,14 +64,11 @@ public class BluetoothPacketDecoder extends PacketDecoder {
} }
int length = buffer.length; int length = buffer.length;
// NOTE his code allows running status across packets,
// although the specification does not allow that.
if (length < 1) { if (length < 1) {
Log.e(TAG, "empty packet"); Log.e(TAG, "empty packet");
return; return;
} }
byte header = buffer[0]; byte header = buffer[0];
if ((header & 0xC0) != 0x80) { if ((header & 0xC0) != 0x80) {
Log.e(TAG, "packet does not start with header"); Log.e(TAG, "packet does not start with header");
@@ -64,52 +78,46 @@ public class BluetoothPacketDecoder extends PacketDecoder {
// shift bits 0 - 5 to bits 7 - 12 // shift bits 0 - 5 to bits 7 - 12
int highTimestamp = (header & HEADER_TIMESTAMP_MASK) << 7; int highTimestamp = (header & HEADER_TIMESTAMP_MASK) << 7;
boolean lastWasTimestamp = false; boolean lastWasTimestamp = false;
int dataCount = 0;
int previousLowTimestamp = 0; int previousLowTimestamp = 0;
long nanoTimestamp = 0; int currentTimestamp = highTimestamp | mLowTimestamp;
int currentTimestamp = 0;
// iterate through the rest of the packet, separating MIDI data from timestamps // Iterate through the rest of the packet, separating MIDI data from timestamps.
for (int i = 1; i < buffer.length; i++) { for (int i = 1; i < buffer.length; i++) {
byte b = buffer[i]; byte b = buffer[i];
// Is this a timestamp byte?
if ((b & 0x80) != 0 && !lastWasTimestamp) { if ((b & 0x80) != 0 && !lastWasTimestamp) {
lastWasTimestamp = true; lastWasTimestamp = true;
int lowTimestamp = b & TIMESTAMP_MASK_LOW; mLowTimestamp = b & TIMESTAMP_MASK_LOW;
if (lowTimestamp < previousLowTimestamp) {
// If the low timestamp byte wraps within the packet then
// increment the high timestamp byte.
if (mLowTimestamp < previousLowTimestamp) {
highTimestamp = (highTimestamp + 0x0080) & TIMESTAMP_MASK_HIGH; highTimestamp = (highTimestamp + 0x0080) & TIMESTAMP_MASK_HIGH;
} }
previousLowTimestamp = lowTimestamp; previousLowTimestamp = mLowTimestamp;
int newTimestamp = highTimestamp | lowTimestamp; // If the timestamp advances then send any pending data.
int newTimestamp = highTimestamp | mLowTimestamp;
if (newTimestamp != currentTimestamp) { if (newTimestamp != currentTimestamp) {
if (dataCount > 0) { // Send previous message separately since it has a different timestamp.
// send previous message separately since it has a different timestamp flushOutput(receiver);
try {
receiver.send(mBuffer, 0, dataCount, nanoTimestamp);
} catch (IOException e) {
// ???
}
dataCount = 0;
}
currentTimestamp = newTimestamp; currentTimestamp = newTimestamp;
} }
// calculate nanoTimestamp // Calculate MIDI nanosecond timestamp from BLE timestamp.
long now = System.nanoTime(); long now = System.nanoTime();
nanoTimestamp = mTimeTracker.convertTimestampToNanotime(currentTimestamp, now); mNanoTimestamp = mTimeTracker.convertTimestampToNanotime(currentTimestamp, now);
} else { } else {
lastWasTimestamp = false; lastWasTimestamp = false;
mBuffer[dataCount++] = b; // Flush if full before adding more data.
if (mBytesInBuffer == mBuffer.length) {
flushOutput(receiver);
}
mBuffer[mBytesInBuffer++] = b;
} }
} }
if (dataCount > 0) { flushOutput(receiver);
try {
receiver.send(mBuffer, 0, dataCount, nanoTimestamp);
} catch (IOException e) {
// ???
}
}
} }
} }