commit
804e59669e
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
|
||||||
23
.travis.yml
23
.travis.yml
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"board": "arduino:avr:leonardo"
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
84
README.md
84
README.md
|
|
@ -5,29 +5,32 @@
|
||||||
[](https://github.com/FortySevenEffects/arduino_midi_library/releases/latest)
|
[](https://github.com/FortySevenEffects/arduino_midi_library/releases/latest)
|
||||||
[](LICENSE)
|
[](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.
|
||||||

|

|
||||||
|
|
||||||
2. Start coding:
|
2. Start coding:
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
#include <MIDI.h>
|
#include <MIDI.h>
|
||||||
|
|
||||||
// Created and binds the MIDI interface to the default hardware Serial port
|
// Create and bind the MIDI interface to the default hardware Serial port
|
||||||
MIDI_CREATE_DEFAULT_INSTANCE();
|
MIDI_CREATE_DEFAULT_INSTANCE();
|
||||||
|
|
||||||
void setup()
|
void setup()
|
||||||
|
|
@ -49,15 +52,66 @@ This library enables MIDI I/O communications on the Arduino serial ports.
|
||||||
|
|
||||||
## 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)
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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).
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
#include <MIDI.h>
|
||||||
|
|
||||||
|
// Before running the program below, make sure you set
|
||||||
|
// UseReceiverActiveSensing (optionally UseSenderActiveSensing) in Settings.h to true
|
||||||
|
|
||||||
|
MIDI_CREATE_DEFAULT_INSTANCE();
|
||||||
|
|
||||||
|
void handleError(int8_t err)
|
||||||
|
{
|
||||||
|
digitalWrite(LED_BUILTIN, (err == 0)? LOW : HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
pinMode(LED_BUILTIN, OUTPUT);
|
||||||
|
digitalWrite(LED_BUILTIN, LOW);
|
||||||
|
|
||||||
|
MIDI.setHandleError(handleError);
|
||||||
|
MIDI.begin(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
MIDI.read();
|
||||||
|
}
|
||||||
|
|
@ -1,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 +0,0 @@
|
||||||
Subproject commit 1e2508d529e9626efb1b006b3d80d6c20a191e38
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
)
|
)
|
||||||
|
|
|
||||||
18
src/MIDI.cpp
18
src/MIDI.cpp
|
|
@ -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;
|
||||||
|
|
@ -95,7 +103,9 @@ 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
141
src/MIDI.h
141
src/MIDI.h
|
|
@ -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,6 +107,17 @@ 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 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 sendRealTime(MidiType inType);
|
||||||
|
|
||||||
inline void beginRpn(unsigned inNumber,
|
inline void beginRpn(unsigned inNumber,
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
761
src/MIDI.hpp
761
src/MIDI.hpp
File diff suppressed because it is too large
Load Diff
110
src/midi_Defs.h
110
src/midi_Defs.h
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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"
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,7 @@ BEGIN_UNNAMED_NAMESPACE
|
||||||
|
|
||||||
using namespace testing;
|
using namespace testing;
|
||||||
|
|
||||||
TEST(SysExCodec, Encoder)
|
TEST(SysExCodec, EncoderAscii)
|
||||||
{
|
|
||||||
// ASCII content
|
|
||||||
{
|
{
|
||||||
const byte input[] = "Hello, World!";
|
const byte input[] = "Hello, World!";
|
||||||
byte buffer[16];
|
byte buffer[16];
|
||||||
|
|
@ -27,7 +25,8 @@ TEST(SysExCodec, Encoder)
|
||||||
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
|
|
||||||
|
TEST(SysExCodec, EncoderNonAscii)
|
||||||
{
|
{
|
||||||
const byte input[] = {
|
const byte input[] = {
|
||||||
182, 236, 167, 177, 61, 91, 120, // 01111000 -> 120
|
182, 236, 167, 177, 61, 91, 120, // 01111000 -> 120
|
||||||
|
|
@ -45,11 +44,29 @@ TEST(SysExCodec, Encoder)
|
||||||
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(SysExCodec, EncoderNonAsciiFlipHeader)
|
||||||
|
{
|
||||||
|
const byte input[] = {
|
||||||
|
182, 236, 167, 177, 61, 91, 120, // 00011111 -> 15
|
||||||
|
107, 94, 209, 87, 94 // 0xx00100 -> 4
|
||||||
|
};
|
||||||
|
byte buffer[16];
|
||||||
|
memset(buffer, 0, 16 * sizeof(byte));
|
||||||
|
const unsigned encodedSize = midi::encodeSysEx(input, buffer, 12, true);
|
||||||
|
EXPECT_EQ(encodedSize, unsigned(14));
|
||||||
|
const byte expected[16] = {
|
||||||
|
// MSB Data
|
||||||
|
15, 54, 108, 39, 49, 61, 91, 120,
|
||||||
|
4, 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)
|
// -----------------------------------------------------------------------------
|
||||||
{
|
|
||||||
// ASCII content
|
TEST(SysExCodec, DecoderAscii)
|
||||||
{
|
{
|
||||||
const byte input[] = {
|
const byte input[] = {
|
||||||
0, 'H', 'e', 'l', 'l', 'o', ',', ' ',
|
0, 'H', 'e', 'l', 'l', 'o', ',', ' ',
|
||||||
|
|
@ -66,7 +83,9 @@ TEST(SysExCodec, Decoder)
|
||||||
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
|
// Non-ASCII content
|
||||||
|
TEST(SysExCodec, DecoderNonAscii)
|
||||||
{
|
{
|
||||||
const byte input[] = {
|
const byte input[] = {
|
||||||
// MSB Data
|
// MSB Data
|
||||||
|
|
@ -85,11 +104,30 @@ TEST(SysExCodec, Decoder)
|
||||||
EXPECT_THAT(input, Each(Le(0x7f))); // All elements are <= 127
|
EXPECT_THAT(input, Each(Le(0x7f))); // All elements are <= 127
|
||||||
EXPECT_THAT(buffer, ContainerEq(expected));
|
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, Codec)
|
// -----------------------------------------------------------------------------
|
||||||
{
|
|
||||||
// ASCII content
|
TEST(SysExCodec, CodecAscii)
|
||||||
{
|
{
|
||||||
const byte input[] = "Hello, World!";
|
const byte input[] = "Hello, World!";
|
||||||
byte buffer1[16];
|
byte buffer1[16];
|
||||||
|
|
@ -103,7 +141,8 @@ TEST(SysExCodec, Codec)
|
||||||
EXPECT_STREQ(reinterpret_cast<const char*>(buffer2),
|
EXPECT_STREQ(reinterpret_cast<const char*>(buffer2),
|
||||||
reinterpret_cast<const char*>(input));
|
reinterpret_cast<const char*>(input));
|
||||||
}
|
}
|
||||||
// Non-ASCII content
|
|
||||||
|
TEST(SysExCodec, CodecNonAscii)
|
||||||
{
|
{
|
||||||
const byte input[] = {
|
const byte input[] = {
|
||||||
// MSB Data
|
// MSB Data
|
||||||
|
|
@ -120,6 +159,23 @@ TEST(SysExCodec, Codec)
|
||||||
EXPECT_EQ(decodedSize, unsigned(12));
|
EXPECT_EQ(decodedSize, unsigned(12));
|
||||||
EXPECT_THAT(buffer2, ContainerEq(input));
|
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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue