diff --git a/examples/MidiBle/MidiBle.ino b/examples/MidiBle/MidiBle.ino index 919f9dc..7d098f3 100644 --- a/examples/MidiBle/MidiBle.ino +++ b/examples/MidiBle/MidiBle.ino @@ -1,16 +1,15 @@ #define DEBUG 4 -#include -#include +#include +#include - -typedef BLEMIDI_NAMESPACE::BleMidiTransport bleMIDI_t; -bleMIDI_t bm("Huzzah BLE MIDI"); -MIDI_NAMESPACE::MidiInterface MIDI((bleMIDI_t &)bm); +BLEMIDI_CREATE_DEFAULT_ESP32_INSTANCE() USING_NAMESPACE_BLEMIDI unsigned long t0 = millis(); +#ifdef ESP32 bool isConnected = false; +#endif // ----------------------------------------------------------------------------- // diff --git a/src/BLE-MIDI.cpp b/src/BLE-MIDI.cpp new file mode 100755 index 0000000..3ba251c --- /dev/null +++ b/src/BLE-MIDI.cpp @@ -0,0 +1 @@ +#include "BLE-MIDI.h" diff --git a/src/BLE-MIDI.h b/src/BLE-MIDI.h new file mode 100755 index 0000000..2f7317a --- /dev/null +++ b/src/BLE-MIDI.h @@ -0,0 +1,314 @@ +/*! + * @file BLEMIDI.h + */ + +#pragma once + +#include "utility/Logging.h" + +#include +using namespace MIDI_NAMESPACE; + +#include "BLE-MIDI_Settings.h" +#include "BLE-MIDI_Defs.h" +#include "BLE-MIDI_Namespace.h" + +BEGIN_BLEMIDI_NAMESPACE + +template +class BLEMIDI +{ + typedef _Settings Settings; + +private: + byte mRxBuffer[Settings::MaxBufferSize]; + unsigned mRxIndex = 0; + + byte mTxBuffer[Settings::MaxBufferSize]; + unsigned mTxIndex = 0; + + char mDeviceName[24]; + +private: + T mBleClass; + +public: + BLEMIDI(const char* deviceName) + { + strncpy(mDeviceName, deviceName, 24); + + mRxIndex = 0; + mTxIndex = 0; + } + + void begin(MIDI_NAMESPACE::Channel inChannel = 1) + { + mBleClass.begin(mDeviceName, this); + } + + bool beginTransmission(MidiType) + { + getMidiTimestamp(&mTxBuffer[0], &mTxBuffer[1]); + mTxIndex = 2; + + return true; + } + + void write(byte inData) + { + // check for size! SysEx!!! + if (false) + { + // should only happen from SysEx! + // if we approach the end of the buffer, chop-up in segments until + // we reach F7 (end of SysEx) + } + + mTxBuffer[mTxIndex++] = inData; + } + + void endTransmission() + { + mBleClass.write(mTxBuffer, mTxIndex); + mTxIndex = 0; + } + + unsigned available() + { + return mRxIndex; + } + + byte read() + { + return mRxBuffer[--mRxIndex]; + } + +private: + void reverse(byte arr[], int n) + { + for (int low = 0, high = n - 1; low < high; low++, high--) + { + int temp = arr[low]; + arr[low] = arr[high]; + arr[high] = temp; + } + } + +public: + /* + 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. + + Header Byte + bit 7 Set to 1. + bit 6 Set to 0. (Reserved for future use) + bits 5-0 timestampHigh:Most significant 6 bits of timestamp information. + The header byte contains the topmost 6 bits of timing information for MIDI events in the BLE + packet. The remaining 7 bits of timing information for individual MIDI messages encoded in a + packet is expressed by timestamp bytes. + + Timestamp Byte + bit 7 Set to 1. + bits 6-0 timestampLow: Least Significant 7 bits of timestamp information. + + The 13-bit timestamp for the first MIDI message in a packet is calculated using 6 bits from the + header byte and 7 bits from the timestamp byte. + + Timestamps are 13-bit values in milliseconds, and therefore the maximum value is 8,191 ms. + Timestamps must be issued by the sender in a monotonically increasing fashion. + timestampHigh is initially set using the lower 6 bits from the header byte while the timestampLow is + formed of the lower 7 bits from the timestamp byte. Should the timestamp value of a subsequent + MIDI message in the same packet overflow/wrap (i.e., the timestampLow is smaller than a + preceding timestampLow), the receiver is responsible for tracking this by incrementing the + timestampHigh by one (the incremented value is not transmitted, only understood as a result of the + overflow condition). + + In practice, the time difference between MIDI messages in the same BLE packet should not span + more than twice the connection interval. As a result, a maximum of one overflow/wrap may occur + per BLE packet. + + Timestamps are in the sender’s clock domain and are not allowed to be scheduled in the future. + Correlation between the receiver’s clock and the received timestamps must be performed to + ensure accurate rendering of MIDI messages, and is not addressed in this document. + */ + + /* + Calculating a Timestamp + To calculate the timestamp, the built-in millis() is used. + The BLE standard only specifies 13 bits worth of millisecond data though, + so it’s bitwise anded with 0x1FFF for an ever repeating cycle of 13 bits. + This is done right after a MIDI message is detected. It’s split into a 6 upper bits, 7 lower bits, + and the MSB of both bytes are set to indicate that this is a header byte. + Both bytes are placed into the first two position of an array in preparation for a MIDI message. + */ + static void getMidiTimestamp (uint8_t *header, uint8_t *timestamp) + { + auto currentTimeStamp = millis() & 0x01FFF; + + *header = ((currentTimeStamp >> 7) & 0x3F) | 0x80; // 6 bits plus MSB + *timestamp = (currentTimeStamp & 0x7F) | 0x80; // 7 bits plus MSB + } + + static void setMidiTimestamp (uint8_t header, uint8_t *timestamp) + { + } + +public: + // callbacks + void(*_connectedCallback)() = nullptr; + void(*_disconnectedCallback)() = nullptr; + +public: + void onConnected(void(*fptr)()) { + _connectedCallback = fptr; + } + + void onDisconnected(void(*fptr)()) { + _disconnectedCallback = fptr; + } + +}; + +END_BLEMIDI_NAMESPACE diff --git a/src/BLE-MIDI_Defs.h b/src/BLE-MIDI_Defs.h new file mode 100755 index 0000000..5fd8056 --- /dev/null +++ b/src/BLE-MIDI_Defs.h @@ -0,0 +1,38 @@ +#pragma once + +#include "BLE-MIDI_Namespace.h" + +// As specified in +// Specification for MIDI over Bluetooth Low Energy (BLE-MIDI) +// Version 1.0a, NOvember 1, 2015 +// 3. BLE Service and Characteristics Definitions +#define SERVICE_UUID "03b80e5a-ede8-4b33-a751-6ce34ec4c700" +#define CHARACTERISTIC_UUID "7772e5db-3868-4112-a1a9-f2669d106bf3" + +#if ARDUINO +#include +#else +#include +typedef uint8_t byte; +#endif + +BEGIN_BLEMIDI_NAMESPACE + +/*! \brief Create an instance of the library + */ +#define BLEMIDI_CREATE_INSTANCE(Type, DeviceName, Name) \ +typedef BLEMIDI_NAMESPACE::BLEMIDI BLEMIDI_t; \ +BLEMIDI_t Name(DeviceName); \ +MIDI_NAMESPACE::MidiInterface MIDI((BLEMIDI_t &)Name); + +/*! \brief Create an instance for ESP32 named +*/ +#define BLEMIDI_CREATE_ESP32_INSTANCE(DeviceName) \ +BLEMIDI_CREATE_INSTANCE(BLEMIDI_NAMESPACE::BLEMIDI_ESP32, DeviceName, bm); + +/*! \brief Create a default instance for ESP32 named BLE-MIDI +*/ +#define BLEMIDI_CREATE_DEFAULT_ESP32_INSTANCE() \ +BLEMIDI_CREATE_ESP32_INSTANCE("BLE-MIDI") + +END_BLEMIDI_NAMESPACE diff --git a/src/midi_bleNamespace.h b/src/BLE-MIDI_Namespace.h similarity index 100% rename from src/midi_bleNamespace.h rename to src/BLE-MIDI_Namespace.h diff --git a/src/BLE-MIDI_Settings.h b/src/BLE-MIDI_Settings.h new file mode 100755 index 0000000..581cac5 --- /dev/null +++ b/src/BLE-MIDI_Settings.h @@ -0,0 +1,12 @@ +#pragma once + +#include "BLE-MIDI_Namespace.h" + +BEGIN_BLEMIDI_NAMESPACE + +struct DefaultSettings +{ + static const size_t MaxBufferSize = 64; +}; + +END_BLEMIDI_NAMESPACE diff --git a/src/Ble_esp32.h b/src/hardware/BLE-MIDI_ESP32.h similarity index 74% rename from src/Ble_esp32.h rename to src/hardware/BLE-MIDI_ESP32.h index 95a0678..815d172 100755 --- a/src/Ble_esp32.h +++ b/src/hardware/BLE-MIDI_ESP32.h @@ -8,43 +8,40 @@ BEGIN_BLEMIDI_NAMESPACE -#define SERVICE_UUID "03b80e5a-ede8-4b33-a751-6ce34ec4c700" -#define CHARACTERISTIC_UUID "7772e5db-3868-4112-a1a9-f2669d106bf3" - -class BluetoothEsp32 +class BLEMIDI_ESP32 { private: BLEServer* _server = nullptr; BLEAdvertising* _advertising = nullptr; BLECharacteristic* _characteristic = nullptr; - BleMidiTransport* _bleMidiTransport = nullptr; + BLEMIDI* _bleMidiTransport = nullptr; public: - BluetoothEsp32() + BLEMIDI_ESP32() { } - bool begin(const char*, BleMidiTransport*); + bool begin(const char*, BLEMIDI*); - inline void write(uint8_t* data, uint8_t length) + void write(uint8_t* data, uint8_t length) { _characteristic->setValue(data, length); _characteristic->notify(); } - inline void receive(uint8_t* buffer, uint8_t length) + void receive(uint8_t* buffer, uint8_t length) { _bleMidiTransport->receive(buffer, length); } - inline void connected() + void connected() { if (_bleMidiTransport->_connectedCallback) _bleMidiTransport->_connectedCallback(); } - inline void disconnected() + void disconnected() { if (_bleMidiTransport->_disconnectedCallback) _bleMidiTransport->_disconnectedCallback(); @@ -53,12 +50,12 @@ public: class MyServerCallbacks: public BLEServerCallbacks { public: - MyServerCallbacks(BluetoothEsp32* bluetoothEsp32) + MyServerCallbacks(BLEMIDI_ESP32* bluetoothEsp32) : _bluetoothEsp32(bluetoothEsp32) { } protected: - BluetoothEsp32* _bluetoothEsp32 = nullptr; + BLEMIDI_ESP32* _bluetoothEsp32 = nullptr; void onConnect(BLEServer* server) { _bluetoothEsp32->connected(); @@ -71,22 +68,22 @@ protected: class MyCharacteristicCallbacks: public BLECharacteristicCallbacks { public: - MyCharacteristicCallbacks(BluetoothEsp32* bluetoothEsp32) + MyCharacteristicCallbacks(BLEMIDI_ESP32* bluetoothEsp32) : _bluetoothEsp32(bluetoothEsp32 ) { } protected: - BluetoothEsp32* _bluetoothEsp32 = nullptr; + BLEMIDI_ESP32* _bluetoothEsp32 = nullptr; void onWrite(BLECharacteristic * characteristic) { std::string rxValue = characteristic->getValue(); - if (rxValue.length() > 2) { + if (rxValue.length() > 0) { _bluetoothEsp32->receive((uint8_t *)(rxValue.c_str()), rxValue.length()); } } }; -bool BluetoothEsp32::begin(const char* deviceName, BleMidiTransport* bleMidiTransport) +bool BLEMIDI_ESP32::begin(const char* deviceName, BLEMIDI* bleMidiTransport) { _bleMidiTransport = bleMidiTransport; diff --git a/src/midi_bleDefs.h b/src/midi_bleDefs.h deleted file mode 100755 index 1f0b965..0000000 --- a/src/midi_bleDefs.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include "midi_bleNamespace.h" - -#if ARDUINO -#include -#else -#include -typedef uint8_t byte; -#endif - -BEGIN_BLEMIDI_NAMESPACE - -#define BleBuffer_t Deque - -/*! \brief Create an instance of the library - */ -#define BLEMIDI_CREATE_INSTANCE(Type, Name) \ - BLEMIDI_NAMESPACE::BleMidiTransport Name((Type&)SerialPort); - - -/*! \brief -*/ -#define BLEMIDI_CREATE_DEFAULT_INSTANCE() \ - BLEMIDI_CREATE_INSTANCE(bm); - -END_BLEMIDI_NAMESPACE diff --git a/src/midi_bleSettings.h b/src/midi_bleSettings.h deleted file mode 100755 index 8771a06..0000000 --- a/src/midi_bleSettings.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -#include "midi_bleNamespace.h" diff --git a/src/midi_bleTransport.cpp b/src/midi_bleTransport.cpp deleted file mode 100755 index fef6562..0000000 --- a/src/midi_bleTransport.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "midi_bleTransport.h" diff --git a/src/midi_bleTransport.h b/src/midi_bleTransport.h deleted file mode 100755 index 3622996..0000000 --- a/src/midi_bleTransport.h +++ /dev/null @@ -1,158 +0,0 @@ -/*! - * @file midi_bleTransport.h - */ - -#pragma once - -#include "utility/midi_feat4_4_0/MIDI.h" - -#include "utility/Logging.h" - -#include "midi_bleSettings.h" -#include "midi_bleDefs.h" - -#include "utility/Deque.h" - -BEGIN_BLEMIDI_NAMESPACE - -template -class BleMidiTransport -{ -private: - byte mRxBuffer[44]; - unsigned mRxIndex = 0; - - byte mTxBuffer[44]; - unsigned mTxIndex = 0; - - char mDeviceName[24]; - -private: - BleClass mBleClass; - -public: - BleMidiTransport(const char* deviceName) - { - strncpy(mDeviceName, deviceName, 24); - - mRxIndex = 0; - mTxIndex = 0; - } - - void begin(MIDI_NAMESPACE::Channel inChannel = 1) - { - mBleClass.begin(mDeviceName, this); - } - - bool beginTransmission() - { - getMidiTimestamp(&mTxBuffer[0], &mTxBuffer[1]); - mTxIndex = 2; - - return true; - } - - void write(byte inData) - { - // check for size! SysEx!!! - if (false) - { - // should only happen from SysEx! - // if we approach the end of the buffer, chop-up in segments until - // we reach F7 (end of SysEx) - } - - mTxBuffer[mTxIndex++] = inData; - } - - void endTransmission() - { - mBleClass.write(mTxBuffer, mTxIndex); - mTxIndex = 0; - } - - unsigned available() - { - return mRxIndex; - } - - byte read() - { - return mRxBuffer[--mRxIndex]; - } - -public: - void receive(uint8_t* buffer, uint8_t length) - { - // drop the first 2 bytes - - for (int i = 2; i < length; i++) - mRxBuffer[length - i - 1] = buffer[i]; - - mRxIndex = (length - 2); - } - -protected: - /* - The first byte of all BLE packets must be a header byte. This is followed by timestamp bytes and MIDI messages. - Header Byte - bit 7 Set to 1. - bit 6 Set to 0. (Reserved for future use) - bits 5-0 timestampHigh:Most significant 6 bits of timestamp information. - The header byte contains the topmost 6 bits of timing information for MIDI events in the BLE - packet. The remaining 7 bits of timing information for individual MIDI messages encoded in a - packet is expressed by timestamp bytes. - Timestamp Byte - bit 7 Set to 1. - bits 6-0 timestampLow: Least Significant 7 bits of timestamp information. - The 13-bit timestamp for the first MIDI message in a packet is calculated using 6 bits from the - header byte and 7 bits from the timestamp byte. - Timestamps are 13-bit values in milliseconds, and therefore the maximum value is 8,191 ms. - Timestamps must be issued by the sender in a monotonically increasing fashion. - timestampHigh is initially set using the lower 6 bits from the header byte while the timestampLow is - formed of the lower 7 bits from the timestamp byte. Should the timestamp value of a subsequent - MIDI message in the same packet overflow/wrap (i.e., the timestampLow is smaller than a - preceding timestampLow), the receiver is responsible for tracking this by incrementing the - timestampHigh by one (the incremented value is not transmitted, only understood as a result of the - overflow condition). - In practice, the time difference between MIDI messages in the same BLE packet should not span - more than twice the connection interval. As a result, a maximum of one overflow/wrap may occur - per BLE packet. - Timestamps are in the sender’s clock domain and are not allowed to be scheduled in the future. - Correlation between the receiver’s clock and the received timestamps must be performed to - ensure accurate rendering of MIDI messages, and is not addressed in this document. - */ - /* - Calculating a Timestamp - To calculate the timestamp, the built-in millis() is used. - The BLE standard only specifies 13 bits worth of millisecond data though, - so it’s bitwise anded with 0x1FFF for an ever repeating cycle of 13 bits. - This is done right after a MIDI message is detected. It’s split into a 6 upper bits, 7 lower bits, - and the MSB of both bytes are set to indicate that this is a header byte. - Both bytes are placed into the first two position of an array in preparation for a MIDI message. - */ - inline static void getMidiTimestamp (uint8_t *header, uint8_t *timestamp) - { - auto currentTimeStamp = millis() & 0x01FFF; - - *header = ((currentTimeStamp >> 7) & 0x3F) | 0x80; // 6 bits plus MSB - *timestamp = (currentTimeStamp & 0x7F) | 0x80; // 7 bits plus MSB - } - -public: - // callbacks - void(*_connectedCallback)() = nullptr; - void(*_disconnectedCallback)() = nullptr; - -public: - void onConnected(void(*fptr)()) { - _connectedCallback = fptr; - } - - void onDisconnected(void(*fptr)()) { - _disconnectedCallback = fptr; - } - -}; - -END_BLEMIDI_NAMESPACE diff --git a/src/utility/endian.h b/src/utility/endian.h deleted file mode 100644 index 0f9271c..0000000 --- a/src/utility/endian.h +++ /dev/null @@ -1,139 +0,0 @@ -#pragma once - -#ifndef BYTE_ORDER - -#ifndef BIG_ENDIAN -#define BIG_ENDIAN 4321 -#endif -#ifndef LITTLE_ENDIAN -#define LITTLE_ENDIAN 1234 -#endif - -#define TEST_LITTLE_ENDIAN (((union { unsigned x; unsigned char c; }){1}).c) - -#ifdef TEST_LITTLE_ENDIAN -#define BYTE_ORDER LITTLE_ENDIAN -#else -#define BYTE_ORDER BIG_ENDIAN -#endif - -#undef TEST_LITTLE_ENDIAN -#endif - -#include - -#ifndef __bswap16 -#define __bswap16(x) ((uint16_t)((((uint16_t)(x)&0xff00) >> 8) | (((uint16_t)(x)&0x00ff) << 8))) -#endif - -#ifndef __bswap32 -#define __bswap32(x) \ - ((uint32_t)((((uint32_t)(x)&0xff000000) >> 24) | (((uint32_t)(x)&0x00ff0000) >> 8) | \ - (((uint32_t)(x)&0x0000ff00) << 8) | (((uint32_t)(x)&0x000000ff) << 24))) -#endif - -#ifndef __bswap64 -#define __bswap64(x) \ - ((uint64_t)((((uint64_t)(x)&0xff00000000000000ULL) >> 56) | \ - (((uint64_t)(x)&0x00ff000000000000ULL) >> 40) | \ - (((uint64_t)(x)&0x0000ff0000000000ULL) >> 24) | \ - (((uint64_t)(x)&0x000000ff00000000ULL) >> 8) | \ - (((uint64_t)(x)&0x00000000ff000000ULL) << 8) | \ - (((uint64_t)(x)&0x0000000000ff0000ULL) << 24) | \ - (((uint64_t)(x)&0x000000000000ff00ULL) << 40) | \ - (((uint64_t)(x)&0x00000000000000ffULL) << 56))) -#endif - -union conversionBuffer -{ - uint8_t value8; - uint16_t value16; - uint32_t value32; - uint64_t value64; - byte buffer[8]; -}; - -#if BYTE_ORDER == LITTLE_ENDIAN - -// Definitions from musl libc -#define htobe16(x) __bswap16(x) -#define be16toh(x) __bswap16(x) -#define betoh16(x) __bswap16(x) -#define htobe32(x) __bswap32(x) -#define be32toh(x) __bswap32(x) -#define betoh32(x) __bswap32(x) -#define htobe64(x) __bswap64(x) -#define be64toh(x) __bswap64(x) -#define betoh64(x) __bswap64(x) -#define htole16(x) (uint16_t)(x) -#define le16toh(x) (uint16_t)(x) -#define letoh16(x) (uint16_t)(x) -#define htole32(x) (uint32_t)(x) -#define le32toh(x) (uint32_t)(x) -#define letoh32(x) (uint32_t)(x) -#define htole64(x) (uint64_t)(x) -#define le64toh(x) (uint64_t)(x) -#define letoh64(x) (uint64_t)(x) - -// From Apple Open Source Libc -#define ntohs(x) __bswap16(x) -#define htons(x) __bswap16(x) -#define ntohl(x) __bswap32(x) -#define htonl(x) __bswap32(x) -#define ntohll(x) __bswap64(x) -#define htonll(x) __bswap64(x) - -#define NTOHL(x) (x) = ntohl((uint32_t)x) -#define NTOHS(x) (x) = ntohs((uint16_t)x) -#define NTOHLL(x) (x) = ntohll((uint64_t)x) -#define HTONL(x) (x) = htonl((uint32_t)x) -#define HTONS(x) (x) = htons((uint16_t)x) -#define HTONLL(x) (x) = htonll((uint64_t)x) - -#else // BIG_ENDIAN - -// Definitions from musl libc - -#define htobe16(x) (uint16_t)(x) -#define be16toh(x) (uint16_t)(x) -#define betoh16(x) (uint16_t)(x) -#define htobe32(x) (uint32_t)(x) -#define be32toh(x) (uint32_t)(x) -#define betoh32(x) (uint32_t)(x) -#define htobe64(x) (uint64_t)(x) -#define be64toh(x) (uint64_t)(x) -#define betoh64(x) (uint64_t)(x) -#define htole16(x) __bswap16(x) -#define le16toh(x) __bswap16(x) -#define letoh16(x) __bswap16(x) -#define htole32(x) __bswap32(x) -#define le32toh(x) __bswap32(x) -#define letoh32(x) __bswap32(x) -#define htole64(x) __bswap64(x) -#define le64toh(x) __bswap64(x) -#define letoh64(x) __bswap64(x) - -// From Apple Open Source libc -#define ntohl(x) ((uint32_t)(x)) -#define ntohs(x) ((uint16_t)(x)) -#define htonl(x) ((uint32_t)(x)) -#define htons(x) ((uint16_t)(x)) -#define ntohll(x) ((uint64_t)(x)) -#define htonll(x) ((uint64_t)(x)) - -#define NTOHL(x) (x) -#define NTOHS(x) (x) -#define NTOHLL(x) (x) -#define HTONL(x) (x) -#define HTONS(x) (x) -#define HTONLL(x) (x) - - -void aa(uint64_t value) -{ - if ( value >= 10 ) - aa(value / 10); - N_DEBUG_PRINT((uint32_t)(value % 10)); -} - -#endif diff --git a/src/utility/midi_feat4_4_0/MIDI.cpp b/src/utility/midi_feat4_4_0/MIDI.cpp deleted file mode 100644 index 6d9b6a7..0000000 --- a/src/utility/midi_feat4_4_0/MIDI.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/*! - * @file MIDI.cpp - * Project Arduino MIDI Library - * @brief MIDI Library for the Arduino - * @author Francois Best - * @date 24/02/11 - * @license MIT - Copyright (c) 2015 Francois Best - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "MIDI.h" - -// ----------------------------------------------------------------------------- - -BEGIN_MIDI_NAMESPACE - -/*! \brief Encode System Exclusive messages. - SysEx messages are encoded to guarantee transmission of data bytes higher than - 127 without breaking the MIDI protocol. Use this static method to convert the - data you want to send. - \param inData The data to encode. - \param outSysEx The output buffer where to store the encoded message. - \param inLength The lenght of the input buffer. - \param inFlipHeaderBits True for Korg and other who store MSB in reverse order - \return The lenght of the encoded output buffer. - @see decodeSysEx - Code inspired from Ruin & Wesen's SysEx encoder/decoder - http://ruinwesen.com - */ -unsigned encodeSysEx(const byte* inData, - byte* outSysEx, - unsigned inLength, - bool inFlipHeaderBits) -{ - unsigned outLength = 0; // Num bytes in output array. - byte count = 0; // Num 7bytes in a block. - outSysEx[0] = 0; - - for (unsigned i = 0; i < inLength; ++i) - { - const byte data = inData[i]; - const byte msb = data >> 7; - const byte body = data & 0x7f; - - outSysEx[0] |= (msb << (inFlipHeaderBits ? count : (6 - count))); - outSysEx[1 + count] = body; - - if (count++ == 6) - { - outSysEx += 8; - outLength += 8; - outSysEx[0] = 0; - count = 0; - } - } - return outLength + count + (count != 0 ? 1 : 0); -} - -/*! \brief Decode System Exclusive messages. - SysEx messages are encoded to guarantee transmission of data bytes higher than - 127 without breaking the MIDI protocol. Use this static method to reassemble - your received message. - \param inSysEx The SysEx data received from MIDI in. - \param outData The output buffer where to store the decrypted message. - \param inLength The lenght of the input buffer. - \param inFlipHeaderBits True for Korg and other who store MSB in reverse order - \return The lenght of the output buffer. - @see encodeSysEx @see getSysExArrayLength - Code inspired from Ruin & Wesen's SysEx encoder/decoder - http://ruinwesen.com - */ -unsigned decodeSysEx(const byte* inSysEx, - byte* outData, - unsigned inLength, - bool inFlipHeaderBits) -{ - unsigned count = 0; - byte msbStorage = 0; - byte byteIndex = 0; - - for (unsigned i = 0; i < inLength; ++i) - { - if ((i % 8) == 0) - { - msbStorage = inSysEx[i]; - byteIndex = 6; - } - else - { - const byte body = inSysEx[i]; - const byte shift = inFlipHeaderBits ? 6 - byteIndex : byteIndex; - const byte msb = byte(((msbStorage >> shift) & 1) << 7); - byteIndex--; - outData[count++] = msb | body; - } - } - return count; -} - -END_MIDI_NAMESPACE diff --git a/src/utility/midi_feat4_4_0/MIDI.h b/src/utility/midi_feat4_4_0/MIDI.h deleted file mode 100644 index 9edc8ee..0000000 --- a/src/utility/midi_feat4_4_0/MIDI.h +++ /dev/null @@ -1,266 +0,0 @@ -/*! - * @file MIDI.h - * Project Arduino MIDI Library - * @brief MIDI Library for the Arduino - * @author Francois Best - * @date 24/02/11 - * @license MIT - Copyright (c) 2015 Francois Best - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#pragma once - -#include "midi_Defs.h" -#include "midi_Settings.h" -#include "midi_Message.h" - -// ----------------------------------------------------------------------------- - -BEGIN_MIDI_NAMESPACE - -/*! \brief The main class for MIDI handling. -It is templated over the type of serial port to provide abstraction from -the hardware interface, meaning you can use HardwareSerial, SoftwareSerial -or ak47's Uart classes. The only requirement is that the class implements -the begin, read, write and available methods. - */ -template -class MidiInterface -{ -public: - typedef _Settings Settings; - -public: - inline MidiInterface(Encoder&); - inline ~MidiInterface(); - -public: - void begin(Channel inChannel = 1); - - // ------------------------------------------------------------------------- - // MIDI Output - -public: - inline void sendNoteOn(DataByte inNoteNumber, - DataByte inVelocity, - Channel inChannel); - - inline void sendNoteOff(DataByte inNoteNumber, - DataByte inVelocity, - Channel inChannel); - - inline void sendProgramChange(DataByte inProgramNumber, - Channel inChannel); - - inline void sendControlChange(DataByte inControlNumber, - DataByte inControlValue, - Channel inChannel); - - inline void sendPitchBend(int inPitchValue, Channel inChannel); - inline void sendPitchBend(double inPitchValue, Channel inChannel); - - inline void sendPolyPressure(DataByte inNoteNumber, - DataByte inPressure, - Channel inChannel) __attribute__ ((deprecated)); - - inline void sendAfterTouch(DataByte inPressure, - Channel inChannel); - inline void sendAfterTouch(DataByte inNoteNumber, - DataByte inPressure, - Channel inChannel); - - inline void sendSysEx(unsigned inLength, - const byte* inArray, - bool inArrayContainsBoundaries = false); - - inline void sendTimeCodeQuarterFrame(DataByte inTypeNibble, - DataByte inValuesNibble); - inline void sendTimeCodeQuarterFrame(DataByte inData); - - inline void sendSongPosition(unsigned inBeats); - inline void sendSongSelect(DataByte inSongNumber); - inline void sendTuneRequest(); - inline void sendRealTime(MidiType inType); - - inline void beginRpn(unsigned inNumber, - Channel inChannel); - inline void sendRpnValue(unsigned inValue, - Channel inChannel); - inline void sendRpnValue(byte inMsb, - byte inLsb, - Channel inChannel); - inline void sendRpnIncrement(byte inAmount, - Channel inChannel); - inline void sendRpnDecrement(byte inAmount, - Channel inChannel); - inline void endRpn(Channel inChannel); - - inline void beginNrpn(unsigned inNumber, - Channel inChannel); - inline void sendNrpnValue(unsigned inValue, - Channel inChannel); - inline void sendNrpnValue(byte inMsb, - byte inLsb, - Channel inChannel); - inline void sendNrpnIncrement(byte inAmount, - Channel inChannel); - inline void sendNrpnDecrement(byte inAmount, - Channel inChannel); - inline void endNrpn(Channel inChannel); - -public: - void send(MidiType inType, - DataByte inData1, - DataByte inData2, - Channel inChannel); - - // ------------------------------------------------------------------------- - // MIDI Input - -public: - inline bool read(); - inline bool read(Channel inChannel); - -public: - inline MidiType getType() const; - inline Channel getChannel() const; - inline DataByte getData1() const; - inline DataByte getData2() const; - inline const byte* getSysExArray() const; - inline unsigned getSysExArrayLength() const; - inline bool check() const; - -public: - inline Channel getInputChannel() const; - inline void setInputChannel(Channel inChannel); - -public: - static inline MidiType getTypeFromStatusByte(byte inStatus); - static inline Channel getChannelFromStatusByte(byte inStatus); - static inline bool isChannelMessage(MidiType inType); - - // ------------------------------------------------------------------------- - // Input Callbacks - -public: - inline void setHandleNoteOff(void (*fptr)(byte channel, byte note, byte velocity)); - inline void setHandleNoteOn(void (*fptr)(byte channel, byte note, byte velocity)); - inline void setHandleAfterTouchPoly(void (*fptr)(byte channel, byte note, byte pressure)); - inline void setHandleControlChange(void (*fptr)(byte channel, byte number, byte value)); - inline void setHandleProgramChange(void (*fptr)(byte channel, byte number)); - inline void setHandleAfterTouchChannel(void (*fptr)(byte channel, byte pressure)); - inline void setHandlePitchBend(void (*fptr)(byte channel, int bend)); - inline void setHandleSystemExclusive(void (*fptr)(byte * array, unsigned size)); - inline void setHandleTimeCodeQuarterFrame(void (*fptr)(byte data)); - inline void setHandleSongPosition(void (*fptr)(unsigned beats)); - inline void setHandleSongSelect(void (*fptr)(byte songnumber)); - inline void setHandleTuneRequest(void (*fptr)(void)); - inline void setHandleClock(void (*fptr)(void)); - inline void setHandleStart(void (*fptr)(void)); - inline void setHandleContinue(void (*fptr)(void)); - inline void setHandleStop(void (*fptr)(void)); - inline void setHandleActiveSensing(void (*fptr)(void)); - inline void setHandleSystemReset(void (*fptr)(void)); - - inline void disconnectCallbackFromType(MidiType inType); - -private: - void launchCallback(); - - void (*mNoteOffCallback)(byte channel, byte note, byte velocity); - void (*mNoteOnCallback)(byte channel, byte note, byte velocity); - void (*mAfterTouchPolyCallback)(byte channel, byte note, byte velocity); - void (*mControlChangeCallback)(byte channel, byte, byte); - void (*mProgramChangeCallback)(byte channel, byte); - void (*mAfterTouchChannelCallback)(byte channel, byte); - void (*mPitchBendCallback)(byte channel, int); - void (*mSystemExclusiveCallback)(byte * array, unsigned size); - void (*mTimeCodeQuarterFrameCallback)(byte data); - void (*mSongPositionCallback)(unsigned beats); - void (*mSongSelectCallback)(byte songnumber); - void (*mTuneRequestCallback)(void); - void (*mClockCallback)(void); - void (*mStartCallback)(void); - void (*mContinueCallback)(void); - void (*mStopCallback)(void); - void (*mActiveSensingCallback)(void); - void (*mSystemResetCallback)(void); - - // ------------------------------------------------------------------------- - // MIDI Soft Thru - -public: - inline Thru::Mode getFilterMode() const; - inline bool getThruState() const; - - inline void turnThruOn(Thru::Mode inThruFilterMode = Thru::Full); - inline void turnThruOff(); - inline void setThruFilterMode(Thru::Mode inThruFilterMode); - -private: - void thruFilter(byte inChannel); - -private: - bool parse(); - inline void handleNullVelocityNoteOnAsNoteOff(); - inline bool inputFilter(Channel inChannel); - inline void resetInput(); - -private: - typedef Message MidiMessage; - -private: - Encoder& mEncoder; - -private: - Channel mInputChannel; - StatusByte mRunningStatus_RX; - StatusByte mRunningStatus_TX; - byte mPendingMessage[3]; - unsigned mPendingMessageExpectedLenght; - unsigned mPendingMessageIndex; - unsigned mCurrentRpnNumber; - unsigned mCurrentNrpnNumber; - bool mThruActivated : 1; - Thru::Mode mThruFilterMode : 7; - MidiMessage mMessage; - - unsigned long mLastMessageSentTime; - bool mSenderActiveSensingActivated; - -private: - inline StatusByte getStatus(MidiType inType, - Channel inChannel) const; -}; - -// ----------------------------------------------------------------------------- - -unsigned encodeSysEx(const byte* inData, - byte* outSysEx, - unsigned inLenght, - bool inFlipHeaderBits = false); -unsigned decodeSysEx(const byte* inSysEx, - byte* outData, - unsigned inLenght, - bool inFlipHeaderBits = false); - -END_MIDI_NAMESPACE - -#include "MIDI.hpp" diff --git a/src/utility/midi_feat4_4_0/MIDI.hpp b/src/utility/midi_feat4_4_0/MIDI.hpp deleted file mode 100644 index 1a53659..0000000 --- a/src/utility/midi_feat4_4_0/MIDI.hpp +++ /dev/null @@ -1,1428 +0,0 @@ -/*! - * @file MIDI.hpp - * Project Arduino MIDI Library - * @brief MIDI Library for the Arduino - Inline implementations - * @author Francois Best - * @date 24/02/11 - * @license MIT - Copyright (c) 2015 Francois Best - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#pragma once - -BEGIN_MIDI_NAMESPACE - -/// \brief Constructor for MidiInterface. -template -inline MidiInterface::MidiInterface(Encoder& inEncoder) - : mEncoder(inEncoder) - , mInputChannel(0) - , mRunningStatus_RX(InvalidType) - , mRunningStatus_TX(InvalidType) - , mPendingMessageExpectedLenght(0) - , mPendingMessageIndex(0) - , mCurrentRpnNumber(0xffff) - , mCurrentNrpnNumber(0xffff) - , mLastMessageSentTime(0) - , mSenderActiveSensingActivated(false) - , mThruActivated(false) - , mThruFilterMode(Thru::Full) -{ - mNoteOffCallback = 0; - mNoteOnCallback = 0; - mAfterTouchPolyCallback = 0; - mControlChangeCallback = 0; - mProgramChangeCallback = 0; - mAfterTouchChannelCallback = 0; - mPitchBendCallback = 0; - mSystemExclusiveCallback = 0; - mTimeCodeQuarterFrameCallback = 0; - mSongPositionCallback = 0; - mSongSelectCallback = 0; - mTuneRequestCallback = 0; - mClockCallback = 0; - mStartCallback = 0; - mContinueCallback = 0; - mStopCallback = 0; - mActiveSensingCallback = 0; - mSystemResetCallback = 0; -} - -/*! \brief Destructor for MidiInterface. - - This is not really useful for the Arduino, as it is never called... - */ -template -inline MidiInterface::~MidiInterface() -{ -} - -// ----------------------------------------------------------------------------- - -/*! \brief Call the begin method in the setup() function of the Arduino. - - All parameters are set to their default values: - - Input channel set to 1 if no value is specified - - Full thru mirroring - */ -template -void MidiInterface::begin(Channel inChannel) -{ - // Initialise the Serial port - mEncoder.begin(); - - mInputChannel = inChannel; - mRunningStatus_TX = InvalidType; - mRunningStatus_RX = InvalidType; - - mPendingMessageIndex = 0; - mPendingMessageExpectedLenght = 0; - - mCurrentRpnNumber = 0xffff; - mCurrentNrpnNumber = 0xffff; - - mSenderActiveSensingActivated = Settings::UseSenderActiveSensing; - mLastMessageSentTime = millis(); - - mMessage.valid = false; - mMessage.type = InvalidType; - mMessage.channel = 0; - mMessage.data1 = 0; - mMessage.data2 = 0; - - mThruFilterMode = Thru::Full; - mThruActivated = false; -} - -// ----------------------------------------------------------------------------- -// Output -// ----------------------------------------------------------------------------- - -/*! \addtogroup output - @{ - */ - -/*! \brief Generate and send a MIDI message from the values given. - \param inType The message type (see type defines for reference) - \param inData1 The first data byte. - \param inData2 The second data byte (if the message contains only 1 data byte, - set this one to 0). - \param inChannel The output channel on which the message will be sent - (values from 1 to 16). Note: you cannot send to OMNI. - - This is an internal method, use it only if you need to send raw data - from your code, at your own risks. - */ -template -void MidiInterface::send(MidiType inType, - DataByte inData1, - DataByte inData2, - Channel inChannel) -{ - // Then test if channel is valid - if (inChannel >= MIDI_CHANNEL_OFF || - inChannel == MIDI_CHANNEL_OMNI || - inType < 0x80) - { - return; // Don't send anything - } - - if (inType <= PitchBend) // Channel messages - { - // Protection: remove MSBs on data - inData1 &= 0x7f; - inData2 &= 0x7f; - - const StatusByte status = getStatus(inType, inChannel); - - if (mEncoder.beginTransmission()) - { - if (Settings::UseRunningStatus) - { - if (mRunningStatus_TX != status) - { - // New message, memorise and send header - mRunningStatus_TX = status; - mEncoder.write(mRunningStatus_TX); - } - } - else - { - // Don't care about running status, send the status byte. - mEncoder.write(status); - } - - // Then send data - mEncoder.write(inData1); - if (inType != ProgramChange && inType != AfterTouchChannel) - { - mEncoder.write(inData2); - } - - mEncoder.endTransmission(); - } - } - else if (inType >= Clock && inType <= SystemReset) - { - sendRealTime(inType); // System Real-time and 1 byte. - } - - if (mSenderActiveSensingActivated) - mLastMessageSentTime = millis(); -} - -// ----------------------------------------------------------------------------- - -/*! \brief Send a Note On message - \param inNoteNumber Pitch value in the MIDI format (0 to 127). - \param inVelocity Note attack velocity (0 to 127). A NoteOn with 0 velocity - is considered as a NoteOff. - \param inChannel The channel on which the message will be sent (1 to 16). - - Take a look at the values, names and frequencies of notes here: - http://www.phys.unsw.edu.au/jw/notes.html - */ -template -void MidiInterface::sendNoteOn(DataByte inNoteNumber, - DataByte inVelocity, - Channel inChannel) -{ - send(NoteOn, inNoteNumber, inVelocity, inChannel); -} - -/*! \brief Send a Note Off message - \param inNoteNumber Pitch value in the MIDI format (0 to 127). - \param inVelocity Release velocity (0 to 127). - \param inChannel The channel on which the message will be sent (1 to 16). - - Note: you can send NoteOn with zero velocity to make a NoteOff, this is based - on the Running Status principle, to avoid sending status messages and thus - sending only NoteOn data. sendNoteOff will always send a real NoteOff message. - Take a look at the values, names and frequencies of notes here: - http://www.phys.unsw.edu.au/jw/notes.html - */ -template -void MidiInterface::sendNoteOff(DataByte inNoteNumber, - DataByte inVelocity, - Channel inChannel) -{ - send(NoteOff, inNoteNumber, inVelocity, inChannel); -} - -/*! \brief Send a Program Change message - \param inProgramNumber The Program to select (0 to 127). - \param inChannel The channel on which the message will be sent (1 to 16). - */ -template -void MidiInterface::sendProgramChange(DataByte inProgramNumber, - Channel inChannel) -{ - send(ProgramChange, inProgramNumber, 0, inChannel); -} - -/*! \brief Send a Control Change message - \param inControlNumber The controller number (0 to 127). - \param inControlValue The value for the specified controller (0 to 127). - \param inChannel The channel on which the message will be sent (1 to 16). - @see MidiControlChangeNumber - */ -template -void MidiInterface::sendControlChange(DataByte inControlNumber, - DataByte inControlValue, - Channel inChannel) -{ - send(ControlChange, inControlNumber, inControlValue, inChannel); -} - -/*! \brief Send a Polyphonic AfterTouch message (applies to a specified note) - \param inNoteNumber The note to apply AfterTouch to (0 to 127). - \param inPressure The amount of AfterTouch to apply (0 to 127). - \param inChannel The channel on which the message will be sent (1 to 16). - Note: this method is deprecated and will be removed in a future revision of the - library, @see sendAfterTouch to send polyphonic and monophonic AfterTouch messages. - */ -template -void MidiInterface::sendPolyPressure(DataByte inNoteNumber, - DataByte inPressure, - Channel inChannel) -{ - send(AfterTouchPoly, inNoteNumber, inPressure, inChannel); -} - -/*! \brief Send a MonoPhonic AfterTouch message (applies to all notes) - \param inPressure The amount of AfterTouch to apply to all notes. - \param inChannel The channel on which the message will be sent (1 to 16). - */ -template -void MidiInterface::sendAfterTouch(DataByte inPressure, - Channel inChannel) -{ - send(AfterTouchChannel, inPressure, 0, inChannel); -} - -/*! \brief Send a Polyphonic AfterTouch message (applies to a specified note) - \param inNoteNumber The note to apply AfterTouch to (0 to 127). - \param inPressure The amount of AfterTouch to apply (0 to 127). - \param inChannel The channel on which the message will be sent (1 to 16). - @see Replaces sendPolyPressure (which is now deprecated). - */ -template -void MidiInterface::sendAfterTouch(DataByte inNoteNumber, - DataByte inPressure, - Channel inChannel) -{ - send(AfterTouchPoly, inNoteNumber, inPressure, inChannel); -} - -/*! \brief Send a Pitch Bend message using a signed integer value. - \param inPitchValue The amount of bend to send (in a signed integer format), - between MIDI_PITCHBEND_MIN and MIDI_PITCHBEND_MAX, - center value is 0. - \param inChannel The channel on which the message will be sent (1 to 16). - */ -template -void MidiInterface::sendPitchBend(int inPitchValue, - Channel inChannel) -{ - const unsigned bend = unsigned(inPitchValue - int(MIDI_PITCHBEND_MIN)); - send(PitchBend, (bend & 0x7f), (bend >> 7) & 0x7f, inChannel); -} - - -/*! \brief Send a Pitch Bend message using a floating point value. - \param inPitchValue The amount of bend to send (in a floating point format), - between -1.0f (maximum downwards bend) - and +1.0f (max upwards bend), center value is 0.0f. - \param inChannel The channel on which the message will be sent (1 to 16). - */ -template -void MidiInterface::sendPitchBend(double inPitchValue, - Channel inChannel) -{ - const int scale = inPitchValue > 0.0 ? MIDI_PITCHBEND_MAX : MIDI_PITCHBEND_MIN; - const int value = int(inPitchValue * double(scale)); - sendPitchBend(value, inChannel); -} - -/*! \brief Generate and send a System Exclusive frame. - \param inLength The size of the array to send - \param inArray The byte array containing the data to send - \param inArrayContainsBoundaries When set to 'true', 0xf0 & 0xf7 bytes - (start & stop SysEx) will NOT be sent - (and therefore must be included in the array). - default value for ArrayContainsBoundaries is set to 'false' for compatibility - with previous versions of the library. - */ -template -void MidiInterface::sendSysEx(unsigned inLength, - const byte* inArray, - bool inArrayContainsBoundaries) -{ - const bool writeBeginEndBytes = !inArrayContainsBoundaries; - - if (mEncoder.beginTransmission()) - { - if (writeBeginEndBytes) - mEncoder.write(0xf0); - - for (unsigned i = 0; i < inLength; ++i) - mEncoder.write(inArray[i]); - - if (writeBeginEndBytes) - mEncoder.write(0xf7); - - mEncoder.endTransmission(); - } - - if (Settings::UseRunningStatus) - { - mRunningStatus_TX = InvalidType; - } -} - -/*! \brief Send a Tune Request message. - - When a MIDI unit receives this message, - it should tune its oscillators (if equipped with any). - */ -template -void MidiInterface::sendTuneRequest() -{ - if (mEncoder.beginTransmission()) - { - mEncoder.write(TuneRequest); - mEncoder.endTransmission(); - } - - if (Settings::UseRunningStatus) - { - mRunningStatus_TX = InvalidType; - } -} - -/*! \brief Send a MIDI Time Code Quarter Frame. - - \param inTypeNibble MTC type - \param inValuesNibble MTC data - See MIDI Specification for more information. - */ -template -void MidiInterface::sendTimeCodeQuarterFrame(DataByte inTypeNibble, - DataByte inValuesNibble) -{ - const byte data = byte((((inTypeNibble & 0x07) << 4) | (inValuesNibble & 0x0f))); - sendTimeCodeQuarterFrame(data); -} - -/*! \brief Send a MIDI Time Code Quarter Frame. - - See MIDI Specification for more information. - \param inData if you want to encode directly the nibbles in your program, - you can send the byte here. - */ -template -void MidiInterface::sendTimeCodeQuarterFrame(DataByte inData) -{ - if (mEncoder.beginTransmission()) - { - mEncoder.write((byte)TimeCodeQuarterFrame); - mEncoder.write(inData); - mEncoder.endTransmission(); - } - - if (Settings::UseRunningStatus) - { - mRunningStatus_TX = InvalidType; - } -} - -/*! \brief Send a Song Position Pointer message. - \param inBeats The number of beats since the start of the song. - */ -template -void MidiInterface::sendSongPosition(unsigned inBeats) -{ - if (mEncoder.beginTransmission()) - { - mEncoder.write((byte)SongPosition); - mEncoder.write(inBeats & 0x7f); - mEncoder.write((inBeats >> 7) & 0x7f); - mEncoder.endTransmission(); - } - - if (Settings::UseRunningStatus) - { - mRunningStatus_TX = InvalidType; - } -} - -/*! \brief Send a Song Select message */ -template -void MidiInterface::sendSongSelect(DataByte inSongNumber) -{ - if (mEncoder.beginTransmission()) - { - mEncoder.write((byte)SongSelect); - mEncoder.write(inSongNumber & 0x7f); - mEncoder.endTransmission(); - } - - if (Settings::UseRunningStatus) - { - mRunningStatus_TX = InvalidType; - } -} - -/*! \brief Send a Real Time (one byte) message. - - \param inType The available Real Time types are: - Start, Stop, Continue, Clock, ActiveSensing and SystemReset. - @see MidiType - */ -template -void MidiInterface::sendRealTime(MidiType inType) -{ - // Do not invalidate Running Status for real-time messages - // as they can be interleaved within any message. - - switch (inType) - { - case Clock: - case Start: - case Stop: - case Continue: - case ActiveSensing: - case SystemReset: - if (mEncoder.beginTransmission()) - { - mEncoder.write((byte)inType); - mEncoder.endTransmission(); - } - break; - default: - // Invalid Real Time marker - break; - } -} - -/*! \brief Start a Registered Parameter Number frame. - \param inNumber The 14-bit number of the RPN you want to select. - \param inChannel The channel on which the message will be sent (1 to 16). -*/ -template -inline void MidiInterface::beginRpn(unsigned inNumber, - Channel inChannel) -{ - if (mCurrentRpnNumber != inNumber) - { - const byte numMsb = 0x7f & (inNumber >> 7); - const byte numLsb = 0x7f & inNumber; - sendControlChange(RPNLSB, numLsb, inChannel); - sendControlChange(RPNMSB, numMsb, inChannel); - mCurrentRpnNumber = inNumber; - } -} - -/*! \brief Send a 14-bit value for the currently selected RPN number. - \param inValue The 14-bit value of the selected RPN. - \param inChannel The channel on which the message will be sent (1 to 16). -*/ -template -inline void MidiInterface::sendRpnValue(unsigned inValue, - Channel inChannel) -{; - const byte valMsb = 0x7f & (inValue >> 7); - const byte valLsb = 0x7f & inValue; - sendControlChange(DataEntryMSB, valMsb, inChannel); - sendControlChange(DataEntryLSB, valLsb, inChannel); -} - -/*! \brief Send separate MSB/LSB values for the currently selected RPN number. - \param inMsb The MSB part of the value to send. Meaning depends on RPN number. - \param inLsb The LSB part of the value to send. Meaning depends on RPN number. - \param inChannel The channel on which the message will be sent (1 to 16). -*/ -template -inline void MidiInterface::sendRpnValue(byte inMsb, - byte inLsb, - Channel inChannel) -{ - sendControlChange(DataEntryMSB, inMsb, inChannel); - sendControlChange(DataEntryLSB, inLsb, inChannel); -} - -/* \brief Increment the value of the currently selected RPN number by the specified amount. - \param inAmount The amount to add to the currently selected RPN value. -*/ -template -inline void MidiInterface::sendRpnIncrement(byte inAmount, - Channel inChannel) -{ - sendControlChange(DataIncrement, inAmount, inChannel); -} - -/* \brief Decrement the value of the currently selected RPN number by the specified amount. - \param inAmount The amount to subtract to the currently selected RPN value. -*/ -template -inline void MidiInterface::sendRpnDecrement(byte inAmount, - Channel inChannel) -{ - sendControlChange(DataDecrement, inAmount, inChannel); -} - -/*! \brief Terminate an RPN frame. -This will send a Null Function to deselect the currently selected RPN. - \param inChannel The channel on which the message will be sent (1 to 16). -*/ -template -inline void MidiInterface::endRpn(Channel inChannel) -{ - sendControlChange(RPNLSB, 0x7f, inChannel); - sendControlChange(RPNMSB, 0x7f, inChannel); - mCurrentRpnNumber = 0xffff; -} - - - -/*! \brief Start a Non-Registered Parameter Number frame. - \param inNumber The 14-bit number of the NRPN you want to select. - \param inChannel The channel on which the message will be sent (1 to 16). -*/ -template -inline void MidiInterface::beginNrpn(unsigned inNumber, - Channel inChannel) -{ - if (mCurrentNrpnNumber != inNumber) - { - const byte numMsb = 0x7f & (inNumber >> 7); - const byte numLsb = 0x7f & inNumber; - sendControlChange(NRPNLSB, numLsb, inChannel); - sendControlChange(NRPNMSB, numMsb, inChannel); - mCurrentNrpnNumber = inNumber; - } -} - -/*! \brief Send a 14-bit value for the currently selected NRPN number. - \param inValue The 14-bit value of the selected NRPN. - \param inChannel The channel on which the message will be sent (1 to 16). -*/ -template -inline void MidiInterface::sendNrpnValue(unsigned inValue, - Channel inChannel) -{; - const byte valMsb = 0x7f & (inValue >> 7); - const byte valLsb = 0x7f & inValue; - sendControlChange(DataEntryMSB, valMsb, inChannel); - sendControlChange(DataEntryLSB, valLsb, inChannel); -} - -/*! \brief Send separate MSB/LSB values for the currently selected NRPN number. - \param inMsb The MSB part of the value to send. Meaning depends on NRPN number. - \param inLsb The LSB part of the value to send. Meaning depends on NRPN number. - \param inChannel The channel on which the message will be sent (1 to 16). -*/ -template -inline void MidiInterface::sendNrpnValue(byte inMsb, - byte inLsb, - Channel inChannel) -{ - sendControlChange(DataEntryMSB, inMsb, inChannel); - sendControlChange(DataEntryLSB, inLsb, inChannel); -} - -/* \brief Increment the value of the currently selected NRPN number by the specified amount. - \param inAmount The amount to add to the currently selected NRPN value. -*/ -template -inline void MidiInterface::sendNrpnIncrement(byte inAmount, - Channel inChannel) -{ - sendControlChange(DataIncrement, inAmount, inChannel); -} - -/* \brief Decrement the value of the currently selected NRPN number by the specified amount. - \param inAmount The amount to subtract to the currently selected NRPN value. -*/ -template -inline void MidiInterface::sendNrpnDecrement(byte inAmount, - Channel inChannel) -{ - sendControlChange(DataDecrement, inAmount, inChannel); -} - -/*! \brief Terminate an NRPN frame. -This will send a Null Function to deselect the currently selected NRPN. - \param inChannel The channel on which the message will be sent (1 to 16). -*/ -template -inline void MidiInterface::endNrpn(Channel inChannel) -{ - sendControlChange(NRPNLSB, 0x7f, inChannel); - sendControlChange(NRPNMSB, 0x7f, inChannel); - mCurrentNrpnNumber = 0xffff; -} - -/*! @} */ // End of doc group MIDI Output - -// ----------------------------------------------------------------------------- - -template -StatusByte MidiInterface::getStatus(MidiType inType, - Channel inChannel) const -{ - return StatusByte(((byte)inType | ((inChannel - 1) & 0x0f))); -} - -// ----------------------------------------------------------------------------- -// Input -// ----------------------------------------------------------------------------- - -/*! \addtogroup input - @{ -*/ - -/*! \brief Read messages from the serial port using the main input channel. - - \return True if a valid message has been stored in the structure, false if not. - A valid message is a message that matches the input channel. \n\n - If the Thru is enabled and the message matches the filter, - it is sent back on the MIDI output. - @see see setInputChannel() - */ -template -inline bool MidiInterface::read() -{ - return read(mInputChannel); -} - -/*! \brief Read messages on a specified channel. - */ -template -inline bool MidiInterface::read(Channel inChannel) -{ - // Active Sensing. This message is intended to be sent - // repeatedly to tell the receiver that a connection is alive. Use - // of this message is optional. When initially received, the - // receiver will expect to receive another Active Sensing - // message each 300ms (max), and if it does not then it will - // assume that the connection has been terminated. At - // termination, the receiver will turn off all voices and return to - // normal (non- active sensing) operation. - if (mSenderActiveSensingActivated && (millis() - mLastMessageSentTime) > 270) - { - sendRealTime(ActiveSensing); - mLastMessageSentTime = millis(); - } - - if (inChannel >= MIDI_CHANNEL_OFF) - return false; // MIDI Input disabled. - - if (!parse()) - return false; - - handleNullVelocityNoteOnAsNoteOff(); - const bool channelMatch = inputFilter(inChannel); - - if (channelMatch) - { - launchCallback(); - } - - thruFilter(inChannel); - - return channelMatch; -} - -// ----------------------------------------------------------------------------- - -// Private method: MIDI parser -template -bool MidiInterface::parse() -{ - if (mEncoder.available() == 0) - { - // No data available. - return false; - } - - // Parsing algorithm: - // Get a byte from the serial buffer. - // If there is no pending message to be recomposed, start a new one. - // - Find type and channel (if pertinent) - // - Look for other bytes in buffer, call parser recursively, - // until the message is assembled or the buffer is empty. - // Else, add the extracted byte to the pending message, and check validity. - // When the message is done, store it. - - const byte extracted = mEncoder.read(); - - // Ignore Undefined - if (extracted == 0xf9 || extracted == 0xfd) - { - if (Settings::Use1ByteParsing) - { - return false; - } - else - { - return parse(); - } - } - - if (mPendingMessageIndex == 0) - { - // Start a new pending message - mPendingMessage[0] = extracted; - - // Check for running status first - if (isChannelMessage(getTypeFromStatusByte(mRunningStatus_RX))) - { - // Only these types allow Running Status - - // If the status byte is not received, prepend it - // to the pending message - if (extracted < 0x80) - { - mPendingMessage[0] = mRunningStatus_RX; - mPendingMessage[1] = extracted; - mPendingMessageIndex = 1; - } - // Else: well, we received another status byte, - // so the running status does not apply here. - // It will be updated upon completion of this message. - } - - const MidiType pendingType = getTypeFromStatusByte(mPendingMessage[0]); - - switch (pendingType) - { - // 1 byte messages - case Start: - case Continue: - case Stop: - case Clock: - case ActiveSensing: - case SystemReset: - case TuneRequest: - // Handle the message type directly here. - mMessage.type = pendingType; - mMessage.channel = 0; - mMessage.data1 = 0; - mMessage.data2 = 0; - mMessage.valid = true; - - // Do not reset all input attributes, Running Status must remain unchanged. - // We still need to reset these - mPendingMessageIndex = 0; - mPendingMessageExpectedLenght = 0; - - return true; - break; - - // 2 bytes messages - case ProgramChange: - case AfterTouchChannel: - case TimeCodeQuarterFrame: - case SongSelect: - mPendingMessageExpectedLenght = 2; - break; - - // 3 bytes messages - case NoteOn: - case NoteOff: - case ControlChange: - case PitchBend: - case AfterTouchPoly: - case SongPosition: - mPendingMessageExpectedLenght = 3; - break; - - case SystemExclusiveStart: - case SystemExclusiveEnd: - // The message can be any lenght - // between 3 and MidiMessage::sSysExMaxSize bytes - mPendingMessageExpectedLenght = MidiMessage::sSysExMaxSize; - mRunningStatus_RX = InvalidType; - mMessage.sysexArray[0] = pendingType; - break; - - case InvalidType: - default: - // This is obviously wrong. Let's get the hell out'a here. - resetInput(); - return false; - break; - } - - if (mPendingMessageIndex >= (mPendingMessageExpectedLenght - 1)) - { - // Reception complete - mMessage.type = pendingType; - mMessage.channel = getChannelFromStatusByte(mPendingMessage[0]); - mMessage.data1 = mPendingMessage[1]; - mMessage.data2 = 0; // Completed new message has 1 data byte - - mPendingMessageIndex = 0; - mPendingMessageExpectedLenght = 0; - mMessage.valid = true; - return true; - } - else - { - // Waiting for more data - mPendingMessageIndex++; - } - - if (Settings::Use1ByteParsing) - { - // Message is not complete. - return false; - } - else - { - // Call the parser recursively - // to parse the rest of the message. - return parse(); - } - } - else - { - // First, test if this is a status byte - if (extracted >= 0x80) - { - // Reception of status bytes in the middle of an uncompleted message - // are allowed only for interleaved Real Time message or EOX - switch (extracted) - { - case Clock: - case Start: - case Continue: - case Stop: - case ActiveSensing: - case SystemReset: - - // Here we will have to extract the one-byte message, - // pass it to the structure for being read outside - // the MIDI class, and recompose the message it was - // interleaved into. Oh, and without killing the running status.. - // This is done by leaving the pending message as is, - // it will be completed on next calls. - - mMessage.type = (MidiType)extracted; - mMessage.data1 = 0; - mMessage.data2 = 0; - mMessage.channel = 0; - mMessage.valid = true; - return true; - - // Exclusive - case SystemExclusiveStart: - case SystemExclusiveEnd: - if ((mMessage.sysexArray[0] == SystemExclusiveStart) - || (mMessage.sysexArray[0] == SystemExclusiveEnd)) - { - // Store the last byte (EOX) - mMessage.sysexArray[mPendingMessageIndex++] = extracted; - mMessage.type = SystemExclusive; - - // Get length - mMessage.data1 = mPendingMessageIndex & 0xff; // LSB - mMessage.data2 = byte(mPendingMessageIndex >> 8); // MSB - mMessage.channel = 0; - mMessage.valid = true; - - resetInput(); - return true; - } - else - { - // Well well well.. error. - resetInput(); - return false; - } - - default: - break; // LCOV_EXCL_LINE - Coverage blind spot - } - } - - // Add extracted data byte to pending message - if ((mPendingMessage[0] == SystemExclusiveStart) - || (mPendingMessage[0] == SystemExclusiveEnd)) - mMessage.sysexArray[mPendingMessageIndex] = extracted; - else - mPendingMessage[mPendingMessageIndex] = extracted; - - // Now we are going to check if we have reached the end of the message - if (mPendingMessageIndex >= (mPendingMessageExpectedLenght - 1)) - { - // "FML" case: fall down here with an overflown SysEx.. - // This means we received the last possible data byte that can fit - // the buffer. If this happens, try increasing MidiMessage::sSysExMaxSize. - if (mPendingMessage[0] == SystemExclusive) - { - resetInput(); - return false; - } - - mMessage.type = getTypeFromStatusByte(mPendingMessage[0]); - - if (isChannelMessage(mMessage.type)) - mMessage.channel = getChannelFromStatusByte(mPendingMessage[0]); - else - mMessage.channel = 0; - - mMessage.data1 = mPendingMessage[1]; - - // Save data2 only if applicable - mMessage.data2 = mPendingMessageExpectedLenght == 3 ? mPendingMessage[2] : 0; - - // Reset local variables - mPendingMessageIndex = 0; - mPendingMessageExpectedLenght = 0; - - mMessage.valid = true; - - // Activate running status (if enabled for the received type) - switch (mMessage.type) - { - case NoteOff: - case NoteOn: - case AfterTouchPoly: - case ControlChange: - case ProgramChange: - case AfterTouchChannel: - case PitchBend: - // Running status enabled: store it from received message - mRunningStatus_RX = mPendingMessage[0]; - break; - - default: - // No running status - mRunningStatus_RX = InvalidType; - break; - } - return true; - } - else - { - // Then update the index of the pending message. - mPendingMessageIndex++; - - if (Settings::Use1ByteParsing) - { - // Message is not complete. - return false; - } - else - { - // Call the parser recursively to parse the rest of the message. - return parse(); - } - } - } -} - -// Private method, see midi_Settings.h for documentation -template -inline void MidiInterface::handleNullVelocityNoteOnAsNoteOff() -{ - if (Settings::HandleNullVelocityNoteOnAsNoteOff && - getType() == NoteOn && getData2() == 0) - { - mMessage.type = NoteOff; - } -} - -// Private method: check if the received message is on the listened channel -template -inline bool MidiInterface::inputFilter(Channel inChannel) -{ - // This method handles recognition of channel - // (to know if the message is destinated to the Arduino) - - // First, check if the received message is Channel - if (mMessage.type >= NoteOff && mMessage.type <= PitchBend) - { - // Then we need to know if we listen to it - if ((mMessage.channel == inChannel) || - (inChannel == MIDI_CHANNEL_OMNI)) - { - return true; - } - else - { - // We don't listen to this channel - return false; - } - } - else - { - // System messages are always received - return true; - } -} - -// Private method: reset input attributes -template -inline void MidiInterface::resetInput() -{ - mPendingMessageIndex = 0; - mPendingMessageExpectedLenght = 0; - mRunningStatus_RX = InvalidType; -} - -// ----------------------------------------------------------------------------- - -/*! \brief Get the last received message's type - - Returns an enumerated type. @see MidiType - */ -template -inline MidiType MidiInterface::getType() const -{ - return mMessage.type; -} - -/*! \brief Get the channel of the message stored in the structure. - - \return Channel range is 1 to 16. - For non-channel messages, this will return 0. - */ -template -inline Channel MidiInterface::getChannel() const -{ - return mMessage.channel; -} - -/*! \brief Get the first data byte of the last received message. */ -template -inline DataByte MidiInterface::getData1() const -{ - return mMessage.data1; -} - -/*! \brief Get the second data byte of the last received message. */ -template -inline DataByte MidiInterface::getData2() const -{ - return mMessage.data2; -} - -/*! \brief Get the System Exclusive byte array. - - @see getSysExArrayLength to get the array's length in bytes. - */ -template -inline const byte* MidiInterface::getSysExArray() const -{ - return mMessage.sysexArray; -} - -/*! \brief Get the lenght of the System Exclusive array. - - It is coded using data1 as LSB and data2 as MSB. - \return The array's length, in bytes. - */ -template -inline unsigned MidiInterface::getSysExArrayLength() const -{ - return mMessage.getSysExSize(); -} - -/*! \brief Check if a valid message is stored in the structure. */ -template -inline bool MidiInterface::check() const -{ - return mMessage.valid; -} - -// ----------------------------------------------------------------------------- - -template -inline Channel MidiInterface::getInputChannel() const -{ - return mInputChannel; -} - -/*! \brief Set the value for the input MIDI channel - \param inChannel the channel value. Valid values are 1 to 16, MIDI_CHANNEL_OMNI - if you want to listen to all channels, and MIDI_CHANNEL_OFF to disable input. - */ -template -inline void MidiInterface::setInputChannel(Channel inChannel) -{ - mInputChannel = inChannel; -} - -// ----------------------------------------------------------------------------- - -/*! \brief Extract an enumerated MIDI type from a status byte. - - This is a utility static method, used internally, - made public so you can handle MidiTypes more easily. - */ -template -MidiType MidiInterface::getTypeFromStatusByte(byte inStatus) -{ - if ((inStatus < 0x80) || - (inStatus == 0xf4) || - (inStatus == 0xf5) || - (inStatus == 0xf9) || - (inStatus == 0xfD)) - { - // Data bytes and undefined. - return InvalidType; - } - if (inStatus < 0xf0) - { - // Channel message, remove channel nibble. - return MidiType(inStatus & 0xf0); - } - - return MidiType(inStatus); -} - -/*! \brief Returns channel in the range 1-16 - */ -template -inline Channel MidiInterface::getChannelFromStatusByte(byte inStatus) -{ - return Channel((inStatus & 0x0f) + 1); -} - -template -bool MidiInterface::isChannelMessage(MidiType inType) -{ - return (inType == NoteOff || - inType == NoteOn || - inType == ControlChange || - inType == AfterTouchPoly || - inType == AfterTouchChannel || - inType == PitchBend || - inType == ProgramChange); -} - -// ----------------------------------------------------------------------------- - -/*! \addtogroup callbacks - @{ - */ - -template void MidiInterface::setHandleNoteOff(void (*fptr)(byte channel, byte note, byte velocity)) { mNoteOffCallback = fptr; } -template void MidiInterface::setHandleNoteOn(void (*fptr)(byte channel, byte note, byte velocity)) { mNoteOnCallback = fptr; } -template void MidiInterface::setHandleAfterTouchPoly(void (*fptr)(byte channel, byte note, byte pressure)) { mAfterTouchPolyCallback = fptr; } -template void MidiInterface::setHandleControlChange(void (*fptr)(byte channel, byte number, byte value)) { mControlChangeCallback = fptr; } -template void MidiInterface::setHandleProgramChange(void (*fptr)(byte channel, byte number)) { mProgramChangeCallback = fptr; } -template void MidiInterface::setHandleAfterTouchChannel(void (*fptr)(byte channel, byte pressure)) { mAfterTouchChannelCallback = fptr; } -template void MidiInterface::setHandlePitchBend(void (*fptr)(byte channel, int bend)) { mPitchBendCallback = fptr; } -template void MidiInterface::setHandleSystemExclusive(void (*fptr)(byte* array, unsigned size)) { mSystemExclusiveCallback = fptr; } -template void MidiInterface::setHandleTimeCodeQuarterFrame(void (*fptr)(byte data)) { mTimeCodeQuarterFrameCallback = fptr; } -template void MidiInterface::setHandleSongPosition(void (*fptr)(unsigned beats)) { mSongPositionCallback = fptr; } -template void MidiInterface::setHandleSongSelect(void (*fptr)(byte songnumber)) { mSongSelectCallback = fptr; } -template void MidiInterface::setHandleTuneRequest(void (*fptr)(void)) { mTuneRequestCallback = fptr; } -template void MidiInterface::setHandleClock(void (*fptr)(void)) { mClockCallback = fptr; } -template void MidiInterface::setHandleStart(void (*fptr)(void)) { mStartCallback = fptr; } -template void MidiInterface::setHandleContinue(void (*fptr)(void)) { mContinueCallback = fptr; } -template void MidiInterface::setHandleStop(void (*fptr)(void)) { mStopCallback = fptr; } -template void MidiInterface::setHandleActiveSensing(void (*fptr)(void)) { mActiveSensingCallback = fptr; } -template void MidiInterface::setHandleSystemReset(void (*fptr)(void)) { mSystemResetCallback = fptr; } - -/*! \brief Detach an external function from the given type. - - Use this method to cancel the effects of setHandle********. - \param inType The type of message to unbind. - When a message of this type is received, no function will be called. - */ -template -void MidiInterface::disconnectCallbackFromType(MidiType inType) -{ - switch (inType) - { - case NoteOff: mNoteOffCallback = 0; break; - case NoteOn: mNoteOnCallback = 0; break; - case AfterTouchPoly: mAfterTouchPolyCallback = 0; break; - case ControlChange: mControlChangeCallback = 0; break; - case ProgramChange: mProgramChangeCallback = 0; break; - case AfterTouchChannel: mAfterTouchChannelCallback = 0; break; - case PitchBend: mPitchBendCallback = 0; break; - case SystemExclusive: mSystemExclusiveCallback = 0; break; - case TimeCodeQuarterFrame: mTimeCodeQuarterFrameCallback = 0; break; - case SongPosition: mSongPositionCallback = 0; break; - case SongSelect: mSongSelectCallback = 0; break; - case TuneRequest: mTuneRequestCallback = 0; break; - case Clock: mClockCallback = 0; break; - case Start: mStartCallback = 0; break; - case Continue: mContinueCallback = 0; break; - case Stop: mStopCallback = 0; break; - case ActiveSensing: mActiveSensingCallback = 0; break; - case SystemReset: mSystemResetCallback = 0; break; - default: - break; - } -} - -/*! @} */ // End of doc group MIDI Callbacks - -// Private - launch callback function based on received type. -template -void MidiInterface::launchCallback() -{ - // The order is mixed to allow frequent messages to trigger their callback faster. - switch (mMessage.type) - { - // Notes - case NoteOff: if (mNoteOffCallback != 0) mNoteOffCallback(mMessage.channel, mMessage.data1, mMessage.data2); break; - case NoteOn: if (mNoteOnCallback != 0) mNoteOnCallback(mMessage.channel, mMessage.data1, mMessage.data2); break; - - // Real-time messages - case Clock: if (mClockCallback != 0) mClockCallback(); break; - case Start: if (mStartCallback != 0) mStartCallback(); break; - case Continue: if (mContinueCallback != 0) mContinueCallback(); break; - case Stop: if (mStopCallback != 0) mStopCallback(); break; - case ActiveSensing: if (mActiveSensingCallback != 0) mActiveSensingCallback(); break; - - // Continuous controllers - case ControlChange: if (mControlChangeCallback != 0) mControlChangeCallback(mMessage.channel, mMessage.data1, mMessage.data2); break; - case PitchBend: if (mPitchBendCallback != 0) mPitchBendCallback(mMessage.channel, (int)((mMessage.data1 & 0x7f) | ((mMessage.data2 & 0x7f) << 7)) + MIDI_PITCHBEND_MIN); break; - case AfterTouchPoly: if (mAfterTouchPolyCallback != 0) mAfterTouchPolyCallback(mMessage.channel, mMessage.data1, mMessage.data2); break; - case AfterTouchChannel: if (mAfterTouchChannelCallback != 0) mAfterTouchChannelCallback(mMessage.channel, mMessage.data1); break; - - case ProgramChange: if (mProgramChangeCallback != 0) mProgramChangeCallback(mMessage.channel, mMessage.data1); break; - case SystemExclusive: if (mSystemExclusiveCallback != 0) mSystemExclusiveCallback(mMessage.sysexArray, mMessage.getSysExSize()); break; - - // Occasional messages - case TimeCodeQuarterFrame: if (mTimeCodeQuarterFrameCallback != 0) mTimeCodeQuarterFrameCallback(mMessage.data1); break; - case SongPosition: if (mSongPositionCallback != 0) mSongPositionCallback(unsigned((mMessage.data1 & 0x7f) | ((mMessage.data2 & 0x7f) << 7))); break; - case SongSelect: if (mSongSelectCallback != 0) mSongSelectCallback(mMessage.data1); break; - case TuneRequest: if (mTuneRequestCallback != 0) mTuneRequestCallback(); break; - - case SystemReset: if (mSystemResetCallback != 0) mSystemResetCallback(); break; - - case InvalidType: - default: - break; // LCOV_EXCL_LINE - Unreacheable code, but prevents unhandled case warning. - } -} - -/*! @} */ // End of doc group MIDI Input - -// ----------------------------------------------------------------------------- -// Thru -// ----------------------------------------------------------------------------- - -/*! \addtogroup thru - @{ - */ - -/*! \brief Set the filter for thru mirroring - \param inThruFilterMode a filter mode - - @see Thru::Mode - */ -template -inline void MidiInterface::setThruFilterMode(Thru::Mode inThruFilterMode) -{ - mThruFilterMode = inThruFilterMode; - mThruActivated = mThruFilterMode != Thru::Off; -} - -template -inline Thru::Mode MidiInterface::getFilterMode() const -{ - return mThruFilterMode; -} - -template -inline bool MidiInterface::getThruState() const -{ - return mThruActivated; -} - -template -inline void MidiInterface::turnThruOn(Thru::Mode inThruFilterMode) -{ - mThruActivated = true; - mThruFilterMode = inThruFilterMode; -} - -template -inline void MidiInterface::turnThruOff() -{ - mThruActivated = false; - mThruFilterMode = Thru::Off; -} - -/*! @} */ // End of doc group MIDI Thru - -// This method is called upon reception of a message -// and takes care of Thru filtering and sending. -// - All system messages (System Exclusive, Common and Real Time) are passed -// to output unless filter is set to Off. -// - Channel messages are passed to the output whether their channel -// is matching the input channel and the filter setting -template -void MidiInterface::thruFilter(Channel inChannel) -{ - // If the feature is disabled, don't do anything. - if (!mThruActivated || (mThruFilterMode == Thru::Off)) - return; - - // First, check if the received message is Channel - if (mMessage.type >= NoteOff && mMessage.type <= PitchBend) - { - const bool filter_condition = ((mMessage.channel == inChannel) || - (inChannel == MIDI_CHANNEL_OMNI)); - - // Now let's pass it to the output - switch (mThruFilterMode) - { - case Thru::Full: - send(mMessage.type, - mMessage.data1, - mMessage.data2, - mMessage.channel); - break; - - case Thru::SameChannel: - if (filter_condition) - { - send(mMessage.type, - mMessage.data1, - mMessage.data2, - mMessage.channel); - } - break; - - case Thru::DifferentChannel: - if (!filter_condition) - { - send(mMessage.type, - mMessage.data1, - mMessage.data2, - mMessage.channel); - } - break; - - default: - break; - } - } - else - { - // Send the message to the output - switch (mMessage.type) - { - // Real Time and 1 byte - case Clock: - case Start: - case Stop: - case Continue: - case ActiveSensing: - case SystemReset: - case TuneRequest: - sendRealTime(mMessage.type); - break; - - case SystemExclusive: - // Send SysEx (0xf0 and 0xf7 are included in the buffer) - sendSysEx(getSysExArrayLength(), getSysExArray(), true); - break; - - case SongSelect: - sendSongSelect(mMessage.data1); - break; - - case SongPosition: - sendSongPosition(mMessage.data1 | ((unsigned)mMessage.data2 << 7)); - break; - - case TimeCodeQuarterFrame: - sendTimeCodeQuarterFrame(mMessage.data1,mMessage.data2); - break; - - default: - break; // LCOV_EXCL_LINE - Unreacheable code, but prevents unhandled case warning. - } - } -} - -END_MIDI_NAMESPACE diff --git a/src/utility/midi_feat4_4_0/midi_Defs.h b/src/utility/midi_feat4_4_0/midi_Defs.h deleted file mode 100644 index 810e8de..0000000 --- a/src/utility/midi_feat4_4_0/midi_Defs.h +++ /dev/null @@ -1,209 +0,0 @@ -/*! - * @file midi_Defs.h - * Project Arduino MIDI Library - * @brief MIDI Library for the Arduino - Definitions - * @author Francois Best - * @date 24/02/11 - * @license MIT - Copyright (c) 2015 Francois Best - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#pragma once - -#include "midi_Namespace.h" - -#if ARDUINO -#include -#else -#include -typedef uint8_t byte; -#endif - -BEGIN_MIDI_NAMESPACE - -#define MIDI_LIBRARY_VERSION 0x040400 -#define MIDI_LIBRARY_VERSION_MAJOR 4 -#define MIDI_LIBRARY_VERSION_MINOR 4 -#define MIDI_LIBRARY_VERSION_PATCH 0 - -// ----------------------------------------------------------------------------- - -#define MIDI_CHANNEL_OMNI 0 -#define MIDI_CHANNEL_OFF 17 // and over - -#define MIDI_PITCHBEND_MIN -8192 -#define MIDI_PITCHBEND_MAX 8191 - -// ----------------------------------------------------------------------------- -// Type definitions - -typedef byte StatusByte; -typedef byte DataByte; -typedef byte Channel; -typedef byte FilterMode; - -// ----------------------------------------------------------------------------- - -/*! Enumeration of MIDI types */ -enum MidiType: uint8_t -{ - InvalidType = 0x00, ///< For notifying errors - NoteOff = 0x80, ///< Note Off - NoteOn = 0x90, ///< Note On - AfterTouchPoly = 0xA0, ///< Polyphonic AfterTouch - ControlChange = 0xB0, ///< Control Change / Channel Mode - ProgramChange = 0xC0, ///< Program Change - AfterTouchChannel = 0xD0, ///< Channel (monophonic) AfterTouch - PitchBend = 0xE0, ///< Pitch Bend - SystemExclusive = 0xF0, ///< System Exclusive - SystemExclusiveStart = SystemExclusive, ///< System Exclusive Start - TimeCodeQuarterFrame = 0xF1, ///< System Common - MIDI Time Code Quarter Frame - SongPosition = 0xF2, ///< System Common - Song Position Pointer - SongSelect = 0xF3, ///< System Common - Song Select - TuneRequest = 0xF6, ///< System Common - Tune Request - SystemExclusiveEnd = 0xF7, ///< System Exclusive End - Clock = 0xF8, ///< System Real Time - Timing Clock - Start = 0xFA, ///< System Real Time - Start - Continue = 0xFB, ///< System Real Time - Continue - Stop = 0xFC, ///< System Real Time - Stop - ActiveSensing = 0xFE, ///< System Real Time - Active Sensing - SystemReset = 0xFF, ///< System Real Time - System Reset -}; - -// ----------------------------------------------------------------------------- - -/*! Enumeration of Thru filter modes */ -struct Thru -{ - enum Mode - { - Off = 0, ///< Thru disabled (nothing passes through). - Full = 1, ///< Fully enabled Thru (every incoming message is sent back). - SameChannel = 2, ///< Only the messages on the Input Channel will be sent back. - DifferentChannel = 3, ///< All the messages but the ones on the Input Channel will be sent back. - }; -}; - -/*! Deprecated: use Thru::Mode instead. - Will be removed in v5.0. -*/ -enum __attribute__ ((deprecated)) MidiFilterMode -{ - Off = Thru::Off, - Full = Thru::Full, - SameChannel = Thru::SameChannel, - DifferentChannel = Thru::DifferentChannel, -}; - -// ----------------------------------------------------------------------------- - -/*! \brief Enumeration of Control Change command numbers. - See the detailed controllers numbers & description here: - http://www.somascape.org/midi/tech/spec.html#ctrlnums - */ -enum MidiControlChangeNumber: uint8_t -{ - // High resolution Continuous Controllers MSB (+32 for LSB) ---------------- - BankSelect = 0, - ModulationWheel = 1, - BreathController = 2, - // CC3 undefined - FootController = 4, - PortamentoTime = 5, - DataEntryMSB = 6, - ChannelVolume = 7, - Balance = 8, - // CC9 undefined - Pan = 10, - ExpressionController = 11, - EffectControl1 = 12, - EffectControl2 = 13, - // CC14 undefined - // CC15 undefined - GeneralPurposeController1 = 16, - GeneralPurposeController2 = 17, - GeneralPurposeController3 = 18, - GeneralPurposeController4 = 19, - - DataEntryLSB = 38, - - // Switches ---------------------------------------------------------------- - Sustain = 64, - Portamento = 65, - Sostenuto = 66, - SoftPedal = 67, - Legato = 68, - Hold = 69, - - // Low resolution continuous controllers ----------------------------------- - SoundController1 = 70, ///< Synth: Sound Variation FX: Exciter On/Off - SoundController2 = 71, ///< Synth: Harmonic Content FX: Compressor On/Off - SoundController3 = 72, ///< Synth: Release Time FX: Distortion On/Off - SoundController4 = 73, ///< Synth: Attack Time FX: EQ On/Off - SoundController5 = 74, ///< Synth: Brightness FX: Expander On/Off - SoundController6 = 75, ///< Synth: Decay Time FX: Reverb On/Off - SoundController7 = 76, ///< Synth: Vibrato Rate FX: Delay On/Off - SoundController8 = 77, ///< Synth: Vibrato Depth FX: Pitch Transpose On/Off - SoundController9 = 78, ///< Synth: Vibrato Delay FX: Flange/Chorus On/Off - SoundController10 = 79, ///< Synth: Undefined FX: Special Effects On/Off - GeneralPurposeController5 = 80, - GeneralPurposeController6 = 81, - GeneralPurposeController7 = 82, - GeneralPurposeController8 = 83, - PortamentoControl = 84, - // CC85 to CC90 undefined - Effects1 = 91, ///< Reverb send level - Effects2 = 92, ///< Tremolo depth - Effects3 = 93, ///< Chorus send level - Effects4 = 94, ///< Celeste depth - Effects5 = 95, ///< Phaser depth - DataIncrement = 96, - DataDecrement = 97, - NRPNLSB = 98, ///< Non-Registered Parameter Number (LSB) - NRPNMSB = 99, ///< Non-Registered Parameter Number (MSB) - RPNLSB = 100, ///< Registered Parameter Number (LSB) - RPNMSB = 101, ///< Registered Parameter Number (MSB) - - // Channel Mode messages --------------------------------------------------- - AllSoundOff = 120, - ResetAllControllers = 121, - LocalControl = 122, - AllNotesOff = 123, - OmniModeOff = 124, - OmniModeOn = 125, - MonoModeOn = 126, - PolyModeOn = 127 -}; - -struct RPN -{ - enum RegisteredParameterNumbers: uint16_t - { - PitchBendSensitivity = 0x0000, - ChannelFineTuning = 0x0001, - ChannelCoarseTuning = 0x0002, - SelectTuningProgram = 0x0003, - SelectTuningBank = 0x0004, - ModulationDepthRange = 0x0005, - NullFunction = (0x7f << 7) + 0x7f, - }; -}; - -END_MIDI_NAMESPACE diff --git a/src/utility/midi_feat4_4_0/midi_Message.h b/src/utility/midi_feat4_4_0/midi_Message.h deleted file mode 100644 index 04b56c9..0000000 --- a/src/utility/midi_feat4_4_0/midi_Message.h +++ /dev/null @@ -1,101 +0,0 @@ -/*! - * @file midi_Message.h - * Project Arduino MIDI Library - * @brief MIDI Library for the Arduino - Message struct definition - * @author Francois Best - * @date 11/06/14 - * @license MIT - Copyright (c) 2015 Francois Best - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#pragma once - -#include "midi_Namespace.h" -#include "midi_Defs.h" -#ifndef ARDUINO -#include -#endif - -BEGIN_MIDI_NAMESPACE - -/*! The Message structure contains decoded data of a MIDI message - read from the serial port with read() - */ -template -struct Message -{ - /*! Default constructor - \n Initializes the attributes with their default values. - */ - inline Message() - : channel(0) - , type(MIDI_NAMESPACE::InvalidType) - , data1(0) - , data2(0) - , valid(false) - { - memset(sysexArray, 0, sSysExMaxSize * sizeof(DataByte)); - } - - /*! The maximum size for the System Exclusive array. - */ - static const unsigned sSysExMaxSize = SysExMaxSize; - - /*! The MIDI channel on which the message was recieved. - \n Value goes from 1 to 16. - */ - Channel channel; - - /*! The type of the message - (see the MidiType enum for types reference) - */ - MidiType type; - - /*! The first data byte. - \n Value goes from 0 to 127. - */ - DataByte data1; - - /*! The second data byte. - If the message is only 2 bytes long, this one is null. - \n Value goes from 0 to 127. - */ - DataByte data2; - - /*! System Exclusive dedicated byte array. - \n Array length is stocked on 16 bits, - in data1 (LSB) and data2 (MSB) - */ - DataByte sysexArray[sSysExMaxSize]; - - /*! This boolean indicates if the message is valid or not. - There is no channel consideration here, - validity means the message respects the MIDI norm. - */ - bool valid; - - inline unsigned getSysExSize() const - { - const unsigned size = unsigned(data2) << 8 | data1; - return size > sSysExMaxSize ? sSysExMaxSize : size; - } -}; - -END_MIDI_NAMESPACE diff --git a/src/utility/midi_feat4_4_0/midi_Namespace.h b/src/utility/midi_feat4_4_0/midi_Namespace.h deleted file mode 100644 index cab0a2c..0000000 --- a/src/utility/midi_feat4_4_0/midi_Namespace.h +++ /dev/null @@ -1,38 +0,0 @@ -/*! - * @file midi_Namespace.h - * Project Arduino MIDI Library - * @brief MIDI Library for the Arduino - Namespace declaration - * @author Francois Best - * @date 24/02/11 - * @license MIT - Copyright (c) 2015 Francois Best - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#pragma once - -#define MIDI_NAMESPACE midi_v440 -#define BEGIN_MIDI_NAMESPACE namespace MIDI_NAMESPACE { -#define END_MIDI_NAMESPACE } - -#define USING_NAMESPACE_MIDI using namespace MIDI_NAMESPACE; - -BEGIN_MIDI_NAMESPACE - -END_MIDI_NAMESPACE diff --git a/src/utility/midi_feat4_4_0/midi_Settings.h b/src/utility/midi_feat4_4_0/midi_Settings.h deleted file mode 100644 index 60f034c..0000000 --- a/src/utility/midi_feat4_4_0/midi_Settings.h +++ /dev/null @@ -1,87 +0,0 @@ -/*! - * @file midi_Settings.h - * Project Arduino MIDI Library - * @brief MIDI Library for the Arduino - Settings - * @author Francois Best - * @date 24/02/11 - * @license MIT - Copyright (c) 2015 Francois Best - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#pragma once - -#include "midi_Defs.h" - -BEGIN_MIDI_NAMESPACE - -/*! \brief Default Settings for the MIDI Library. - - To change the default settings, don't edit them there, create a subclass and - override the values in that subclass, then use the MIDI_CREATE_CUSTOM_INSTANCE - macro to create your instance. The settings you don't override will keep their - default value. Eg: - \code{.cpp} - struct MySettings : public MIDI::DefaultSettings - { - static const unsigned SysExMaxSize = 1024; // Accept SysEx messages up to 1024 bytes long. - }; - - MIDI_CREATE_CUSTOM_INSTANCE(HardwareSerial, Serial2, MIDI, MySettings); - \endcode - */ -struct DefaultSettings -{ - /*! Running status enables short messages when sending multiple values - of the same type and channel.\n - Must be disabled to send USB MIDI messages to a computer - Warning: does not work with some hardware, enable with caution. - */ - static const bool UseRunningStatus = false; - - /*! NoteOn with 0 velocity should be handled as NoteOf.\n - Set to true to get NoteOff events when receiving null-velocity NoteOn messages.\n - Set to false to get NoteOn events when receiving null-velocity NoteOn messages. - */ - static const bool HandleNullVelocityNoteOnAsNoteOff = true; - - /*! Active Sensing is intended to be sent - repeatedly by the sender to tell the receiver that a connection is alive. Use - of this message is optional. When initially received, the - receiver will expect to receive another Active Sensing - message each 300ms (max), and if it does not then it will - assume that the connection has been terminated. At - termination, the receiver will turn off all voices and return to - normal (non- active sensing) operation.. - */ - static const bool UseSenderActiveSensing = false; - - /*! Setting this to true will make MIDI.read parse only one byte of data for each - call when data is available. This can speed up your application if receiving - a lot of traffic, but might induce MIDI Thru and treatment latency. - */ - static const bool Use1ByteParsing = false; - - /*! Maximum size of SysEx receivable. Decrease to save RAM if you don't expect - to receive SysEx, or adjust accordingly. - */ - static const unsigned SysExMaxSize = 128; -}; - -END_MIDI_NAMESPACE diff --git a/test/Arduino.h b/test/Arduino.h index c4df0cc..ffc2042 100644 --- a/test/Arduino.h +++ b/test/Arduino.h @@ -87,4 +87,9 @@ template const T& min(const T& a, const T& b) { return !(b < a) ? a : b; // or: return !comp(b,a)?a:b; for version (2) } +bool bitRead(byte value, uint8_t bitToCheck) +{ + return value & (1 << bitToCheck) +} + #define F(x) x diff --git a/test/NoteOn.cpp b/test/NoteOn.cpp index 1399dfa..f48de2c 100644 --- a/test/NoteOn.cpp +++ b/test/NoteOn.cpp @@ -1,7 +1,7 @@ #define DEBUG 7 #define APPLEMIDI_INITIATOR -#include "../src/midi_bleTransport.h" +#include "../src/BLEMIDI.h" void begin() { diff --git a/test/bleMidi.xcodeproj/project.xcworkspace/xcuserdata/bart.xcuserdatad/UserInterfaceState.xcuserstate b/test/bleMidi.xcodeproj/project.xcworkspace/xcuserdata/bart.xcuserdatad/UserInterfaceState.xcuserstate index d447496..0322d87 100644 Binary files a/test/bleMidi.xcodeproj/project.xcworkspace/xcuserdata/bart.xcuserdatad/UserInterfaceState.xcuserstate and b/test/bleMidi.xcodeproj/project.xcworkspace/xcuserdata/bart.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/test/bleMidi.xcodeproj/xcshareddata/xcschemes/rtpMidi.xcscheme b/test/bleMidi.xcodeproj/xcshareddata/xcschemes/rtpMidi.xcscheme new file mode 100644 index 0000000..3b0872e --- /dev/null +++ b/test/bleMidi.xcodeproj/xcshareddata/xcschemes/rtpMidi.xcscheme @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/bleMidi.xcodeproj/xcuserdata/bart.xcuserdatad/xcschemes/xcschememanagement.plist b/test/bleMidi.xcodeproj/xcuserdata/bart.xcuserdatad/xcschemes/xcschememanagement.plist index 47e8994..16bf0a1 100644 --- a/test/bleMidi.xcodeproj/xcuserdata/bart.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/test/bleMidi.xcodeproj/xcuserdata/bart.xcuserdatad/xcschemes/xcschememanagement.plist @@ -10,5 +10,13 @@ 0 + SuppressBuildableAutocreation + + CCE329B423C2037C00A197D1 + + primary + + +