Merge pull request #95 from FortySevenEffects/feat/4.4.0

v5.0.0
This commit is contained in:
Francois Best 2020-04-20 17:02:01 +02:00 committed by GitHub
commit 804e59669e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
49 changed files with 1535 additions and 1475 deletions

9
.editorconfig Normal file
View File

@ -0,0 +1,9 @@
root = true
[*]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

5
.gitignore vendored
View File

@ -3,3 +3,8 @@
logs/ logs/
build/ build/
.vscode/.cmaketools.json .vscode/.cmaketools.json
src/.DS_Store
examples/.DS_Store
.DS_Store
test/xcode
.development

3
.gitmodules vendored
View File

@ -1,6 +1,3 @@
[submodule "external/google-test"] [submodule "external/google-test"]
path = external/google-test path = external/google-test
url = https://github.com/google/googletest.git url = https://github.com/google/googletest.git
[submodule "external/midi-usb"]
path = external/midi-usb
url = https://github.com/arduino-libraries/MIDIUSB.git

View File

@ -25,10 +25,11 @@ env:
- PLATFORMIO_CI_SRC=examples/Bench - PLATFORMIO_CI_SRC=examples/Bench
- PLATFORMIO_CI_SRC=examples/Callbacks - PLATFORMIO_CI_SRC=examples/Callbacks
- PLATFORMIO_CI_SRC=examples/DualMerger - PLATFORMIO_CI_SRC=examples/DualMerger
- PLATFORMIO_CI_SRC=examples/ErrorCallback
- PLATFORMIO_CI_SRC=examples/Input - PLATFORMIO_CI_SRC=examples/Input
- PLATFORMIO_CI_SRC=examples/MidiUSB REQUIRES_USB=1
- PLATFORMIO_CI_SRC=examples/RPN_NRPN - PLATFORMIO_CI_SRC=examples/RPN_NRPN
- PLATFORMIO_CI_SRC=examples/SimpleSynth - PLATFORMIO_CI_SRC=examples/SimpleSynth
- PLATFORMIO_CI_SRC=examples/AltPinSerial
addons: addons:
apt: apt:
@ -48,7 +49,7 @@ install:
# Install newer lcov (1.9 seems to fail: http://gronlier.fr/blog/2015/01/adding-code-coverage-to-your-c-project/) # Install newer lcov (1.9 seems to fail: http://gronlier.fr/blog/2015/01/adding-code-coverage-to-your-c-project/)
export LCOV_ROOT="$HOME/lcov" export LCOV_ROOT="$HOME/lcov"
mkdir -p "$LCOV_ROOT" mkdir -p "$LCOV_ROOT"
wget http://ftp.de.debian.org/debian/pool/main/l/lcov/lcov_1.12.orig.tar.gz --output-document="$LCOV_ROOT/lcov.tar.gz" wget http://ftp.de.debian.org/debian/pool/main/l/lcov/lcov_1.14.orig.tar.gz --output-document="$LCOV_ROOT/lcov.tar.gz"
tar xf "$LCOV_ROOT/lcov.tar.gz" --strip-components=1 -C $LCOV_ROOT tar xf "$LCOV_ROOT/lcov.tar.gz" --strip-components=1 -C $LCOV_ROOT
export PATH="$LCOV_ROOT/bin:$PATH" export PATH="$LCOV_ROOT/bin:$PATH"
which lcov which lcov
@ -74,17 +75,25 @@ script:
# Build current example # Build current example
- | - |
if [ ! "${BUILD_UNIT_TESTS}" ]; then if [ ! "${BUILD_UNIT_TESTS}" ]; then
if [ "${REQUIRES_USB}" ]; then platformio ci --lib="." \
platformio ci --lib="." --lib=external/midi-usb --board="due" --board="dueUSB" --board="zero" --board="zeroUSB" --board="leonardo" --board="uno" \
else --board="due" \
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" --board="zero" \
fi --board="leonardo" \
--board="micro" \
--board="nanoatmega328" \
--board="megaatmega2560" \
--board="teensy2" \
--board="teensy30" \
--board="teensy31" \
--board="teensylc"
fi fi
after_success: after_success:
- | - |
if [ "${GENERATE_COVERAGE}" ]; then if [ "${GENERATE_COVERAGE}" ]; then
# Generate code coverage information & send to Coveralls # Generate code coverage information & send to Coveralls
rm -rf ./external/google-test/googletest/CMakeFiles/gtest.dir/src/gtest-all.cc.gcda
lcov --gcov-tool $GCOV --directory . --capture --output-file coverage.info lcov --gcov-tool $GCOV --directory . --capture --output-file coverage.info
lcov --gcov-tool $GCOV --remove coverage.info 'test/*' '/usr/*' 'external/*' --output-file coverage.info lcov --gcov-tool $GCOV --remove coverage.info 'test/*' '/usr/*' 'external/*' --output-file coverage.info
lcov --list coverage.info lcov --list coverage.info

3
.vscode/arduino.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"board": "arduino:avr:leonardo"
}

View File

@ -3,6 +3,8 @@
{ {
"name": "Mac", "name": "Mac",
"includePath": [ "includePath": [
"/Applications/Arduino.app/Contents/Java/tools/**",
"/Applications/Arduino.app/Contents/Java/hardware/arduino/avr/**",
"/Applications/Arduino.app/Contents/Java/hardware/tools/avr/include", "/Applications/Arduino.app/Contents/Java/hardware/tools/avr/include",
"/Applications/Arduino.app/Contents/Java/hardware/arduino/avr/cores/arduino", "/Applications/Arduino.app/Contents/Java/hardware/arduino/avr/cores/arduino",
"${workspaceRoot}" "${workspaceRoot}"
@ -20,7 +22,11 @@
"macFrameworkPath": [ "macFrameworkPath": [
"/System/Library/Frameworks", "/System/Library/Frameworks",
"/Library/Frameworks" "/Library/Frameworks"
] ],
"forcedInclude": [
"/Applications/Arduino.app/Contents/Java/hardware/arduino/avr/cores/arduino/Arduino.h"
],
"configurationProvider": "vector-of-bool.cmake-tools"
}, },
{ {
"name": "Linux", "name": "Linux",
@ -55,5 +61,5 @@
"intelliSenseMode": "msvc-x64" "intelliSenseMode": "msvc-x64"
} }
], ],
"version": 3 "version": 4
} }

15
.vscode/settings.json vendored
View File

@ -1,4 +1,13 @@
// Place your settings in this file to overwrite default and user settings.
{ {
"cmake.experimental.enableTargetDebugging": true "files.associations": {
} "cstddef": "cpp",
"ostream": "cpp",
"__locale": "cpp",
"functional": "cpp",
"iterator": "cpp",
"string": "cpp",
"string_view": "cpp",
"vector": "cpp",
"istream": "cpp"
}
}

28
.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,28 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "Build",
"command": "make",
"args": ["all"],
"options": {
"cwd": "${workspaceRoot}/build"
},
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "Run Tests",
"command": "${workspaceRoot}/build/test/unit-tests/unit-tests",
"group": {
"kind": "test",
"isDefault": true
},
"dependsOn": ["Build"]
}
]
}

118
README.md
View File

@ -5,59 +5,113 @@
[![GitHub release](https://img.shields.io/github/release/FortySevenEffects/arduino_midi_library.svg?maxAge=3600)](https://github.com/FortySevenEffects/arduino_midi_library/releases/latest) [![GitHub release](https://img.shields.io/github/release/FortySevenEffects/arduino_midi_library.svg?maxAge=3600)](https://github.com/FortySevenEffects/arduino_midi_library/releases/latest)
[![License](https://img.shields.io/github/license/FortySevenEffects/arduino_midi_library.svg?maxAge=3600)](LICENSE) [![License](https://img.shields.io/github/license/FortySevenEffects/arduino_midi_library.svg?maxAge=3600)](LICENSE)
This library enables MIDI I/O communications on the Arduino serial ports. This library adds MIDI I/O communications to an Arduino board.
### Features ### Features
* Compatible with all Arduino boards (and clones with an AVR processor).
* Simple and fast way to send and receive every kind of MIDI message (including all System messages, SysEx, Clock, etc..). - **New** : USB MIDI Device support with [`MIDIUSB`](https://github.com/arduino-libraries/MIDIUSB).
* OMNI input reading (read all channels). - Compatible with all Arduino boards (and clones with an AVR processor).
* Software Thru, with message filtering. - Simple and fast way to send and receive every kind of MIDI message (including all System messages, SysEx, Clock, etc..).
* [Callbacks](http://playground.arduino.cc/Main/MIDILibraryCallbacks) to handle input messages more easily. - OMNI input reading (read all channels).
* Last received message is saved until a new one arrives. - Software Thru, with message filtering.
* Configurable: [overridable template-based settings](https://github.com/FortySevenEffects/arduino_midi_library/wiki/Using-custom-Settings). - [Callbacks](https://github.com/FortySevenEffects/arduino_midi_library/wiki/Using-Callbacks) to handle input messages more easily.
* Create more than one MIDI port for mergers/splitters applications. - Last received message is saved until a new one arrives.
* Use any serial port, hardware or software. - Configurable: [overridable template-based settings](https://github.com/FortySevenEffects/arduino_midi_library/wiki/Using-custom-Settings).
- Create more than one MIDI interface for mergers/splitters applications.
- Use any serial port, hardware or software.
### Getting Started ### Getting Started
1. Use Arduino's Library Manager to install the library. 1. Use the Arduino Library Manager to install the library.
![Type "MIDI" in the Arduino IDE Library Manager](res/library-manager.jpg) ![Type "MIDI" in the Arduino IDE Library Manager](res/library-manager.jpg)
2. Start coding: 2. Start coding:
```c++
#include <MIDI.h>
// Created and binds the MIDI interface to the default hardware Serial port ```c++
MIDI_CREATE_DEFAULT_INSTANCE(); #include <MIDI.h>
void setup() // Create and bind the MIDI interface to the default hardware Serial port
{ MIDI_CREATE_DEFAULT_INSTANCE();
MIDI.begin(MIDI_CHANNEL_OMNI); // Listen to all incoming messages
}
void loop() void setup()
{ {
// Send note 42 with velocity 127 on channel 1 MIDI.begin(MIDI_CHANNEL_OMNI); // Listen to all incoming messages
MIDI.sendNoteOn(42, 127, 1); }
// Read incoming messages void loop()
MIDI.read(); {
} // Send note 42 with velocity 127 on channel 1
``` MIDI.sendNoteOn(42, 127, 1);
// Read incoming messages
MIDI.read();
}
```
3. Read the [documentation](#documentation) or watch the awesome video tutorials from [Notes & Volts](https://www.youtube.com/playlist?list=PL4_gPbvyebyH2xfPXePHtx8gK5zPBrVkg). 3. Read the [documentation](#documentation) or watch the awesome video tutorials from [Notes & Volts](https://www.youtube.com/playlist?list=PL4_gPbvyebyH2xfPXePHtx8gK5zPBrVkg).
## Documentation ## Documentation
- [Doxygen Extended Documentation](http://fortyseveneffects.github.io/arduino_midi_library/). - [Doxygen Extended Documentation](https://fortyseveneffects.github.io/arduino_midi_library/).
- [GitHub wiki](https://github.com/FortySevenEffects/arduino_midi_library/wiki). - [GitHub wiki](https://github.com/FortySevenEffects/arduino_midi_library/wiki).
## USB Migration (4.x to 5.x)
All USB related code has been moved into a separate repository [Arduino-USB-MIDI](https://github.com/lathoub/Arduino-USBMIDI), USB MIDI Device support with [`MIDIUSB`](https://github.com/arduino-libraries/MIDIUSB), still using this library to do all the MIDI heavy-lifting.
Migration has been made as easy as possible: only the declaration of the MIDI object has been modified, the rest of your code remains identical.
`4.3.1` code:
```c++
#include <MIDI.h>
#include <midi_UsbTransport.h>
static const unsigned sUsbTransportBufferSize = 16;
typedef midi::UsbTransport<sUsbTransportBufferSize> UsbTransport;
UsbTransport sUsbTransport;
MIDI_CREATE_INSTANCE(UsbTransport, sUsbTransport, MIDI);
// ...
```
now becomes in `5.0.0`:
```c++
#include <USB-MIDI.h>
USBMIDI_CREATE_DEFAULT_INSTANCE();
// ...
```
Start with the [NoteOnOffEverySec](https://github.com/lathoub/Arduino-USBMIDI/blob/master/examples/NoteOnOffEverySec/NoteOnOffEverySec.ino) example that is based on the original MidiUSB [sketch](https://github.com/lathoub/arduino_midi_library/blob/master/examples/MidiUSB/MidiUSB.ino). Note the only difference is in the declaration.
The [USB-MIDI](https://github.com/lathoub/Arduino-USBMIDI) Arduino library depends on [this library](https://github.com/FortySevenEffects/arduino_midi_library) and the [MIDIUSB](https://github.com/arduino-libraries/MIDIUSB) library.
[USB-MIDI](https://github.com/lathoub/Arduino-USBMIDI) uses the latest Arduino IDE `depends` feature in the `library.properties` file installing all the dependencies automatically when installing from the IDE.
## Other Transport mechanisms
Version 5 of this library, allows for other Transport layers than the
original MIDI 1.0 Electrical Specification (hardware serial).
- [USB-MIDI](https://github.com/lathoub/Arduino-USBMIDI)
- [AppleMIDI or rtpMIDI](https://github.com/lathoub/Arduino-AppleMIDI-Library)
- [ipMIDI](https://github.com/lathoub/Arduino-ipMIDI)
- [BLE-MIDI](https://github.com/lathoub/Arduino-BLE-MIDI)
All these Transport layers use this library for all the underlying MIDI
work, making it easy to switch transport protocols or making transport
protocol bridges.
## Contact ## Contact
To report a bug, contribute, discuss on usage, or simply request support, please [create an issue here](https://github.com/FortySevenEffects/arduino_midi_library/issues/new). To report a bug, contribute, discuss on usage, or simply request support, please [create an issue here](https://github.com/FortySevenEffects/arduino_midi_library/issues/new).
You can also get informations about bug fixes and updates on my twitter account: [@fortysevenfx](http://twitter.com/fortysevenfx). You can also contact me on Twitter: [@fortysevenfx](https://twitter.com/fortysevenfx).
## License ## License
MIT © 2016 [Francois Best](http://fortyseveneffects.com) MIT © 2009 - present [Francois Best](https://francoisbest.com)

View File

@ -8,7 +8,18 @@ macro(setup_builder)
include_directories(${ROOT_SOURCE_DIR}) include_directories(${ROOT_SOURCE_DIR})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -W -Wshadow -Wunused-variable -Wunused-parameter -Wunused-function -Wunused -Wno-system-headers -Wno-deprecated -Woverloaded-virtual") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} \
-Wall \
-W \
-Wshadow \
-Wunused-variable \
-Wunused-parameter \
-Wunused-function \
-Wunused \
-Wno-system-headers \
-Wno-deprecated \
-Woverloaded-virtual \
")
if (BUILDER_ENABLE_PROFILING) if (BUILDER_ENABLE_PROFILING)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -O0") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -O0")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} --coverage") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} --coverage")
@ -16,3 +27,7 @@ macro(setup_builder)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
endmacro() endmacro()
macro(increase_warning_level)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wconversion -Wsign-conversion")
endmacro()

View File

@ -38,7 +38,7 @@ PROJECT_NAME = "Arduino MIDI Library"
# could be handy for archiving the generated documentation or if some version # could be handy for archiving the generated documentation or if some version
# control system is used. # control system is used.
PROJECT_NUMBER = "Version 4.3.1" PROJECT_NUMBER = "Version 4.4.0"
# Using the PROJECT_BRIEF tag one can provide an optional one line description # Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a # for a project that appears at the top of each page and should give viewer a

87
doc/sysex-codec.md Normal file
View File

@ -0,0 +1,87 @@
# SysEx Encoding & Decoding
There are various ways of encoding & decoding arbitrary 8-bit wide data into
SysEx, which is 7-bit wide.
The [official documentation](http://www.somascape.org/midi/tech/spec.html#nusx_fd)
for FileDump data exchanges states the following:
> The 8-bit file data needs to be converted to 7-bit form,
> with the result that every 7 bytes of file data translates
> to 8 bytes in the MIDI stream.
>
> For each group of 7 bytes (of file data) the top bit from each
> is used to construct an eigth byte, which is sent first.
> So:
> ```
> AAAAaaaa BBBBbbbb CCCCcccc DDDDdddd EEEEeeee FFFFffff GGGGgggg
> ```
> becomes:
> ```
> 0ABCDEFG 0AAAaaaa 0BBBbbbb 0CCCcccc 0DDDdddd 0EEEeeee 0FFFffff 0GGGgggg
> ```
>
> The final group may have less than 7 bytes, and is coded as follows
> (e.g. with 3 bytes in the final group):
> ```
> 0ABC0000 0AAAaaaa 0BBBbbbb 0CCCcccc
> ```
## SysEx encoding / decoding functions
The MIDI library supplies two functions to do this, `encodeSysEx` and `decodeSysEx`.
Example usage:
```c++
#include <MIDI.h>
static const byte myData[12] = {
// Hex dump: CAFEBABE BAADF00D FACADE42
0xca, 0xfe, 0xba, 0xbe, 0xba, 0xad, 0xf0, 0x0d,
0xfa, 0xca, 0xde, 0x42
};
byte encoded[16];
const unsigned encodedSize = midi::encodeSysEx(myData, encoded, 12);
// Encoded hex dump: 07 4a 7e 3a 3e 3a 2d 70 07 0d 7a 4a 5e 42
byte decoded[12];
const unsigned decoded = midi::decodeSysEx(encoded, decoded, encodedSize);
```
## Special case for Korg devices
Korg apparently uses another convention for their SysEx encoding / decoding,
where:
```
AAAAaaaa BBBBbbbb CCCCcccc DDDDdddd EEEEeeee FFFFffff GGGGgggg
```
becomes:
```
0GFEDCBA 0AAAaaaa 0BBBbbbb 0CCCcccc 0DDDdddd 0EEEeeee 0FFFffff 0GGGgggg
```
The order of the bits in the "header" byte is reversed.
To follow this beheaviour, set the inFlipHeaderBits argument to true.
Example:
```c++
void handleSysEx(byte* inData, unsigned inSize)
{
// SysEx body data starts at 3rd byte: F0 42 aa bb cc dd F7
// 42 being the hex value of the Korg SysEx ID.
const unsigned dataStartOffset = 2;
const unsigned encodedDataLength = inSize - 3; // Remove F0 42 & F7
// Create a large enough buffer where to decode the message
byte decodedData[64];
const unsigned decodedSize = decodeSysEx(inData + dataStartOffset,
decodedData,
encodedDataLength,
true); // flip header bits
// Do stuff with your message
}
```
See original discussion in issue [#92](FortySevenEffects/arduino_midi_library#92).

View File

@ -0,0 +1,35 @@
#include <MIDI.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.
#if defined(ARDUINO_SAM_DUE) || defined(SAMD_SERIES)
/* example not relevant for this hardware */
MIDI_CREATE_DEFAULT_INSTANCE();
#else
#include <SoftwareSerial.h>
int rxPin = 18;
int txPin = 19;
SoftwareSerial mySerial = SoftwareSerial(rxPin, txPin);
MIDI_NAMESPACE::SerialMIDI<SoftwareSerial> serialMIDI(mySerial);
MIDI_NAMESPACE::MidiInterface<MIDI_NAMESPACE::SerialMIDI<SoftwareSerial>> MIDI((MIDI_NAMESPACE::SerialMIDI<SoftwareSerial>&)serialMIDI);
#endif
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);
}
}

View File

@ -6,11 +6,9 @@
MIDI_CREATE_DEFAULT_INSTANCE(); MIDI_CREATE_DEFAULT_INSTANCE();
static const unsigned ledPin = 13; // LED pin on Arduino Uno
void setup() void setup()
{ {
pinMode(ledPin, OUTPUT); pinMode(LED_BUILTIN, OUTPUT);
MIDI.begin(4); // Launch MIDI and listen to channel 4 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 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) MIDI.sendNoteOn(42, 127, 1); // Send a Note (pitch 42, velo 127 on channel 1)
delay(1000); // Wait for a second delay(1000); // Wait for a second
MIDI.sendNoteOff(42, 0, 1); // Stop the note MIDI.sendNoteOff(42, 0, 1); // Stop the note
digitalWrite(ledPin, LOW); digitalWrite(LED_BUILTIN, LOW);
} }
} }

View File

@ -71,8 +71,8 @@ void setup()
midiBench.setHandleNoteOn(handleNoteOn); midiBench.setHandleNoteOn(handleNoteOn);
midiBench.begin(); midiBench.begin();
while(!Serial);
Serial.begin(115200); Serial.begin(115200);
while(!Serial);
Serial.println("Arduino Ready"); Serial.println("Arduino Ready");
midiBench.sendNoteOn(69,127,1); midiBench.sendNoteOn(69,127,1);

View File

@ -6,12 +6,17 @@
// A out = A in + B in // A out = A in + B in
// B out = B in + A 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, Serial, midiA);
MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, midiB); MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, midiB);
#elif defined(ARDUINO_SAMD_ZERO) #elif defined(ARDUINO_SAMD_ZERO)
MIDI_CREATE_INSTANCE(HardwareSerial, SerialUSB, midiA); MIDI_CREATE_INSTANCE(Serial_, SerialUSB, midiA);
MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, midiB); 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 #else
#include <SoftwareSerial.h> #include <SoftwareSerial.h>
SoftwareSerial softSerial(2,3); SoftwareSerial softSerial(2,3);

View File

@ -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();
}

View File

@ -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 a2b8a8e07628e5fd60644b6dd99c1b5e7d7f1f47 Subproject commit 703bd9caab50b139428cea1aaff9974ebee5742e

1
external/midi-usb vendored

@ -1 +0,0 @@
Subproject commit 1e2508d529e9626efb1b006b3d80d6c20a191e38

View File

@ -29,6 +29,14 @@ sendSongPosition KEYWORD2
sendSongSelect KEYWORD2 sendSongSelect KEYWORD2
sendTuneRequest KEYWORD2 sendTuneRequest KEYWORD2
sendRealTime KEYWORD2 sendRealTime KEYWORD2
sendCommon KEYWORD2
sendClock KEYWORD2
sendStart KEYWORD2
sendStop KEYWORD2
sendTick KEYWORD2
sendContinue KEYWORD2
sendActiveSensing KEYWORD2
sendSystemReset KEYWORD2
beginRpn KEYWORD2 beginRpn KEYWORD2
sendRpnValue KEYWORD2 sendRpnValue KEYWORD2
sendRpnIncrement KEYWORD2 sendRpnIncrement KEYWORD2

View File

@ -1,6 +1,6 @@
{ {
"name": "MIDI Library", "name": "MIDI Library",
"version": "4.3.1", "version": "5.0.0",
"keywords": "midi", "keywords": "midi",
"description": "Enables MIDI I/O communications on the Arduino serial ports", "description": "Enables MIDI I/O communications on the Arduino serial ports",
"license": "MIT", "license": "MIT",
@ -17,7 +17,7 @@
"url": "https://github.com/FortySevenEffects/arduino_midi_library.git", "url": "https://github.com/FortySevenEffects/arduino_midi_library.git",
"branch": "master" "branch": "master"
}, },
"export": { "export": {
"include": [ "include": [
"src", "src",
"examples" "examples"

View File

@ -1,6 +1,6 @@
name=MIDI Library name=MIDI Library
version=4.3.1 version=5.0.0
author=Forty Seven Effects author=Forty Seven Effects, lathoub
maintainer=Francois Best <francois.best@fortyseveneffects.com> maintainer=Francois Best <francois.best@fortyseveneffects.com>
sentence=MIDI I/Os for Arduino sentence=MIDI I/Os for Arduino
paragraph=Read & send MIDI messages to interface with your controllers and synths paragraph=Read & send MIDI messages to interface with your controllers and synths

View File

@ -1,15 +1,15 @@
increase_warning_level()
project(midi) project(midi)
add_library(midi STATIC add_library(midi STATIC
midi_Namespace.h midi_Namespace.h
midi_Defs.h midi_Defs.h
midi_Message.h midi_Message.h
midi_Platform.h
midi_Settings.h midi_Settings.h
midi_RingBuffer.h
midi_RingBuffer.hpp
midi_UsbTransport.h
midi_UsbTransport.hpp
MIDI.cpp MIDI.cpp
MIDI.hpp MIDI.hpp
MIDI.h MIDI.h
serialMIDI.h
) )

View File

@ -38,11 +38,15 @@ BEGIN_MIDI_NAMESPACE
\param inData The data to encode. \param inData The data to encode.
\param outSysEx The output buffer where to store the encoded message. \param outSysEx The output buffer where to store the encoded message.
\param inLength The lenght of the input buffer. \param inLength The lenght of the input buffer.
\param inFlipHeaderBits True for Korg and other who store MSB in reverse order
\return The lenght of the encoded output buffer. \return The lenght of the encoded output buffer.
@see decodeSysEx @see decodeSysEx
Code inspired from Ruin & Wesen's SysEx encoder/decoder - http://ruinwesen.com Code inspired from Ruin & Wesen's SysEx encoder/decoder - http://ruinwesen.com
*/ */
unsigned encodeSysEx(const byte* inData, byte* outSysEx, unsigned inLength) unsigned encodeSysEx(const byte* inData,
byte* outSysEx,
unsigned inLength,
bool inFlipHeaderBits)
{ {
unsigned outLength = 0; // Num bytes in output array. unsigned outLength = 0; // Num bytes in output array.
byte count = 0; // Num 7bytes in a block. byte count = 0; // Num 7bytes in a block.
@ -54,7 +58,7 @@ unsigned encodeSysEx(const byte* inData, byte* outSysEx, unsigned inLength)
const byte msb = data >> 7; const byte msb = data >> 7;
const byte body = data & 0x7f; const byte body = data & 0x7f;
outSysEx[0] |= (msb << (6 - count)); outSysEx[0] |= (msb << (inFlipHeaderBits ? count : (6 - count)));
outSysEx[1 + count] = body; outSysEx[1 + count] = body;
if (count++ == 6) if (count++ == 6)
@ -75,11 +79,15 @@ unsigned encodeSysEx(const byte* inData, byte* outSysEx, unsigned inLength)
\param inSysEx The SysEx data received from MIDI in. \param inSysEx The SysEx data received from MIDI in.
\param outData The output buffer where to store the decrypted message. \param outData The output buffer where to store the decrypted message.
\param inLength The lenght of the input buffer. \param inLength The lenght of the input buffer.
\param inFlipHeaderBits True for Korg and other who store MSB in reverse order
\return The lenght of the output buffer. \return The lenght of the output buffer.
@see encodeSysEx @see getSysExArrayLength @see encodeSysEx @see getSysExArrayLength
Code inspired from Ruin & Wesen's SysEx encoder/decoder - http://ruinwesen.com Code inspired from Ruin & Wesen's SysEx encoder/decoder - http://ruinwesen.com
*/ */
unsigned decodeSysEx(const byte* inSysEx, byte* outData, unsigned inLength) unsigned decodeSysEx(const byte* inSysEx,
byte* outData,
unsigned inLength,
bool inFlipHeaderBits)
{ {
unsigned count = 0; unsigned count = 0;
byte msbStorage = 0; byte msbStorage = 0;
@ -94,8 +102,10 @@ unsigned decodeSysEx(const byte* inSysEx, byte* outData, unsigned inLength)
} }
else else
{ {
const byte body = inSysEx[i]; const byte body = inSysEx[i];
const byte msb = ((msbStorage >> byteIndex--) & 1) << 7; const byte shift = inFlipHeaderBits ? 6 - byteIndex : byteIndex;
const byte msb = byte(((msbStorage >> shift) & 1) << 7);
byteIndex--;
outData[count++] = msb | body; outData[count++] = msb | body;
} }
} }

View File

@ -2,7 +2,7 @@
* @file MIDI.h * @file MIDI.h
* Project Arduino MIDI Library * Project Arduino MIDI Library
* @brief MIDI Library for the Arduino * @brief MIDI Library for the Arduino
* @author Francois Best * @author Francois Best, lathoub
* @date 24/02/11 * @date 24/02/11
* @license MIT - Copyright (c) 2015 Francois Best * @license MIT - Copyright (c) 2015 Francois Best
* *
@ -28,27 +28,37 @@
#pragma once #pragma once
#include "midi_Defs.h" #include "midi_Defs.h"
#include "midi_Platform.h"
#include "midi_Settings.h" #include "midi_Settings.h"
#include "midi_Message.h" #include "midi_Message.h"
#include "serialMIDI.h"
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
BEGIN_MIDI_NAMESPACE 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. /*! \brief The main class for MIDI handling.
It is templated over the type of serial port to provide abstraction from It is templated over the type of serial port to provide abstraction from
the hardware interface, meaning you can use HardwareSerial, SoftwareSerial the hardware interface, meaning you can use HardwareSerial, SoftwareSerial
or ak47's Uart classes. The only requirement is that the class implements or ak47's Uart classes. The only requirement is that the class implements
the begin, read, write and available methods. the begin, read, write and available methods.
*/ */
template<class SerialPort, class _Settings = DefaultSettings> template<class Transport, class _Settings = DefaultSettings, class _Platform = DefaultPlatform>
class MidiInterface class MidiInterface
{ {
public: public:
typedef _Settings Settings; typedef _Settings Settings;
typedef _Platform Platform;
typedef Message<Settings::SysExMaxSize> MidiMessage;
public: public:
inline MidiInterface(SerialPort& inSerial); inline MidiInterface(Transport&);
inline ~MidiInterface(); inline ~MidiInterface();
public: public:
@ -97,8 +107,19 @@ public:
inline void sendSongPosition(unsigned inBeats); inline void sendSongPosition(unsigned inBeats);
inline void sendSongSelect(DataByte inSongNumber); inline void sendSongSelect(DataByte inSongNumber);
inline void sendTuneRequest(); inline void sendTuneRequest();
inline void sendRealTime(MidiType inType);
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, inline void beginRpn(unsigned inNumber,
Channel inChannel); Channel inChannel);
inline void sendRpnValue(unsigned inValue, inline void sendRpnValue(unsigned inValue,
@ -125,6 +146,8 @@ public:
Channel inChannel); Channel inChannel);
inline void endNrpn(Channel inChannel); inline void endNrpn(Channel inChannel);
inline void send(const MidiMessage&);
public: public:
void send(MidiType inType, void send(MidiType inType,
DataByte inData1, DataByte inData1,
@ -160,48 +183,54 @@ public:
// Input Callbacks // Input Callbacks
public: public:
inline void setHandleNoteOff(void (*fptr)(byte channel, byte note, byte velocity)); inline void setHandleMessage(void (*fptr)(const MidiMessage&)) { mMessageCallback = fptr; };
inline void setHandleNoteOn(void (*fptr)(byte channel, byte note, byte velocity)); inline void setHandleError(ErrorCallback fptr) { mErrorCallback = fptr; }
inline void setHandleAfterTouchPoly(void (*fptr)(byte channel, byte note, byte pressure)); inline void setHandleNoteOff(NoteOffCallback fptr) { mNoteOffCallback = fptr; }
inline void setHandleControlChange(void (*fptr)(byte channel, byte number, byte value)); inline void setHandleNoteOn(NoteOnCallback fptr) { mNoteOnCallback = fptr; }
inline void setHandleProgramChange(void (*fptr)(byte channel, byte number)); inline void setHandleAfterTouchPoly(AfterTouchPolyCallback fptr) { mAfterTouchPolyCallback = fptr; }
inline void setHandleAfterTouchChannel(void (*fptr)(byte channel, byte pressure)); inline void setHandleControlChange(ControlChangeCallback fptr) { mControlChangeCallback = fptr; }
inline void setHandlePitchBend(void (*fptr)(byte channel, int bend)); inline void setHandleProgramChange(ProgramChangeCallback fptr) { mProgramChangeCallback = fptr; }
inline void setHandleSystemExclusive(void (*fptr)(byte * array, unsigned size)); inline void setHandleAfterTouchChannel(AfterTouchChannelCallback fptr) { mAfterTouchChannelCallback = fptr; }
inline void setHandleTimeCodeQuarterFrame(void (*fptr)(byte data)); inline void setHandlePitchBend(PitchBendCallback fptr) { mPitchBendCallback = fptr; }
inline void setHandleSongPosition(void (*fptr)(unsigned beats)); inline void setHandleSystemExclusive(SystemExclusiveCallback fptr) { mSystemExclusiveCallback = fptr; }
inline void setHandleSongSelect(void (*fptr)(byte songnumber)); inline void setHandleTimeCodeQuarterFrame(TimeCodeQuarterFrameCallback fptr) { mTimeCodeQuarterFrameCallback = fptr; }
inline void setHandleTuneRequest(void (*fptr)(void)); inline void setHandleSongPosition(SongPositionCallback fptr) { mSongPositionCallback = fptr; }
inline void setHandleClock(void (*fptr)(void)); inline void setHandleSongSelect(SongSelectCallback fptr) { mSongSelectCallback = fptr; }
inline void setHandleStart(void (*fptr)(void)); inline void setHandleTuneRequest(TuneRequestCallback fptr) { mTuneRequestCallback = fptr; }
inline void setHandleContinue(void (*fptr)(void)); inline void setHandleClock(ClockCallback fptr) { mClockCallback = fptr; }
inline void setHandleStop(void (*fptr)(void)); inline void setHandleStart(StartCallback fptr) { mStartCallback = fptr; }
inline void setHandleActiveSensing(void (*fptr)(void)); inline void setHandleTick(TickCallback fptr) { mTickCallback = fptr; }
inline void setHandleSystemReset(void (*fptr)(void)); 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); inline void disconnectCallbackFromType(MidiType inType);
private: private:
void launchCallback(); void launchCallback();
void (*mNoteOffCallback)(byte channel, byte note, byte velocity); void (*mMessageCallback)(const MidiMessage& message) = nullptr;
void (*mNoteOnCallback)(byte channel, byte note, byte velocity); ErrorCallback mErrorCallback = nullptr;
void (*mAfterTouchPolyCallback)(byte channel, byte note, byte velocity); NoteOffCallback mNoteOffCallback = nullptr;
void (*mControlChangeCallback)(byte channel, byte, byte); NoteOnCallback mNoteOnCallback = nullptr;
void (*mProgramChangeCallback)(byte channel, byte); AfterTouchPolyCallback mAfterTouchPolyCallback = nullptr;
void (*mAfterTouchChannelCallback)(byte channel, byte); ControlChangeCallback mControlChangeCallback = nullptr;
void (*mPitchBendCallback)(byte channel, int); ProgramChangeCallback mProgramChangeCallback = nullptr;
void (*mSystemExclusiveCallback)(byte * array, unsigned size); AfterTouchChannelCallback mAfterTouchChannelCallback = nullptr;
void (*mTimeCodeQuarterFrameCallback)(byte data); PitchBendCallback mPitchBendCallback = nullptr;
void (*mSongPositionCallback)(unsigned beats); SystemExclusiveCallback mSystemExclusiveCallback = nullptr;
void (*mSongSelectCallback)(byte songnumber); TimeCodeQuarterFrameCallback mTimeCodeQuarterFrameCallback = nullptr;
void (*mTuneRequestCallback)(void); SongPositionCallback mSongPositionCallback = nullptr;
void (*mClockCallback)(void); SongSelectCallback mSongSelectCallback = nullptr;
void (*mStartCallback)(void); TuneRequestCallback mTuneRequestCallback = nullptr;
void (*mContinueCallback)(void); ClockCallback mClockCallback = nullptr;
void (*mStopCallback)(void); StartCallback mStartCallback = nullptr;
void (*mActiveSensingCallback)(void); TickCallback mTickCallback = nullptr;
void (*mSystemResetCallback)(void); ContinueCallback mContinueCallback = nullptr;
StopCallback mStopCallback = nullptr;
ActiveSensingCallback mActiveSensingCallback = nullptr;
SystemResetCallback mSystemResetCallback = nullptr;
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// MIDI Soft Thru // MIDI Soft Thru
@ -217,31 +246,45 @@ public:
private: private:
void thruFilter(byte inChannel); void thruFilter(byte inChannel);
// -------------------------------------------------------------------------
// MIDI Parsing
private: private:
bool parse(); bool parse();
inline void handleNullVelocityNoteOnAsNoteOff(); inline void handleNullVelocityNoteOnAsNoteOff();
inline bool inputFilter(Channel inChannel); inline bool inputFilter(Channel inChannel);
inline void resetInput(); inline void resetInput();
inline void UpdateLastSentTime();
// -------------------------------------------------------------------------
// Transport
public:
Transport* getTransport() { return &mTransport; };
private: private:
typedef Message<Settings::SysExMaxSize> MidiMessage; Transport& mTransport;
private: // -------------------------------------------------------------------------
SerialPort& mSerial; // Internal variables
private: private:
Channel mInputChannel; Channel mInputChannel;
StatusByte mRunningStatus_RX; StatusByte mRunningStatus_RX;
StatusByte mRunningStatus_TX; StatusByte mRunningStatus_TX;
byte mPendingMessage[3]; byte mPendingMessage[3];
unsigned mPendingMessageExpectedLenght; unsigned mPendingMessageExpectedLength;
unsigned mPendingMessageIndex; unsigned mPendingMessageIndex;
unsigned mCurrentRpnNumber; unsigned mCurrentRpnNumber;
unsigned mCurrentNrpnNumber; unsigned mCurrentNrpnNumber;
bool mThruActivated : 1; bool mThruActivated : 1;
Thru::Mode mThruFilterMode : 7; Thru::Mode mThruFilterMode : 7;
MidiMessage mMessage; MidiMessage mMessage;
unsigned long mLastMessageSentTime;
unsigned long mLastMessageReceivedTime;
unsigned long mSenderActiveSensingPeriodicity;
bool mReceiverActiveSensingActivated;
int8_t mLastError;
private: private:
inline StatusByte getStatus(MidiType inType, inline StatusByte getStatus(MidiType inType,
@ -250,8 +293,14 @@ private:
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
unsigned encodeSysEx(const byte* inData, byte* outSysEx, unsigned inLenght); unsigned encodeSysEx(const byte* inData,
unsigned decodeSysEx(const byte* inSysEx, byte* outData, unsigned inLenght); byte* outSysEx,
unsigned inLenght,
bool inFlipHeaderBits = false);
unsigned decodeSysEx(const byte* inSysEx,
byte* outData,
unsigned inLenght,
bool inFlipHeaderBits = false);
END_MIDI_NAMESPACE END_MIDI_NAMESPACE

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,7 @@
* @file midi_Defs.h * @file midi_Defs.h
* Project Arduino MIDI Library * Project Arduino MIDI Library
* @brief MIDI Library for the Arduino - Definitions * @brief MIDI Library for the Arduino - Definitions
* @author Francois Best * @author Francois Best, lathoub
* @date 24/02/11 * @date 24/02/11
* @license MIT - Copyright (c) 2015 Francois Best * @license MIT - Copyright (c) 2015 Francois Best
* *
@ -38,11 +38,6 @@ typedef uint8_t byte;
BEGIN_MIDI_NAMESPACE BEGIN_MIDI_NAMESPACE
#define MIDI_LIBRARY_VERSION 0x040300
#define MIDI_LIBRARY_VERSION_MAJOR 4
#define MIDI_LIBRARY_VERSION_MINOR 3
#define MIDI_LIBRARY_VERSION_PATCH 0
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
#define MIDI_CHANNEL_OMNI 0 #define MIDI_CHANNEL_OMNI 0
@ -51,6 +46,10 @@ BEGIN_MIDI_NAMESPACE
#define MIDI_PITCHBEND_MIN -8192 #define MIDI_PITCHBEND_MIN -8192
#define MIDI_PITCHBEND_MAX 8191 #define MIDI_PITCHBEND_MAX 8191
/*! Receiving Active Sensing
*/
static const uint16_t ActiveSensingTimeout = 300;
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Type definitions // Type definitions
@ -59,28 +58,65 @@ typedef byte DataByte;
typedef byte Channel; typedef byte Channel;
typedef byte FilterMode; 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 */ /*! Enumeration of MIDI types */
enum MidiType enum MidiType: uint8_t
{ {
InvalidType = 0x00, ///< For notifying errors InvalidType = 0x00, ///< For notifying errors
NoteOff = 0x80, ///< Note Off NoteOff = 0x80, ///< Channel Message - Note Off
NoteOn = 0x90, ///< Note On NoteOn = 0x90, ///< Channel Message - Note On
AfterTouchPoly = 0xA0, ///< Polyphonic AfterTouch AfterTouchPoly = 0xA0, ///< Channel Message - Polyphonic AfterTouch
ControlChange = 0xB0, ///< Control Change / Channel Mode ControlChange = 0xB0, ///< Channel Message - Control Change / Channel Mode
ProgramChange = 0xC0, ///< Program Change ProgramChange = 0xC0, ///< Channel Message - Program Change
AfterTouchChannel = 0xD0, ///< Channel (monophonic) AfterTouch AfterTouchChannel = 0xD0, ///< Channel Message - Channel (monophonic) AfterTouch
PitchBend = 0xE0, ///< Pitch Bend PitchBend = 0xE0, ///< Channel Message - Pitch Bend
SystemExclusive = 0xF0, ///< System Exclusive SystemExclusive = 0xF0, ///< System Exclusive
SystemExclusiveStart = SystemExclusive, ///< System Exclusive Start
TimeCodeQuarterFrame = 0xF1, ///< System Common - MIDI Time Code Quarter Frame TimeCodeQuarterFrame = 0xF1, ///< System Common - MIDI Time Code Quarter Frame
SongPosition = 0xF2, ///< System Common - Song Position Pointer SongPosition = 0xF2, ///< System Common - Song Position Pointer
SongSelect = 0xF3, ///< System Common - Song Select SongSelect = 0xF3, ///< System Common - Song Select
Undefined_F4 = 0xF4,
Undefined_F5 = 0xF5,
TuneRequest = 0xF6, ///< System Common - Tune Request TuneRequest = 0xF6, ///< System Common - Tune Request
SystemExclusiveEnd = 0xF7, ///< System Exclusive End
Clock = 0xF8, ///< System Real Time - Timing Clock 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 Start = 0xFA, ///< System Real Time - Start
Continue = 0xFB, ///< System Real Time - Continue Continue = 0xFB, ///< System Real Time - Continue
Stop = 0xFC, ///< System Real Time - Stop Stop = 0xFC, ///< System Real Time - Stop
Undefined_FD = 0xFD,
ActiveSensing = 0xFE, ///< System Real Time - Active Sensing ActiveSensing = 0xFE, ///< System Real Time - Active Sensing
SystemReset = 0xFF, ///< System Real Time - System Reset SystemReset = 0xFF, ///< System Real Time - System Reset
}; };
@ -99,24 +135,13 @@ 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. /*! \brief Enumeration of Control Change command numbers.
See the detailed controllers numbers & description here: See the detailed controllers numbers & description here:
http://www.somascape.org/midi/tech/spec.html#ctrlnums http://www.somascape.org/midi/tech/spec.html#ctrlnums
*/ */
enum MidiControlChangeNumber enum MidiControlChangeNumber: uint8_t
{ {
// High resolution Continuous Controllers MSB (+32 for LSB) ---------------- // High resolution Continuous Controllers MSB (+32 for LSB) ----------------
BankSelect = 0, BankSelect = 0,
@ -192,7 +217,7 @@ enum MidiControlChangeNumber
struct RPN struct RPN
{ {
enum RegisteredParameterNumbers enum RegisteredParameterNumbers: uint16_t
{ {
PitchBendSensitivity = 0x0000, PitchBendSensitivity = 0x0000,
ChannelFineTuning = 0x0001, ChannelFineTuning = 0x0001,
@ -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 END_MIDI_NAMESPACE

View File

@ -46,7 +46,7 @@ struct Message
*/ */
inline Message() inline Message()
: channel(0) : channel(0)
, type(midi::InvalidType) , type(MIDI_NAMESPACE::InvalidType)
, data1(0) , data1(0)
, data2(0) , data2(0)
, valid(false) , valid(false)
@ -91,6 +91,10 @@ struct Message
*/ */
bool valid; bool valid;
/*! Total Length of the message.
*/
unsigned length;
inline unsigned getSysExSize() const inline unsigned getSysExSize() const
{ {
const unsigned size = unsigned(data2) << 8 | data1; const unsigned size = unsigned(data2) << 8 | data1;

View File

@ -1,10 +1,10 @@
/*! /*!
* @file midi_RingBuffer.h * @file midi_Platform.h
* Project Arduino MIDI Library * Project Arduino MIDI Library
* @brief MIDI Library for Arduino - Ring Buffer * @brief MIDI Library for the Arduino - Platform
* @author Francois Best * @license MIT - Copyright (c) 2015 Francois Best
* @date 10/10/2016 * @author lathoub
* @license MIT - Copyright (c) 2016 Francois Best * @date 22/03/20
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -27,36 +27,25 @@
#pragma once #pragma once
#include "midi_Namespace.h" #include "midi_Defs.h"
BEGIN_MIDI_NAMESPACE BEGIN_MIDI_NAMESPACE
template<typename DataType, int Size> #if ARDUINO
class RingBuffer
// DefaultPlatform is the Arduino Platform
struct DefaultPlatform
{ {
public: static unsigned long now() { return ::millis(); };
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 read();
void read(DataType* outData, int inSize);
private:
DataType mData[Size];
DataType* mWriteHead;
DataType* mReadHead;
}; };
END_MIDI_NAMESPACE #else
#include "midi_RingBuffer.hpp" struct DefaultPlatform
{
static unsigned long now() { return 0; };
};
#endif
END_MIDI_NAMESPACE

View File

@ -1,121 +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
BEGIN_MIDI_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>::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();
}
}
END_MIDI_NAMESPACE

View File

@ -50,6 +50,7 @@ struct DefaultSettings
{ {
/*! Running status enables short messages when sending multiple values /*! Running status enables short messages when sending multiple values
of the same type and channel.\n of the same type and channel.\n
Must be disabled to send USB MIDI messages to a computer
Warning: does not work with some hardware, enable with caution. Warning: does not work with some hardware, enable with caution.
*/ */
static const bool UseRunningStatus = false; static const bool UseRunningStatus = false;
@ -66,16 +67,38 @@ struct DefaultSettings
*/ */
static const bool Use1ByteParsing = true; 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 /*! Maximum size of SysEx receivable. Decrease to save RAM if you don't expect
to receive SysEx, or adjust accordingly. to receive SysEx, or adjust accordingly.
*/ */
static const unsigned SysExMaxSize = 128; 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 END_MIDI_NAMESPACE

View File

@ -1,144 +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 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:
case singleByte:
return 1;
default:
break;
}
return 0; // Can be any length (1, 2 or 3).
}
};
// -----------------------------------------------------------------------------
struct UsbMidiEventPacket
{
public:
inline UsbMidiEventPacket()
{
memset(mData, 0, 4 * sizeof(byte));
}
public:
inline void setHeader(byte inCableNumber, byte inCodeIndexNumber)
{
const byte msb = (0x0f & inCableNumber) << 4;
const byte lsb = (0x0f & inCodeIndexNumber);
mData[0] = msb | lsb;
}
inline void setMidiData(const byte* inData)
{
mData[1] = *inData++;
mData[2] = *inData++;
mData[3] = *inData;
}
inline byte getCableNumber() const
{
return mData[0] >> 4;
}
inline byte getCodeIndexNumber() const
{
return mData[0] & 0x0f;
}
inline const byte* getMidiData() const
{
return mData + 1;
}
inline byte* getMidiData()
{
return mData + 1;
}
inline UsbMidiEventPacket& operator=(const byte* inData)
{
mData[0] = *inData++;
setMidiData(inData);
return *this;
}
public:
byte mData[4];
};
END_MIDI_NAMESPACE

View File

@ -1,72 +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 <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 bool pollUsbMidi();
inline void recomposeAndSendTxPackets();
inline void resetTx();
static inline byte encodePacketHeader(StatusByte inStatusByte);
static inline int getPacketLength(const midiEventPacket_t& inPacket);
private:
typedef RingBuffer<byte, BuffersSize> Buffer;
Buffer mTxBuffer;
Buffer mRxBuffer;
union TxPacket
{
byte mDataArray[4];
midiEventPacket_t mPacket;
};
TxPacket mCurrentTxPacket;
int mCurrentTxPacketByteIndex;
};
END_MIDI_NAMESPACE
#include "midi_UsbTransport.hpp"

View File

@ -1,180 +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 bool UsbTransport<BufferSize>::pollUsbMidi()
{
bool received = false;
midiEventPacket_t packet = MidiUSB.read();
while (packet.header != 0)
{
received = true;
switch (packet.header << 4)
{
// 3 bytes messages
case midi::NoteOff:
case midi::NoteOn:
case midi::AfterTouchPoly:
case midi::ControlChange:
case midi::PitchBend:
mRxBuffer.write(packet.byte1);
mRxBuffer.write(packet.byte2);
mRxBuffer.write(packet.byte3);
break;
// 2 bytes messages
case midi::ProgramChange:
case midi::AfterTouchChannel:
mRxBuffer.write(packet.byte1);
mRxBuffer.write(packet.byte2);
break;
// 1 byte message
case midi::TuneRequest:
case midi::Clock:
case midi::Start:
case midi::Continue:
case midi::Stop:
case midi::ActiveSensing:
case midi::SystemReset:
mRxBuffer.write(packet.byte1);
break;
// Special cases
// case midi::SystemExclusive:
// case midi::TimeCodeQuarterFrame:
// case midi::SongPosition:
// case midi::SongSelect:
// break;
default:
break;
}
packet = MidiUSB.read();
}
return received;
}
template<unsigned BufferSize>
inline void UsbTransport<BufferSize>::recomposeAndSendTxPackets()
{
while (!mTxBuffer.isEmpty())
{
const byte data = mTxBuffer.read();
if (mCurrentTxPacketByteIndex == 0)
{
mCurrentTxPacket.mPacket.header = encodePacketHeader(data);
}
else
{
mCurrentTxPacket.mDataArray[mCurrentTxPacketByteIndex] = data;
}
mCurrentTxPacketByteIndex++;
const int packetLength = getPacketLength(mCurrentTxPacket.mPacket);
if (mCurrentTxPacketByteIndex == packetLength)
{
MidiUSB.write(mCurrentTxPacket.mDataArray, packetLength);
resetTx();
}
}
}
template<unsigned BufferSize>
inline void UsbTransport<BufferSize>::resetTx()
{
mCurrentTxPacket.mPacket.header = 0;
mCurrentTxPacket.mPacket.byte1 = 0;
mCurrentTxPacket.mPacket.byte2 = 0;
mCurrentTxPacket.mPacket.byte3 = 0;
mCurrentTxPacketByteIndex = 0;
}
template<unsigned BufferSize>
inline byte UsbTransport<BufferSize>::encodePacketHeader(StatusByte inStatusByte)
{
// todo: fix me for other types than channel
return inStatusByte >> 4;
}
template<unsigned BufferSize>
inline int UsbTransport<BufferSize>::getPacketLength(const midiEventPacket_t& inPacket)
{
return 3;
}
END_MIDI_NAMESPACE

115
src/serialMIDI.h Normal file
View File

@ -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

View File

@ -4,8 +4,11 @@ add_library(test-mocks STATIC
test-mocks.cpp test-mocks.cpp
test-mocks.h test-mocks.h
test-mocks_Namespace.h test-mocks_Namespace.h
test-mocks_Defs.h
test-mocks_SerialMock.cpp test-mocks_SerialMock.cpp
test-mocks_SerialMock.hpp test-mocks_SerialMock.hpp
test-mocks_SerialMock.h test-mocks_SerialMock.h
) )
target_link_libraries(test-mocks
midi
)

View File

@ -1,10 +0,0 @@
#pragma once
#include "test-mocks.h"
#include <inttypes.h>
BEGIN_TEST_MOCKS_NAMESPACE
typedef uint8_t uint8;
END_TEST_MOCKS_NAMESPACE

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include "test-mocks.h" #include "test-mocks.h"
#include "test-mocks_Defs.h" #include <inttypes.h>
BEGIN_TEST_MOCKS_NAMESPACE BEGIN_TEST_MOCKS_NAMESPACE
@ -32,8 +32,6 @@ private:
DataType* mReadHead; DataType* mReadHead;
}; };
// -----------------------------------------------------------------------------
template<int BufferSize> template<int BufferSize>
class SerialMock class SerialMock
{ {
@ -44,14 +42,14 @@ public:
public: // Arduino Serial API public: // Arduino Serial API
void begin(int inBaudrate); void begin(int inBaudrate);
int available() const; int available() const;
void write(uint8 inData); void write(uint8_t inData);
uint8 read(); uint8_t read();
public: // Test Helpers API public: // Test Helpers API
void moveTxToRx(); // Simulate loopback void moveTxToRx(); // Simulate loopback
public: public:
typedef RingBuffer<uint8, BufferSize> Buffer; typedef RingBuffer<uint8_t, BufferSize> Buffer;
Buffer mTxBuffer; Buffer mTxBuffer;
Buffer mRxBuffer; Buffer mRxBuffer;
int mBaudrate; int mBaudrate;

View File

@ -126,13 +126,13 @@ int SerialMock<BufferSize>::available() const
} }
template<int BufferSize> template<int BufferSize>
void SerialMock<BufferSize>::write(uint8 inData) void SerialMock<BufferSize>::write(uint8_t inData)
{ {
mTxBuffer.write(inData); mTxBuffer.write(inData);
} }
template<int BufferSize> template<int BufferSize>
uint8 SerialMock<BufferSize>::read() uint8_t SerialMock<BufferSize>::read()
{ {
return mRxBuffer.read(); return mRxBuffer.read();
} }

View File

@ -3,13 +3,12 @@ include(CMakeToolsHelpers OPTIONAL)
project(unit-tests) project(unit-tests)
include_directories( include_directories(
${unit-tests_SOURCE_DIR} "${unit-tests_SOURCE_DIR}"
${gtest_SOURCE_DIR}/include "${gtest_SOURCE_DIR}/include"
${gmock_SOURCE_DIR}/include "${gmock_SOURCE_DIR}/include"
) )
add_executable(unit-tests add_executable(unit-tests
unit-tests.cpp unit-tests.cpp
unit-tests.h unit-tests.h
unit-tests_Namespace.h unit-tests_Namespace.h
@ -18,12 +17,10 @@ add_executable(unit-tests
tests/unit-tests_Settings.cpp tests/unit-tests_Settings.cpp
tests/unit-tests_Settings.h tests/unit-tests_Settings.h
tests/unit-tests_SysExCodec.cpp tests/unit-tests_SysExCodec.cpp
tests/unit-tests_SerialMock.cpp
tests/unit-tests_MidiInput.cpp tests/unit-tests_MidiInput.cpp
tests/unit-tests_MidiInputCallbacks.cpp tests/unit-tests_MidiInputCallbacks.cpp
tests/unit-tests_MidiOutput.cpp tests/unit-tests_MidiOutput.cpp
tests/unit-tests_MidiThru.cpp tests/unit-tests_MidiThru.cpp
tests/unit-tests_MidiUsb.cpp
) )
target_link_libraries(unit-tests target_link_libraries(unit-tests

View File

@ -14,7 +14,8 @@ BEGIN_UNNAMED_NAMESPACE
using namespace testing; using namespace testing;
USING_NAMESPACE_UNIT_TESTS USING_NAMESPACE_UNIT_TESTS
typedef test_mocks::SerialMock<32> SerialMock; typedef test_mocks::SerialMock<32> SerialMock;
typedef midi::MidiInterface<SerialMock> MidiInterface; typedef midi::SerialMIDI<SerialMock> Transport;
typedef midi::MidiInterface<Transport> MidiInterface;
template<unsigned Size> template<unsigned Size>
struct VariableSysExSettings : midi::DefaultSettings struct VariableSysExSettings : midi::DefaultSettings
@ -53,7 +54,6 @@ TEST(MidiInput, getTypeFromStatusByte)
} }
EXPECT_EQ(MidiInterface::getTypeFromStatusByte(0xf4), midi::InvalidType); EXPECT_EQ(MidiInterface::getTypeFromStatusByte(0xf4), midi::InvalidType);
EXPECT_EQ(MidiInterface::getTypeFromStatusByte(0xf5), midi::InvalidType); EXPECT_EQ(MidiInterface::getTypeFromStatusByte(0xf5), midi::InvalidType);
EXPECT_EQ(MidiInterface::getTypeFromStatusByte(0xf9), midi::InvalidType);
EXPECT_EQ(MidiInterface::getTypeFromStatusByte(0xfd), midi::InvalidType); EXPECT_EQ(MidiInterface::getTypeFromStatusByte(0xfd), midi::InvalidType);
} }
@ -93,7 +93,8 @@ TEST(MidiInput, isChannelMessage)
TEST(MidiInput, begin) TEST(MidiInput, begin)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
// Default channel // Default channel
midi.begin(); midi.begin();
@ -109,7 +110,8 @@ TEST(MidiInput, begin)
TEST(MidiInput, initInputChannel) TEST(MidiInput, initInputChannel)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
EXPECT_EQ(midi.getInputChannel(), 0); EXPECT_EQ(midi.getInputChannel(), 0);
midi.setInputChannel(12); midi.setInputChannel(12);
@ -119,7 +121,9 @@ TEST(MidiInput, initInputChannel)
TEST(MidiInput, initMessage) TEST(MidiInput, initMessage)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
EXPECT_EQ(midi.getType(), midi::InvalidType); EXPECT_EQ(midi.getType(), midi::InvalidType);
EXPECT_EQ(midi.getChannel(), 0); EXPECT_EQ(midi.getChannel(), 0);
EXPECT_EQ(midi.getData1(), 0); EXPECT_EQ(midi.getData1(), 0);
@ -131,7 +135,9 @@ TEST(MidiInput, initMessage)
TEST(MidiInput, channelFiltering) TEST(MidiInput, channelFiltering)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
static const unsigned rxSize = 3; static const unsigned rxSize = 3;
static const byte rxData[rxSize] = { 0x9b, 12, 34 }; static const byte rxData[rxSize] = { 0x9b, 12, 34 };
midi.begin(4); // Mistmatching channel midi.begin(4); // Mistmatching channel
@ -144,7 +150,9 @@ TEST(MidiInput, channelFiltering)
TEST(MidiInput, noRxData) TEST(MidiInput, noRxData)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
midi.begin(); midi.begin();
EXPECT_EQ(midi.read(), false); EXPECT_EQ(midi.read(), false);
} }
@ -152,7 +160,9 @@ TEST(MidiInput, noRxData)
TEST(MidiInput, inputDisabled) TEST(MidiInput, inputDisabled)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
static const unsigned rxSize = 3; static const unsigned rxSize = 3;
static const byte rxData[rxSize] = { 0x9b, 12, 34 }; static const byte rxData[rxSize] = { 0x9b, 12, 34 };
midi.begin(MIDI_CHANNEL_OFF); // Invalid channel midi.begin(MIDI_CHANNEL_OFF); // Invalid channel
@ -165,10 +175,12 @@ TEST(MidiInput, inputDisabled)
TEST(MidiInput, multiByteParsing) TEST(MidiInput, multiByteParsing)
{ {
typedef VariableSettings<false, false> Settings; typedef VariableSettings<false, false> Settings;
typedef midi::MidiInterface<SerialMock, Settings> MultiByteMidiInterface; typedef midi::MidiInterface<Transport, Settings> MultiByteMidiInterface;
SerialMock serial; SerialMock serial;
MultiByteMidiInterface midi(serial); Transport transport(serial);
MultiByteMidiInterface midi(transport);
static const unsigned rxSize = 3; static const unsigned rxSize = 3;
static const byte rxData[rxSize] = { 0x9b, 12, 34 }; static const byte rxData[rxSize] = { 0x9b, 12, 34 };
midi.begin(12); midi.begin(12);
@ -179,7 +191,9 @@ TEST(MidiInput, multiByteParsing)
TEST(MidiInput, noteOn) TEST(MidiInput, noteOn)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
static const unsigned rxSize = 10; static const unsigned rxSize = 10;
static const byte rxData[rxSize] = { static const byte rxData[rxSize] = {
0x9b, 12, 34, 0x9b, 12, 34,
@ -230,7 +244,9 @@ TEST(MidiInput, noteOn)
TEST(MidiInput, noteOff) TEST(MidiInput, noteOff)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
static const unsigned rxSize = 8; static const unsigned rxSize = 8;
static const byte rxData[rxSize] = { static const byte rxData[rxSize] = {
0x8b, 12, 34, 0x8b, 12, 34,
@ -272,7 +288,9 @@ TEST(MidiInput, noteOff)
TEST(MidiInput, programChange) TEST(MidiInput, programChange)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
static const unsigned rxSize = 6; static const unsigned rxSize = 6;
static const byte rxData[rxSize] = { static const byte rxData[rxSize] = {
0xc3, 12, 34, 0xc3, 12, 34,
@ -316,7 +334,9 @@ TEST(MidiInput, programChange)
TEST(MidiInput, controlChange) TEST(MidiInput, controlChange)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
static const unsigned rxSize = 8; static const unsigned rxSize = 8;
static const byte rxData[rxSize] = { static const byte rxData[rxSize] = {
0xbb, 12, 34, 0xbb, 12, 34,
@ -358,7 +378,9 @@ TEST(MidiInput, controlChange)
TEST(MidiInput, pitchBend) TEST(MidiInput, pitchBend)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
static const unsigned rxSize = 8; static const unsigned rxSize = 8;
static const byte rxData[rxSize] = { static const byte rxData[rxSize] = {
0xeb, 12, 34, 0xeb, 12, 34,
@ -400,7 +422,9 @@ TEST(MidiInput, pitchBend)
TEST(MidiInput, afterTouchPoly) TEST(MidiInput, afterTouchPoly)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
static const unsigned rxSize = 8; static const unsigned rxSize = 8;
static const byte rxData[rxSize] = { static const byte rxData[rxSize] = {
0xab, 12, 34, 0xab, 12, 34,
@ -442,7 +466,9 @@ TEST(MidiInput, afterTouchPoly)
TEST(MidiInput, afterTouchChannel) TEST(MidiInput, afterTouchChannel)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
static const unsigned rxSize = 6; static const unsigned rxSize = 6;
static const byte rxData[rxSize] = { static const byte rxData[rxSize] = {
0xd3, 12, 34, 0xd3, 12, 34,
@ -487,10 +513,12 @@ TEST(MidiInput, sysExWithinBufferSize)
{ {
typedef VariableSysExSettings<1024> Settings; typedef VariableSysExSettings<1024> Settings;
typedef test_mocks::SerialMock<2048> LargerSerialMock; 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; LargerSerialMock serial;
LargerMidiInterface midi(serial); LargerTransport transport(serial);
LargerMidiInterface midi(transport);
// Short Frame < 256 // Short Frame < 256
{ {
@ -553,10 +581,11 @@ TEST(MidiInput, sysExWithinBufferSize)
TEST(MidiInput, sysExOverBufferSize) TEST(MidiInput, sysExOverBufferSize)
{ {
typedef VariableSysExSettings<8> Settings; typedef VariableSysExSettings<8> Settings;
typedef midi::MidiInterface<SerialMock, Settings> SmallMidiInterface; typedef midi::MidiInterface<Transport, Settings> SmallMidiInterface;
SerialMock serial; SerialMock serial;
SmallMidiInterface midi(serial); Transport transport(serial);
SmallMidiInterface midi(transport);
static const unsigned frameLength = 15; static const unsigned frameLength = 15;
static const byte frame[frameLength] = { static const byte frame[frameLength] = {
@ -566,17 +595,29 @@ TEST(MidiInput, sysExOverBufferSize)
midi.begin(); midi.begin();
serial.mRxBuffer.write(frame, frameLength); serial.mRxBuffer.write(frame, frameLength);
for (unsigned i = 0; i < frameLength - 1; ++i) EXPECT_EQ(midi.read(), false); // start sysex f0
{ EXPECT_EQ(midi.read(), false); // H
EXPECT_EQ(midi.read(), false); EXPECT_EQ(midi.read(), false); // e
} EXPECT_EQ(midi.read(), false); // l
EXPECT_EQ(midi.read(), false); 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) TEST(MidiInput, mtcQuarterFrame)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
static const unsigned rxSize = 4; static const unsigned rxSize = 4;
static const byte rxData[rxSize] = { static const byte rxData[rxSize] = {
0xf1, 12, 0xf1, 12,
@ -606,7 +647,9 @@ TEST(MidiInput, mtcQuarterFrame)
TEST(MidiInput, songPosition) TEST(MidiInput, songPosition)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
static const unsigned rxSize = 6; static const unsigned rxSize = 6;
static const byte rxData[rxSize] = { static const byte rxData[rxSize] = {
0xf2, 12, 34, 0xf2, 12, 34,
@ -638,7 +681,9 @@ TEST(MidiInput, songPosition)
TEST(MidiInput, songSelect) TEST(MidiInput, songSelect)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
static const unsigned rxSize = 4; static const unsigned rxSize = 4;
static const byte rxData[rxSize] = { static const byte rxData[rxSize] = {
0xf3, 12, 0xf3, 12,
@ -668,7 +713,9 @@ TEST(MidiInput, songSelect)
TEST(MidiInput, tuneRequest) TEST(MidiInput, tuneRequest)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
static const unsigned rxSize = 1; static const unsigned rxSize = 1;
static const byte rxData[rxSize] = { static const byte rxData[rxSize] = {
0xf6 0xf6
@ -686,7 +733,9 @@ TEST(MidiInput, tuneRequest)
TEST(MidiInput, realTime) TEST(MidiInput, realTime)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
static const unsigned rxSize = 8; static const unsigned rxSize = 8;
static const byte rxData[rxSize] = { static const byte rxData[rxSize] = {
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
@ -700,7 +749,11 @@ TEST(MidiInput, realTime)
EXPECT_EQ(midi.getData1(), 0); EXPECT_EQ(midi.getData1(), 0);
EXPECT_EQ(midi.getData2(), 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.read(), true);
EXPECT_EQ(midi.getType(), midi::Start); EXPECT_EQ(midi.getType(), midi::Start);
@ -740,7 +793,8 @@ TEST(MidiInput, realTime)
TEST(MidiInput, interleavedRealTime) TEST(MidiInput, interleavedRealTime)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
// Interleaved Clocks between NoteOn / Off messages (with running status) // Interleaved Clocks between NoteOn / Off messages (with running status)
{ {
@ -754,6 +808,7 @@ TEST(MidiInput, interleavedRealTime)
}; };
midi.begin(12); midi.begin(12);
serial.mRxBuffer.write(rxData, rxSize); serial.mRxBuffer.write(rxData, rxSize);
EXPECT_EQ(midi.read(), false); EXPECT_EQ(midi.read(), false);
EXPECT_EQ(midi.read(), false); EXPECT_EQ(midi.read(), false);
@ -816,6 +871,7 @@ TEST(MidiInput, interleavedRealTime)
}; };
midi.begin(12); midi.begin(12);
serial.mRxBuffer.write(rxData, rxSize); serial.mRxBuffer.write(rxData, rxSize);
EXPECT_EQ(midi.read(), false); EXPECT_EQ(midi.read(), false);
EXPECT_EQ(midi.read(), false); 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 ? // A stray End of Exclusive will reset the parser, but should it ?
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
static const unsigned rxSize = 4; static const unsigned rxSize = 4;
static const byte rxData[rxSize] = { static const byte rxData[rxSize] = {
0x8b, 42, 0xf7, 12 0x8b, 42, 0xf7, 12
}; };
midi.begin(MIDI_CHANNEL_OMNI); midi.begin(MIDI_CHANNEL_OMNI);
serial.mRxBuffer.write(rxData, rxSize); serial.mRxBuffer.write(rxData, rxSize);
EXPECT_EQ(midi.read(), false); EXPECT_EQ(midi.read(), false);
EXPECT_EQ(midi.read(), false); 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) TEST(MidiInput, strayUndefinedOneByteParsing)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
static const unsigned rxSize = 13; static const unsigned rxSize = 13;
static const byte rxData[rxSize] = { static const byte rxData[rxSize] = {
0xbb, 12, 0xf9, 34, 0xbb, 12, 0xfd, 34,
12, 0, 12, 0,
42, 0xfd, 127, 42, 0xfd, 127,
0xf9, 0xfd,
42, 0xfd, 0 42, 0xfd, 0
}; };
midi.begin(12); midi.begin(12);
serial.mRxBuffer.write(rxData, rxSize); serial.mRxBuffer.write(rxData, rxSize);
EXPECT_EQ(midi.read(), false); EXPECT_EQ(midi.read(), false);
EXPECT_EQ(midi.read(), false); EXPECT_EQ(midi.read(), false);
EXPECT_EQ(midi.read(), false); // Invalid, should not reset parser EXPECT_EQ(midi.read(), false); // Invalid, should not reset parser
@ -907,17 +968,19 @@ TEST(MidiInput, strayUndefinedOneByteParsing)
TEST(MidiInput, strayUndefinedMultiByteParsing) TEST(MidiInput, strayUndefinedMultiByteParsing)
{ {
typedef VariableSettings<false, false> Settings; typedef VariableSettings<false, false> Settings;
typedef midi::MidiInterface<SerialMock, Settings> MultiByteMidiInterface; typedef midi::MidiInterface<Transport, Settings> MultiByteMidiInterface;
SerialMock serial; SerialMock serial;
MultiByteMidiInterface midi(serial); Transport transport(serial);
MultiByteMidiInterface midi(transport);
static const unsigned rxSize = 4; static const unsigned rxSize = 4;
static const byte rxData[rxSize] = { static const byte rxData[rxSize] = {
0xbb, 12, 0xf9, 34, 0xbb, 12, 0xfd, 34,
}; };
midi.begin(12); midi.begin(12);
serial.mRxBuffer.write(rxData, rxSize); serial.mRxBuffer.write(rxData, rxSize);
EXPECT_EQ(midi.read(), true); EXPECT_EQ(midi.read(), true);
EXPECT_EQ(midi.getType(), midi::ControlChange); EXPECT_EQ(midi.getType(), midi::ControlChange);
EXPECT_EQ(midi.getChannel(), 12); EXPECT_EQ(midi.getChannel(), 12);

View File

@ -21,8 +21,10 @@ struct VariableSysExSettings : midi::DefaultSettings
}; };
typedef test_mocks::SerialMock<256> SerialMock; typedef test_mocks::SerialMock<256> SerialMock;
typedef midi::SerialMIDI<SerialMock> Transport;
typedef VariableSysExSettings<256> Settings; typedef VariableSysExSettings<256> Settings;
typedef midi::MidiInterface<SerialMock, Settings> MidiInterface; typedef midi::MidiInterface<Transport, Settings> MidiInterface;
MidiInterface* midi; MidiInterface* midi;
@ -30,7 +32,8 @@ class MidiInputCallbacks : public Test
{ {
public: public:
MidiInputCallbacks() MidiInputCallbacks()
: mMidi(mSerial) : mTransport(mSerial)
, mMidi(mTransport)
{ {
} }
virtual ~MidiInputCallbacks() virtual ~MidiInputCallbacks()
@ -50,6 +53,7 @@ protected:
protected: protected:
SerialMock mSerial; SerialMock mSerial;
Transport mTransport;
MidiInterface mMidi; MidiInterface mMidi;
}; };

View File

@ -15,7 +15,8 @@ using namespace testing;
USING_NAMESPACE_UNIT_TESTS; USING_NAMESPACE_UNIT_TESTS;
typedef test_mocks::SerialMock<32> SerialMock; 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; typedef std::vector<uint8_t> Buffer;
@ -24,7 +25,8 @@ typedef std::vector<uint8_t> Buffer;
TEST(MidiOutput, sendInvalid) TEST(MidiOutput, sendInvalid)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
midi.begin(); midi.begin();
midi.send(midi::NoteOn, 42, 42, 42); // Invalid channel > OFF midi.send(midi::NoteOn, 42, 42, 42); // Invalid channel > OFF
@ -40,7 +42,9 @@ TEST(MidiOutput, sendInvalid)
TEST(MidiOutput, sendGenericSingle) TEST(MidiOutput, sendGenericSingle)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
Buffer buffer; Buffer buffer;
buffer.resize(3); buffer.resize(3);
@ -54,10 +58,12 @@ TEST(MidiOutput, sendGenericSingle)
TEST(MidiOutput, sendGenericWithRunningStatus) TEST(MidiOutput, sendGenericWithRunningStatus)
{ {
typedef VariableSettings<true, false> Settings; typedef VariableSettings<true, false> Settings;
typedef midi::MidiInterface<SerialMock, Settings> RsMidiInterface; typedef midi::MidiInterface<Transport, Settings> RsMidiInterface;
SerialMock serial; SerialMock serial;
RsMidiInterface midi(serial); Transport transport(serial);
RsMidiInterface midi((Transport&)transport);
Buffer buffer; Buffer buffer;
buffer.resize(5); buffer.resize(5);
@ -74,10 +80,12 @@ TEST(MidiOutput, sendGenericWithRunningStatus)
TEST(MidiOutput, sendGenericWithoutRunningStatus) TEST(MidiOutput, sendGenericWithoutRunningStatus)
{ {
typedef VariableSettings<false, true> Settings; // No running status typedef VariableSettings<false, true> Settings; // No running status
typedef midi::MidiInterface<SerialMock, Settings> NoRsMidiInterface; typedef midi::MidiInterface<Transport, Settings> NoRsMidiInterface;
SerialMock serial; SerialMock serial;
NoRsMidiInterface midi(serial); Transport transport(serial);
NoRsMidiInterface midi((Transport&)transport);
Buffer buffer; Buffer buffer;
buffer.resize(6); buffer.resize(6);
@ -103,7 +111,9 @@ TEST(MidiOutput, sendGenericWithoutRunningStatus)
TEST(MidiOutput, sendGenericBreakingRunningStatus) TEST(MidiOutput, sendGenericBreakingRunningStatus)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
Buffer buffer; Buffer buffer;
buffer.resize(6); buffer.resize(6);
@ -118,7 +128,9 @@ TEST(MidiOutput, sendGenericBreakingRunningStatus)
TEST(MidiOutput, sendGenericRealTimeShortcut) TEST(MidiOutput, sendGenericRealTimeShortcut)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
Buffer buffer; Buffer buffer;
buffer.resize(6); buffer.resize(6);
@ -140,7 +152,9 @@ TEST(MidiOutput, sendGenericRealTimeShortcut)
TEST(MidiOutput, sendNoteOn) TEST(MidiOutput, sendNoteOn)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
Buffer buffer; Buffer buffer;
buffer.resize(6); buffer.resize(6);
@ -155,7 +169,9 @@ TEST(MidiOutput, sendNoteOn)
TEST(MidiOutput, sendNoteOff) TEST(MidiOutput, sendNoteOff)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
Buffer buffer; Buffer buffer;
buffer.resize(6); buffer.resize(6);
@ -170,7 +186,9 @@ TEST(MidiOutput, sendNoteOff)
TEST(MidiOutput, sendProgramChange) TEST(MidiOutput, sendProgramChange)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
Buffer buffer; Buffer buffer;
buffer.resize(4); buffer.resize(4);
@ -185,7 +203,9 @@ TEST(MidiOutput, sendProgramChange)
TEST(MidiOutput, sendControlChange) TEST(MidiOutput, sendControlChange)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
Buffer buffer; Buffer buffer;
buffer.resize(6); buffer.resize(6);
@ -200,7 +220,9 @@ TEST(MidiOutput, sendControlChange)
TEST(MidiOutput, sendPitchBend) TEST(MidiOutput, sendPitchBend)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
Buffer buffer; Buffer buffer;
// Int signature - arbitrary values // Int signature - arbitrary values
@ -257,7 +279,9 @@ TEST(MidiOutput, sendPolyPressure)
// This test is kept for coverage until removal of sendPolyPressure. // This test is kept for coverage until removal of sendPolyPressure.
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
Buffer buffer; Buffer buffer;
buffer.resize(6); buffer.resize(6);
@ -272,7 +296,9 @@ TEST(MidiOutput, sendPolyPressure)
TEST(MidiOutput, sendAfterTouchMono) TEST(MidiOutput, sendAfterTouchMono)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
Buffer buffer; Buffer buffer;
buffer.resize(4); buffer.resize(4);
@ -287,7 +313,9 @@ TEST(MidiOutput, sendAfterTouchMono)
TEST(MidiOutput, sendAfterTouchPoly) TEST(MidiOutput, sendAfterTouchPoly)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
Buffer buffer; Buffer buffer;
buffer.resize(6); buffer.resize(6);
@ -302,10 +330,13 @@ TEST(MidiOutput, sendAfterTouchPoly)
TEST(MidiOutput, sendSysEx) TEST(MidiOutput, sendSysEx)
{ {
typedef test_mocks::SerialMock<1024> LargeSerialMock; typedef test_mocks::SerialMock<1024> LargeSerialMock;
typedef midi::MidiInterface<LargeSerialMock> LargeMidiInterface; typedef midi::SerialMIDI<LargeSerialMock> LargeTransport;
typedef midi::MidiInterface<LargeTransport> LargeMidiInterface;
LargeSerialMock serial; LargeSerialMock serial;
LargeMidiInterface midi(serial); LargeTransport transport(serial);
LargeMidiInterface midi((LargeTransport&)transport);
Buffer buffer; Buffer buffer;
// Short frame // Short frame
@ -384,7 +415,9 @@ TEST(MidiOutput, sendSysEx)
TEST(MidiOutput, sendTimeCodeQuarterFrame) TEST(MidiOutput, sendTimeCodeQuarterFrame)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
Buffer buffer; Buffer buffer;
// Separate Nibbles // Separate Nibbles
@ -418,7 +451,9 @@ TEST(MidiOutput, sendTimeCodeQuarterFrame)
TEST(MidiOutput, sendSongPosition) TEST(MidiOutput, sendSongPosition)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
Buffer buffer; Buffer buffer;
buffer.resize(6); buffer.resize(6);
@ -434,7 +469,9 @@ TEST(MidiOutput, sendSongPosition)
TEST(MidiOutput, sendSongSelect) TEST(MidiOutput, sendSongSelect)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
Buffer buffer; Buffer buffer;
buffer.resize(4); buffer.resize(4);
@ -449,7 +486,9 @@ TEST(MidiOutput, sendSongSelect)
TEST(MidiOutput, sendTuneRequest) TEST(MidiOutput, sendTuneRequest)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
Buffer buffer; Buffer buffer;
buffer.resize(1); buffer.resize(1);
@ -463,7 +502,9 @@ TEST(MidiOutput, sendTuneRequest)
TEST(MidiOutput, sendRealTime) TEST(MidiOutput, sendRealTime)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
Buffer buffer; Buffer buffer;
// Test valid RealTime messages // Test valid RealTime messages
@ -509,10 +550,12 @@ TEST(MidiOutput, sendRealTime)
TEST(MidiOutput, RPN) TEST(MidiOutput, RPN)
{ {
typedef VariableSettings<true, true> Settings; typedef VariableSettings<true, true> Settings;
typedef midi::MidiInterface<SerialMock, Settings> RsMidiInterface; typedef midi::MidiInterface<Transport, Settings> RsMidiInterface;
SerialMock serial; SerialMock serial;
RsMidiInterface midi(serial); Transport transport(serial);
RsMidiInterface midi((Transport&)transport);
Buffer buffer; Buffer buffer;
// 14-bit Value Single Frame // 14-bit Value Single Frame
@ -625,10 +668,12 @@ TEST(MidiOutput, RPN)
TEST(MidiOutput, NRPN) TEST(MidiOutput, NRPN)
{ {
typedef VariableSettings<true, true> Settings; typedef VariableSettings<true, true> Settings;
typedef midi::MidiInterface<SerialMock, Settings> RsMidiInterface; typedef midi::MidiInterface<Transport, Settings> RsMidiInterface;
SerialMock serial; SerialMock serial;
RsMidiInterface midi(serial); Transport transport(serial);
RsMidiInterface midi((Transport&)transport);
Buffer buffer; Buffer buffer;
// 14-bit Value Single Frame // 14-bit Value Single Frame
@ -741,10 +786,12 @@ TEST(MidiOutput, NRPN)
TEST(MidiOutput, runningStatusCancellation) TEST(MidiOutput, runningStatusCancellation)
{ {
typedef VariableSettings<true, false> Settings; typedef VariableSettings<true, false> Settings;
typedef midi::MidiInterface<SerialMock, Settings> RsMidiInterface; typedef midi::MidiInterface<Transport, Settings> RsMidiInterface;
SerialMock serial; SerialMock serial;
RsMidiInterface midi(serial); Transport transport(serial);
RsMidiInterface midi((Transport&)transport);
Buffer buffer; Buffer buffer;
static const unsigned sysExLength = 13; static const unsigned sysExLength = 13;

View File

@ -14,7 +14,8 @@ BEGIN_UNNAMED_NAMESPACE
using namespace testing; using namespace testing;
USING_NAMESPACE_UNIT_TESTS USING_NAMESPACE_UNIT_TESTS
typedef test_mocks::SerialMock<32> SerialMock; 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; typedef std::vector<byte> Buffer;
template<unsigned Size> template<unsigned Size>
@ -28,7 +29,8 @@ struct VariableSysExSettings : midi::DefaultSettings
TEST(MidiThru, defaultValues) TEST(MidiThru, defaultValues)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
EXPECT_EQ(midi.getThruState(), true); EXPECT_EQ(midi.getThruState(), true);
EXPECT_EQ(midi.getFilterMode(), midi::Thru::Full); EXPECT_EQ(midi.getFilterMode(), midi::Thru::Full);
@ -40,7 +42,8 @@ TEST(MidiThru, defaultValues)
TEST(MidiThru, beginEnablesThru) TEST(MidiThru, beginEnablesThru)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
midi.turnThruOff(); midi.turnThruOff();
EXPECT_EQ(midi.getThruState(), false); EXPECT_EQ(midi.getThruState(), false);
@ -53,7 +56,8 @@ TEST(MidiThru, beginEnablesThru)
TEST(MidiThru, setGet) TEST(MidiThru, setGet)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
midi.turnThruOff(); midi.turnThruOff();
EXPECT_EQ(midi.getThruState(), false); EXPECT_EQ(midi.getThruState(), false);
@ -86,7 +90,8 @@ TEST(MidiThru, setGet)
TEST(MidiThru, off) TEST(MidiThru, off)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
midi.begin(MIDI_CHANNEL_OMNI); midi.begin(MIDI_CHANNEL_OMNI);
midi.turnThruOff(); midi.turnThruOff();
@ -106,7 +111,9 @@ TEST(MidiThru, off)
TEST(MidiThru, full) TEST(MidiThru, full)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
Buffer buffer; Buffer buffer;
midi.begin(MIDI_CHANNEL_OMNI); midi.begin(MIDI_CHANNEL_OMNI);
@ -148,7 +155,9 @@ TEST(MidiThru, full)
TEST(MidiThru, sameChannel) TEST(MidiThru, sameChannel)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
Buffer buffer; Buffer buffer;
midi.begin(12); midi.begin(12);
@ -177,7 +186,9 @@ TEST(MidiThru, sameChannel)
TEST(MidiThru, sameChannelOmni) // Acts like full TEST(MidiThru, sameChannelOmni) // Acts like full
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
Buffer buffer; Buffer buffer;
midi.begin(MIDI_CHANNEL_OMNI); midi.begin(MIDI_CHANNEL_OMNI);
@ -219,7 +230,9 @@ TEST(MidiThru, sameChannelOmni) // Acts like full
TEST(MidiThru, differentChannel) TEST(MidiThru, differentChannel)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
Buffer buffer; Buffer buffer;
midi.begin(12); midi.begin(12);
@ -248,7 +261,9 @@ TEST(MidiThru, differentChannel)
TEST(MidiThru, differentChannelOmni) // Acts like off TEST(MidiThru, differentChannelOmni) // Acts like off
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
Buffer buffer; Buffer buffer;
midi.begin(MIDI_CHANNEL_OMNI); midi.begin(MIDI_CHANNEL_OMNI);
@ -276,10 +291,12 @@ TEST(MidiThru, differentChannelOmni) // Acts like off
TEST(MidiThru, multiByteThru) TEST(MidiThru, multiByteThru)
{ {
typedef VariableSettings<false, false> MultiByteParsing; typedef VariableSettings<false, false> MultiByteParsing;
typedef midi::MidiInterface<SerialMock, MultiByteParsing> MultiByteMidiInterface; typedef midi::MidiInterface<Transport, MultiByteParsing> MultiByteMidiInterface;
SerialMock serial; SerialMock serial;
MultiByteMidiInterface midi(serial); Transport transport(serial);
MultiByteMidiInterface midi((Transport&)transport);
Buffer buffer; Buffer buffer;
midi.begin(MIDI_CHANNEL_OMNI); midi.begin(MIDI_CHANNEL_OMNI);
@ -305,10 +322,12 @@ TEST(MidiThru, multiByteThru)
TEST(MidiThru, withTxRunningStatus) TEST(MidiThru, withTxRunningStatus)
{ {
typedef VariableSettings<true, true> Settings; typedef VariableSettings<true, true> Settings;
typedef midi::MidiInterface<SerialMock, Settings> RsMidiInterface; typedef midi::MidiInterface<Transport, Settings> RsMidiInterface;
SerialMock serial; SerialMock serial;
RsMidiInterface midi(serial); Transport transport(serial);
RsMidiInterface midi((Transport&)transport);
Buffer buffer; Buffer buffer;
midi.begin(MIDI_CHANNEL_OMNI); midi.begin(MIDI_CHANNEL_OMNI);
@ -348,7 +367,8 @@ TEST(MidiThru, withTxRunningStatus)
TEST(MidiThru, invalidMode) TEST(MidiThru, invalidMode)
{ {
SerialMock serial; SerialMock serial;
MidiInterface midi(serial); Transport transport(serial);
MidiInterface midi((Transport&)transport);
midi.begin(MIDI_CHANNEL_OMNI); midi.begin(MIDI_CHANNEL_OMNI);
midi.setThruFilterMode(midi::Thru::Mode(42)); midi.setThruFilterMode(midi::Thru::Mode(42));

View File

@ -1,75 +0,0 @@
#include "unit-tests.h"
#include <src/midi_UsbDefs.h>
BEGIN_MIDI_NAMESPACE
END_MIDI_NAMESPACE
// -----------------------------------------------------------------------------
BEGIN_UNNAMED_NAMESPACE
TEST(MidiUsb, 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);
}
TEST(MidiUsb, UsbMidiEventPacket)
{
midi::UsbMidiEventPacket packet;
EXPECT_EQ(packet.mData[0], 0);
EXPECT_EQ(packet.mData[1], 0);
EXPECT_EQ(packet.mData[2], 0);
EXPECT_EQ(packet.mData[3], 0);
EXPECT_EQ(packet.getCableNumber(), 0);
EXPECT_EQ(packet.getCodeIndexNumber(), 0);
packet.setHeader(12, 7);
EXPECT_EQ(packet.mData[0], 0xc7);
EXPECT_EQ(packet.getCableNumber(), 12);
EXPECT_EQ(packet.getCodeIndexNumber(), 7);
const byte midiData[3] = { 12, 42, 47 };
packet.setMidiData(midiData);
EXPECT_EQ(packet.mData[0], 0xc7);
EXPECT_EQ(packet.mData[1], 12);
EXPECT_EQ(packet.mData[2], 42);
EXPECT_EQ(packet.mData[3], 47);
const byte fullData[4] = { 12, 34, 56, 78 };
packet = fullData;
EXPECT_EQ(packet.mData[0], 12);
EXPECT_EQ(packet.mData[1], 34);
EXPECT_EQ(packet.mData[2], 56);
EXPECT_EQ(packet.mData[3], 78);
const byte* midiDataConst = packet.getMidiData();
EXPECT_EQ(midiDataConst[0], 34);
EXPECT_EQ(midiDataConst[1], 56);
EXPECT_EQ(midiDataConst[2], 78);
byte* midiDataMutable = packet.getMidiData();
EXPECT_EQ(midiDataMutable[0], 34);
EXPECT_EQ(midiDataMutable[1], 56);
EXPECT_EQ(midiDataMutable[2], 78);
}
END_UNNAMED_NAMESPACE

View File

@ -1,64 +0,0 @@
#include "unit-tests.h"
#include <test/mocks/test-mocks_SerialMock.h>
BEGIN_UNNAMED_NAMESPACE
USING_NAMESPACE_TEST_MOCKS
using namespace testing;
TEST(RingBuffer, initialState)
{
typedef RingBuffer<uint8, 32> Buffer;
Buffer buffer;
EXPECT_EQ(buffer.getLength(), 0);
EXPECT_EQ(buffer.isEmpty(), true);
buffer.clear();
EXPECT_EQ(buffer.getLength(), 0);
EXPECT_EQ(buffer.isEmpty(), true);
}
TEST(RingBuffer, uint8)
{
typedef RingBuffer<uint8, 8> Buffer;
Buffer buffer;
buffer.write(42);
EXPECT_EQ(buffer.getLength(), 1);
EXPECT_EQ(buffer.isEmpty(), false);
const uint8 read = buffer.read();
EXPECT_EQ(read, 42);
EXPECT_EQ(buffer.getLength(), 0);
EXPECT_EQ(buffer.isEmpty(), true);
const uint8 data[] = "Hello, World!";
buffer.write(data, 13);
EXPECT_EQ(buffer.getLength(), 5); // 13 % 8
EXPECT_EQ(buffer.isEmpty(), false);
uint8 output[8] = { 0 };
buffer.read(output, 8);
const uint8 expected[8] = {
'o', 'r', 'l', 'd', '!', ',', ' ', 'W',
};
EXPECT_THAT(output, ContainerEq(expected));
buffer.clear();
EXPECT_EQ(buffer.getLength(), 0);
EXPECT_EQ(buffer.isEmpty(), true);
}
TEST(RingBuffer, uint32)
{
typedef RingBuffer<uint32_t, 32> Buffer;
Buffer buffer;
buffer.write(42);
EXPECT_EQ(buffer.getLength(), 1);
EXPECT_EQ(buffer.isEmpty(), false);
const uint8 read = buffer.read();
EXPECT_EQ(read, 42);
EXPECT_EQ(buffer.getLength(), 0);
EXPECT_EQ(buffer.isEmpty(), true);
}
END_UNNAMED_NAMESPACE

View File

@ -5,7 +5,6 @@ BEGIN_MIDI_NAMESPACE
const bool DefaultSettings::UseRunningStatus; const bool DefaultSettings::UseRunningStatus;
const bool DefaultSettings::HandleNullVelocityNoteOnAsNoteOff; const bool DefaultSettings::HandleNullVelocityNoteOnAsNoteOff;
const bool DefaultSettings::Use1ByteParsing; const bool DefaultSettings::Use1ByteParsing;
const long DefaultSettings::BaudRate;
const unsigned DefaultSettings::SysExMaxSize; const unsigned DefaultSettings::SysExMaxSize;
END_MIDI_NAMESPACE END_MIDI_NAMESPACE
@ -19,7 +18,6 @@ TEST(Settings, hasTheRightDefaultValues)
EXPECT_EQ(midi::DefaultSettings::UseRunningStatus, false); EXPECT_EQ(midi::DefaultSettings::UseRunningStatus, false);
EXPECT_EQ(midi::DefaultSettings::HandleNullVelocityNoteOnAsNoteOff, true); EXPECT_EQ(midi::DefaultSettings::HandleNullVelocityNoteOnAsNoteOff, true);
EXPECT_EQ(midi::DefaultSettings::Use1ByteParsing, true); EXPECT_EQ(midi::DefaultSettings::Use1ByteParsing, true);
EXPECT_EQ(midi::DefaultSettings::BaudRate, 31250);
EXPECT_EQ(midi::DefaultSettings::SysExMaxSize, unsigned(128)); EXPECT_EQ(midi::DefaultSettings::SysExMaxSize, unsigned(128));
} }

View File

@ -11,115 +11,171 @@ BEGIN_UNNAMED_NAMESPACE
using namespace testing; using namespace testing;
TEST(SysExCodec, Encoder) TEST(SysExCodec, EncoderAscii)
{ {
// ASCII content const byte input[] = "Hello, World!";
{ byte buffer[16];
const byte input[] = "Hello, World!"; memset(buffer, 0, 16 * sizeof(byte));
byte buffer[16]; const unsigned encodedSize = midi::encodeSysEx(input, buffer, 13);
memset(buffer, 0, 16 * sizeof(byte)); EXPECT_EQ(encodedSize, unsigned(15));
const unsigned encodedSize = midi::encodeSysEx(input, buffer, 13); const byte expected[16] = {
EXPECT_EQ(encodedSize, unsigned(15)); 0, 'H', 'e', 'l', 'l', 'o', ',', ' ',
const byte expected[16] = { 0, 'W', 'o', 'r', 'l', 'd', '!', 0,
0, 'H', 'e', 'l', 'l', 'o', ',', ' ', };
0, 'W', 'o', 'r', 'l', 'd', '!', 0, EXPECT_THAT(buffer, Each(Le(0x7f))); // All elements are <= 127
}; EXPECT_THAT(buffer, ContainerEq(expected));
EXPECT_THAT(buffer, Each(Le(0x7f))); // All elements are <= 127
EXPECT_THAT(buffer, ContainerEq(expected));
}
// Non-ASCII content
{
const byte input[] = {
182, 236, 167, 177, 61, 91, 120, // 01111000 -> 120
107, 94, 209, 87, 94 // 000100xx -> 16
};
byte buffer[16];
memset(buffer, 0, 16 * sizeof(byte));
const unsigned encodedSize = midi::encodeSysEx(input, buffer, 12);
EXPECT_EQ(encodedSize, unsigned(14));
const byte expected[16] = {
// MSB Data
120, 54, 108, 39, 49, 61, 91, 120,
16, 107, 94, 81, 87, 94, 0, 0,
};
EXPECT_THAT(buffer, Each(Le(0x7f))); // All elements are <= 127
EXPECT_THAT(buffer, ContainerEq(expected));
}
} }
TEST(SysExCodec, Decoder) TEST(SysExCodec, EncoderNonAscii)
{ {
// ASCII content const byte input[] = {
{ 182, 236, 167, 177, 61, 91, 120, // 01111000 -> 120
const byte input[] = { 107, 94, 209, 87, 94 // 000100xx -> 16
0, 'H', 'e', 'l', 'l', 'o', ',', ' ', };
0, 'W', 'o', 'r', 'l', 'd', '!', byte buffer[16];
}; memset(buffer, 0, 16 * sizeof(byte));
byte buffer[16]; const unsigned encodedSize = midi::encodeSysEx(input, buffer, 12);
memset(buffer, 0, 16 * sizeof(byte)); EXPECT_EQ(encodedSize, unsigned(14));
const unsigned decodedSize = midi::decodeSysEx(input, buffer, 15); const byte expected[16] = {
EXPECT_EQ(decodedSize, unsigned(13)); // MSB Data
const byte expected[16] = { 120, 54, 108, 39, 49, 61, 91, 120,
'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 16, 107, 94, 81, 87, 94, 0, 0,
'o', 'r', 'l', 'd', '!', 0, 0, 0, };
}; EXPECT_THAT(buffer, Each(Le(0x7f))); // All elements are <= 127
EXPECT_THAT(buffer, Each(Le(0x7f))); // All elements are <= 127 EXPECT_THAT(buffer, ContainerEq(expected));
EXPECT_THAT(buffer, ContainerEq(expected));
}
// Non-ASCII content
{
const byte input[] = {
// MSB Data
120, 54, 108, 39, 49, 61, 91, 120,
16, 107, 94, 81, 87, 94,
};
byte buffer[16];
memset(buffer, 0, 16 * sizeof(byte));
const unsigned encodedSize = midi::decodeSysEx(input, buffer, 14);
EXPECT_EQ(encodedSize, unsigned(12));
const byte expected[16] = {
182, 236, 167, 177, 61, 91, 120,
107, 94, 209, 87, 94, 0, 0,
0, 0,
};
EXPECT_THAT(input, Each(Le(0x7f))); // All elements are <= 127
EXPECT_THAT(buffer, ContainerEq(expected));
}
} }
TEST(SysExCodec, Codec) TEST(SysExCodec, EncoderNonAsciiFlipHeader)
{ {
// ASCII content const byte input[] = {
{ 182, 236, 167, 177, 61, 91, 120, // 00011111 -> 15
const byte input[] = "Hello, World!"; 107, 94, 209, 87, 94 // 0xx00100 -> 4
byte buffer1[16]; };
byte buffer2[16]; byte buffer[16];
memset(buffer1, 0, 16 * sizeof(byte)); memset(buffer, 0, 16 * sizeof(byte));
memset(buffer2, 0, 16 * sizeof(byte)); const unsigned encodedSize = midi::encodeSysEx(input, buffer, 12, true);
const unsigned encodedSize = midi::encodeSysEx(input, buffer1, 13); EXPECT_EQ(encodedSize, unsigned(14));
EXPECT_EQ(encodedSize, unsigned(15)); const byte expected[16] = {
const unsigned decodedSize = midi::decodeSysEx(buffer1, buffer2, encodedSize); // MSB Data
EXPECT_EQ(decodedSize, unsigned(13)); 15, 54, 108, 39, 49, 61, 91, 120,
EXPECT_STREQ(reinterpret_cast<const char*>(buffer2), 4, 107, 94, 81, 87, 94, 0, 0,
reinterpret_cast<const char*>(input)); };
} EXPECT_THAT(buffer, Each(Le(0x7f))); // All elements are <= 127
EXPECT_THAT(buffer, ContainerEq(expected));
}
// -----------------------------------------------------------------------------
TEST(SysExCodec, DecoderAscii)
{
const byte input[] = {
0, 'H', 'e', 'l', 'l', 'o', ',', ' ',
0, 'W', 'o', 'r', 'l', 'd', '!',
};
byte buffer[16];
memset(buffer, 0, 16 * sizeof(byte));
const unsigned decodedSize = midi::decodeSysEx(input, buffer, 15);
EXPECT_EQ(decodedSize, unsigned(13));
const byte expected[16] = {
'H', 'e', 'l', 'l', 'o', ',', ' ', 'W',
'o', 'r', 'l', 'd', '!', 0, 0, 0,
};
EXPECT_THAT(buffer, Each(Le(0x7f))); // All elements are <= 127
EXPECT_THAT(buffer, ContainerEq(expected));
}
// Non-ASCII content // Non-ASCII content
{ TEST(SysExCodec, DecoderNonAscii)
const byte input[] = { {
// MSB Data const byte input[] = {
182, 236, 167, 177, 61, 91, 120, // MSB Data
107, 94, 209, 87, 94 120, 54, 108, 39, 49, 61, 91, 120,
}; 16, 107, 94, 81, 87, 94,
byte buffer1[14]; };
byte buffer2[12]; byte buffer[16];
memset(buffer1, 0, 14 * sizeof(byte)); memset(buffer, 0, 16 * sizeof(byte));
memset(buffer2, 0, 12 * sizeof(byte)); const unsigned encodedSize = midi::decodeSysEx(input, buffer, 14);
const unsigned encodedSize = midi::encodeSysEx(input, buffer1, 12); EXPECT_EQ(encodedSize, unsigned(12));
EXPECT_EQ(encodedSize, unsigned(14)); const byte expected[16] = {
const unsigned decodedSize = midi::decodeSysEx(buffer1, buffer2, encodedSize); 182, 236, 167, 177, 61, 91, 120,
EXPECT_EQ(decodedSize, unsigned(12)); 107, 94, 209, 87, 94, 0, 0,
EXPECT_THAT(buffer2, ContainerEq(input)); 0, 0,
} };
EXPECT_THAT(input, Each(Le(0x7f))); // All elements are <= 127
EXPECT_THAT(buffer, ContainerEq(expected));
}
TEST(SysExCodec, DecoderNonAsciiFlipHeader)
{
const byte input[] = {
// MSB Data
15, 54, 108, 39, 49, 61, 91, 120,
4, 107, 94, 81, 87, 94,
};
byte buffer[16];
memset(buffer, 0, 16 * sizeof(byte));
const unsigned encodedSize = midi::decodeSysEx(input, buffer, 14, true);
EXPECT_EQ(encodedSize, unsigned(12));
const byte expected[16] = {
182, 236, 167, 177, 61, 91, 120,
107, 94, 209, 87, 94, 0, 0,
0, 0,
};
EXPECT_THAT(input, Each(Le(0x7f))); // All elements are <= 127
EXPECT_THAT(buffer, ContainerEq(expected));
}
// -----------------------------------------------------------------------------
TEST(SysExCodec, CodecAscii)
{
const byte input[] = "Hello, World!";
byte buffer1[16];
byte buffer2[16];
memset(buffer1, 0, 16 * sizeof(byte));
memset(buffer2, 0, 16 * sizeof(byte));
const unsigned encodedSize = midi::encodeSysEx(input, buffer1, 13);
EXPECT_EQ(encodedSize, unsigned(15));
const unsigned decodedSize = midi::decodeSysEx(buffer1, buffer2, encodedSize);
EXPECT_EQ(decodedSize, unsigned(13));
EXPECT_STREQ(reinterpret_cast<const char*>(buffer2),
reinterpret_cast<const char*>(input));
}
TEST(SysExCodec, CodecNonAscii)
{
const byte input[] = {
// MSB Data
182, 236, 167, 177, 61, 91, 120,
107, 94, 209, 87, 94
};
byte buffer1[14];
byte buffer2[12];
memset(buffer1, 0, 14 * sizeof(byte));
memset(buffer2, 0, 12 * sizeof(byte));
const unsigned encodedSize = midi::encodeSysEx(input, buffer1, 12);
EXPECT_EQ(encodedSize, unsigned(14));
const unsigned decodedSize = midi::decodeSysEx(buffer1, buffer2, encodedSize);
EXPECT_EQ(decodedSize, unsigned(12));
EXPECT_THAT(buffer2, ContainerEq(input));
}
TEST(SysExCodec, CodecNonAsciiFlipHeader)
{
const byte input[] = {
// MSB Data
182, 236, 167, 177, 61, 91, 120,
107, 94, 209, 87, 94
};
byte buffer1[14];
byte buffer2[12];
memset(buffer1, 0, 14 * sizeof(byte));
memset(buffer2, 0, 12 * sizeof(byte));
const unsigned encodedSize = midi::encodeSysEx(input, buffer1, 12, true);
EXPECT_EQ(encodedSize, unsigned(14));
const unsigned decodedSize = midi::decodeSysEx(buffer1, buffer2, encodedSize, true);
EXPECT_EQ(decodedSize, unsigned(12));
EXPECT_THAT(buffer2, ContainerEq(input));
} }
END_UNNAMED_NAMESPACE END_UNNAMED_NAMESPACE