From f80e22508002b3333983ee5d61f6e83ddb572ceb Mon Sep 17 00:00:00 2001 From: lathoub Date: Mon, 9 Mar 2020 22:56:47 +0100 Subject: [PATCH] added support for running Status --- src/BLE-MIDI.h | 142 ---------------------------------- src/hardware/BLE-MIDI_ESP32.h | 45 ++++++++++- 2 files changed, 41 insertions(+), 146 deletions(-) diff --git a/src/BLE-MIDI.h b/src/BLE-MIDI.h index 7dcc1d2..ad615c9 100755 --- a/src/BLE-MIDI.h +++ b/src/BLE-MIDI.h @@ -106,148 +106,6 @@ public: public: QueueHandle_t mRxQueue; - /* - The general form of a MIDI message follows: - n-byte MIDI Message - Byte 0 MIDI message Status byte, Bit 7 is Set to 1. - Bytes 1 to n-1 MIDI message Data bytes, if n > 1. Bit 7 is Set to 0 - There are two types of MIDI messages that can appear in a single packet: full MIDI messages and - Running Status MIDI messages. Each is encoded differently. - A full MIDI message is simply the MIDI message with the Status byte included. - A Running Status MIDI message is a MIDI message with the Status byte omitted. Running Status - MIDI messages may only be placed in the data stream if the following criteria are met: - 1. The original MIDI message is 2 bytes or greater and is not a System Common or System - Real-Time message. - 2. The omitted Status byte matches the most recently preceding full MIDI message’s Status - byte within the same BLE packet. - In addition, the following rules apply with respect to Running Status: - 1. A Running Status MIDI message is allowed within the packet after at least one full MIDI - message. - 2. Every MIDI Status byte must be preceded by a timestamp byte. Running Status MIDI - messages may be preceded by a timestamp byte. If a Running Status MIDI message is not - preceded by a timestamp byte, the timestamp byte of the most recently preceding message - in the same packet is used. - 3. System Common and System Real-Time messages do not cancel Running Status if - interspersed between Running Status MIDI messages. However, a timestamp byte must - precede the Running Status MIDI message that follows. - 4. The end of a BLE packet does cancel Running Status. - In the MIDI 1.0 protocol, System Real-Time messages can be sent at any time and may be - inserted anywhere in a MIDI data stream, including between Status and Data bytes of any other - MIDI messages. In the MIDI BLE protocol, the System Real-Time messages must be deinterleaved - from other messages – except for System Exclusive messages. - */ - void receive(byte* buffer, size_t bufferSize) - { - size_t index = 0; - size_t i = 0; - - N_DEBUG_PRINT("Received ("); - N_DEBUG_PRINT(bufferSize); - N_DEBUG_PRINTLN(") :"); - for (int j = 0; j < bufferSize; j++) { - N_DEBUG_PRINT("0x"); - N_DEBUG_PRINT(buffer[j], HEX); - N_DEBUG_PRINT(" "); - } - N_DEBUG_PRINTLN(); - N_DEBUG_PRINTLN(); - - // Pointers used to search through payload. - uint8_t lPtr = 0; - uint8_t rPtr = 0; - - // lastStatus used to capture runningStatus - uint8_t lastStatus; - - // Decode first packet -- SHALL be "Full MIDI message" - lPtr = 2; //Start at first MIDI status -- SHALL be "MIDI status" - - // While statement contains incrementing pointers and breaks when buffer size exceeded. - while (true) - { - lastStatus = buffer[lPtr]; - if( (buffer[lPtr] < 0x80) ) - break; // Status message not present, bail - - // Point to next non-data byte - rPtr = lPtr; - while ((buffer[rPtr + 1] < 0x80) - && (rPtr < (bufferSize - 1)) ) - rPtr++; - - // look at l and r pointers and decode by size. - if( rPtr - lPtr < 1 ) - { - mRxBuffer[i++] = lastStatus; - } - else if( rPtr - lPtr < 2 ) { - mRxBuffer[i++] = lastStatus; - mRxBuffer[i++] = buffer[lPtr + 1]; - } - else if( rPtr - lPtr < 3 ) { - mRxBuffer[i++] = lastStatus; - mRxBuffer[i++] = buffer[lPtr + 1]; - mRxBuffer[i++] = buffer[lPtr + 2]; - } - else - { -/* //Too much data - //If not System Common or System Real-Time, send it as running status - switch( buffer[lPtr] & 0xF0 ) - { - case NoteOff: - case NoteOn: - case AfterTouchPoly: - case ControlChange: - case PitchBend: - for(int i = lPtr; i < rPtr; i = i + 2) - sendMIDI(lastStatus, buffer[i + 1], buffer[i + 2]); - break; - case ProgramChange: - case AfterTouchChannel: - for(int i = lPtr; i < rPtr; i = i + 1) - sendMIDI(lastStatus, buffer[i + 1]); - break; - default: - break; - } -*/ - } - - // Point to next status - lPtr = rPtr + 2; - - if (lPtr >= bufferSize) - break; //end of packet - } - - - - - - - - - - - - - reverse(mRxBuffer, i); - - N_DEBUG_PRINT("mRxBuffer ("); - N_DEBUG_PRINT(i); - N_DEBUG_PRINTLN(") :"); - for (int j = 0; j < i; j++) { - N_DEBUG_PRINT("0x"); - N_DEBUG_PRINT(mRxBuffer[j], HEX); - N_DEBUG_PRINT(" "); - } - N_DEBUG_PRINTLN(); - N_DEBUG_PRINTLN(); - - mRxIndex = i; - } - protected: /* The first byte of all BLE packets must be a header byte. This is followed by timestamp bytes and MIDI messages. diff --git a/src/hardware/BLE-MIDI_ESP32.h b/src/hardware/BLE-MIDI_ESP32.h index a0bcc1a..85ffeae 100755 --- a/src/hardware/BLE-MIDI_ESP32.h +++ b/src/hardware/BLE-MIDI_ESP32.h @@ -30,6 +30,36 @@ public: _characteristic->notify(); } + /* + The general form of a MIDI message follows: + n-byte MIDI Message + Byte 0 MIDI message Status byte, Bit 7 is Set to 1. + Bytes 1 to n-1 MIDI message Data bytes, if n > 1. Bit 7 is Set to 0 + There are two types of MIDI messages that can appear in a single packet: full MIDI messages and + Running Status MIDI messages. Each is encoded differently. + A full MIDI message is simply the MIDI message with the Status byte included. + A Running Status MIDI message is a MIDI message with the Status byte omitted. Running Status + MIDI messages may only be placed in the data stream if the following criteria are met: + 1. The original MIDI message is 2 bytes or greater and is not a System Common or System + Real-Time message. + 2. The omitted Status byte matches the most recently preceding full MIDI message’s Status + byte within the same BLE packet. + In addition, the following rules apply with respect to Running Status: + 1. A Running Status MIDI message is allowed within the packet after at least one full MIDI + message. + 2. Every MIDI Status byte must be preceded by a timestamp byte. Running Status MIDI + messages may be preceded by a timestamp byte. If a Running Status MIDI message is not + preceded by a timestamp byte, the timestamp byte of the most recently preceding message + in the same packet is used. + 3. System Common and System Real-Time messages do not cancel Running Status if + interspersed between Running Status MIDI messages. However, a timestamp byte must + precede the Running Status MIDI message that follows. + 4. The end of a BLE packet does cancel Running Status. + In the MIDI 1.0 protocol, System Real-Time messages can be sent at any time and may be + inserted anywhere in a MIDI data stream, including between Status and Data bytes of any other + MIDI messages. In the MIDI BLE protocol, the System Real-Time messages must be deinterleaved + from other messages – except for System Exclusive messages. + */ void receive(uint8_t* buffer, size_t length) { // Pointers used to search through payload. @@ -75,13 +105,20 @@ public: case 0xA0: case 0xB0: case 0xE0: - // for (auto i = lPtr; i < rPtr; i = i + 2) - // transmitMIDIonDIN( lastStatus, buffer[i + 1], buffer[i + 2] ); + for (auto i = lPtr; i < rPtr; i = i + 2) + { + xQueueSend(_bleMidiTransport->mRxQueue, &buffer[i], portMAX_DELAY); + xQueueSend(_bleMidiTransport->mRxQueue, &buffer[i + 1], portMAX_DELAY); + xQueueSend(_bleMidiTransport->mRxQueue, &buffer[i + 2], portMAX_DELAY); + } break; case 0xC0: case 0xD0: - // for (auto i = lPtr; i < rPtr; i = i + 1) - // transmitMIDIonDIN( lastStatus, buffer[i + 1], 0 ); + for (auto i = lPtr; i < rPtr; i = i + 1) + { + xQueueSend(_bleMidiTransport->mRxQueue, &buffer[i], portMAX_DELAY); + xQueueSend(_bleMidiTransport->mRxQueue, &buffer[i + 1], portMAX_DELAY); + } break; case 0xF0: xQueueSend(_bleMidiTransport->mRxQueue, &buffer[lPtr], portMAX_DELAY);