Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e5545c3c authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "BLE-MIDI: fix timestamps for sysex data" into rvc-dev am: 2682bcf6 am: ec1e4705

Change-Id: Iac7c42389f4e78a85e063ff95c0b62a6248eff75
parents 3eefddd4 ec1e4705
Loading
Loading
Loading
Loading
+44 −36
Original line number Original line Diff line number Diff line
@@ -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) {
            try {
                receiver.send(mBuffer, 0, dataCount, nanoTimestamp);
            } catch (IOException e) {
                // ???
            }
            }
        }
        }

        flushOutput(receiver);
    }
    }
}
}