Merge "BLE-MIDI: fix timestamps for sysex data" into rvc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
2682bcf618
@@ -22,24 +22,41 @@ import android.util.Log;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This is an abstract base class that decodes a packet buffer and passes it to a
|
||||
* {@link android.media.midi.MidiReceiver}
|
||||
* This is an abstract base class that decodes a BLE-MIDI packet
|
||||
* buffer and passes it to a {@link android.media.midi.MidiReceiver}
|
||||
*/
|
||||
public class BluetoothPacketDecoder extends PacketDecoder {
|
||||
|
||||
private static final String TAG = "BluetoothPacketDecoder";
|
||||
|
||||
private final byte[] mBuffer;
|
||||
private int mBytesInBuffer;
|
||||
private MidiBtleTimeTracker mTimeTracker;
|
||||
|
||||
private final int TIMESTAMP_MASK_HIGH = 0x1F80;
|
||||
private final int TIMESTAMP_MASK_LOW = 0x7F;
|
||||
private final int HEADER_TIMESTAMP_MASK = 0x3F;
|
||||
private int mLowTimestamp;
|
||||
private long mNanoTimestamp;
|
||||
|
||||
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) {
|
||||
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
|
||||
public void decodePacket(byte[] buffer, MidiReceiver receiver) {
|
||||
if (mTimeTracker == null) {
|
||||
@@ -47,14 +64,11 @@ public class BluetoothPacketDecoder extends PacketDecoder {
|
||||
}
|
||||
|
||||
int length = buffer.length;
|
||||
|
||||
// NOTE his code allows running status across packets,
|
||||
// although the specification does not allow that.
|
||||
|
||||
if (length < 1) {
|
||||
Log.e(TAG, "empty packet");
|
||||
return;
|
||||
}
|
||||
|
||||
byte header = buffer[0];
|
||||
if ((header & 0xC0) != 0x80) {
|
||||
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
|
||||
int highTimestamp = (header & HEADER_TIMESTAMP_MASK) << 7;
|
||||
boolean lastWasTimestamp = false;
|
||||
int dataCount = 0;
|
||||
int previousLowTimestamp = 0;
|
||||
long nanoTimestamp = 0;
|
||||
int currentTimestamp = 0;
|
||||
int currentTimestamp = highTimestamp | mLowTimestamp;
|
||||
|
||||
// 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++) {
|
||||
byte b = buffer[i];
|
||||
|
||||
// Is this a timestamp byte?
|
||||
if ((b & 0x80) != 0 && !lastWasTimestamp) {
|
||||
lastWasTimestamp = true;
|
||||
int lowTimestamp = b & TIMESTAMP_MASK_LOW;
|
||||
if (lowTimestamp < previousLowTimestamp) {
|
||||
mLowTimestamp = b & TIMESTAMP_MASK_LOW;
|
||||
|
||||
// If the low timestamp byte wraps within the packet then
|
||||
// increment the high timestamp byte.
|
||||
if (mLowTimestamp < previousLowTimestamp) {
|
||||
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 (dataCount > 0) {
|
||||
// send previous message separately since it has a different timestamp
|
||||
try {
|
||||
receiver.send(mBuffer, 0, dataCount, nanoTimestamp);
|
||||
} catch (IOException e) {
|
||||
// ???
|
||||
}
|
||||
dataCount = 0;
|
||||
}
|
||||
// Send previous message separately since it has a different timestamp.
|
||||
flushOutput(receiver);
|
||||
currentTimestamp = newTimestamp;
|
||||
}
|
||||
|
||||
// calculate nanoTimestamp
|
||||
// Calculate MIDI nanosecond timestamp from BLE timestamp.
|
||||
long now = System.nanoTime();
|
||||
nanoTimestamp = mTimeTracker.convertTimestampToNanotime(currentTimestamp, now);
|
||||
mNanoTimestamp = mTimeTracker.convertTimestampToNanotime(currentTimestamp, now);
|
||||
} else {
|
||||
lastWasTimestamp = false;
|
||||
mBuffer[dataCount++] = b;
|
||||
// Flush if full before adding more data.
|
||||
if (mBytesInBuffer == mBuffer.length) {
|
||||
flushOutput(receiver);
|
||||
}
|
||||
mBuffer[mBytesInBuffer++] = b;
|
||||
}
|
||||
}
|
||||
|
||||
if (dataCount > 0) {
|
||||
try {
|
||||
receiver.send(mBuffer, 0, dataCount, nanoTimestamp);
|
||||
} catch (IOException e) {
|
||||
// ???
|
||||
}
|
||||
}
|
||||
flushOutput(receiver);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user