Added support for Active Sensing and SysEx command segments (v4.4.0) (#138)
* stuff to ignore list * Update midi_Defs.h * added support for ActiveSensing From: https://www.midi.org/specifications/item/table-1-summary-of-midi-message 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. * replaced ActiveSensing with Sender Active Sensing Receiver active Sensing is not implemented (yet) * added support for receiving SysEx command segments Very long SysEx mesaages are cut in to multiple command segments Where a normal SysEx starts with F0 and ends with F7, the first segment will start with F0 and end with F0, the middle section (optional) start with F7 and ends with F7 - the last segments starts with F7 and ends with F0 * lift and shift of the Serial code into a seperate class, allowing for other serializers lift and shift of the Serial code into a seperate class, allowing for other serializers as AppleMIDI, USBMIDI, ipMIDI, BLE-MIDI * added Platform class to abstract millis() * add MidiType to beginTransmission Avoids reparsing of the stream in the transport layer, in order to get the MidiType * active sensing defaults to false, to avoid spamming devices * set ActiveSensing Periodicity in ms Gives more control over the bool value. Typical value is 300 (ms) - an Active Sensing command is send every 300ms; or 0 (zero) to disable sending ActiveSensing * added namespace reference * renamed Encoder -> Transport, added MidiType to beginTransmission in serialMIDI * added callback for Message before the specific callback are called, a generic mMessage callback can be fired to inform the user that 'a' message has been received. * added send(MidiMessage), added (untested) bridge example added send(MidiMessage) for Bridge application (that convert MIDI transport x into MIDI transport y), avoiding parsing entry a stream, setting up all callback - whilst this allows for passing the content, without to much processing/parsing. Had to move mPendingMessageExpectedLenght into MidiMessage to avoid parsing the data again, just to know the size Added Bridge example (untested) * changed based on Franky47's feedback - send: pass the message as a const ref, to avoid copies - add mSerial.begin (with Baudrate - added Settings) - ThruActivated defaults to true - class name serialMIDI => SerialMIDI * return reference to Transport layer * return a *pointer* (not a ref) to the transport layer * mPendingMessageExpectedLength as before mMessage.length is reset to 0 before the callback, so bring back mPendingMessageExpectedLength as before, and set mMessage.length (and not reset it) * DefaultPlatform for Arduino * strong typing Channel in the callbacks * aliasing for callbacks (and default initializers * cleanup setHandleMessage unfortunately, not using aliases yet (too complex) * Fixed "FML" case: fall down here with an overflown SysEx.. Splitting larger incoming messages into smaller SysEx packets - using an RrtpMidi trick: // first: 0xF0 .... 0xF0 // midlle: 0xF7 .... 0xF0 // last: 0xF7 .... 0xF7 see: https://tools.ietf.org/html/rfc4695#section-3.2 (Understanding this is not part of the original MIDI spec, but does allow for receiving very very large SysEx messages on a small footprint (does require some 'handy' parsing)) SysExMaxSize in Settings can be reduced significatly (16bytes works fine - pending use case) * + receiver ActiveSensing, + error Callback 1) Active Sensing: Once an ActiveSensing message is received, the system checks for timeouts: if no message is received within the specified 300ms (see in _Defs), an error is set and the checks for timeout stop. 2) added a callback for errors. 2 errors are defined: parse error and ActiveSensing timeout * cleanup of basic example use LED_BUILTIN * + Manufacturer System Exclusive ID (incomplete) * + noteValues * added SendCommon, consistent with SendRealTime including: sendClock, sendStart, sendStop, sendContinue, sendActiveSensing, sendSystemReset * UseSenderActiveSensing & UseReceiverActiveSensing to enable/disable Active Sensing UseSenderActiveSensing & UseReceiverActiveSensing in Settings are global switches to turn on/off ActiveSensing (and save memory) * use #defined value, not the literal * cleanup * removed deprecated MidiFilterMode (to be removed for v5) * getting ready for v5 * prepare for v5 * updating authors * Removed USB examples * added header * removed typedef when instanciating multiple instances of SerialMIDI, a redefinition error accors because of typing of the serial##Name. Fix: removed the typdef, a bit harder to read, but avoided complex #ifdef * move bridge example to other Transport mechanisms * Update Bench.ino * Create NoteNames.ino demonstrate use of MIDI_NAMESPACE::NoteValues[inNote].strptr * moved #version to MIDI.h #version of the library does not belong in general MIDI definitions (making midi_Defs.h as generic as possible - usable on other platforms) * adding comment section * shorter syntax using iif * moved code to avoid doc clash * added Tick (0xF9) * Simplified NoteValues Need need for extra index (that is the same as the noteName anyway) * Removed Undefined_F9 (Tick) as an invalid token (so it valid now) * removed references to USB in the test scripts * setting the CMake env * removed USB references * struggling with travis * LCOV_EXCL_LINE in sendCommon * order of initialization * reorder variables for initialisation * extending platforms * adding boards (but not the Zero) * fixing cmake * moved RingBuffer to SerialMock * fix cmake removing RingBuffer * Update CMakeLists.txt * using bitwire operators (works on all platforms) * Update midi_Platform.h * removed NoteNames * simplify test (will be rolled back later) * Update unit-tests_MidiInput.cpp * Update unit-tests_MidiInput.cpp * Revert "Update midi_Platform.h" This reverts commitbd2f6476b2. * bring in other Platform (remove usb) * added BaudRate * Revert "using bitwire operators (works on all platforms)" This reverts commit122ebe1dc3. * Revert "moved code to avoid doc clash" This reverts commitef878344cd. * restored after very funcky commits and rollbacks (Sorry!) * add Transport layer * removed SerialMock test * Update unit-tests_MidiInput.cpp * Update unit-tests_MidiInput.cpp * Update unit-tests_MidiInput.cpp * Update unit-tests_MidiInput.cpp * fixed MidiInterface<SerialMock => MidiInterface<Transport * SerialMIDI should not aware of the channel * Update unit-tests_MidiThru.cpp * Update midi_Defs.h * avoid shadow parameters and buf fix * Update CMakeLists.txt * Update unit-tests_MidiOutput.cpp * Update midi_Settings.h * Update unit-tests_MidiInput.cpp * Update unit-tests_MidiInput.cpp * Update unit-tests_MidiInput.cpp * tmp removed teensy, bug fix sendCommon (unsigned, not byte) * Update unit-tests_MidiInput.cpp * fix for Leonardo * Update DualMerger.ino * adding tests_MidiInputCallbacks * Update unit-tests_MidiInputCallbacks.cpp * preparing to release 5.0.0 * added Alternative Pin for Serial port example * default listen on all channel as in #96 * Update unit-tests_MidiInput.cpp Co-authored-by: lathoub <lathoub@gmail.com>
This commit is contained in:
parent
cab564b995
commit
2c657a38d1
|
|
@ -3,3 +3,8 @@
|
|||
logs/
|
||||
build/
|
||||
.vscode/.cmaketools.json
|
||||
src/.DS_Store
|
||||
examples/.DS_Store
|
||||
.DS_Store
|
||||
test/xcode
|
||||
.development
|
||||
|
|
|
|||
10
.travis.yml
10
.travis.yml
|
|
@ -25,10 +25,8 @@ env:
|
|||
- PLATFORMIO_CI_SRC=examples/Bench
|
||||
- PLATFORMIO_CI_SRC=examples/Callbacks
|
||||
- PLATFORMIO_CI_SRC=examples/DualMerger
|
||||
- PLATFORMIO_CI_SRC=examples/ErrorCallback
|
||||
- PLATFORMIO_CI_SRC=examples/Input
|
||||
- PLATFORMIO_CI_SRC=examples/MidiUSB REQUIRES_USB=1
|
||||
- PLATFORMIO_CI_SRC=examples/MidiUSB-CompleteAPI REQUIRES_USB=1
|
||||
- PLATFORMIO_CI_SRC=examples/MidiUSB-Thru REQUIRES_USB=1
|
||||
- PLATFORMIO_CI_SRC=examples/RPN_NRPN
|
||||
- PLATFORMIO_CI_SRC=examples/SimpleSynth
|
||||
|
||||
|
|
@ -76,11 +74,7 @@ script:
|
|||
# Build current example
|
||||
- |
|
||||
if [ ! "${BUILD_UNIT_TESTS}" ]; then
|
||||
if [ "${REQUIRES_USB}" ]; then
|
||||
platformio ci --lib="." --lib=external/midi-usb --board="due" --board="dueUSB" --board="zero" --board="zeroUSB" --board="leonardo"
|
||||
else
|
||||
platformio ci --lib="." --board=uno --board="due" --board="zero" --board="leonardo" --board="micro" --board="nanoatmega328" --board="megaatmega2560" --board="teensy20" --board="teensy20pp" --board="teensy30" --board="teensy31"
|
||||
fi
|
||||
platformio ci --lib="." --board=uno --board="due" --board="leonardo" --board="micro" --board="nanoatmega328" --board="megaatmega2560"
|
||||
fi
|
||||
|
||||
after_success:
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
# Using the library for MIDI through USB
|
||||
|
||||
Some boards have "native" USB functionality, which means they can directly
|
||||
connect to a computer and appear as a USB MIDI device.
|
||||
|
||||
Here are the officially supported boards:
|
||||
|
||||
- Arduino Leonardo
|
||||
- Arduino Due
|
||||
|
||||
## Pre-requisites
|
||||
|
||||
To use USB MIDI to send messages to the computer, you must disable Running
|
||||
Status in the settings. This is because the USB transport is stateless and has
|
||||
no knowledge of the last message's running status.
|
||||
The setting is off by default, so if you use custom settings, keep that in mind.
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
#include <MIDI.h>
|
||||
#include "altPinSerialMIDI.h"
|
||||
|
||||
// Simple tutorial on how to receive and send MIDI messages.
|
||||
// Here, when receiving any message on channel 4, the Arduino
|
||||
// will blink a led and play back a note for 1 second.
|
||||
|
||||
AltSerialMIDI<HardwareSerial> serialMIDI(Serial1, 18, 19);
|
||||
MIDI_NAMESPACE::MidiInterface<AltSerialMIDI<HardwareSerial>> MIDI((AltSerialMIDI<HardwareSerial>&)serialMIDI);
|
||||
|
||||
void setup()
|
||||
{
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
MIDI.begin(4); // Launch MIDI and listen to channel 4
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (MIDI.read()) // If we have received a message
|
||||
{
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
MIDI.sendNoteOn(42, 127, 1); // Send a Note (pitch 42, velo 127 on channel 1)
|
||||
delay(1000); // Wait for a second
|
||||
MIDI.sendNoteOff(42, 0, 1); // Stop the note
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
struct DefaultAltSerialSettings
|
||||
{
|
||||
static const long BaudRate = 31250;
|
||||
};
|
||||
|
||||
template <class SerialPort, class _Settings = DefaultAltSerialSettings>
|
||||
class AltSerialMIDI
|
||||
{
|
||||
typedef _Settings Settings;
|
||||
|
||||
uint8_t rxPin = 0;
|
||||
uint8_t txPin = 0;
|
||||
|
||||
friend class midi::MidiInterface<AltSerialMIDI<SerialPort>>;
|
||||
|
||||
public:
|
||||
AltSerialMIDI(SerialPort& inSerial, uint8_t inRxPin, uint8_t inTxPin)
|
||||
: mSerial(inSerial), rxPin(inRxPin), txPin(inTxPin)
|
||||
{
|
||||
};
|
||||
|
||||
protected:
|
||||
void begin()
|
||||
{
|
||||
mSerial.begin(Settings::BaudRate, SERIAL_8N1, rxPin, txPin);
|
||||
}
|
||||
|
||||
bool beginTransmission(midi::MidiType)
|
||||
{
|
||||
return true;
|
||||
};
|
||||
|
||||
void write(byte value)
|
||||
{
|
||||
mSerial.write(value);
|
||||
};
|
||||
|
||||
void endTransmission()
|
||||
{
|
||||
};
|
||||
|
||||
byte read()
|
||||
{
|
||||
return mSerial.read();
|
||||
};
|
||||
|
||||
unsigned available()
|
||||
{
|
||||
return mSerial.available();
|
||||
};
|
||||
|
||||
private:
|
||||
SerialPort& mSerial;
|
||||
};
|
||||
|
|
@ -6,11 +6,9 @@
|
|||
|
||||
MIDI_CREATE_DEFAULT_INSTANCE();
|
||||
|
||||
static const unsigned ledPin = 13; // LED pin on Arduino Uno
|
||||
|
||||
void setup()
|
||||
{
|
||||
pinMode(ledPin, OUTPUT);
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
MIDI.begin(4); // Launch MIDI and listen to channel 4
|
||||
}
|
||||
|
||||
|
|
@ -18,10 +16,10 @@ void loop()
|
|||
{
|
||||
if (MIDI.read()) // If we have received a message
|
||||
{
|
||||
digitalWrite(ledPin, HIGH);
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
MIDI.sendNoteOn(42, 127, 1); // Send a Note (pitch 42, velo 127 on channel 1)
|
||||
delay(1000); // Wait for a second
|
||||
MIDI.sendNoteOff(42, 0, 1); // Stop the note
|
||||
digitalWrite(ledPin, LOW);
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,8 +71,8 @@ void setup()
|
|||
midiBench.setHandleNoteOn(handleNoteOn);
|
||||
midiBench.begin();
|
||||
|
||||
while(!Serial);
|
||||
Serial.begin(115200);
|
||||
while(!Serial);
|
||||
Serial.println("Arduino Ready");
|
||||
|
||||
midiBench.sendNoteOn(69,127,1);
|
||||
|
|
|
|||
|
|
@ -6,12 +6,17 @@
|
|||
// A out = A in + B in
|
||||
// B out = B in + A in
|
||||
|
||||
#ifdef ARDUINO_SAM_DUE
|
||||
#if defined(ARDUINO_SAM_DUE)
|
||||
MIDI_CREATE_INSTANCE(HardwareSerial, Serial, midiA);
|
||||
MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, midiB);
|
||||
#elif defined(ARDUINO_SAMD_ZERO)
|
||||
MIDI_CREATE_INSTANCE(HardwareSerial, SerialUSB, midiA);
|
||||
MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, midiB);
|
||||
#elif defined(USBCON) || defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MKL26Z64__)
|
||||
#include <SoftwareSerial.h>
|
||||
SoftwareSerial softSerial(2,3);
|
||||
MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, midiA);
|
||||
MIDI_CREATE_INSTANCE(SoftwareSerial, softSerial, midiB);
|
||||
#else
|
||||
#include <SoftwareSerial.h>
|
||||
SoftwareSerial softSerial(2,3);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
#include <MIDI.h>
|
||||
|
||||
// Before running the program below, make sure you set
|
||||
// UseReceiverActiveSensing (optionally UseSenderActiveSensing) in Settings.h to true
|
||||
|
||||
MIDI_CREATE_DEFAULT_INSTANCE();
|
||||
|
||||
void handleError(int8_t err)
|
||||
{
|
||||
digitalWrite(LED_BUILTIN, (err == 0)? LOW : HIGH);
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
|
||||
MIDI.setHandleError(handleError);
|
||||
MIDI.begin(1);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
MIDI.read();
|
||||
}
|
||||
|
|
@ -1,181 +0,0 @@
|
|||
#include <MIDI.h>
|
||||
|
||||
#if defined(USBCON)
|
||||
#include <midi_UsbTransport.h>
|
||||
|
||||
static const unsigned sUsbTransportBufferSize = 16;
|
||||
typedef midi::UsbTransport<sUsbTransportBufferSize> UsbTransport;
|
||||
|
||||
UsbTransport sUsbTransport;
|
||||
|
||||
MIDI_CREATE_INSTANCE(UsbTransport, sUsbTransport, MIDI);
|
||||
|
||||
#else // No USB available, fallback to Serial
|
||||
MIDI_CREATE_DEFAULT_INSTANCE();
|
||||
#endif
|
||||
|
||||
// --
|
||||
|
||||
void setupRxBenchmark()
|
||||
{
|
||||
MIDI.setHandleNoteOff(handleNoteOff);
|
||||
MIDI.setHandleNoteOn(handleNoteOn);
|
||||
MIDI.setHandleControlChange(handleControlChange);
|
||||
MIDI.setHandleProgramChange(handleProgramChange);
|
||||
MIDI.setHandleAfterTouchChannel(handleAfterTouchChannel);
|
||||
MIDI.setHandleAfterTouchPoly(handleAfterTouchPoly);
|
||||
MIDI.setHandlePitchBend(handlePitchBend);
|
||||
MIDI.setHandleStart(handleStart);
|
||||
MIDI.setHandleStop(handleStop);
|
||||
MIDI.setHandleContinue(handleContinue);
|
||||
MIDI.setHandleClock(handleClock);
|
||||
MIDI.setHandleSystemExclusive(handleSysEx);
|
||||
}
|
||||
|
||||
void startTxBenchmark()
|
||||
{
|
||||
for (int i = 0; i < 128; ++i)
|
||||
{
|
||||
MIDI.sendNoteOn(i, 127, 1);
|
||||
MIDI.sendNoteOff(i, 127, 1);
|
||||
}
|
||||
for (int i = 0; i < 128; ++i)
|
||||
{
|
||||
MIDI.sendControlChange(i, 127, 1);
|
||||
MIDI.sendControlChange(i, 0, 1);
|
||||
}
|
||||
for (int i = 0; i < 128; ++i)
|
||||
{
|
||||
MIDI.sendProgramChange(i, 1);
|
||||
}
|
||||
MIDI.sendRealTime(midi::Start);
|
||||
MIDI.sendRealTime(midi::Stop);
|
||||
MIDI.sendRealTime(midi::Continue);
|
||||
MIDI.sendRealTime(midi::Clock);
|
||||
|
||||
const byte length = 128;
|
||||
const byte data[128] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
|
||||
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
||||
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
|
||||
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
|
||||
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
|
||||
0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
|
||||
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
|
||||
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
|
||||
0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
|
||||
};
|
||||
MIDI.sendSysEx(length, data, false);
|
||||
}
|
||||
|
||||
// --
|
||||
|
||||
void printChannel(byte inChannel)
|
||||
{
|
||||
Serial.print("[");
|
||||
Serial.print(inChannel);
|
||||
Serial.print("] ");
|
||||
}
|
||||
|
||||
void handleNoteOff(byte inChannel, byte inNote, byte inVelocity)
|
||||
{
|
||||
printChannel(inChannel);
|
||||
Serial.print("Note Off\t");
|
||||
Serial.print(inNote);
|
||||
Serial.print(' ');
|
||||
Serial.println(inVelocity);
|
||||
}
|
||||
void handleNoteOn(byte inChannel, byte inNote, byte inVelocity)
|
||||
{
|
||||
printChannel(inChannel);
|
||||
Serial.print("Note On\t");
|
||||
Serial.print(inNote);
|
||||
Serial.print(' ');
|
||||
Serial.println(inVelocity);
|
||||
}
|
||||
void handleControlChange(byte inChannel, byte inControl, byte inValue)
|
||||
{
|
||||
printChannel(inChannel);
|
||||
Serial.print("Control Change\t");
|
||||
Serial.print(inControl);
|
||||
Serial.print(' ');
|
||||
Serial.println(inValue);
|
||||
}
|
||||
void handleProgramChange(byte inChannel, byte inProgram)
|
||||
{
|
||||
printChannel(inChannel);
|
||||
Serial.print("Program Change\t");
|
||||
Serial.println(inProgram);
|
||||
}
|
||||
void handleAfterTouchChannel(byte inChannel, byte inPressure)
|
||||
{
|
||||
printChannel(inChannel);
|
||||
Serial.print("AT Channel\t");
|
||||
Serial.println(inPressure);
|
||||
}
|
||||
void handleAfterTouchPoly(byte inChannel, byte inNote, byte inPressure)
|
||||
{
|
||||
printChannel(inChannel);
|
||||
Serial.print("AT Poly\t");
|
||||
Serial.print(inNote);
|
||||
Serial.print(' ');
|
||||
Serial.println(inPressure);
|
||||
}
|
||||
void handlePitchBend(byte inChannel, int inBend)
|
||||
{
|
||||
printChannel(inChannel);
|
||||
Serial.print("Pitch Bend\t");
|
||||
Serial.println(inBend);
|
||||
}
|
||||
void handleStart()
|
||||
{
|
||||
Serial.println("Start");
|
||||
}
|
||||
void handleStop()
|
||||
{
|
||||
Serial.println("Stop");
|
||||
}
|
||||
void handleContinue()
|
||||
{
|
||||
Serial.println("Continue");
|
||||
}
|
||||
void handleClock()
|
||||
{
|
||||
Serial.println("Clock");
|
||||
}
|
||||
void handleSysEx(byte* inArray, unsigned inSize)
|
||||
{
|
||||
Serial.print("SysEx\t[ ");
|
||||
for (unsigned i = 0; i < inSize; ++i)
|
||||
{
|
||||
Serial.print(inArray[i], HEX);
|
||||
Serial.print(' ');
|
||||
}
|
||||
Serial.println(']');
|
||||
}
|
||||
|
||||
// --
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while(!Serial); // Wait for the Serial Monitor to open
|
||||
|
||||
MIDI.begin();
|
||||
MIDI.turnThruOff();
|
||||
|
||||
setupRxBenchmark();
|
||||
startTxBenchmark();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
MIDI.read();
|
||||
}
|
||||
|
|
@ -1,135 +0,0 @@
|
|||
#include <MIDI.h>
|
||||
|
||||
#if defined(USBCON)
|
||||
#include <midi_UsbTransport.h>
|
||||
|
||||
static const unsigned sUsbTransportBufferSize = 16;
|
||||
typedef midi::UsbTransport<sUsbTransportBufferSize> UsbTransport;
|
||||
|
||||
UsbTransport sUsbTransport;
|
||||
|
||||
MIDI_CREATE_INSTANCE(UsbTransport, sUsbTransport, MIDI);
|
||||
|
||||
#else // No USB available, fallback to Serial
|
||||
MIDI_CREATE_DEFAULT_INSTANCE();
|
||||
#endif
|
||||
|
||||
// --
|
||||
|
||||
void attachCallbacks()
|
||||
{
|
||||
MIDI.setHandleNoteOff(handleNoteOff);
|
||||
MIDI.setHandleNoteOn(handleNoteOn);
|
||||
MIDI.setHandleControlChange(handleControlChange);
|
||||
MIDI.setHandleProgramChange(handleProgramChange);
|
||||
MIDI.setHandleAfterTouchChannel(handleAfterTouchChannel);
|
||||
MIDI.setHandleAfterTouchPoly(handleAfterTouchPoly);
|
||||
MIDI.setHandlePitchBend(handlePitchBend);
|
||||
MIDI.setHandleStart(handleStart);
|
||||
MIDI.setHandleStop(handleStop);
|
||||
MIDI.setHandleContinue(handleContinue);
|
||||
MIDI.setHandleClock(handleClock);
|
||||
MIDI.setHandleSystemExclusive(handleSysEx);
|
||||
}
|
||||
|
||||
// --
|
||||
|
||||
void printChannel(byte inChannel)
|
||||
{
|
||||
Serial.print("[");
|
||||
Serial.print(inChannel);
|
||||
Serial.print("] ");
|
||||
}
|
||||
|
||||
void handleNoteOff(byte inChannel, byte inNote, byte inVelocity)
|
||||
{
|
||||
printChannel(inChannel);
|
||||
Serial.print("Note Off\t");
|
||||
Serial.print(inNote);
|
||||
Serial.print(' ');
|
||||
Serial.println(inVelocity);
|
||||
}
|
||||
void handleNoteOn(byte inChannel, byte inNote, byte inVelocity)
|
||||
{
|
||||
printChannel(inChannel);
|
||||
Serial.print("Note On\t");
|
||||
Serial.print(inNote);
|
||||
Serial.print(' ');
|
||||
Serial.println(inVelocity);
|
||||
}
|
||||
void handleControlChange(byte inChannel, byte inControl, byte inValue)
|
||||
{
|
||||
printChannel(inChannel);
|
||||
Serial.print("Control Change\t");
|
||||
Serial.print(inControl);
|
||||
Serial.print(' ');
|
||||
Serial.println(inValue);
|
||||
}
|
||||
void handleProgramChange(byte inChannel, byte inProgram)
|
||||
{
|
||||
printChannel(inChannel);
|
||||
Serial.print("Program Change\t");
|
||||
Serial.println(inProgram);
|
||||
}
|
||||
void handleAfterTouchChannel(byte inChannel, byte inPressure)
|
||||
{
|
||||
printChannel(inChannel);
|
||||
Serial.print("AT Channel\t");
|
||||
Serial.println(inPressure);
|
||||
}
|
||||
void handleAfterTouchPoly(byte inChannel, byte inNote, byte inPressure)
|
||||
{
|
||||
printChannel(inChannel);
|
||||
Serial.print("AT Poly\t");
|
||||
Serial.print(inNote);
|
||||
Serial.print(' ');
|
||||
Serial.println(inPressure);
|
||||
}
|
||||
void handlePitchBend(byte inChannel, int inBend)
|
||||
{
|
||||
printChannel(inChannel);
|
||||
Serial.print("Pitch Bend\t");
|
||||
Serial.println(inBend);
|
||||
}
|
||||
void handleStart()
|
||||
{
|
||||
Serial.println("Start");
|
||||
}
|
||||
void handleStop()
|
||||
{
|
||||
Serial.println("Stop");
|
||||
}
|
||||
void handleContinue()
|
||||
{
|
||||
Serial.println("Continue");
|
||||
}
|
||||
void handleClock()
|
||||
{
|
||||
Serial.println("Clock");
|
||||
}
|
||||
void handleSysEx(byte* inArray, unsigned inSize)
|
||||
{
|
||||
Serial.print("SysEx\t[ ");
|
||||
for (unsigned i = 0; i < inSize; ++i)
|
||||
{
|
||||
Serial.print(inArray[i], HEX);
|
||||
Serial.print(' ');
|
||||
}
|
||||
Serial.println(']');
|
||||
}
|
||||
|
||||
// --
|
||||
|
||||
void setup()
|
||||
{
|
||||
MIDI.begin(MIDI_CHANNEL_OMNI);
|
||||
|
||||
// attachCallbacks();
|
||||
// Serial.begin(115200);
|
||||
// while(!Serial); // Wait for the Serial Monitor to open
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
MIDI.read();
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
#include <MIDI.h>
|
||||
|
||||
#if defined(USBCON)
|
||||
#include <midi_UsbTransport.h>
|
||||
|
||||
static const unsigned sUsbTransportBufferSize = 16;
|
||||
typedef midi::UsbTransport<sUsbTransportBufferSize> UsbTransport;
|
||||
|
||||
UsbTransport sUsbTransport;
|
||||
|
||||
MIDI_CREATE_INSTANCE(UsbTransport, sUsbTransport, MIDI);
|
||||
|
||||
#else // No USB available, fallback to Serial
|
||||
MIDI_CREATE_DEFAULT_INSTANCE();
|
||||
#endif
|
||||
|
||||
// --
|
||||
|
||||
void handleNoteOn(byte inChannel, byte inNumber, byte inVelocity)
|
||||
{
|
||||
Serial.print("NoteOn ");
|
||||
Serial.print(inNumber);
|
||||
Serial.print("\tvelocity: ");
|
||||
Serial.println(inVelocity);
|
||||
}
|
||||
void handleNoteOff(byte inChannel, byte inNumber, byte inVelocity)
|
||||
{
|
||||
Serial.print("NoteOff ");
|
||||
Serial.print(inNumber);
|
||||
Serial.print("\tvelocity: ");
|
||||
Serial.println(inVelocity);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
while (!Serial);
|
||||
MIDI.begin();
|
||||
MIDI.setHandleNoteOn(handleNoteOn);
|
||||
MIDI.setHandleNoteOff(handleNoteOff);
|
||||
Serial.println("Arduino ready.");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
MIDI.read();
|
||||
}
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit ec44c6c1675c25b9827aacd08c02433cccde7780
|
||||
Subproject commit ecd530865cefdfa7dea58e84f6aa1b548950363d
|
||||
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 1f81cc9f52184bbc271bfcee63b5a0efb03c8cf7
|
||||
|
|
@ -29,6 +29,14 @@ sendSongPosition KEYWORD2
|
|||
sendSongSelect KEYWORD2
|
||||
sendTuneRequest KEYWORD2
|
||||
sendRealTime KEYWORD2
|
||||
sendCommon KEYWORD2
|
||||
sendClock KEYWORD2
|
||||
sendStart KEYWORD2
|
||||
sendStop KEYWORD2
|
||||
sendTick KEYWORD2
|
||||
sendContinue KEYWORD2
|
||||
sendActiveSensing KEYWORD2
|
||||
sendSystemReset KEYWORD2
|
||||
beginRpn KEYWORD2
|
||||
sendRpnValue KEYWORD2
|
||||
sendRpnIncrement KEYWORD2
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "MIDI Library",
|
||||
"version": "4.4.0",
|
||||
"version": "5.0.0",
|
||||
"keywords": "midi",
|
||||
"description": "Enables MIDI I/O communications on the Arduino serial ports",
|
||||
"license": "MIT",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
name=MIDI Library
|
||||
version=4.4.0
|
||||
author=Forty Seven Effects
|
||||
version=5.0.0
|
||||
author=Forty Seven Effects, lathoub
|
||||
maintainer=Francois Best <francois.best@fortyseveneffects.com>
|
||||
sentence=MIDI I/Os for Arduino
|
||||
paragraph=Read & send MIDI messages to interface with your controllers and synths
|
||||
|
|
|
|||
|
|
@ -6,12 +6,10 @@ add_library(midi STATIC
|
|||
midi_Namespace.h
|
||||
midi_Defs.h
|
||||
midi_Message.h
|
||||
midi_Platform.h
|
||||
midi_Settings.h
|
||||
midi_RingBuffer.h
|
||||
midi_RingBuffer.hpp
|
||||
midi_UsbTransport.h
|
||||
midi_UsbTransport.hpp
|
||||
MIDI.cpp
|
||||
MIDI.hpp
|
||||
MIDI.h
|
||||
serialMIDI.h
|
||||
)
|
||||
|
|
|
|||
133
src/MIDI.h
133
src/MIDI.h
|
|
@ -2,7 +2,7 @@
|
|||
* @file MIDI.h
|
||||
* Project Arduino MIDI Library
|
||||
* @brief MIDI Library for the Arduino
|
||||
* @author Francois Best
|
||||
* @author Francois Best, lathoub
|
||||
* @date 24/02/11
|
||||
* @license MIT - Copyright (c) 2015 Francois Best
|
||||
*
|
||||
|
|
@ -28,31 +28,41 @@
|
|||
#pragma once
|
||||
|
||||
#include "midi_Defs.h"
|
||||
#include "midi_Platform.h"
|
||||
#include "midi_Settings.h"
|
||||
#include "midi_Message.h"
|
||||
|
||||
#include "serialMIDI.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
BEGIN_MIDI_NAMESPACE
|
||||
|
||||
#define MIDI_LIBRARY_VERSION 0x050000
|
||||
#define MIDI_LIBRARY_VERSION_MAJOR 5
|
||||
#define MIDI_LIBRARY_VERSION_MINOR 0
|
||||
#define MIDI_LIBRARY_VERSION_PATCH 0
|
||||
|
||||
/*! \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 SerialPort, class _Settings = DefaultSettings>
|
||||
template<class Transport, class _Settings = DefaultSettings, class _Platform = DefaultPlatform>
|
||||
class MidiInterface
|
||||
{
|
||||
public:
|
||||
typedef _Settings Settings;
|
||||
typedef _Platform Platform;
|
||||
typedef Message<Settings::SysExMaxSize> MidiMessage;
|
||||
|
||||
public:
|
||||
inline MidiInterface(SerialPort& inSerial);
|
||||
inline MidiInterface(Transport&);
|
||||
inline ~MidiInterface();
|
||||
|
||||
public:
|
||||
void begin(Channel inChannel = 1);
|
||||
void begin(Channel inChannel = MIDI_CHANNEL_OMNI);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// MIDI Output
|
||||
|
|
@ -97,6 +107,17 @@ public:
|
|||
inline void sendSongPosition(unsigned inBeats);
|
||||
inline void sendSongSelect(DataByte inSongNumber);
|
||||
inline void sendTuneRequest();
|
||||
|
||||
inline void sendCommon(MidiType inType, unsigned = 0);
|
||||
|
||||
inline void sendClock() { sendRealTime(Clock); };
|
||||
inline void sendStart() { sendRealTime(Start); };
|
||||
inline void sendStop() { sendRealTime(Stop); };
|
||||
inline void sendTick() { sendRealTime(Tick); };
|
||||
inline void sendContinue() { sendRealTime(Continue); };
|
||||
inline void sendActiveSensing() { sendRealTime(ActiveSensing); };
|
||||
inline void sendSystemReset() { sendRealTime(SystemReset); };
|
||||
|
||||
inline void sendRealTime(MidiType inType);
|
||||
|
||||
inline void beginRpn(unsigned inNumber,
|
||||
|
|
@ -125,6 +146,8 @@ public:
|
|||
Channel inChannel);
|
||||
inline void endNrpn(Channel inChannel);
|
||||
|
||||
inline void send(const MidiMessage&);
|
||||
|
||||
public:
|
||||
void send(MidiType inType,
|
||||
DataByte inData1,
|
||||
|
|
@ -160,48 +183,54 @@ public:
|
|||
// 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 setHandleMessage(void (*fptr)(const MidiMessage&)) { mMessageCallback = fptr; };
|
||||
inline void setHandleError(ErrorCallback fptr) { mErrorCallback = fptr; }
|
||||
inline void setHandleNoteOff(NoteOffCallback fptr) { mNoteOffCallback = fptr; }
|
||||
inline void setHandleNoteOn(NoteOnCallback fptr) { mNoteOnCallback = fptr; }
|
||||
inline void setHandleAfterTouchPoly(AfterTouchPolyCallback fptr) { mAfterTouchPolyCallback = fptr; }
|
||||
inline void setHandleControlChange(ControlChangeCallback fptr) { mControlChangeCallback = fptr; }
|
||||
inline void setHandleProgramChange(ProgramChangeCallback fptr) { mProgramChangeCallback = fptr; }
|
||||
inline void setHandleAfterTouchChannel(AfterTouchChannelCallback fptr) { mAfterTouchChannelCallback = fptr; }
|
||||
inline void setHandlePitchBend(PitchBendCallback fptr) { mPitchBendCallback = fptr; }
|
||||
inline void setHandleSystemExclusive(SystemExclusiveCallback fptr) { mSystemExclusiveCallback = fptr; }
|
||||
inline void setHandleTimeCodeQuarterFrame(TimeCodeQuarterFrameCallback fptr) { mTimeCodeQuarterFrameCallback = fptr; }
|
||||
inline void setHandleSongPosition(SongPositionCallback fptr) { mSongPositionCallback = fptr; }
|
||||
inline void setHandleSongSelect(SongSelectCallback fptr) { mSongSelectCallback = fptr; }
|
||||
inline void setHandleTuneRequest(TuneRequestCallback fptr) { mTuneRequestCallback = fptr; }
|
||||
inline void setHandleClock(ClockCallback fptr) { mClockCallback = fptr; }
|
||||
inline void setHandleStart(StartCallback fptr) { mStartCallback = fptr; }
|
||||
inline void setHandleTick(TickCallback fptr) { mTickCallback = fptr; }
|
||||
inline void setHandleContinue(ContinueCallback fptr) { mContinueCallback = fptr; }
|
||||
inline void setHandleStop(StopCallback fptr) { mStopCallback = fptr; }
|
||||
inline void setHandleActiveSensing(ActiveSensingCallback fptr) { mActiveSensingCallback = fptr; }
|
||||
inline void setHandleSystemReset(SystemResetCallback fptr) { mSystemResetCallback = fptr; }
|
||||
|
||||
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);
|
||||
void (*mMessageCallback)(const MidiMessage& message) = nullptr;
|
||||
ErrorCallback mErrorCallback = nullptr;
|
||||
NoteOffCallback mNoteOffCallback = nullptr;
|
||||
NoteOnCallback mNoteOnCallback = nullptr;
|
||||
AfterTouchPolyCallback mAfterTouchPolyCallback = nullptr;
|
||||
ControlChangeCallback mControlChangeCallback = nullptr;
|
||||
ProgramChangeCallback mProgramChangeCallback = nullptr;
|
||||
AfterTouchChannelCallback mAfterTouchChannelCallback = nullptr;
|
||||
PitchBendCallback mPitchBendCallback = nullptr;
|
||||
SystemExclusiveCallback mSystemExclusiveCallback = nullptr;
|
||||
TimeCodeQuarterFrameCallback mTimeCodeQuarterFrameCallback = nullptr;
|
||||
SongPositionCallback mSongPositionCallback = nullptr;
|
||||
SongSelectCallback mSongSelectCallback = nullptr;
|
||||
TuneRequestCallback mTuneRequestCallback = nullptr;
|
||||
ClockCallback mClockCallback = nullptr;
|
||||
StartCallback mStartCallback = nullptr;
|
||||
TickCallback mTickCallback = nullptr;
|
||||
ContinueCallback mContinueCallback = nullptr;
|
||||
StopCallback mStopCallback = nullptr;
|
||||
ActiveSensingCallback mActiveSensingCallback = nullptr;
|
||||
SystemResetCallback mSystemResetCallback = nullptr;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// MIDI Soft Thru
|
||||
|
|
@ -217,31 +246,45 @@ public:
|
|||
private:
|
||||
void thruFilter(byte inChannel);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// MIDI Parsing
|
||||
|
||||
private:
|
||||
bool parse();
|
||||
inline void handleNullVelocityNoteOnAsNoteOff();
|
||||
inline bool inputFilter(Channel inChannel);
|
||||
inline void resetInput();
|
||||
inline void UpdateLastSentTime();
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Transport
|
||||
|
||||
public:
|
||||
Transport* getTransport() { return &mTransport; };
|
||||
|
||||
private:
|
||||
typedef Message<Settings::SysExMaxSize> MidiMessage;
|
||||
Transport& mTransport;
|
||||
|
||||
private:
|
||||
SerialPort& mSerial;
|
||||
// -------------------------------------------------------------------------
|
||||
// Internal variables
|
||||
|
||||
private:
|
||||
Channel mInputChannel;
|
||||
StatusByte mRunningStatus_RX;
|
||||
StatusByte mRunningStatus_TX;
|
||||
byte mPendingMessage[3];
|
||||
unsigned mPendingMessageExpectedLenght;
|
||||
unsigned mPendingMessageExpectedLength;
|
||||
unsigned mPendingMessageIndex;
|
||||
unsigned mCurrentRpnNumber;
|
||||
unsigned mCurrentNrpnNumber;
|
||||
bool mThruActivated : 1;
|
||||
Thru::Mode mThruFilterMode : 7;
|
||||
MidiMessage mMessage;
|
||||
|
||||
unsigned long mLastMessageSentTime;
|
||||
unsigned long mLastMessageReceivedTime;
|
||||
unsigned long mSenderActiveSensingPeriodicity;
|
||||
bool mReceiverActiveSensingActivated;
|
||||
int8_t mLastError;
|
||||
|
||||
private:
|
||||
inline StatusByte getStatus(MidiType inType,
|
||||
|
|
|
|||
745
src/MIDI.hpp
745
src/MIDI.hpp
File diff suppressed because it is too large
Load Diff
104
src/midi_Defs.h
104
src/midi_Defs.h
|
|
@ -2,7 +2,7 @@
|
|||
* @file midi_Defs.h
|
||||
* Project Arduino MIDI Library
|
||||
* @brief MIDI Library for the Arduino - Definitions
|
||||
* @author Francois Best
|
||||
* @author Francois Best, lathoub
|
||||
* @date 24/02/11
|
||||
* @license MIT - Copyright (c) 2015 Francois Best
|
||||
*
|
||||
|
|
@ -38,11 +38,6 @@ typedef uint8_t byte;
|
|||
|
||||
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
|
||||
|
|
@ -51,6 +46,10 @@ BEGIN_MIDI_NAMESPACE
|
|||
#define MIDI_PITCHBEND_MIN -8192
|
||||
#define MIDI_PITCHBEND_MAX 8191
|
||||
|
||||
/*! Receiving Active Sensing
|
||||
*/
|
||||
static const uint16_t ActiveSensingTimeout = 300;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Type definitions
|
||||
|
||||
|
|
@ -59,28 +58,65 @@ typedef byte DataByte;
|
|||
typedef byte Channel;
|
||||
typedef byte FilterMode;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Errors
|
||||
static const uint8_t ErrorParse = 0;
|
||||
static const uint8_t ErrorActiveSensingTimeout = 1;
|
||||
static const uint8_t WarningSplitSysEx = 2;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Aliasing
|
||||
|
||||
using ErrorCallback = void (*)(int8_t);
|
||||
using NoteOffCallback = void (*)(Channel channel, byte note, byte velocity);
|
||||
using NoteOnCallback = void (*)(Channel channel, byte note, byte velocity);
|
||||
using AfterTouchPolyCallback = void (*)(Channel channel, byte note, byte velocity);
|
||||
using ControlChangeCallback = void (*)(Channel channel, byte, byte);
|
||||
using ProgramChangeCallback = void (*)(Channel channel, byte);
|
||||
using AfterTouchChannelCallback = void (*)(Channel channel, byte);
|
||||
using PitchBendCallback = void (*)(Channel channel, int);
|
||||
using SystemExclusiveCallback = void (*)(byte * array, unsigned size);
|
||||
using TimeCodeQuarterFrameCallback = void (*)(byte data);
|
||||
using SongPositionCallback = void (*)(unsigned beats);
|
||||
using SongSelectCallback = void (*)(byte songnumber);
|
||||
using TuneRequestCallback = void (*)(void);
|
||||
using ClockCallback = void (*)(void);
|
||||
using StartCallback = void (*)(void);
|
||||
using TickCallback = void (*)(void);
|
||||
using ContinueCallback = void (*)(void);
|
||||
using StopCallback = void (*)(void);
|
||||
using ActiveSensingCallback = void (*)(void);
|
||||
using SystemResetCallback = void (*)(void);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/*! 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
|
||||
NoteOff = 0x80, ///< Channel Message - Note Off
|
||||
NoteOn = 0x90, ///< Channel Message - Note On
|
||||
AfterTouchPoly = 0xA0, ///< Channel Message - Polyphonic AfterTouch
|
||||
ControlChange = 0xB0, ///< Channel Message - Control Change / Channel Mode
|
||||
ProgramChange = 0xC0, ///< Channel Message - Program Change
|
||||
AfterTouchChannel = 0xD0, ///< Channel Message - Channel (monophonic) AfterTouch
|
||||
PitchBend = 0xE0, ///< Channel Message - 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
|
||||
Undefined_F4 = 0xF4,
|
||||
Undefined_F5 = 0xF5,
|
||||
TuneRequest = 0xF6, ///< System Common - Tune Request
|
||||
SystemExclusiveEnd = 0xF7, ///< System Exclusive End
|
||||
Clock = 0xF8, ///< System Real Time - Timing Clock
|
||||
Undefined_F9 = 0xF9,
|
||||
Tick = Undefined_F9, ///< System Real Time - Timing Tick (1 tick = 10 milliseconds)
|
||||
Start = 0xFA, ///< System Real Time - Start
|
||||
Continue = 0xFB, ///< System Real Time - Continue
|
||||
Stop = 0xFC, ///< System Real Time - Stop
|
||||
Undefined_FD = 0xFD,
|
||||
ActiveSensing = 0xFE, ///< System Real Time - Active Sensing
|
||||
SystemReset = 0xFF, ///< System Real Time - System Reset
|
||||
};
|
||||
|
|
@ -99,17 +135,6 @@ struct Thru
|
|||
};
|
||||
};
|
||||
|
||||
/*! 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.
|
||||
|
|
@ -204,35 +229,4 @@ struct RPN
|
|||
};
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/*! \brief Create an instance of the library attached to a serial port.
|
||||
You can use HardwareSerial or SoftwareSerial for the serial port.
|
||||
Example: MIDI_CREATE_INSTANCE(HardwareSerial, Serial2, midi2);
|
||||
Then call midi2.begin(), midi2.read() etc..
|
||||
*/
|
||||
#define MIDI_CREATE_INSTANCE(Type, SerialPort, Name) \
|
||||
midi::MidiInterface<Type> Name((Type&)SerialPort);
|
||||
|
||||
#if defined(SERIAL_PORT_HARDWARE_OPEN)
|
||||
// Use recommended default external serial port.
|
||||
#define MIDI_CREATE_DEFAULT_INSTANCE() \
|
||||
MIDI_CREATE_INSTANCE(HardwareSerial, SERIAL_PORT_HARDWARE_OPEN, MIDI);
|
||||
#else
|
||||
/*! \brief Create an instance of the library with default name, serial port
|
||||
and settings, for compatibility with sketches written with pre-v4.2 MIDI Lib,
|
||||
or if you don't bother using custom names, serial port or settings.
|
||||
*/
|
||||
#define MIDI_CREATE_DEFAULT_INSTANCE() \
|
||||
MIDI_CREATE_INSTANCE(HardwareSerial, Serial, MIDI);
|
||||
#endif
|
||||
|
||||
/*! \brief Create an instance of the library attached to a serial port with
|
||||
custom settings.
|
||||
@see DefaultSettings
|
||||
@see MIDI_CREATE_INSTANCE
|
||||
*/
|
||||
#define MIDI_CREATE_CUSTOM_INSTANCE(Type, SerialPort, Name, Settings) \
|
||||
midi::MidiInterface<Type, Settings> Name((Type&)SerialPort);
|
||||
|
||||
END_MIDI_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ struct Message
|
|||
*/
|
||||
inline Message()
|
||||
: channel(0)
|
||||
, type(midi::InvalidType)
|
||||
, type(MIDI_NAMESPACE::InvalidType)
|
||||
, data1(0)
|
||||
, data2(0)
|
||||
, valid(false)
|
||||
|
|
@ -91,6 +91,10 @@ struct Message
|
|||
*/
|
||||
bool valid;
|
||||
|
||||
/*! Total Length of the message.
|
||||
*/
|
||||
unsigned length;
|
||||
|
||||
inline unsigned getSysExSize() const
|
||||
{
|
||||
const unsigned size = unsigned(data2) << 8 | data1;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
/*!
|
||||
* @file midi_UsbPacketInterface.h
|
||||
* @file midi_Platform.h
|
||||
* Project Arduino MIDI Library
|
||||
* @brief MIDI Library for the Arduino - Transport layer for USB MIDI
|
||||
* @author Francois Best
|
||||
* @date 2018-11-03
|
||||
* @license MIT - Copyright (c) 2018 Francois Best
|
||||
* @brief MIDI Library for the Arduino - Platform
|
||||
* @license MIT - Copyright (c) 2015 Francois Best
|
||||
* @author lathoub
|
||||
* @date 22/03/20
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
@ -28,17 +28,24 @@
|
|||
#pragma once
|
||||
|
||||
#include "midi_Defs.h"
|
||||
#include "midi_UsbDefs.h"
|
||||
#include <MIDIUSB_Defs.h>
|
||||
|
||||
BEGIN_MIDI_NAMESPACE
|
||||
|
||||
template<typename Buffer>
|
||||
bool composeTxPacket(Buffer& inBuffer, midiEventPacket_t& outPacket);
|
||||
#if ARDUINO
|
||||
|
||||
template<typename Buffer>
|
||||
void serialiseRxPacket(const midiEventPacket_t& inPacket, Buffer& outBuffer);
|
||||
// DefaultPlatform is the Arduino Platform
|
||||
struct DefaultPlatform
|
||||
{
|
||||
static unsigned long now() { return ::millis(); };
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
struct DefaultPlatform
|
||||
{
|
||||
static unsigned long now() { return 0; };
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
END_MIDI_NAMESPACE
|
||||
|
||||
#include "midi_UsbPacketInterface.hpp"
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
/*!
|
||||
* @file midi_RingBuffer.h
|
||||
* Project Arduino MIDI Library
|
||||
* @brief MIDI Library for Arduino - Ring Buffer
|
||||
* @author Francois Best
|
||||
* @date 10/10/2016
|
||||
* @license MIT - Copyright (c) 2016 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"
|
||||
|
||||
BEGIN_MIDI_NAMESPACE
|
||||
|
||||
template<typename DataType, int Size>
|
||||
class RingBuffer
|
||||
{
|
||||
private:
|
||||
static const int sMask = Size - 1;
|
||||
|
||||
public:
|
||||
RingBuffer();
|
||||
~RingBuffer();
|
||||
|
||||
public:
|
||||
inline int getLength() const;
|
||||
inline bool isEmpty() const;
|
||||
|
||||
public:
|
||||
void write(DataType inData);
|
||||
void write(const DataType* inData, int inSize);
|
||||
void pop(int inNumberOfItems = 1);
|
||||
void clear();
|
||||
|
||||
public:
|
||||
DataType peek(int inOffset = 0) const;
|
||||
DataType read();
|
||||
void read(DataType* outData, int inSize);
|
||||
|
||||
private:
|
||||
DataType mData[Size];
|
||||
int mLength;
|
||||
int mWriteHead;
|
||||
int mReadHead;
|
||||
};
|
||||
|
||||
END_MIDI_NAMESPACE
|
||||
|
||||
#include "midi_RingBuffer.hpp"
|
||||
|
|
@ -1,145 +0,0 @@
|
|||
/*!
|
||||
* @file midi_RingBuffer.hpp
|
||||
* Project Arduino MIDI Library
|
||||
* @brief MIDI Library for Arduino - Ring Buffer
|
||||
* @author Francois Best
|
||||
* @date 10/10/2016
|
||||
* @license MIT - Copyright (c) 2016 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
|
||||
|
||||
namespace {
|
||||
|
||||
template<int N>
|
||||
struct isPowerOfTwo
|
||||
{
|
||||
static const bool value = N && !(N & (N - 1));
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// --
|
||||
|
||||
BEGIN_MIDI_NAMESPACE
|
||||
|
||||
template<typename DataType, int Size>
|
||||
RingBuffer<DataType, Size>::RingBuffer()
|
||||
: mLength(0)
|
||||
, mWriteHead(0)
|
||||
, mReadHead(0)
|
||||
{
|
||||
static_assert(isPowerOfTwo<Size>::value, "Size must be a power of two.");
|
||||
memset(mData, DataType(0), Size * sizeof(DataType));
|
||||
}
|
||||
|
||||
template<typename DataType, int Size>
|
||||
RingBuffer<DataType, Size>::~RingBuffer()
|
||||
{
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
template<typename DataType, int Size>
|
||||
inline int RingBuffer<DataType, Size>::getLength() const
|
||||
{
|
||||
return mLength;
|
||||
}
|
||||
|
||||
template<typename DataType, int Size>
|
||||
inline bool RingBuffer<DataType, Size>::isEmpty() const
|
||||
{
|
||||
return mLength == 0;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
template<typename DataType, int Size>
|
||||
void RingBuffer<DataType, Size>::write(DataType inData)
|
||||
{
|
||||
mData[mWriteHead] = inData;
|
||||
mWriteHead = (mWriteHead + 1) & sMask;
|
||||
mLength++;
|
||||
if (mLength > Size) {
|
||||
mLength = Size;
|
||||
mReadHead = (mReadHead + 1) & sMask;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename DataType, int Size>
|
||||
void RingBuffer<DataType, Size>::write(const DataType* inData, int inSize)
|
||||
{
|
||||
for (int i = 0; i < inSize; ++i)
|
||||
{
|
||||
write(inData[i]);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename DataType, int Size>
|
||||
void RingBuffer<DataType, Size>::pop(int inNumberOfItems)
|
||||
{
|
||||
for (int i = 0; i < inNumberOfItems; ++i)
|
||||
{
|
||||
read();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename DataType, int Size>
|
||||
void RingBuffer<DataType, Size>::clear()
|
||||
{
|
||||
memset(mData, DataType(0), Size * sizeof(DataType));
|
||||
mReadHead = 0;
|
||||
mWriteHead = 0;
|
||||
mLength = 0;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
template<typename DataType, int Size>
|
||||
DataType RingBuffer<DataType, Size>::peek(int inOffset) const
|
||||
{
|
||||
const int head = (mReadHead + inOffset) & sMask;
|
||||
return mData[head];
|
||||
}
|
||||
|
||||
template<typename DataType, int Size>
|
||||
DataType RingBuffer<DataType, Size>::read()
|
||||
{
|
||||
mLength--;
|
||||
if (mLength < 0) {
|
||||
mLength = 0;
|
||||
return 0;
|
||||
}
|
||||
const DataType data = mData[mReadHead];
|
||||
mReadHead = (mReadHead + 1) & sMask;
|
||||
return data;
|
||||
}
|
||||
|
||||
template<typename DataType, int Size>
|
||||
void RingBuffer<DataType, Size>::read(DataType* outData, int inSize)
|
||||
{
|
||||
for (int i = 0; i < inSize; ++i)
|
||||
{
|
||||
outData[i] = read();
|
||||
}
|
||||
}
|
||||
|
||||
END_MIDI_NAMESPACE
|
||||
|
|
@ -67,16 +67,38 @@ struct DefaultSettings
|
|||
*/
|
||||
static const bool Use1ByteParsing = true;
|
||||
|
||||
/*! Override the default MIDI baudrate to transmit over USB serial, to
|
||||
a decoding program such as Hairless MIDI (set baudrate to 115200)\n
|
||||
http://projectgus.github.io/hairless-midiserial/
|
||||
*/
|
||||
static const long BaudRate = 31250;
|
||||
|
||||
/*! 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;
|
||||
|
||||
/*! Global switch to turn on/off sender ActiveSensing
|
||||
Set to true to send ActiveSensing
|
||||
Set to false will not send ActiveSensing message (will also save memory)
|
||||
*/
|
||||
static const bool UseSenderActiveSensing = false;
|
||||
|
||||
/*! Global switch to turn on/off receiver ActiveSensing
|
||||
Set to true to check for message timeouts (via ErrorCallback)
|
||||
Set to false will not check if chained device are still alive (if they use ActiveSensing) (will also save memory)
|
||||
*/
|
||||
static const bool UseReceiverActiveSensing = false;
|
||||
|
||||
/*! 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.
|
||||
|
||||
Typical value is 250 (ms) - an Active Sensing command is send every 250ms.
|
||||
(All Roland devices send Active Sensing every 250ms)
|
||||
|
||||
Setting this field to 0 will disable sending MIDI active sensing.
|
||||
*/
|
||||
static const uint16_t SenderActiveSensingPeriodicity = 0;
|
||||
};
|
||||
|
||||
END_MIDI_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -1,135 +0,0 @@
|
|||
/*!
|
||||
* @file midi_UsbDefs.h
|
||||
* Project Arduino MIDI Library
|
||||
* @brief MIDI Library for the Arduino - Definitions
|
||||
* @author Francois Best
|
||||
* @date 24/02/11
|
||||
* @license MIT - Copyright (c) 2016 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
|
||||
|
||||
struct CodeIndexNumbers
|
||||
{
|
||||
enum
|
||||
{
|
||||
reserved = 0x00,
|
||||
misc = reserved,
|
||||
|
||||
cableEvent = 0x01,
|
||||
systemCommon2Bytes = 0x02,
|
||||
systemCommon3Bytes = 0x03,
|
||||
|
||||
sysExStart = 0x04,
|
||||
sysExContinue = sysExStart,
|
||||
|
||||
systemCommon1Byte = 0x05,
|
||||
sysExEnds1Byte = systemCommon1Byte,
|
||||
|
||||
sysExEnds2Bytes = 0x06,
|
||||
sysExEnds3Bytes = 0x07,
|
||||
noteOff = 0x08,
|
||||
noteOn = 0x09,
|
||||
polyPressure = 0x0A,
|
||||
controlChange = 0x0B,
|
||||
programChange = 0x0C,
|
||||
channelPressure = 0x0D,
|
||||
pitchBend = 0x0E,
|
||||
singleByte = 0x0F,
|
||||
};
|
||||
|
||||
static inline byte fromStatus(StatusByte inStatus)
|
||||
{
|
||||
const byte statusWithoutChannel = inStatus & 0xf0;
|
||||
if (statusWithoutChannel >= midi::NoteOff &&
|
||||
statusWithoutChannel <= midi::PitchBend)
|
||||
{
|
||||
// Channel Voice Messages
|
||||
return inStatus >> 4;
|
||||
}
|
||||
switch (inStatus)
|
||||
{
|
||||
// System Real Time Messages
|
||||
case midi::Clock:
|
||||
case midi::Start:
|
||||
case midi::Continue:
|
||||
case midi::Stop:
|
||||
case midi::ActiveSensing:
|
||||
case midi::SystemReset:
|
||||
return CodeIndexNumbers::singleByte;
|
||||
|
||||
// System Exclusive
|
||||
case midi::SystemExclusive:
|
||||
return CodeIndexNumbers::sysExStart;
|
||||
case 0xf7:
|
||||
return CodeIndexNumbers::sysExEnds1Byte;
|
||||
|
||||
// System Common Messages
|
||||
case midi::TimeCodeQuarterFrame:
|
||||
return CodeIndexNumbers::systemCommon2Bytes;
|
||||
case midi::SongPosition:
|
||||
return CodeIndexNumbers::systemCommon3Bytes;
|
||||
case midi::SongSelect:
|
||||
return CodeIndexNumbers::systemCommon2Bytes;
|
||||
case midi::TuneRequest:
|
||||
return CodeIndexNumbers::systemCommon1Byte;
|
||||
|
||||
default:
|
||||
return CodeIndexNumbers::reserved;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static inline byte getSize(byte inCodeIndexNumber)
|
||||
{
|
||||
switch (inCodeIndexNumber)
|
||||
{
|
||||
case noteOn:
|
||||
case noteOff:
|
||||
case controlChange:
|
||||
case pitchBend:
|
||||
case polyPressure:
|
||||
case systemCommon3Bytes:
|
||||
case sysExEnds3Bytes:
|
||||
case sysExStart:
|
||||
return 3;
|
||||
|
||||
case programChange:
|
||||
case channelPressure:
|
||||
case systemCommon2Bytes:
|
||||
case sysExEnds2Bytes:
|
||||
return 2;
|
||||
|
||||
case systemCommon1Byte: // also sysExEnds1Byte
|
||||
case singleByte:
|
||||
return 1;
|
||||
|
||||
default:
|
||||
return 0; // Can be any length (1, 2 or 3).
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
END_MIDI_NAMESPACE
|
||||
|
|
@ -1,146 +0,0 @@
|
|||
/*!
|
||||
* @file midi_UsbPacketInterface.hpp
|
||||
* Project Arduino MIDI Library
|
||||
* @brief MIDI Library for the Arduino - Transport layer for USB MIDI
|
||||
* @author Francois Best
|
||||
* @date 2018-11-03
|
||||
* @license MIT - Copyright (c) 2018 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
|
||||
|
||||
template<typename Buffer>
|
||||
bool composeTxPacket(Buffer& inBuffer, midiEventPacket_t& outPacket)
|
||||
{
|
||||
if (inBuffer.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
const int bufferLength = inBuffer.getLength();
|
||||
const byte status = inBuffer.peek();
|
||||
const byte cin = midi::CodeIndexNumbers::fromStatus(status);
|
||||
const byte messageLength = midi::CodeIndexNumbers::getSize(cin);
|
||||
|
||||
if (status == 0xf0)
|
||||
{
|
||||
// Start of SysEx, check if it can end in one go.
|
||||
if (bufferLength == 2 && inBuffer.peek(1) == 0xf7)
|
||||
{
|
||||
outPacket.header = midi::CodeIndexNumbers::sysExEnds2Bytes;
|
||||
outPacket.byte1 = status;
|
||||
outPacket.byte2 = 0xf7;
|
||||
outPacket.byte3 = 0x00;
|
||||
inBuffer.pop(2);
|
||||
return true;
|
||||
}
|
||||
if (bufferLength >= 3 && inBuffer.peek(2) == 0xf7)
|
||||
{
|
||||
outPacket.header = midi::CodeIndexNumbers::sysExEnds3Bytes;
|
||||
outPacket.byte1 = status;
|
||||
outPacket.byte2 = inBuffer.peek(1);
|
||||
outPacket.byte3 = 0xf7;
|
||||
inBuffer.pop(3);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ((status & 0x80) == 0x00)
|
||||
{
|
||||
// First byte is data, consider it's part of a running SysEx message.
|
||||
// We look for the SysEx end byte in the next 2 bytes
|
||||
// At this point, bufferLength should be 2 or more to continue.
|
||||
if (bufferLength == 1)
|
||||
{
|
||||
return false; // Not enough data
|
||||
}
|
||||
if (bufferLength == 2)
|
||||
{
|
||||
const bool isSysExEnd = inBuffer.peek(1) == 0xf7;
|
||||
if (!isSysExEnd)
|
||||
{
|
||||
return false; // Not enough data (eg: 0x12 0x42)
|
||||
}
|
||||
// eg: 0x42 0xf7
|
||||
outPacket.header = midi::CodeIndexNumbers::sysExEnds2Bytes;
|
||||
outPacket.byte1 = status;
|
||||
outPacket.byte2 = inBuffer.peek(1);
|
||||
outPacket.byte3 = 0x00;
|
||||
inBuffer.pop(2);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// bufferLength > 2
|
||||
const byte byte3 = inBuffer.peek(2);
|
||||
outPacket.header = byte3 == 0xf7
|
||||
? midi::CodeIndexNumbers::sysExEnds3Bytes
|
||||
: midi::CodeIndexNumbers::sysExContinue;
|
||||
outPacket.byte1 = status;
|
||||
outPacket.byte2 = inBuffer.peek(1);
|
||||
outPacket.byte3 = byte3;
|
||||
inBuffer.pop(3);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (bufferLength < messageLength) {
|
||||
return false; // Not enough data in the buffer to compose a full packet.
|
||||
}
|
||||
|
||||
outPacket.header = cin;
|
||||
outPacket.byte1 = status;
|
||||
outPacket.byte2 = messageLength >= 2 ? inBuffer.peek(1) : 0x00;
|
||||
outPacket.byte3 = messageLength >= 3 ? inBuffer.peek(2) : 0x00;
|
||||
|
||||
inBuffer.pop(messageLength);
|
||||
return true;
|
||||
|
||||
// todo: handle interleaved RealTime messages
|
||||
}
|
||||
|
||||
template<typename Buffer>
|
||||
void serialiseRxPacket(const midiEventPacket_t& inPacket, Buffer& outBuffer)
|
||||
{
|
||||
const byte cin = inPacket.header & 0x0f;
|
||||
const byte messageLength = midi::CodeIndexNumbers::getSize(cin);
|
||||
switch (messageLength)
|
||||
{
|
||||
case 1:
|
||||
outBuffer.write(inPacket.byte1);
|
||||
return;
|
||||
case 2:
|
||||
outBuffer.write(inPacket.byte1);
|
||||
outBuffer.write(inPacket.byte2);
|
||||
return;
|
||||
case 3:
|
||||
outBuffer.write(inPacket.byte1);
|
||||
outBuffer.write(inPacket.byte2);
|
||||
outBuffer.write(inPacket.byte3);
|
||||
return;
|
||||
case 0:
|
||||
default:
|
||||
// Invalid or ignored messages, don't serialise.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
END_MIDI_NAMESPACE
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
/*!
|
||||
* @file midi_UsbTransport.h
|
||||
* Project Arduino MIDI Library
|
||||
* @brief MIDI Library for the Arduino - Transport layer for USB MIDI
|
||||
* @author Francois Best
|
||||
* @date 10/10/2016
|
||||
* @license MIT - Copyright (c) 2016 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_RingBuffer.h"
|
||||
#include "midi_UsbPacketInterface.h"
|
||||
#include <MIDIUSB.h>
|
||||
|
||||
BEGIN_MIDI_NAMESPACE
|
||||
|
||||
template<unsigned BuffersSize>
|
||||
class UsbTransport
|
||||
{
|
||||
public:
|
||||
inline UsbTransport();
|
||||
inline ~UsbTransport();
|
||||
|
||||
public: // Serial / Stream API required for template compatibility
|
||||
inline void begin(unsigned inBaudrate);
|
||||
inline unsigned available();
|
||||
inline byte read();
|
||||
inline void write(byte inData);
|
||||
|
||||
private:
|
||||
inline void pollUsbMidi();
|
||||
inline void recomposeAndSendTxPackets();
|
||||
|
||||
private:
|
||||
typedef RingBuffer<byte, BuffersSize> Buffer;
|
||||
Buffer mTxBuffer;
|
||||
Buffer mRxBuffer;
|
||||
};
|
||||
|
||||
END_MIDI_NAMESPACE
|
||||
|
||||
#include "midi_UsbTransport.hpp"
|
||||
|
|
@ -1,102 +0,0 @@
|
|||
/*!
|
||||
* @file midi_UsbTransport.hpp
|
||||
* Project Arduino MIDI Library
|
||||
* @brief MIDI Library for the Arduino - Transport layer for USB MIDI
|
||||
* @author Francois Best
|
||||
* @date 10/10/2016
|
||||
* @license MIT - Copyright (c) 2016 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
|
||||
|
||||
template<unsigned BufferSize>
|
||||
inline UsbTransport<BufferSize>::UsbTransport()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template<unsigned BufferSize>
|
||||
inline UsbTransport<BufferSize>::~UsbTransport()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
template<unsigned BufferSize>
|
||||
inline void UsbTransport<BufferSize>::begin(unsigned inBaudrate)
|
||||
{
|
||||
mTxBuffer.clear();
|
||||
mRxBuffer.clear();
|
||||
}
|
||||
|
||||
template<unsigned BufferSize>
|
||||
inline unsigned UsbTransport<BufferSize>::available()
|
||||
{
|
||||
pollUsbMidi();
|
||||
return mRxBuffer.getLength();
|
||||
}
|
||||
|
||||
template<unsigned BufferSize>
|
||||
inline byte UsbTransport<BufferSize>::read()
|
||||
{
|
||||
return mRxBuffer.read();
|
||||
}
|
||||
|
||||
template<unsigned BufferSize>
|
||||
inline void UsbTransport<BufferSize>::write(byte inData)
|
||||
{
|
||||
mTxBuffer.write(inData);
|
||||
recomposeAndSendTxPackets();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
template<unsigned BufferSize>
|
||||
inline void UsbTransport<BufferSize>::pollUsbMidi()
|
||||
{
|
||||
midiEventPacket_t packet = MidiUSB.read();
|
||||
while (packet.header != 0)
|
||||
{
|
||||
serialiseRxPacket(packet, mRxBuffer);
|
||||
packet = MidiUSB.read();
|
||||
}
|
||||
}
|
||||
|
||||
template<unsigned BufferSize>
|
||||
inline void UsbTransport<BufferSize>::recomposeAndSendTxPackets()
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
bool sent = false;
|
||||
while (composeTxPacket(mTxBuffer, packet))
|
||||
{
|
||||
MidiUSB.sendMIDI(packet);
|
||||
sent = true;
|
||||
}
|
||||
if (sent)
|
||||
{
|
||||
MidiUSB.flush();
|
||||
}
|
||||
}
|
||||
|
||||
END_MIDI_NAMESPACE
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
/*!
|
||||
* @file serialMIDI.h
|
||||
* Project Arduino MIDI Library
|
||||
* @brief MIDI Library for the Arduino - Platform
|
||||
* @license MIT - Copyright (c) 2015 Francois Best
|
||||
* @author lathoub, Francois Best
|
||||
* @date 22/03/20
|
||||
*
|
||||
* 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"
|
||||
|
||||
BEGIN_MIDI_NAMESPACE
|
||||
|
||||
struct DefaultSerialSettings
|
||||
{
|
||||
/*! Override the default MIDI baudrate to transmit over USB serial, to
|
||||
a decoding program such as Hairless MIDI (set baudrate to 115200)\n
|
||||
http://projectgus.github.io/hairless-midiserial/
|
||||
*/
|
||||
static const long BaudRate = 31250;
|
||||
};
|
||||
|
||||
template <class SerialPort, class _Settings = DefaultSerialSettings>
|
||||
class SerialMIDI
|
||||
{
|
||||
typedef _Settings Settings;
|
||||
|
||||
public:
|
||||
SerialMIDI(SerialPort& inSerial)
|
||||
: mSerial(inSerial)
|
||||
{
|
||||
};
|
||||
|
||||
public:
|
||||
void begin()
|
||||
{
|
||||
// Initialise the Serial port
|
||||
#if defined(AVR_CAKE)
|
||||
mSerial. template open<Settings::BaudRate>();
|
||||
#else
|
||||
mSerial.begin(Settings::BaudRate);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool beginTransmission(MidiType)
|
||||
{
|
||||
return true;
|
||||
};
|
||||
|
||||
void write(byte value)
|
||||
{
|
||||
mSerial.write(value);
|
||||
};
|
||||
|
||||
void endTransmission()
|
||||
{
|
||||
};
|
||||
|
||||
byte read()
|
||||
{
|
||||
return mSerial.read();
|
||||
};
|
||||
|
||||
unsigned available()
|
||||
{
|
||||
return mSerial.available();
|
||||
};
|
||||
|
||||
private:
|
||||
SerialPort& mSerial;
|
||||
};
|
||||
|
||||
/*! \brief Create an instance of the library attached to a serial port.
|
||||
You can use HardwareSerial or SoftwareSerial for the serial port.
|
||||
Example: MIDI_CREATE_INSTANCE(HardwareSerial, Serial2, midi2);
|
||||
Then call midi2.begin(), midi2.read() etc..
|
||||
*/
|
||||
#define MIDI_CREATE_INSTANCE(Type, SerialPort, Name) \
|
||||
MIDI_NAMESPACE::SerialMIDI<Type> serial##Name(SerialPort);\
|
||||
MIDI_NAMESPACE::MidiInterface<MIDI_NAMESPACE::SerialMIDI<Type>> Name((MIDI_NAMESPACE::SerialMIDI<Type>&)serial##Name);
|
||||
|
||||
#if defined(ARDUINO_SAM_DUE) || defined(USBCON) || defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MKL26Z64__)
|
||||
// Leonardo, Due and other USB boards use Serial1 by default.
|
||||
#define MIDI_CREATE_DEFAULT_INSTANCE() \
|
||||
MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI);
|
||||
#else
|
||||
/*! \brief Create an instance of the library with default name, serial port
|
||||
and settings, for compatibility with sketches written with pre-v4.2 MIDI Lib,
|
||||
or if you don't bother using custom names, serial port or settings.
|
||||
*/
|
||||
#define MIDI_CREATE_DEFAULT_INSTANCE() \
|
||||
MIDI_CREATE_INSTANCE(HardwareSerial, Serial, MIDI);
|
||||
#endif
|
||||
|
||||
|
||||
END_MIDI_NAMESPACE
|
||||
|
|
@ -2,10 +2,36 @@
|
|||
|
||||
#include "test-mocks.h"
|
||||
#include <inttypes.h>
|
||||
#include <src/midi_RingBuffer.h>
|
||||
|
||||
BEGIN_TEST_MOCKS_NAMESPACE
|
||||
|
||||
template<typename DataType, int Size>
|
||||
class RingBuffer
|
||||
{
|
||||
public:
|
||||
RingBuffer();
|
||||
~RingBuffer();
|
||||
|
||||
public:
|
||||
int getLength() const;
|
||||
bool isEmpty() const;
|
||||
|
||||
public:
|
||||
void write(DataType inData);
|
||||
void write(const DataType* inData, int inSize);
|
||||
void clear();
|
||||
|
||||
public:
|
||||
DataType peek() const;
|
||||
DataType read();
|
||||
void read(DataType* outData, int inSize);
|
||||
|
||||
private:
|
||||
DataType mData[Size];
|
||||
DataType* mWriteHead;
|
||||
DataType* mReadHead;
|
||||
};
|
||||
|
||||
template<int BufferSize>
|
||||
class SerialMock
|
||||
{
|
||||
|
|
@ -23,7 +49,7 @@ public: // Test Helpers API
|
|||
void moveTxToRx(); // Simulate loopback
|
||||
|
||||
public:
|
||||
typedef midi::RingBuffer<uint8_t, BufferSize> Buffer;
|
||||
typedef RingBuffer<uint8_t, BufferSize> Buffer;
|
||||
Buffer mTxBuffer;
|
||||
Buffer mRxBuffer;
|
||||
int mBaudrate;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,103 @@
|
|||
|
||||
BEGIN_TEST_MOCKS_NAMESPACE
|
||||
|
||||
template<typename DataType, int Size>
|
||||
RingBuffer<DataType, Size>::RingBuffer()
|
||||
: mWriteHead(mData)
|
||||
, mReadHead(mData)
|
||||
{
|
||||
memset(mData, DataType(0), Size * sizeof(DataType));
|
||||
}
|
||||
|
||||
template<typename DataType, int Size>
|
||||
RingBuffer<DataType, Size>::~RingBuffer()
|
||||
{
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
template<typename DataType, int Size>
|
||||
int RingBuffer<DataType, Size>::getLength() const
|
||||
{
|
||||
if (mReadHead == mWriteHead)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (mWriteHead > mReadHead)
|
||||
{
|
||||
return int(mWriteHead - mReadHead);
|
||||
}
|
||||
else
|
||||
{
|
||||
return int(mWriteHead - mData) + Size - int(mReadHead - mData);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename DataType, int Size>
|
||||
bool RingBuffer<DataType, Size>::isEmpty() const
|
||||
{
|
||||
return mReadHead == mWriteHead;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
template<typename DataType, int Size>
|
||||
void RingBuffer<DataType, Size>::write(DataType inData)
|
||||
{
|
||||
*mWriteHead++ = inData;
|
||||
if (mWriteHead >= mData + Size)
|
||||
{
|
||||
mWriteHead = mData;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename DataType, int Size>
|
||||
void RingBuffer<DataType, Size>::write(const DataType* inData, int inSize)
|
||||
{
|
||||
for (int i = 0; i < inSize; ++i)
|
||||
{
|
||||
write(inData[i]);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename DataType, int Size>
|
||||
void RingBuffer<DataType, Size>::clear()
|
||||
{
|
||||
memset(mData, DataType(0), Size * sizeof(DataType));
|
||||
mReadHead = mData;
|
||||
mWriteHead = mData;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
template<typename DataType, int Size>
|
||||
DataType RingBuffer<DataType, Size>::peek() const
|
||||
{
|
||||
return *mReadHead;
|
||||
}
|
||||
|
||||
template<typename DataType, int Size>
|
||||
DataType RingBuffer<DataType, Size>::read()
|
||||
{
|
||||
const DataType data = *mReadHead++;
|
||||
if (mReadHead >= mData + Size)
|
||||
{
|
||||
mReadHead = mData;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
template<typename DataType, int Size>
|
||||
void RingBuffer<DataType, Size>::read(DataType* outData, int inSize)
|
||||
{
|
||||
for (int i = 0; i < inSize; ++i)
|
||||
{
|
||||
outData[i] = read();
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
||||
template<int BufferSize>
|
||||
SerialMock<BufferSize>::SerialMock()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ include_directories(
|
|||
"${unit-tests_SOURCE_DIR}"
|
||||
"${gtest_SOURCE_DIR}/include"
|
||||
"${gmock_SOURCE_DIR}/include"
|
||||
"${ROOT_SOURCE_DIR}/external/midi-usb/src"
|
||||
)
|
||||
|
||||
add_executable(unit-tests
|
||||
|
|
@ -18,13 +17,10 @@ add_executable(unit-tests
|
|||
tests/unit-tests_Settings.cpp
|
||||
tests/unit-tests_Settings.h
|
||||
tests/unit-tests_SysExCodec.cpp
|
||||
tests/unit-tests_RingBuffer.cpp
|
||||
tests/unit-tests_MidiInput.cpp
|
||||
tests/unit-tests_MidiInputCallbacks.cpp
|
||||
tests/unit-tests_MidiOutput.cpp
|
||||
tests/unit-tests_MidiThru.cpp
|
||||
tests/unit-tests_MidiUsbDefs.cpp
|
||||
tests/unit-tests_MidiUsbPacketInterface.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(unit-tests
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@ BEGIN_UNNAMED_NAMESPACE
|
|||
using namespace testing;
|
||||
USING_NAMESPACE_UNIT_TESTS
|
||||
typedef test_mocks::SerialMock<32> SerialMock;
|
||||
typedef midi::MidiInterface<SerialMock> MidiInterface;
|
||||
typedef midi::SerialMIDI<SerialMock> Transport;
|
||||
typedef midi::MidiInterface<Transport> MidiInterface;
|
||||
|
||||
template<unsigned Size>
|
||||
struct VariableSysExSettings : midi::DefaultSettings
|
||||
|
|
@ -53,7 +54,6 @@ TEST(MidiInput, getTypeFromStatusByte)
|
|||
}
|
||||
EXPECT_EQ(MidiInterface::getTypeFromStatusByte(0xf4), midi::InvalidType);
|
||||
EXPECT_EQ(MidiInterface::getTypeFromStatusByte(0xf5), midi::InvalidType);
|
||||
EXPECT_EQ(MidiInterface::getTypeFromStatusByte(0xf9), midi::InvalidType);
|
||||
EXPECT_EQ(MidiInterface::getTypeFromStatusByte(0xfd), midi::InvalidType);
|
||||
}
|
||||
|
||||
|
|
@ -93,12 +93,13 @@ TEST(MidiInput, isChannelMessage)
|
|||
TEST(MidiInput, begin)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
// Default channel
|
||||
midi.begin();
|
||||
EXPECT_EQ(serial.mBaudrate, 31250);
|
||||
EXPECT_EQ(midi.getInputChannel(), 1);
|
||||
EXPECT_EQ(midi.getInputChannel(), 0);
|
||||
|
||||
// Specific channel
|
||||
midi.begin(12);
|
||||
|
|
@ -109,7 +110,8 @@ TEST(MidiInput, begin)
|
|||
TEST(MidiInput, initInputChannel)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
EXPECT_EQ(midi.getInputChannel(), 0);
|
||||
midi.setInputChannel(12);
|
||||
|
|
@ -119,7 +121,9 @@ TEST(MidiInput, initInputChannel)
|
|||
TEST(MidiInput, initMessage)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
EXPECT_EQ(midi.getType(), midi::InvalidType);
|
||||
EXPECT_EQ(midi.getChannel(), 0);
|
||||
EXPECT_EQ(midi.getData1(), 0);
|
||||
|
|
@ -131,7 +135,9 @@ TEST(MidiInput, initMessage)
|
|||
TEST(MidiInput, channelFiltering)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
static const unsigned rxSize = 3;
|
||||
static const byte rxData[rxSize] = { 0x9b, 12, 34 };
|
||||
midi.begin(4); // Mistmatching channel
|
||||
|
|
@ -144,7 +150,9 @@ TEST(MidiInput, channelFiltering)
|
|||
TEST(MidiInput, noRxData)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
midi.begin();
|
||||
EXPECT_EQ(midi.read(), false);
|
||||
}
|
||||
|
|
@ -152,7 +160,9 @@ TEST(MidiInput, noRxData)
|
|||
TEST(MidiInput, inputDisabled)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
static const unsigned rxSize = 3;
|
||||
static const byte rxData[rxSize] = { 0x9b, 12, 34 };
|
||||
midi.begin(MIDI_CHANNEL_OFF); // Invalid channel
|
||||
|
|
@ -165,10 +175,12 @@ TEST(MidiInput, inputDisabled)
|
|||
TEST(MidiInput, multiByteParsing)
|
||||
{
|
||||
typedef VariableSettings<false, false> Settings;
|
||||
typedef midi::MidiInterface<SerialMock, Settings> MultiByteMidiInterface;
|
||||
typedef midi::MidiInterface<Transport, Settings> MultiByteMidiInterface;
|
||||
|
||||
SerialMock serial;
|
||||
MultiByteMidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MultiByteMidiInterface midi(transport);
|
||||
|
||||
static const unsigned rxSize = 3;
|
||||
static const byte rxData[rxSize] = { 0x9b, 12, 34 };
|
||||
midi.begin(12);
|
||||
|
|
@ -179,7 +191,9 @@ TEST(MidiInput, multiByteParsing)
|
|||
TEST(MidiInput, noteOn)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
static const unsigned rxSize = 10;
|
||||
static const byte rxData[rxSize] = {
|
||||
0x9b, 12, 34,
|
||||
|
|
@ -230,7 +244,9 @@ TEST(MidiInput, noteOn)
|
|||
TEST(MidiInput, noteOff)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
static const unsigned rxSize = 8;
|
||||
static const byte rxData[rxSize] = {
|
||||
0x8b, 12, 34,
|
||||
|
|
@ -272,7 +288,9 @@ TEST(MidiInput, noteOff)
|
|||
TEST(MidiInput, programChange)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
static const unsigned rxSize = 6;
|
||||
static const byte rxData[rxSize] = {
|
||||
0xc3, 12, 34,
|
||||
|
|
@ -316,7 +334,9 @@ TEST(MidiInput, programChange)
|
|||
TEST(MidiInput, controlChange)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
static const unsigned rxSize = 8;
|
||||
static const byte rxData[rxSize] = {
|
||||
0xbb, 12, 34,
|
||||
|
|
@ -358,7 +378,9 @@ TEST(MidiInput, controlChange)
|
|||
TEST(MidiInput, pitchBend)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
static const unsigned rxSize = 8;
|
||||
static const byte rxData[rxSize] = {
|
||||
0xeb, 12, 34,
|
||||
|
|
@ -400,7 +422,9 @@ TEST(MidiInput, pitchBend)
|
|||
TEST(MidiInput, afterTouchPoly)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
static const unsigned rxSize = 8;
|
||||
static const byte rxData[rxSize] = {
|
||||
0xab, 12, 34,
|
||||
|
|
@ -442,7 +466,9 @@ TEST(MidiInput, afterTouchPoly)
|
|||
TEST(MidiInput, afterTouchChannel)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
static const unsigned rxSize = 6;
|
||||
static const byte rxData[rxSize] = {
|
||||
0xd3, 12, 34,
|
||||
|
|
@ -487,10 +513,12 @@ TEST(MidiInput, sysExWithinBufferSize)
|
|||
{
|
||||
typedef VariableSysExSettings<1024> Settings;
|
||||
typedef test_mocks::SerialMock<2048> LargerSerialMock;
|
||||
typedef midi::MidiInterface<LargerSerialMock, Settings> LargerMidiInterface;
|
||||
typedef midi::SerialMIDI<LargerSerialMock> LargerTransport;
|
||||
typedef midi::MidiInterface<LargerTransport, Settings> LargerMidiInterface;
|
||||
|
||||
LargerSerialMock serial;
|
||||
LargerMidiInterface midi(serial);
|
||||
LargerTransport transport(serial);
|
||||
LargerMidiInterface midi(transport);
|
||||
|
||||
// Short Frame < 256
|
||||
{
|
||||
|
|
@ -553,10 +581,11 @@ TEST(MidiInput, sysExWithinBufferSize)
|
|||
TEST(MidiInput, sysExOverBufferSize)
|
||||
{
|
||||
typedef VariableSysExSettings<8> Settings;
|
||||
typedef midi::MidiInterface<SerialMock, Settings> SmallMidiInterface;
|
||||
typedef midi::MidiInterface<Transport, Settings> SmallMidiInterface;
|
||||
|
||||
SerialMock serial;
|
||||
SmallMidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
SmallMidiInterface midi(transport);
|
||||
|
||||
static const unsigned frameLength = 15;
|
||||
static const byte frame[frameLength] = {
|
||||
|
|
@ -566,17 +595,29 @@ TEST(MidiInput, sysExOverBufferSize)
|
|||
midi.begin();
|
||||
serial.mRxBuffer.write(frame, frameLength);
|
||||
|
||||
for (unsigned i = 0; i < frameLength - 1; ++i)
|
||||
{
|
||||
EXPECT_EQ(midi.read(), false);
|
||||
}
|
||||
EXPECT_EQ(midi.read(), false);
|
||||
EXPECT_EQ(midi.read(), false); // start sysex f0
|
||||
EXPECT_EQ(midi.read(), false); // H
|
||||
EXPECT_EQ(midi.read(), false); // e
|
||||
EXPECT_EQ(midi.read(), false); // l
|
||||
EXPECT_EQ(midi.read(), false); // l
|
||||
EXPECT_EQ(midi.read(), false); // o
|
||||
EXPECT_EQ(midi.read(), false); // , message send and buffer cleared.
|
||||
EXPECT_EQ(midi.read(), false); // start sysex
|
||||
EXPECT_EQ(midi.read(), false); // (space)
|
||||
EXPECT_EQ(midi.read(), false); // W
|
||||
EXPECT_EQ(midi.read(), false); // o
|
||||
EXPECT_EQ(midi.read(), false); // r
|
||||
EXPECT_EQ(midi.read(), false); // l
|
||||
EXPECT_EQ(midi.read(), false); // d
|
||||
EXPECT_EQ(midi.read(), true); // end sysex
|
||||
}
|
||||
|
||||
TEST(MidiInput, mtcQuarterFrame)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
static const unsigned rxSize = 4;
|
||||
static const byte rxData[rxSize] = {
|
||||
0xf1, 12,
|
||||
|
|
@ -606,7 +647,9 @@ TEST(MidiInput, mtcQuarterFrame)
|
|||
TEST(MidiInput, songPosition)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
static const unsigned rxSize = 6;
|
||||
static const byte rxData[rxSize] = {
|
||||
0xf2, 12, 34,
|
||||
|
|
@ -638,7 +681,9 @@ TEST(MidiInput, songPosition)
|
|||
TEST(MidiInput, songSelect)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
static const unsigned rxSize = 4;
|
||||
static const byte rxData[rxSize] = {
|
||||
0xf3, 12,
|
||||
|
|
@ -668,7 +713,9 @@ TEST(MidiInput, songSelect)
|
|||
TEST(MidiInput, tuneRequest)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
static const unsigned rxSize = 1;
|
||||
static const byte rxData[rxSize] = {
|
||||
0xf6
|
||||
|
|
@ -686,7 +733,9 @@ TEST(MidiInput, tuneRequest)
|
|||
TEST(MidiInput, realTime)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
static const unsigned rxSize = 8;
|
||||
static const byte rxData[rxSize] = {
|
||||
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
|
||||
|
|
@ -700,7 +749,11 @@ TEST(MidiInput, realTime)
|
|||
EXPECT_EQ(midi.getData1(), 0);
|
||||
EXPECT_EQ(midi.getData2(), 0);
|
||||
|
||||
EXPECT_EQ(midi.read(), false); // 0xf9 = undefined
|
||||
EXPECT_EQ(midi.read(), true);
|
||||
EXPECT_EQ(midi.getType(), midi::Tick);
|
||||
EXPECT_EQ(midi.getChannel(), 0);
|
||||
EXPECT_EQ(midi.getData1(), 0);
|
||||
EXPECT_EQ(midi.getData2(), 0);
|
||||
|
||||
EXPECT_EQ(midi.read(), true);
|
||||
EXPECT_EQ(midi.getType(), midi::Start);
|
||||
|
|
@ -740,7 +793,8 @@ TEST(MidiInput, realTime)
|
|||
TEST(MidiInput, interleavedRealTime)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
// Interleaved Clocks between NoteOn / Off messages (with running status)
|
||||
{
|
||||
|
|
@ -754,6 +808,7 @@ TEST(MidiInput, interleavedRealTime)
|
|||
};
|
||||
midi.begin(12);
|
||||
serial.mRxBuffer.write(rxData, rxSize);
|
||||
|
||||
EXPECT_EQ(midi.read(), false);
|
||||
EXPECT_EQ(midi.read(), false);
|
||||
|
||||
|
|
@ -816,6 +871,7 @@ TEST(MidiInput, interleavedRealTime)
|
|||
};
|
||||
midi.begin(12);
|
||||
serial.mRxBuffer.write(rxData, rxSize);
|
||||
|
||||
EXPECT_EQ(midi.read(), false);
|
||||
EXPECT_EQ(midi.read(), false);
|
||||
EXPECT_EQ(midi.read(), false);
|
||||
|
|
@ -841,13 +897,16 @@ TEST(MidiInput, strayEox)
|
|||
{
|
||||
// A stray End of Exclusive will reset the parser, but should it ?
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
static const unsigned rxSize = 4;
|
||||
static const byte rxData[rxSize] = {
|
||||
0x8b, 42, 0xf7, 12
|
||||
};
|
||||
midi.begin(MIDI_CHANNEL_OMNI);
|
||||
serial.mRxBuffer.write(rxData, rxSize);
|
||||
|
||||
EXPECT_EQ(midi.read(), false);
|
||||
EXPECT_EQ(midi.read(), false);
|
||||
EXPECT_EQ(midi.read(), false);
|
||||
|
|
@ -857,18 +916,20 @@ TEST(MidiInput, strayEox)
|
|||
TEST(MidiInput, strayUndefinedOneByteParsing)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
static const unsigned rxSize = 13;
|
||||
static const byte rxData[rxSize] = {
|
||||
0xbb, 12, 0xf9, 34,
|
||||
0xbb, 12, 0xfd, 34,
|
||||
12, 0,
|
||||
42, 0xfd, 127,
|
||||
0xf9,
|
||||
0xfd,
|
||||
42, 0xfd, 0
|
||||
};
|
||||
midi.begin(12);
|
||||
serial.mRxBuffer.write(rxData, rxSize);
|
||||
|
||||
EXPECT_EQ(midi.read(), false);
|
||||
EXPECT_EQ(midi.read(), false);
|
||||
EXPECT_EQ(midi.read(), false); // Invalid, should not reset parser
|
||||
|
|
@ -907,17 +968,19 @@ TEST(MidiInput, strayUndefinedOneByteParsing)
|
|||
TEST(MidiInput, strayUndefinedMultiByteParsing)
|
||||
{
|
||||
typedef VariableSettings<false, false> Settings;
|
||||
typedef midi::MidiInterface<SerialMock, Settings> MultiByteMidiInterface;
|
||||
typedef midi::MidiInterface<Transport, Settings> MultiByteMidiInterface;
|
||||
|
||||
SerialMock serial;
|
||||
MultiByteMidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MultiByteMidiInterface midi(transport);
|
||||
|
||||
static const unsigned rxSize = 4;
|
||||
static const byte rxData[rxSize] = {
|
||||
0xbb, 12, 0xf9, 34,
|
||||
0xbb, 12, 0xfd, 34,
|
||||
};
|
||||
midi.begin(12);
|
||||
serial.mRxBuffer.write(rxData, rxSize);
|
||||
|
||||
EXPECT_EQ(midi.read(), true);
|
||||
EXPECT_EQ(midi.getType(), midi::ControlChange);
|
||||
EXPECT_EQ(midi.getChannel(), 12);
|
||||
|
|
|
|||
|
|
@ -21,8 +21,10 @@ struct VariableSysExSettings : midi::DefaultSettings
|
|||
};
|
||||
|
||||
typedef test_mocks::SerialMock<256> SerialMock;
|
||||
typedef midi::SerialMIDI<SerialMock> Transport;
|
||||
|
||||
typedef VariableSysExSettings<256> Settings;
|
||||
typedef midi::MidiInterface<SerialMock, Settings> MidiInterface;
|
||||
typedef midi::MidiInterface<Transport, Settings> MidiInterface;
|
||||
|
||||
MidiInterface* midi;
|
||||
|
||||
|
|
@ -30,7 +32,8 @@ class MidiInputCallbacks : public Test
|
|||
{
|
||||
public:
|
||||
MidiInputCallbacks()
|
||||
: mMidi(mSerial)
|
||||
: mTransport(mSerial)
|
||||
, mMidi(mTransport)
|
||||
{
|
||||
}
|
||||
virtual ~MidiInputCallbacks()
|
||||
|
|
@ -50,6 +53,7 @@ protected:
|
|||
|
||||
protected:
|
||||
SerialMock mSerial;
|
||||
Transport mTransport;
|
||||
MidiInterface mMidi;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,8 @@ using namespace testing;
|
|||
USING_NAMESPACE_UNIT_TESTS;
|
||||
|
||||
typedef test_mocks::SerialMock<32> SerialMock;
|
||||
typedef midi::MidiInterface<SerialMock> MidiInterface;
|
||||
typedef midi::SerialMIDI<SerialMock> Transport;
|
||||
typedef midi::MidiInterface<Transport> MidiInterface;
|
||||
|
||||
typedef std::vector<uint8_t> Buffer;
|
||||
|
||||
|
|
@ -24,7 +25,8 @@ typedef std::vector<uint8_t> Buffer;
|
|||
TEST(MidiOutput, sendInvalid)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
midi.begin();
|
||||
midi.send(midi::NoteOn, 42, 42, 42); // Invalid channel > OFF
|
||||
|
|
@ -40,7 +42,9 @@ TEST(MidiOutput, sendInvalid)
|
|||
TEST(MidiOutput, sendGenericSingle)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
buffer.resize(3);
|
||||
|
||||
|
|
@ -54,10 +58,12 @@ TEST(MidiOutput, sendGenericSingle)
|
|||
TEST(MidiOutput, sendGenericWithRunningStatus)
|
||||
{
|
||||
typedef VariableSettings<true, false> Settings;
|
||||
typedef midi::MidiInterface<SerialMock, Settings> RsMidiInterface;
|
||||
typedef midi::MidiInterface<Transport, Settings> RsMidiInterface;
|
||||
|
||||
SerialMock serial;
|
||||
RsMidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
RsMidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
buffer.resize(5);
|
||||
|
||||
|
|
@ -74,10 +80,12 @@ TEST(MidiOutput, sendGenericWithRunningStatus)
|
|||
TEST(MidiOutput, sendGenericWithoutRunningStatus)
|
||||
{
|
||||
typedef VariableSettings<false, true> Settings; // No running status
|
||||
typedef midi::MidiInterface<SerialMock, Settings> NoRsMidiInterface;
|
||||
typedef midi::MidiInterface<Transport, Settings> NoRsMidiInterface;
|
||||
|
||||
SerialMock serial;
|
||||
NoRsMidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
NoRsMidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
buffer.resize(6);
|
||||
|
||||
|
|
@ -103,7 +111,9 @@ TEST(MidiOutput, sendGenericWithoutRunningStatus)
|
|||
TEST(MidiOutput, sendGenericBreakingRunningStatus)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
buffer.resize(6);
|
||||
|
||||
|
|
@ -118,7 +128,9 @@ TEST(MidiOutput, sendGenericBreakingRunningStatus)
|
|||
TEST(MidiOutput, sendGenericRealTimeShortcut)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
buffer.resize(6);
|
||||
|
||||
|
|
@ -140,7 +152,9 @@ TEST(MidiOutput, sendGenericRealTimeShortcut)
|
|||
TEST(MidiOutput, sendNoteOn)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
buffer.resize(6);
|
||||
|
||||
|
|
@ -155,7 +169,9 @@ TEST(MidiOutput, sendNoteOn)
|
|||
TEST(MidiOutput, sendNoteOff)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
buffer.resize(6);
|
||||
|
||||
|
|
@ -170,7 +186,9 @@ TEST(MidiOutput, sendNoteOff)
|
|||
TEST(MidiOutput, sendProgramChange)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
buffer.resize(4);
|
||||
|
||||
|
|
@ -185,7 +203,9 @@ TEST(MidiOutput, sendProgramChange)
|
|||
TEST(MidiOutput, sendControlChange)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
buffer.resize(6);
|
||||
|
||||
|
|
@ -200,7 +220,9 @@ TEST(MidiOutput, sendControlChange)
|
|||
TEST(MidiOutput, sendPitchBend)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
|
||||
// Int signature - arbitrary values
|
||||
|
|
@ -257,7 +279,9 @@ TEST(MidiOutput, sendPolyPressure)
|
|||
// This test is kept for coverage until removal of sendPolyPressure.
|
||||
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
buffer.resize(6);
|
||||
|
||||
|
|
@ -272,7 +296,9 @@ TEST(MidiOutput, sendPolyPressure)
|
|||
TEST(MidiOutput, sendAfterTouchMono)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
buffer.resize(4);
|
||||
|
||||
|
|
@ -287,7 +313,9 @@ TEST(MidiOutput, sendAfterTouchMono)
|
|||
TEST(MidiOutput, sendAfterTouchPoly)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
buffer.resize(6);
|
||||
|
||||
|
|
@ -302,10 +330,13 @@ TEST(MidiOutput, sendAfterTouchPoly)
|
|||
TEST(MidiOutput, sendSysEx)
|
||||
{
|
||||
typedef test_mocks::SerialMock<1024> LargeSerialMock;
|
||||
typedef midi::MidiInterface<LargeSerialMock> LargeMidiInterface;
|
||||
typedef midi::SerialMIDI<LargeSerialMock> LargeTransport;
|
||||
typedef midi::MidiInterface<LargeTransport> LargeMidiInterface;
|
||||
|
||||
LargeSerialMock serial;
|
||||
LargeMidiInterface midi(serial);
|
||||
LargeTransport transport(serial);
|
||||
LargeMidiInterface midi((LargeTransport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
|
||||
// Short frame
|
||||
|
|
@ -384,7 +415,9 @@ TEST(MidiOutput, sendSysEx)
|
|||
TEST(MidiOutput, sendTimeCodeQuarterFrame)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
|
||||
// Separate Nibbles
|
||||
|
|
@ -418,7 +451,9 @@ TEST(MidiOutput, sendTimeCodeQuarterFrame)
|
|||
TEST(MidiOutput, sendSongPosition)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
buffer.resize(6);
|
||||
|
||||
|
|
@ -434,7 +469,9 @@ TEST(MidiOutput, sendSongPosition)
|
|||
TEST(MidiOutput, sendSongSelect)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
buffer.resize(4);
|
||||
|
||||
|
|
@ -449,7 +486,9 @@ TEST(MidiOutput, sendSongSelect)
|
|||
TEST(MidiOutput, sendTuneRequest)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
buffer.resize(1);
|
||||
|
||||
|
|
@ -463,7 +502,9 @@ TEST(MidiOutput, sendTuneRequest)
|
|||
TEST(MidiOutput, sendRealTime)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
|
||||
// Test valid RealTime messages
|
||||
|
|
@ -509,10 +550,12 @@ TEST(MidiOutput, sendRealTime)
|
|||
TEST(MidiOutput, RPN)
|
||||
{
|
||||
typedef VariableSettings<true, true> Settings;
|
||||
typedef midi::MidiInterface<SerialMock, Settings> RsMidiInterface;
|
||||
typedef midi::MidiInterface<Transport, Settings> RsMidiInterface;
|
||||
|
||||
SerialMock serial;
|
||||
RsMidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
RsMidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
|
||||
// 14-bit Value Single Frame
|
||||
|
|
@ -625,10 +668,12 @@ TEST(MidiOutput, RPN)
|
|||
TEST(MidiOutput, NRPN)
|
||||
{
|
||||
typedef VariableSettings<true, true> Settings;
|
||||
typedef midi::MidiInterface<SerialMock, Settings> RsMidiInterface;
|
||||
typedef midi::MidiInterface<Transport, Settings> RsMidiInterface;
|
||||
|
||||
SerialMock serial;
|
||||
RsMidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
RsMidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
|
||||
// 14-bit Value Single Frame
|
||||
|
|
@ -741,10 +786,12 @@ TEST(MidiOutput, NRPN)
|
|||
TEST(MidiOutput, runningStatusCancellation)
|
||||
{
|
||||
typedef VariableSettings<true, false> Settings;
|
||||
typedef midi::MidiInterface<SerialMock, Settings> RsMidiInterface;
|
||||
typedef midi::MidiInterface<Transport, Settings> RsMidiInterface;
|
||||
|
||||
SerialMock serial;
|
||||
RsMidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
RsMidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
|
||||
static const unsigned sysExLength = 13;
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@ BEGIN_UNNAMED_NAMESPACE
|
|||
using namespace testing;
|
||||
USING_NAMESPACE_UNIT_TESTS
|
||||
typedef test_mocks::SerialMock<32> SerialMock;
|
||||
typedef midi::MidiInterface<SerialMock> MidiInterface;
|
||||
typedef midi::SerialMIDI<SerialMock> Transport;
|
||||
typedef midi::MidiInterface<Transport> MidiInterface;
|
||||
typedef std::vector<byte> Buffer;
|
||||
|
||||
template<unsigned Size>
|
||||
|
|
@ -28,7 +29,8 @@ struct VariableSysExSettings : midi::DefaultSettings
|
|||
TEST(MidiThru, defaultValues)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
EXPECT_EQ(midi.getThruState(), true);
|
||||
EXPECT_EQ(midi.getFilterMode(), midi::Thru::Full);
|
||||
|
|
@ -40,7 +42,8 @@ TEST(MidiThru, defaultValues)
|
|||
TEST(MidiThru, beginEnablesThru)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
midi.turnThruOff();
|
||||
EXPECT_EQ(midi.getThruState(), false);
|
||||
|
|
@ -53,7 +56,8 @@ TEST(MidiThru, beginEnablesThru)
|
|||
TEST(MidiThru, setGet)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
midi.turnThruOff();
|
||||
EXPECT_EQ(midi.getThruState(), false);
|
||||
|
|
@ -86,7 +90,8 @@ TEST(MidiThru, setGet)
|
|||
TEST(MidiThru, off)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
midi.begin(MIDI_CHANNEL_OMNI);
|
||||
midi.turnThruOff();
|
||||
|
|
@ -106,7 +111,9 @@ TEST(MidiThru, off)
|
|||
TEST(MidiThru, full)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
|
||||
midi.begin(MIDI_CHANNEL_OMNI);
|
||||
|
|
@ -148,7 +155,9 @@ TEST(MidiThru, full)
|
|||
TEST(MidiThru, sameChannel)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
|
||||
midi.begin(12);
|
||||
|
|
@ -177,7 +186,9 @@ TEST(MidiThru, sameChannel)
|
|||
TEST(MidiThru, sameChannelOmni) // Acts like full
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
|
||||
midi.begin(MIDI_CHANNEL_OMNI);
|
||||
|
|
@ -219,7 +230,9 @@ TEST(MidiThru, sameChannelOmni) // Acts like full
|
|||
TEST(MidiThru, differentChannel)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
|
||||
midi.begin(12);
|
||||
|
|
@ -248,7 +261,9 @@ TEST(MidiThru, differentChannel)
|
|||
TEST(MidiThru, differentChannelOmni) // Acts like off
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
|
||||
midi.begin(MIDI_CHANNEL_OMNI);
|
||||
|
|
@ -276,10 +291,12 @@ TEST(MidiThru, differentChannelOmni) // Acts like off
|
|||
TEST(MidiThru, multiByteThru)
|
||||
{
|
||||
typedef VariableSettings<false, false> MultiByteParsing;
|
||||
typedef midi::MidiInterface<SerialMock, MultiByteParsing> MultiByteMidiInterface;
|
||||
typedef midi::MidiInterface<Transport, MultiByteParsing> MultiByteMidiInterface;
|
||||
|
||||
SerialMock serial;
|
||||
MultiByteMidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MultiByteMidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
|
||||
midi.begin(MIDI_CHANNEL_OMNI);
|
||||
|
|
@ -305,10 +322,12 @@ TEST(MidiThru, multiByteThru)
|
|||
TEST(MidiThru, withTxRunningStatus)
|
||||
{
|
||||
typedef VariableSettings<true, true> Settings;
|
||||
typedef midi::MidiInterface<SerialMock, Settings> RsMidiInterface;
|
||||
typedef midi::MidiInterface<Transport, Settings> RsMidiInterface;
|
||||
|
||||
SerialMock serial;
|
||||
RsMidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
RsMidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
|
||||
midi.begin(MIDI_CHANNEL_OMNI);
|
||||
|
|
@ -348,7 +367,8 @@ TEST(MidiThru, withTxRunningStatus)
|
|||
TEST(MidiThru, invalidMode)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
midi.begin(MIDI_CHANNEL_OMNI);
|
||||
midi.setThruFilterMode(midi::Thru::Mode(42));
|
||||
|
|
|
|||
|
|
@ -1,60 +0,0 @@
|
|||
#include "unit-tests.h"
|
||||
#include <src/midi_UsbDefs.h>
|
||||
|
||||
BEGIN_MIDI_NAMESPACE
|
||||
|
||||
END_MIDI_NAMESPACE
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
BEGIN_UNNAMED_NAMESPACE
|
||||
|
||||
TEST(MidiUsbDefs, codeIndexNumberFromStatus)
|
||||
{
|
||||
typedef midi::CodeIndexNumbers CIN;
|
||||
EXPECT_EQ(CIN::fromStatus(midi::InvalidType), CIN::reserved);
|
||||
EXPECT_EQ(CIN::fromStatus(midi::NoteOff), CIN::noteOff);
|
||||
EXPECT_EQ(CIN::fromStatus(midi::NoteOn), CIN::noteOn);
|
||||
EXPECT_EQ(CIN::fromStatus(midi::AfterTouchPoly), CIN::polyPressure);
|
||||
EXPECT_EQ(CIN::fromStatus(midi::ControlChange), CIN::controlChange);
|
||||
EXPECT_EQ(CIN::fromStatus(midi::ProgramChange), CIN::programChange);
|
||||
EXPECT_EQ(CIN::fromStatus(midi::AfterTouchChannel), CIN::channelPressure);
|
||||
EXPECT_EQ(CIN::fromStatus(midi::PitchBend), CIN::pitchBend);
|
||||
EXPECT_EQ(CIN::fromStatus(midi::Clock), CIN::singleByte);
|
||||
EXPECT_EQ(CIN::fromStatus(midi::Start), CIN::singleByte);
|
||||
EXPECT_EQ(CIN::fromStatus(midi::Continue), CIN::singleByte);
|
||||
EXPECT_EQ(CIN::fromStatus(midi::Stop), CIN::singleByte);
|
||||
EXPECT_EQ(CIN::fromStatus(midi::ActiveSensing), CIN::singleByte);
|
||||
EXPECT_EQ(CIN::fromStatus(midi::SystemReset), CIN::singleByte);
|
||||
EXPECT_EQ(CIN::fromStatus(midi::SystemExclusive), CIN::sysExStart);
|
||||
EXPECT_EQ(CIN::fromStatus(midi::TuneRequest), CIN::systemCommon1Byte);
|
||||
EXPECT_EQ(CIN::fromStatus(midi::TimeCodeQuarterFrame), CIN::systemCommon2Bytes);
|
||||
EXPECT_EQ(CIN::fromStatus(midi::SongSelect), CIN::systemCommon2Bytes);
|
||||
EXPECT_EQ(CIN::fromStatus(midi::SongPosition), CIN::systemCommon3Bytes);
|
||||
}
|
||||
|
||||
TEST(MidiUsbDefs, codeIndexNumberSizes)
|
||||
{
|
||||
typedef midi::CodeIndexNumbers CIN;
|
||||
EXPECT_EQ(CIN::getSize(CIN::reserved), 0);
|
||||
EXPECT_EQ(CIN::getSize(CIN::misc), 0);
|
||||
EXPECT_EQ(CIN::getSize(CIN::cableEvent), 0);
|
||||
EXPECT_EQ(CIN::getSize(CIN::systemCommon2Bytes), 2);
|
||||
EXPECT_EQ(CIN::getSize(CIN::systemCommon3Bytes), 3);
|
||||
EXPECT_EQ(CIN::getSize(CIN::sysExStart), 3);
|
||||
EXPECT_EQ(CIN::getSize(CIN::sysExContinue), 3);
|
||||
EXPECT_EQ(CIN::getSize(CIN::systemCommon1Byte), 1);
|
||||
EXPECT_EQ(CIN::getSize(CIN::sysExEnds1Byte), 1);
|
||||
EXPECT_EQ(CIN::getSize(CIN::sysExEnds2Bytes), 2);
|
||||
EXPECT_EQ(CIN::getSize(CIN::sysExEnds3Bytes), 3);
|
||||
EXPECT_EQ(CIN::getSize(CIN::noteOff), 3);
|
||||
EXPECT_EQ(CIN::getSize(CIN::noteOn), 3);
|
||||
EXPECT_EQ(CIN::getSize(CIN::polyPressure), 3);
|
||||
EXPECT_EQ(CIN::getSize(CIN::controlChange), 3);
|
||||
EXPECT_EQ(CIN::getSize(CIN::programChange), 2);
|
||||
EXPECT_EQ(CIN::getSize(CIN::channelPressure), 2);
|
||||
EXPECT_EQ(CIN::getSize(CIN::pitchBend), 3);
|
||||
EXPECT_EQ(CIN::getSize(CIN::singleByte), 1);
|
||||
}
|
||||
|
||||
END_UNNAMED_NAMESPACE
|
||||
|
|
@ -1,843 +0,0 @@
|
|||
#include "unit-tests.h"
|
||||
#include <src/midi_UsbDefs.h>
|
||||
#include <src/midi_RingBuffer.h>
|
||||
#include <src/midi_UsbPacketInterface.h>
|
||||
|
||||
BEGIN_MIDI_NAMESPACE
|
||||
|
||||
END_MIDI_NAMESPACE
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
BEGIN_UNNAMED_NAMESPACE
|
||||
|
||||
using Buffer = midi::RingBuffer<uint8_t, 8>;
|
||||
using CIN = midi::CodeIndexNumbers;
|
||||
|
||||
TEST(MidiUsbPacketInterfaceTx, EmptyBufferShouldNotComposeAPacket)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
|
||||
const bool result = midi::composeTxPacket(buffer, packet);
|
||||
EXPECT_FALSE(result) << "Empty buffer should not compose a packet";
|
||||
}
|
||||
|
||||
TEST(MidiUsbPacketInterfaceTx, IncompleteDataShouldNotComposeAPacket)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
bool result = false;
|
||||
|
||||
buffer.write(0x81);
|
||||
result = midi::composeTxPacket(buffer, packet);
|
||||
EXPECT_FALSE(result) << "Insufficient data should not compose a packet";
|
||||
EXPECT_EQ(1, buffer.getLength()) << "Partial data should not be read out of the buffer";
|
||||
|
||||
buffer.write(0x12);
|
||||
buffer.write(0x42);
|
||||
result = midi::composeTxPacket(buffer, packet);
|
||||
EXPECT_TRUE(result) << "Complete data should compose a packet";
|
||||
EXPECT_EQ(0, buffer.getLength()) << "Complete packet data should be read out of the buffer";
|
||||
EXPECT_EQ(CIN::noteOff, packet.header);
|
||||
EXPECT_EQ(0x81, packet.byte1);
|
||||
EXPECT_EQ(0x12, packet.byte2);
|
||||
EXPECT_EQ(0x42, packet.byte3);
|
||||
}
|
||||
|
||||
// Channel Voice Messages --
|
||||
|
||||
TEST(MidiUsbPacketInterfaceTx, NoteOff)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
|
||||
buffer.write(0x80);
|
||||
buffer.write(0x12);
|
||||
buffer.write(0x42);
|
||||
EXPECT_TRUE(midi::composeTxPacket(buffer, packet));
|
||||
EXPECT_EQ(CIN::noteOff, packet.header);
|
||||
EXPECT_EQ(0x80, packet.byte1);
|
||||
EXPECT_EQ(0x12, packet.byte2);
|
||||
EXPECT_EQ(0x42, packet.byte3);
|
||||
EXPECT_EQ(0, buffer.getLength());
|
||||
}
|
||||
|
||||
TEST(MidiUsbPacketInterfaceTx, NoteOn)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
|
||||
buffer.write(0x91);
|
||||
buffer.write(0x12);
|
||||
buffer.write(0x42);
|
||||
EXPECT_TRUE(midi::composeTxPacket(buffer, packet));
|
||||
EXPECT_EQ(CIN::noteOn, packet.header);
|
||||
EXPECT_EQ(0x91, packet.byte1);
|
||||
EXPECT_EQ(0x12, packet.byte2);
|
||||
EXPECT_EQ(0x42, packet.byte3);
|
||||
EXPECT_EQ(0, buffer.getLength());
|
||||
}
|
||||
|
||||
TEST(MidiUsbPacketInterfaceTx, PolyPressure)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
|
||||
buffer.write(0xA2);
|
||||
buffer.write(0x12);
|
||||
buffer.write(0x42);
|
||||
EXPECT_TRUE(midi::composeTxPacket(buffer, packet));
|
||||
EXPECT_EQ(CIN::polyPressure, packet.header);
|
||||
EXPECT_EQ(0xA2, packet.byte1);
|
||||
EXPECT_EQ(0x12, packet.byte2);
|
||||
EXPECT_EQ(0x42, packet.byte3);
|
||||
EXPECT_EQ(0, buffer.getLength());
|
||||
}
|
||||
|
||||
TEST(MidiUsbPacketInterfaceTx, ControlChange)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
|
||||
buffer.write(0xB3);
|
||||
buffer.write(0x12);
|
||||
buffer.write(0x42);
|
||||
EXPECT_TRUE(midi::composeTxPacket(buffer, packet));
|
||||
EXPECT_EQ(CIN::controlChange, packet.header);
|
||||
EXPECT_EQ(0xB3, packet.byte1);
|
||||
EXPECT_EQ(0x12, packet.byte2);
|
||||
EXPECT_EQ(0x42, packet.byte3);
|
||||
EXPECT_EQ(0, buffer.getLength());
|
||||
}
|
||||
|
||||
TEST(MidiUsbPacketInterfaceTx, ProgramChange)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
|
||||
buffer.write(0xC4);
|
||||
buffer.write(0x12);
|
||||
EXPECT_TRUE(midi::composeTxPacket(buffer, packet));
|
||||
EXPECT_EQ(CIN::programChange, packet.header);
|
||||
EXPECT_EQ(0xC4, packet.byte1);
|
||||
EXPECT_EQ(0x12, packet.byte2);
|
||||
EXPECT_EQ(0x00, packet.byte3);
|
||||
EXPECT_EQ(0, buffer.getLength());
|
||||
}
|
||||
|
||||
TEST(MidiUsbPacketInterfaceTx, ChannelPressure)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
|
||||
buffer.write(0xD5);
|
||||
buffer.write(0x12);
|
||||
EXPECT_TRUE(midi::composeTxPacket(buffer, packet));
|
||||
EXPECT_EQ(CIN::channelPressure, packet.header);
|
||||
EXPECT_EQ(0xD5, packet.byte1);
|
||||
EXPECT_EQ(0x12, packet.byte2);
|
||||
EXPECT_EQ(0x00, packet.byte3);
|
||||
EXPECT_EQ(0, buffer.getLength());
|
||||
}
|
||||
|
||||
TEST(MidiUsbPacketInterfaceTx, PitchBend)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
|
||||
buffer.write(0xE6);
|
||||
buffer.write(0x12);
|
||||
buffer.write(0x42);
|
||||
EXPECT_TRUE(midi::composeTxPacket(buffer, packet));
|
||||
EXPECT_EQ(CIN::pitchBend, packet.header);
|
||||
EXPECT_EQ(0xE6, packet.byte1);
|
||||
EXPECT_EQ(0x12, packet.byte2);
|
||||
EXPECT_EQ(0x42, packet.byte3);
|
||||
EXPECT_EQ(0, buffer.getLength());
|
||||
}
|
||||
|
||||
// System Real Time Messages --
|
||||
|
||||
TEST(MidiUsbPacketInterfaceTx, Clock)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
|
||||
buffer.write(midi::Clock);
|
||||
EXPECT_TRUE(midi::composeTxPacket(buffer, packet));
|
||||
EXPECT_EQ(CIN::singleByte, packet.header);
|
||||
EXPECT_EQ(midi::Clock, packet.byte1);
|
||||
EXPECT_EQ(0x00, packet.byte2);
|
||||
EXPECT_EQ(0x00, packet.byte3);
|
||||
EXPECT_EQ(0, buffer.getLength());
|
||||
}
|
||||
|
||||
TEST(MidiUsbPacketInterfaceTx, Start)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
|
||||
buffer.write(midi::Start);
|
||||
EXPECT_TRUE(midi::composeTxPacket(buffer, packet));
|
||||
EXPECT_EQ(CIN::singleByte, packet.header);
|
||||
EXPECT_EQ(midi::Start, packet.byte1);
|
||||
EXPECT_EQ(0x00, packet.byte2);
|
||||
EXPECT_EQ(0x00, packet.byte3);
|
||||
EXPECT_EQ(0, buffer.getLength());
|
||||
}
|
||||
|
||||
TEST(MidiUsbPacketInterfaceTx, Stop)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
|
||||
buffer.write(midi::Stop);
|
||||
EXPECT_TRUE(midi::composeTxPacket(buffer, packet));
|
||||
EXPECT_EQ(CIN::singleByte, packet.header);
|
||||
EXPECT_EQ(midi::Stop, packet.byte1);
|
||||
EXPECT_EQ(0x00, packet.byte2);
|
||||
EXPECT_EQ(0x00, packet.byte3);
|
||||
EXPECT_EQ(0, buffer.getLength());
|
||||
}
|
||||
|
||||
TEST(MidiUsbPacketInterfaceTx, Continue)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
|
||||
buffer.write(midi::Continue);
|
||||
EXPECT_TRUE(midi::composeTxPacket(buffer, packet));
|
||||
EXPECT_EQ(CIN::singleByte, packet.header);
|
||||
EXPECT_EQ(midi::Continue, packet.byte1);
|
||||
EXPECT_EQ(0x00, packet.byte2);
|
||||
EXPECT_EQ(0x00, packet.byte3);
|
||||
EXPECT_EQ(0, buffer.getLength());
|
||||
}
|
||||
|
||||
TEST(MidiUsbPacketInterfaceTx, ActiveSensing)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
|
||||
buffer.write(midi::ActiveSensing);
|
||||
EXPECT_TRUE(midi::composeTxPacket(buffer, packet));
|
||||
EXPECT_EQ(CIN::singleByte, packet.header);
|
||||
EXPECT_EQ(midi::ActiveSensing, packet.byte1);
|
||||
EXPECT_EQ(0x00, packet.byte2);
|
||||
EXPECT_EQ(0x00, packet.byte3);
|
||||
EXPECT_EQ(0, buffer.getLength());
|
||||
}
|
||||
|
||||
TEST(MidiUsbPacketInterfaceTx, SystemReset)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
|
||||
buffer.write(midi::SystemReset);
|
||||
EXPECT_TRUE(midi::composeTxPacket(buffer, packet));
|
||||
EXPECT_EQ(CIN::singleByte, packet.header);
|
||||
EXPECT_EQ(midi::SystemReset, packet.byte1);
|
||||
EXPECT_EQ(0x00, packet.byte2);
|
||||
EXPECT_EQ(0x00, packet.byte3);
|
||||
EXPECT_EQ(0, buffer.getLength());
|
||||
}
|
||||
|
||||
// System Common Messages --
|
||||
|
||||
TEST(MidiUsbPacketInterfaceTx, TuneRequest)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
|
||||
buffer.write(midi::TuneRequest);
|
||||
EXPECT_TRUE(midi::composeTxPacket(buffer, packet));
|
||||
EXPECT_EQ(CIN::systemCommon1Byte, packet.header);
|
||||
EXPECT_EQ(midi::TuneRequest, packet.byte1);
|
||||
EXPECT_EQ(0x00, packet.byte2);
|
||||
EXPECT_EQ(0x00, packet.byte3);
|
||||
EXPECT_EQ(0, buffer.getLength());
|
||||
}
|
||||
|
||||
TEST(MidiUsbPacketInterfaceTx, SongSelect)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
|
||||
buffer.write(midi::SongSelect);
|
||||
buffer.write(0x12);
|
||||
EXPECT_TRUE(midi::composeTxPacket(buffer, packet));
|
||||
EXPECT_EQ(CIN::systemCommon2Bytes, packet.header);
|
||||
EXPECT_EQ(midi::SongSelect, packet.byte1);
|
||||
EXPECT_EQ(0x12, packet.byte2);
|
||||
EXPECT_EQ(0x00, packet.byte3);
|
||||
EXPECT_EQ(0, buffer.getLength());
|
||||
}
|
||||
|
||||
TEST(MidiUsbPacketInterfaceTx, SongPosition)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
|
||||
buffer.write(midi::SongPosition);
|
||||
buffer.write(0x12);
|
||||
buffer.write(0x42);
|
||||
EXPECT_TRUE(midi::composeTxPacket(buffer, packet));
|
||||
EXPECT_EQ(CIN::systemCommon3Bytes, packet.header);
|
||||
EXPECT_EQ(midi::SongPosition, packet.byte1);
|
||||
EXPECT_EQ(0x12, packet.byte2);
|
||||
EXPECT_EQ(0x42, packet.byte3);
|
||||
EXPECT_EQ(0, buffer.getLength());
|
||||
}
|
||||
|
||||
TEST(MidiUsbPacketInterfaceTx, TimeCodeQuarterFrame)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
|
||||
buffer.write(midi::TimeCodeQuarterFrame);
|
||||
buffer.write(0x12);
|
||||
EXPECT_TRUE(midi::composeTxPacket(buffer, packet));
|
||||
EXPECT_EQ(CIN::systemCommon2Bytes, packet.header);
|
||||
EXPECT_EQ(midi::TimeCodeQuarterFrame, packet.byte1);
|
||||
EXPECT_EQ(0x12, packet.byte2);
|
||||
EXPECT_EQ(0x00, packet.byte3);
|
||||
EXPECT_EQ(0, buffer.getLength());
|
||||
}
|
||||
|
||||
// System Exclusive --
|
||||
|
||||
TEST(MidiUsbPacketInterfaceTx, SysExNotEnoughData)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
|
||||
buffer.write(0x12);
|
||||
buffer.write(0x42);
|
||||
EXPECT_FALSE(midi::composeTxPacket(buffer, packet));
|
||||
EXPECT_EQ(2, buffer.getLength());
|
||||
}
|
||||
|
||||
TEST(MidiUsbPacketInterfaceTx, SysExSinglePacket)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
|
||||
// Two-byte SysEx (utterly useless)
|
||||
buffer.write(0xf0);
|
||||
buffer.write(0xf7);
|
||||
EXPECT_TRUE(midi::composeTxPacket(buffer, packet));
|
||||
EXPECT_EQ(CIN::sysExEnds2Bytes, packet.header);
|
||||
EXPECT_EQ(0xf0, packet.byte1);
|
||||
EXPECT_EQ(0xf7, packet.byte2);
|
||||
EXPECT_EQ(0x00, packet.byte3);
|
||||
EXPECT_EQ(0, buffer.getLength());
|
||||
|
||||
// Single-data byte SysEx (non-spec conformant ?)
|
||||
buffer.write(0xf0);
|
||||
buffer.write(0x12);
|
||||
buffer.write(0xf7);
|
||||
EXPECT_TRUE(midi::composeTxPacket(buffer, packet));
|
||||
EXPECT_EQ(CIN::sysExEnds3Bytes, packet.header);
|
||||
EXPECT_EQ(0xf0, packet.byte1);
|
||||
EXPECT_EQ(0x12, packet.byte2);
|
||||
EXPECT_EQ(0xf7, packet.byte3);
|
||||
EXPECT_EQ(0, buffer.getLength());
|
||||
}
|
||||
|
||||
TEST(MidiUsbPacketInterfaceTx, SysExTwoPackets)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
|
||||
const byte deviceIdentityRequest[6] = {
|
||||
0xf0, 0x7e, 0x7f, 0x06, 0x01, 0xf7
|
||||
};
|
||||
|
||||
buffer.write(deviceIdentityRequest, 6);
|
||||
EXPECT_TRUE(midi::composeTxPacket(buffer, packet));
|
||||
EXPECT_EQ(CIN::sysExStart, packet.header);
|
||||
EXPECT_EQ(0xf0, packet.byte1);
|
||||
EXPECT_EQ(0x7e, packet.byte2);
|
||||
EXPECT_EQ(0x7f, packet.byte3);
|
||||
EXPECT_EQ(3, buffer.getLength());
|
||||
|
||||
EXPECT_TRUE(midi::composeTxPacket(buffer, packet));
|
||||
EXPECT_EQ(CIN::sysExEnds3Bytes, packet.header);
|
||||
EXPECT_EQ(0x06, packet.byte1);
|
||||
EXPECT_EQ(0x01, packet.byte2);
|
||||
EXPECT_EQ(0xf7, packet.byte3);
|
||||
EXPECT_EQ(0, buffer.getLength());
|
||||
}
|
||||
|
||||
TEST(MidiUsbPacketInterfaceTx, SysExMultiplePacketsEndingWith1Byte)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
|
||||
const byte message[7] = {
|
||||
0xf0, 0x01, 0x02, 0x03, 0x04, 0x05, 0xf7
|
||||
};
|
||||
|
||||
buffer.write(message, 7);
|
||||
EXPECT_TRUE(midi::composeTxPacket(buffer, packet));
|
||||
EXPECT_EQ(CIN::sysExStart, packet.header);
|
||||
EXPECT_EQ(0xf0, packet.byte1);
|
||||
EXPECT_EQ(0x01, packet.byte2);
|
||||
EXPECT_EQ(0x02, packet.byte3);
|
||||
EXPECT_EQ(4, buffer.getLength());
|
||||
|
||||
EXPECT_TRUE(midi::composeTxPacket(buffer, packet));
|
||||
EXPECT_EQ(CIN::sysExContinue, packet.header);
|
||||
EXPECT_EQ(0x03, packet.byte1);
|
||||
EXPECT_EQ(0x04, packet.byte2);
|
||||
EXPECT_EQ(0x05, packet.byte3);
|
||||
EXPECT_EQ(1, buffer.getLength());
|
||||
|
||||
EXPECT_TRUE(midi::composeTxPacket(buffer, packet));
|
||||
EXPECT_EQ(CIN::sysExEnds1Byte, packet.header);
|
||||
EXPECT_EQ(0xf7, packet.byte1);
|
||||
EXPECT_EQ(0x00, packet.byte2);
|
||||
EXPECT_EQ(0x00, packet.byte3);
|
||||
EXPECT_EQ(0, buffer.getLength());
|
||||
}
|
||||
|
||||
TEST(MidiUsbPacketInterfaceTx, SysExMultiplePacketsEndingWith2Bytes)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
|
||||
const byte message[8] = {
|
||||
0xf0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0xf7
|
||||
};
|
||||
|
||||
buffer.write(message, 8);
|
||||
EXPECT_TRUE(midi::composeTxPacket(buffer, packet));
|
||||
EXPECT_EQ(CIN::sysExStart, packet.header);
|
||||
EXPECT_EQ(0xf0, packet.byte1);
|
||||
EXPECT_EQ(0x01, packet.byte2);
|
||||
EXPECT_EQ(0x02, packet.byte3);
|
||||
EXPECT_EQ(5, buffer.getLength());
|
||||
|
||||
EXPECT_TRUE(midi::composeTxPacket(buffer, packet));
|
||||
EXPECT_EQ(CIN::sysExContinue, packet.header);
|
||||
EXPECT_EQ(0x03, packet.byte1);
|
||||
EXPECT_EQ(0x04, packet.byte2);
|
||||
EXPECT_EQ(0x05, packet.byte3);
|
||||
EXPECT_EQ(2, buffer.getLength());
|
||||
|
||||
EXPECT_TRUE(midi::composeTxPacket(buffer, packet));
|
||||
EXPECT_EQ(CIN::sysExEnds2Bytes, packet.header);
|
||||
EXPECT_EQ(0x06, packet.byte1);
|
||||
EXPECT_EQ(0xf7, packet.byte2);
|
||||
EXPECT_EQ(0x00, packet.byte3);
|
||||
EXPECT_EQ(0, buffer.getLength());
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
||||
TEST(MidiUsbPacketInterfaceRx, InvalidPacketIsNotSerialised)
|
||||
{
|
||||
Buffer buffer;
|
||||
midiEventPacket_t packet;
|
||||
packet.header = CIN::reserved;
|
||||
packet.byte1 = 0x01;
|
||||
packet.byte2 = 0x02;
|
||||
packet.byte3 = 0x03;
|
||||
midi::serialiseRxPacket(packet, buffer);
|
||||
EXPECT_TRUE(buffer.isEmpty());
|
||||
}
|
||||
|
||||
TEST(MidiUsbPacketInterfaceRx, CableEventsAreNotSerialised)
|
||||
{
|
||||
Buffer buffer;
|
||||
midiEventPacket_t packet;
|
||||
packet.header = CIN::cableEvent;
|
||||
packet.byte1 = 0x01;
|
||||
packet.byte2 = 0x02;
|
||||
packet.byte3 = 0x03;
|
||||
midi::serialiseRxPacket(packet, buffer);
|
||||
EXPECT_TRUE(buffer.isEmpty());
|
||||
}
|
||||
|
||||
// Channel Voice Messages --
|
||||
|
||||
TEST(MidiUsbPacketInterfaceRx, NoteOff)
|
||||
{
|
||||
Buffer buffer;
|
||||
midiEventPacket_t packet;
|
||||
packet.header = CIN::noteOff;
|
||||
packet.byte1 = 0x80;
|
||||
packet.byte2 = 0x12;
|
||||
packet.byte3 = 0x42;
|
||||
midi::serialiseRxPacket(packet, buffer);
|
||||
EXPECT_EQ(3, buffer.getLength());
|
||||
EXPECT_EQ(0x80, buffer.read());
|
||||
EXPECT_EQ(0x12, buffer.read());
|
||||
EXPECT_EQ(0x42, buffer.read());
|
||||
}
|
||||
|
||||
TEST(MidiUsbPacketInterfaceRx, NoteOn)
|
||||
{
|
||||
Buffer buffer;
|
||||
midiEventPacket_t packet;
|
||||
packet.header = CIN::noteOn;
|
||||
packet.byte1 = 0x91;
|
||||
packet.byte2 = 0x12;
|
||||
packet.byte3 = 0x42;
|
||||
midi::serialiseRxPacket(packet, buffer);
|
||||
EXPECT_EQ(3, buffer.getLength());
|
||||
EXPECT_EQ(0x91, buffer.read());
|
||||
EXPECT_EQ(0x12, buffer.read());
|
||||
EXPECT_EQ(0x42, buffer.read());
|
||||
}
|
||||
|
||||
TEST(MidiUsbPacketInterfaceRx, PolyPressure)
|
||||
{
|
||||
Buffer buffer;
|
||||
midiEventPacket_t packet;
|
||||
packet.header = CIN::polyPressure;
|
||||
packet.byte1 = 0xA2;
|
||||
packet.byte2 = 0x12;
|
||||
packet.byte3 = 0x42;
|
||||
midi::serialiseRxPacket(packet, buffer);
|
||||
EXPECT_EQ(3, buffer.getLength());
|
||||
EXPECT_EQ(0xA2, buffer.read());
|
||||
EXPECT_EQ(0x12, buffer.read());
|
||||
EXPECT_EQ(0x42, buffer.read());
|
||||
}
|
||||
|
||||
TEST(MidiUsbPacketInterfaceRx, ControlChange)
|
||||
{
|
||||
Buffer buffer;
|
||||
midiEventPacket_t packet;
|
||||
packet.header = CIN::controlChange;
|
||||
packet.byte1 = 0xB3;
|
||||
packet.byte2 = 0x12;
|
||||
packet.byte3 = 0x42;
|
||||
midi::serialiseRxPacket(packet, buffer);
|
||||
EXPECT_EQ(3, buffer.getLength());
|
||||
EXPECT_EQ(0xB3, buffer.read());
|
||||
EXPECT_EQ(0x12, buffer.read());
|
||||
EXPECT_EQ(0x42, buffer.read());
|
||||
}
|
||||
|
||||
TEST(MidiUsbPacketInterfaceRx, ProgramChange)
|
||||
{
|
||||
Buffer buffer;
|
||||
midiEventPacket_t packet;
|
||||
packet.header = CIN::programChange;
|
||||
packet.byte1 = 0xC4;
|
||||
packet.byte2 = 0x12;
|
||||
packet.byte3 = 0x42; // Should be ignored
|
||||
midi::serialiseRxPacket(packet, buffer);
|
||||
EXPECT_EQ(2, buffer.getLength());
|
||||
EXPECT_EQ(0xC4, buffer.read());
|
||||
EXPECT_EQ(0x12, buffer.read());
|
||||
}
|
||||
|
||||
TEST(MidiUsbPacketInterfaceRx, ChannelPressure)
|
||||
{
|
||||
Buffer buffer;
|
||||
midiEventPacket_t packet;
|
||||
packet.header = CIN::channelPressure;
|
||||
packet.byte1 = 0xD5;
|
||||
packet.byte2 = 0x12;
|
||||
packet.byte3 = 0x42; // Should be ignored
|
||||
midi::serialiseRxPacket(packet, buffer);
|
||||
EXPECT_EQ(2, buffer.getLength());
|
||||
EXPECT_EQ(0xD5, buffer.read());
|
||||
EXPECT_EQ(0x12, buffer.read());
|
||||
}
|
||||
|
||||
TEST(MidiUsbPacketInterfaceRx, PitchBend)
|
||||
{
|
||||
Buffer buffer;
|
||||
midiEventPacket_t packet;
|
||||
packet.header = CIN::pitchBend;
|
||||
packet.byte1 = 0xE6;
|
||||
packet.byte2 = 0x12;
|
||||
packet.byte3 = 0x42;
|
||||
midi::serialiseRxPacket(packet, buffer);
|
||||
EXPECT_EQ(3, buffer.getLength());
|
||||
EXPECT_EQ(0xE6, buffer.read());
|
||||
EXPECT_EQ(0x12, buffer.read());
|
||||
EXPECT_EQ(0x42, buffer.read());
|
||||
}
|
||||
|
||||
// System Real Time Messages --
|
||||
|
||||
TEST(MidiUsbPacketInterfaceRx, Clock)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
|
||||
packet.header = CIN::singleByte;
|
||||
packet.byte1 = midi::Clock;
|
||||
packet.byte2 = 0x12; // Should be ignored
|
||||
packet.byte3 = 0x42; // Should be ignored
|
||||
midi::serialiseRxPacket(packet, buffer);
|
||||
EXPECT_EQ(1, buffer.getLength());
|
||||
EXPECT_EQ(midi::Clock, buffer.read());
|
||||
}
|
||||
|
||||
TEST(MidiUsbPacketInterfaceRx, Start)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
|
||||
packet.header = CIN::singleByte;
|
||||
packet.byte1 = midi::Start;
|
||||
packet.byte2 = 0x12; // Should be ignored
|
||||
packet.byte3 = 0x42; // Should be ignored
|
||||
midi::serialiseRxPacket(packet, buffer);
|
||||
EXPECT_EQ(1, buffer.getLength());
|
||||
EXPECT_EQ(midi::Start, buffer.read());
|
||||
}
|
||||
|
||||
TEST(MidiUsbPacketInterfaceRx, Stop)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
|
||||
packet.header = CIN::singleByte;
|
||||
packet.byte1 = midi::Stop;
|
||||
packet.byte2 = 0x12; // Should be ignored
|
||||
packet.byte3 = 0x42; // Should be ignored
|
||||
midi::serialiseRxPacket(packet, buffer);
|
||||
EXPECT_EQ(1, buffer.getLength());
|
||||
EXPECT_EQ(midi::Stop, buffer.read());
|
||||
}
|
||||
|
||||
TEST(MidiUsbPacketInterfaceRx, Continue)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
|
||||
packet.header = CIN::singleByte;
|
||||
packet.byte1 = midi::Continue;
|
||||
packet.byte2 = 0x12; // Should be ignored
|
||||
packet.byte3 = 0x42; // Should be ignored
|
||||
midi::serialiseRxPacket(packet, buffer);
|
||||
EXPECT_EQ(1, buffer.getLength());
|
||||
EXPECT_EQ(midi::Continue, buffer.read());
|
||||
}
|
||||
|
||||
TEST(MidiUsbPacketInterfaceRx, ActiveSensing)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
|
||||
packet.header = CIN::singleByte;
|
||||
packet.byte1 = midi::ActiveSensing;
|
||||
packet.byte2 = 0x12; // Should be ignored
|
||||
packet.byte3 = 0x42; // Should be ignored
|
||||
midi::serialiseRxPacket(packet, buffer);
|
||||
EXPECT_EQ(1, buffer.getLength());
|
||||
EXPECT_EQ(midi::ActiveSensing, buffer.read());
|
||||
}
|
||||
|
||||
TEST(MidiUsbPacketInterfaceRx, SystemReset)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
|
||||
packet.header = CIN::singleByte;
|
||||
packet.byte1 = midi::SystemReset;
|
||||
packet.byte2 = 0x12; // Should be ignored
|
||||
packet.byte3 = 0x42; // Should be ignored
|
||||
midi::serialiseRxPacket(packet, buffer);
|
||||
EXPECT_EQ(1, buffer.getLength());
|
||||
EXPECT_EQ(midi::SystemReset, buffer.read());
|
||||
}
|
||||
|
||||
// System Common Messages --
|
||||
|
||||
TEST(MidiUsbPacketInterfaceRx, TuneRequest)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
|
||||
packet.header = CIN::systemCommon1Byte;
|
||||
packet.byte1 = midi::TuneRequest;
|
||||
packet.byte2 = 0x12; // Should be ignored
|
||||
packet.byte3 = 0x42; // Should be ignored
|
||||
midi::serialiseRxPacket(packet, buffer);
|
||||
EXPECT_EQ(1, buffer.getLength());
|
||||
EXPECT_EQ(midi::TuneRequest, buffer.read());
|
||||
}
|
||||
|
||||
TEST(MidiUsbPacketInterfaceRx, SongSelect)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
|
||||
packet.header = CIN::systemCommon2Bytes;
|
||||
packet.byte1 = midi::SongSelect;
|
||||
packet.byte2 = 0x12;
|
||||
packet.byte3 = 0x42; // Should be ignored
|
||||
midi::serialiseRxPacket(packet, buffer);
|
||||
EXPECT_EQ(2, buffer.getLength());
|
||||
EXPECT_EQ(midi::SongSelect, buffer.read());
|
||||
EXPECT_EQ(0x12, buffer.read());
|
||||
}
|
||||
|
||||
TEST(MidiUsbPacketInterfaceRx, SongPosition)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
|
||||
packet.header = CIN::systemCommon2Bytes;
|
||||
packet.byte1 = midi::SongPosition;
|
||||
packet.byte2 = 0x12;
|
||||
packet.byte3 = 0x42; // Should be ignored
|
||||
midi::serialiseRxPacket(packet, buffer);
|
||||
EXPECT_EQ(2, buffer.getLength());
|
||||
EXPECT_EQ(midi::SongPosition, buffer.read());
|
||||
EXPECT_EQ(0x12, buffer.read());
|
||||
}
|
||||
|
||||
TEST(MidiUsbPacketInterfaceRx, TimeCodeQuarterFrame)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
|
||||
packet.header = CIN::systemCommon2Bytes;
|
||||
packet.byte1 = midi::TimeCodeQuarterFrame;
|
||||
packet.byte2 = 0x12;
|
||||
packet.byte3 = 0x42; // Should be ignored
|
||||
midi::serialiseRxPacket(packet, buffer);
|
||||
EXPECT_EQ(2, buffer.getLength());
|
||||
EXPECT_EQ(midi::TimeCodeQuarterFrame, buffer.read());
|
||||
EXPECT_EQ(0x12, buffer.read());
|
||||
}
|
||||
|
||||
// System Exclusive --
|
||||
|
||||
TEST(MidiUsbPacketInterfaceRx, SysExSinglePacket2Bytes)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
|
||||
packet.header = CIN::sysExEnds2Bytes;
|
||||
packet.byte1 = 0xf0;
|
||||
packet.byte2 = 0xf7;
|
||||
packet.byte3 = 0x42; // Should be ignored
|
||||
midi::serialiseRxPacket(packet, buffer);
|
||||
EXPECT_EQ(2, buffer.getLength());
|
||||
EXPECT_EQ(0xf0, buffer.read());
|
||||
EXPECT_EQ(0xf7, buffer.read());
|
||||
}
|
||||
|
||||
TEST(MidiUsbPacketInterfaceRx, SysExSinglePacket3Bytes)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
|
||||
packet.header = CIN::sysExEnds3Bytes;
|
||||
packet.byte1 = 0xf0;
|
||||
packet.byte2 = 0x42;
|
||||
packet.byte3 = 0xf7;
|
||||
midi::serialiseRxPacket(packet, buffer);
|
||||
EXPECT_EQ(3, buffer.getLength());
|
||||
EXPECT_EQ(0xf0, buffer.read());
|
||||
EXPECT_EQ(0x42, buffer.read());
|
||||
EXPECT_EQ(0xf7, buffer.read());
|
||||
}
|
||||
|
||||
TEST(MidiUsbPacketInterfaceRx, SysExTwoPackets)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
|
||||
packet.header = CIN::sysExStart;
|
||||
packet.byte1 = 0xf0;
|
||||
packet.byte2 = 0x01;
|
||||
packet.byte3 = 0x02;
|
||||
midi::serialiseRxPacket(packet, buffer);
|
||||
EXPECT_EQ(3, buffer.getLength());
|
||||
EXPECT_EQ(0xf0, buffer.read());
|
||||
EXPECT_EQ(0x01, buffer.read());
|
||||
EXPECT_EQ(0x02, buffer.read());
|
||||
|
||||
packet.header = CIN::sysExEnds3Bytes;
|
||||
packet.byte1 = 0x03;
|
||||
packet.byte2 = 0x04;
|
||||
packet.byte3 = 0xf7;
|
||||
midi::serialiseRxPacket(packet, buffer);
|
||||
EXPECT_EQ(3, buffer.getLength());
|
||||
EXPECT_EQ(0x03, buffer.read());
|
||||
EXPECT_EQ(0x04, buffer.read());
|
||||
EXPECT_EQ(0xf7, buffer.read());
|
||||
}
|
||||
|
||||
TEST(MidiUsbPacketInterfaceRx, SysExMultiplePacketsEndingWith1Byte)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
|
||||
packet.header = CIN::sysExStart;
|
||||
packet.byte1 = 0xf0;
|
||||
packet.byte2 = 0x01;
|
||||
packet.byte3 = 0x02;
|
||||
midi::serialiseRxPacket(packet, buffer);
|
||||
EXPECT_EQ(3, buffer.getLength());
|
||||
EXPECT_EQ(0xf0, buffer.read());
|
||||
EXPECT_EQ(0x01, buffer.read());
|
||||
EXPECT_EQ(0x02, buffer.read());
|
||||
|
||||
packet.header = CIN::sysExContinue;
|
||||
packet.byte1 = 0x03;
|
||||
packet.byte2 = 0x04;
|
||||
packet.byte3 = 0x05;
|
||||
midi::serialiseRxPacket(packet, buffer);
|
||||
EXPECT_EQ(3, buffer.getLength());
|
||||
EXPECT_EQ(0x03, buffer.read());
|
||||
EXPECT_EQ(0x04, buffer.read());
|
||||
EXPECT_EQ(0x05, buffer.read());
|
||||
|
||||
packet.header = CIN::sysExEnds1Byte;
|
||||
packet.byte1 = 0xf7;
|
||||
packet.byte2 = 0x12; // Should be ignored
|
||||
packet.byte3 = 0x42; // Should be ignored
|
||||
midi::serialiseRxPacket(packet, buffer);
|
||||
EXPECT_EQ(1, buffer.getLength());
|
||||
EXPECT_EQ(0xf7, buffer.read());
|
||||
}
|
||||
|
||||
TEST(MidiUsbPacketInterfaceRx, SysExMultiplePacketsEndingWith2Bytes)
|
||||
{
|
||||
midiEventPacket_t packet;
|
||||
Buffer buffer;
|
||||
|
||||
packet.header = CIN::sysExStart;
|
||||
packet.byte1 = 0xf0;
|
||||
packet.byte2 = 0x01;
|
||||
packet.byte3 = 0x02;
|
||||
midi::serialiseRxPacket(packet, buffer);
|
||||
EXPECT_EQ(3, buffer.getLength());
|
||||
EXPECT_EQ(0xf0, buffer.read());
|
||||
EXPECT_EQ(0x01, buffer.read());
|
||||
EXPECT_EQ(0x02, buffer.read());
|
||||
|
||||
packet.header = CIN::sysExContinue;
|
||||
packet.byte1 = 0x03;
|
||||
packet.byte2 = 0x04;
|
||||
packet.byte3 = 0x05;
|
||||
midi::serialiseRxPacket(packet, buffer);
|
||||
EXPECT_EQ(3, buffer.getLength());
|
||||
EXPECT_EQ(0x03, buffer.read());
|
||||
EXPECT_EQ(0x04, buffer.read());
|
||||
EXPECT_EQ(0x05, buffer.read());
|
||||
|
||||
packet.header = CIN::sysExEnds2Bytes;
|
||||
packet.byte1 = 0x06;
|
||||
packet.byte2 = 0xf7; // Should be ignored
|
||||
packet.byte3 = 0x42; // Should be ignored
|
||||
midi::serialiseRxPacket(packet, buffer);
|
||||
EXPECT_EQ(2, buffer.getLength());
|
||||
EXPECT_EQ(0x06, buffer.read());
|
||||
EXPECT_EQ(0xf7, buffer.read());
|
||||
}
|
||||
|
||||
END_UNNAMED_NAMESPACE
|
||||
|
|
@ -1,203 +0,0 @@
|
|||
#include "unit-tests.h"
|
||||
#include <src/midi_RingBuffer.h>
|
||||
|
||||
BEGIN_UNNAMED_NAMESPACE
|
||||
using namespace testing;
|
||||
using Buffer = midi::RingBuffer<uint8_t, 8>;
|
||||
|
||||
TEST(RingBuffer, writeScalar)
|
||||
{
|
||||
Buffer buffer;
|
||||
EXPECT_EQ(buffer.isEmpty(), true);
|
||||
EXPECT_EQ(buffer.getLength(), 0);
|
||||
buffer.write(42);
|
||||
buffer.write(47);
|
||||
EXPECT_EQ(buffer.isEmpty(), false);
|
||||
EXPECT_EQ(buffer.getLength(), 2);
|
||||
}
|
||||
|
||||
TEST(RingBuffer, readScalar)
|
||||
{
|
||||
Buffer buffer;
|
||||
buffer.write(42);
|
||||
EXPECT_EQ(buffer.getLength(), 1);
|
||||
buffer.write(47);
|
||||
EXPECT_EQ(buffer.getLength(), 2);
|
||||
EXPECT_EQ(buffer.read(), 42);
|
||||
EXPECT_EQ(buffer.getLength(), 1);
|
||||
EXPECT_EQ(buffer.read(), 47);
|
||||
EXPECT_EQ(buffer.isEmpty(), true);
|
||||
EXPECT_EQ(buffer.getLength(), 0);
|
||||
}
|
||||
|
||||
TEST(RingBuffer, clear)
|
||||
{
|
||||
Buffer buffer;
|
||||
buffer.write(42);
|
||||
buffer.write(47);
|
||||
buffer.clear();
|
||||
EXPECT_EQ(buffer.isEmpty(), true);
|
||||
EXPECT_EQ(buffer.getLength(), 0);
|
||||
}
|
||||
|
||||
TEST(RingBuffer, writeArray)
|
||||
{
|
||||
Buffer buffer;
|
||||
const uint8_t input[4] = {
|
||||
1, 2, 3, 4
|
||||
};
|
||||
buffer.write(input, 4);
|
||||
EXPECT_EQ(buffer.isEmpty(), false);
|
||||
EXPECT_EQ(buffer.getLength(), 4);
|
||||
}
|
||||
|
||||
TEST(RingBuffer, writeOverflow)
|
||||
{
|
||||
Buffer buffer;
|
||||
|
||||
buffer.write(1);
|
||||
EXPECT_EQ(buffer.getLength(), 1);
|
||||
EXPECT_EQ(buffer.isEmpty(), false);
|
||||
buffer.write(2);
|
||||
EXPECT_EQ(buffer.getLength(), 2);
|
||||
EXPECT_EQ(buffer.isEmpty(), false);
|
||||
buffer.write(3);
|
||||
EXPECT_EQ(buffer.getLength(), 3);
|
||||
EXPECT_EQ(buffer.isEmpty(), false);
|
||||
buffer.write(4);
|
||||
EXPECT_EQ(buffer.getLength(), 4);
|
||||
EXPECT_EQ(buffer.isEmpty(), false);
|
||||
buffer.write(5);
|
||||
EXPECT_EQ(buffer.getLength(), 5);
|
||||
EXPECT_EQ(buffer.isEmpty(), false);
|
||||
buffer.write(6);
|
||||
EXPECT_EQ(buffer.getLength(), 6);
|
||||
EXPECT_EQ(buffer.isEmpty(), false);
|
||||
buffer.write(7);
|
||||
EXPECT_EQ(buffer.getLength(), 7);
|
||||
EXPECT_EQ(buffer.isEmpty(), false);
|
||||
buffer.write(8);
|
||||
EXPECT_EQ(buffer.getLength(), 8);
|
||||
EXPECT_EQ(buffer.isEmpty(), false);
|
||||
buffer.write(9);
|
||||
EXPECT_EQ(buffer.getLength(), 8);
|
||||
EXPECT_EQ(buffer.isEmpty(), false);
|
||||
buffer.write(10);
|
||||
EXPECT_EQ(buffer.getLength(), 8);
|
||||
EXPECT_EQ(buffer.isEmpty(), false);
|
||||
buffer.write(11);
|
||||
EXPECT_EQ(buffer.getLength(), 8);
|
||||
EXPECT_EQ(buffer.isEmpty(), false);
|
||||
buffer.write(12);
|
||||
EXPECT_EQ(buffer.getLength(), 8);
|
||||
EXPECT_EQ(buffer.isEmpty(), false);
|
||||
}
|
||||
|
||||
TEST(RingBuffer, readOverflow)
|
||||
{
|
||||
Buffer buffer;
|
||||
|
||||
buffer.write(1);
|
||||
buffer.write(2);
|
||||
buffer.write(3);
|
||||
buffer.write(4);
|
||||
buffer.write(5);
|
||||
buffer.write(6);
|
||||
buffer.write(7);
|
||||
buffer.write(8);
|
||||
buffer.write(9);
|
||||
buffer.write(10);
|
||||
buffer.write(11);
|
||||
buffer.write(12);
|
||||
EXPECT_EQ(buffer.read(), 5);
|
||||
EXPECT_EQ(buffer.getLength(), 7);
|
||||
EXPECT_EQ(buffer.read(), 6);
|
||||
EXPECT_EQ(buffer.getLength(), 6);
|
||||
EXPECT_EQ(buffer.read(), 7);
|
||||
EXPECT_EQ(buffer.getLength(), 5);
|
||||
EXPECT_EQ(buffer.read(), 8);
|
||||
EXPECT_EQ(buffer.getLength(), 4);
|
||||
EXPECT_EQ(buffer.read(), 9);
|
||||
EXPECT_EQ(buffer.getLength(), 3);
|
||||
EXPECT_EQ(buffer.read(), 10);
|
||||
EXPECT_EQ(buffer.getLength(), 2);
|
||||
EXPECT_EQ(buffer.read(), 11);
|
||||
EXPECT_EQ(buffer.getLength(), 1);
|
||||
EXPECT_EQ(buffer.read(), 12);
|
||||
EXPECT_EQ(buffer.getLength(), 0);
|
||||
EXPECT_EQ(buffer.read(), 0);
|
||||
EXPECT_EQ(buffer.getLength(), 0);
|
||||
}
|
||||
|
||||
TEST(RingBuffer, writeArrayOverflow)
|
||||
{
|
||||
Buffer buffer;
|
||||
const uint8_t input[12] = {
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
|
||||
};
|
||||
buffer.write(input, 12);
|
||||
EXPECT_EQ(buffer.isEmpty(), false);
|
||||
EXPECT_EQ(buffer.getLength(), 8); // Max size
|
||||
}
|
||||
|
||||
TEST(RingBuffer, readArray)
|
||||
{
|
||||
Buffer buffer;
|
||||
const uint8_t input[4] = {
|
||||
1, 2, 3, 4
|
||||
};
|
||||
uint8_t output[4] = { 0 };
|
||||
buffer.write(input, 4);
|
||||
buffer.read(output, 4);
|
||||
EXPECT_THAT(output, ContainerEq(input));
|
||||
}
|
||||
|
||||
TEST(RingBuffer, readArrayOverflow)
|
||||
{
|
||||
Buffer buffer;
|
||||
const uint8_t input[12] = {
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
|
||||
};
|
||||
const uint8_t expected[8] = {
|
||||
5, 6, 7, 8, 9, 10, 11, 12,
|
||||
};
|
||||
uint8_t output[8] = { 0 };
|
||||
|
||||
buffer.write(input, 12);
|
||||
buffer.read(output, 8);
|
||||
EXPECT_THAT(output, ContainerEq(expected));
|
||||
EXPECT_EQ(buffer.isEmpty(), true);
|
||||
EXPECT_EQ(buffer.getLength(), 0);
|
||||
}
|
||||
|
||||
TEST(RingBuffer, peek)
|
||||
{
|
||||
Buffer buffer;
|
||||
const uint8_t input[4] = {
|
||||
1, 2, 3, 4
|
||||
};
|
||||
|
||||
buffer.write(input, 4);
|
||||
EXPECT_EQ(1, buffer.peek());
|
||||
EXPECT_EQ(2, buffer.peek(1));
|
||||
EXPECT_EQ(3, buffer.peek(2));
|
||||
EXPECT_EQ(4, buffer.peek(3));
|
||||
EXPECT_EQ(4, buffer.getLength()) << "Peek should not change buffer length";
|
||||
}
|
||||
|
||||
TEST(RingBuffer, pop)
|
||||
{
|
||||
Buffer buffer;
|
||||
const uint8_t input[4] = {
|
||||
1, 2, 3, 4
|
||||
};
|
||||
|
||||
buffer.write(input, 4);
|
||||
buffer.pop();
|
||||
EXPECT_EQ(3, buffer.getLength());
|
||||
buffer.pop(2);
|
||||
EXPECT_EQ(1, buffer.getLength());
|
||||
}
|
||||
|
||||
END_UNNAMED_NAMESPACE
|
||||
|
||||
|
|
@ -5,7 +5,6 @@ BEGIN_MIDI_NAMESPACE
|
|||
const bool DefaultSettings::UseRunningStatus;
|
||||
const bool DefaultSettings::HandleNullVelocityNoteOnAsNoteOff;
|
||||
const bool DefaultSettings::Use1ByteParsing;
|
||||
const long DefaultSettings::BaudRate;
|
||||
const unsigned DefaultSettings::SysExMaxSize;
|
||||
|
||||
END_MIDI_NAMESPACE
|
||||
|
|
@ -19,7 +18,6 @@ TEST(Settings, hasTheRightDefaultValues)
|
|||
EXPECT_EQ(midi::DefaultSettings::UseRunningStatus, false);
|
||||
EXPECT_EQ(midi::DefaultSettings::HandleNullVelocityNoteOnAsNoteOff, true);
|
||||
EXPECT_EQ(midi::DefaultSettings::Use1ByteParsing, true);
|
||||
EXPECT_EQ(midi::DefaultSettings::BaudRate, 31250);
|
||||
EXPECT_EQ(midi::DefaultSettings::SysExMaxSize, unsigned(128));
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue