Compare commits
134 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
2d64cc3c2f | |
|
|
7c0d716641 | |
|
|
8f8c7cfcc6 | |
|
|
8e9805fc92 | |
|
|
1944aca891 | |
|
|
663b24b0b5 | |
|
|
be557c1f4b | |
|
|
50e33c8b4a | |
|
|
417beca1c7 | |
|
|
c9d3b9b592 | |
|
|
c7922927e5 | |
|
|
892f65a9ee | |
|
|
e1035a03f7 | |
|
|
2012e2a84a | |
|
|
b4daa697a9 | |
|
|
d9873560ad | |
|
|
bf80e99d54 | |
|
|
2f03d9b29d | |
|
|
d2f11d02e2 | |
|
|
9f5317f299 | |
|
|
f356c99ca2 | |
|
|
7ca289d84e | |
|
|
0d605dc8a7 | |
|
|
3f0a2d3fdb | |
|
|
d501f4bb3d | |
|
|
d9149d19df | |
|
|
a93fb27a1c | |
|
|
d967c0c389 | |
|
|
d3c361033d | |
|
|
33b294624a | |
|
|
10ef10bfde | |
|
|
da8ca5e69a | |
|
|
e292cf61b0 | |
|
|
150cecd450 | |
|
|
ff3052ceb4 | |
|
|
e5ee620139 | |
|
|
0d9f6f4731 | |
|
|
80dfb8333c | |
|
|
d0110e4866 | |
|
|
ce57d26d2c | |
|
|
47ce2acc16 | |
|
|
1375b0b6aa | |
|
|
116dba12eb | |
|
|
aa4912b587 | |
|
|
c0a66516f6 | |
|
|
a5e31f15a4 | |
|
|
99a981be5e | |
|
|
419c74adfe | |
|
|
5e9a0165d9 | |
|
|
d600656f04 | |
|
|
804e59669e | |
|
|
fc360d60b3 | |
|
|
b384278b29 | |
|
|
ae49d3037d | |
|
|
2d6bdd6dc2 | |
|
|
c2d17ec429 | |
|
|
c1d2f476b8 | |
|
|
45fb2df88f | |
|
|
05487c5415 | |
|
|
e06e3677f0 | |
|
|
c5330945ee | |
|
|
1e14162bf4 | |
|
|
9d43a8370e | |
|
|
b457f6db7c | |
|
|
be85c7b3e0 | |
|
|
23c53cafe1 | |
|
|
f8707ed49a | |
|
|
a9664ef4a4 | |
|
|
7a96fec0b5 | |
|
|
2c657a38d1 | |
|
|
cab564b995 | |
|
|
2ffbdef8da | |
|
|
843a9e5d8d | |
|
|
f067883dd8 | |
|
|
dac0862657 | |
|
|
d688030c14 | |
|
|
96b7fd4537 | |
|
|
b3ab309781 | |
|
|
faa7bade0b | |
|
|
a9e0db5b73 | |
|
|
39d13e8ac4 | |
|
|
5835806832 | |
|
|
347b67a877 | |
|
|
0e9e505543 | |
|
|
67a13be6c6 | |
|
|
5ccf0159a2 | |
|
|
1ccd7c3ce8 | |
|
|
5b96487362 | |
|
|
3f15b733e4 | |
|
|
a34087c92c | |
|
|
9a0907ea7f | |
|
|
b9397337d2 | |
|
|
db0f65a46e | |
|
|
42b98a78cf | |
|
|
04ae12d9ad | |
|
|
83ad031ee6 | |
|
|
a44d1e7c1c | |
|
|
e486667d8a | |
|
|
58474673b4 | |
|
|
2e8be813c4 | |
|
|
98f7bb8831 | |
|
|
ba6e16442b | |
|
|
1cd638361e | |
|
|
561def7c06 | |
|
|
33bd77dd13 | |
|
|
c5833214a1 | |
|
|
d9cad6034f | |
|
|
064c9d9568 | |
|
|
1c01effbd9 | |
|
|
9b9905fb2a | |
|
|
4f9e629471 | |
|
|
63caf9a564 | |
|
|
ad652d3191 | |
|
|
ed72e06755 | |
|
|
d292b68eaa | |
|
|
43fcb370ed | |
|
|
7809235676 | |
|
|
2a1e4a86b3 | |
|
|
3396ec9429 | |
|
|
724a1caecd | |
|
|
03d73c2b09 | |
|
|
3a31a366e4 | |
|
|
9a4b8b6c86 | |
|
|
77bb518f19 | |
|
|
de51bcfa34 | |
|
|
e615065dc2 | |
|
|
de608f874f | |
|
|
32489bc0ea | |
|
|
ce659116b7 | |
|
|
6b295e6a47 | |
|
|
7aaa7d4e24 | |
|
|
f6b4282821 | |
|
|
8a856e1f9d | |
|
|
3eb65db1a4 |
|
|
@ -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
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
---
|
||||
name: Bug report
|
||||
about: Report something that does not work as intended
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
Before opening an issue, check if your problem already has been solved by looking in:
|
||||
- The existing issues: https://github.com/FortySevenEffects/arduino_midi_library/issues
|
||||
- The discussions: https://github.com/FortySevenEffects/arduino_midi_library/discussions
|
||||
|
||||
Consider opening a discussion instead of an issue if you need help with your project:
|
||||
https://github.com/FortySevenEffects/arduino_midi_library/discussions/new
|
||||
-->
|
||||
|
||||
## Context
|
||||
|
||||
Please answer a few questions to help us understand your problem better and guide you to a solution:
|
||||
|
||||
<!-- Tip: place the letter x in the checkboxes to tick them:
|
||||
- [ ] Unticked checkbox
|
||||
- [x] Ticked checkbox
|
||||
|
||||
You can also tick them by clicking after you've submitted your issue.
|
||||
-->
|
||||
|
||||
- What board are you using ?
|
||||
- `example: Arduino Leonardo`
|
||||
- _Please list any shields or other **relevant** hardware you're using_
|
||||
- What version of the Arduino IDE are you using ?
|
||||
- `example: 1.8.5`
|
||||
- How are you using MIDI ?
|
||||
- [ ] Hardware Serial (DIN plugs)
|
||||
- [ ] USB
|
||||
- [ ] Other (please specify)
|
||||
- Is your problem related to:
|
||||
- [ ] MIDI Input (reading messages from other devices)
|
||||
- [ ] MIDI Output (sending messages to other devices)
|
||||
- How comfortable are you with code ?
|
||||
- [ ] Complete beginner
|
||||
- [ ] I've done basic projects
|
||||
- [ ] I know my way around C/C++
|
||||
- [ ] Advanced / professional
|
||||
|
||||
## Describe your project and what you expect to happen:
|
||||
|
||||
<!--
|
||||
Example: When I press a switch on my pedalboard, it sends a SysEx message that I'd like to receive on my Arduino.
|
||||
|
||||
Note: Attachments (circuit diagrams, code examples) are most welcome and will help us understand your needs better and find a suitable solution for your issue.
|
||||
-->
|
||||
|
||||
## Describe your problem (what does not work):
|
||||
|
||||
<!--
|
||||
Example: I cannot receive SysEx messages coming from my AxeFX 2
|
||||
-->
|
||||
|
||||
## Steps to reproduce
|
||||
|
||||
<!--
|
||||
Please list the steps you took to hit the problem, so we can try and reproduce it.
|
||||
-->
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Discussions
|
||||
url: https://github.com/FortySevenEffects/arduino_midi_library/discussions
|
||||
about: Not a bug or a feature request ? Discuss your problem, ask for help or show what you've built in Discussions.
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: new feature
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
name: CMake
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
env:
|
||||
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
|
||||
BUILD_TYPE: Debug
|
||||
GENERATE_COVERAGE: true
|
||||
LCOV_ROOT: ${{github.workspace}}/lcov
|
||||
|
||||
jobs:
|
||||
build:
|
||||
# The CMake configure and build commands are platform agnostic and should work equally
|
||||
# well on Windows or Mac. You can convert this to a matrix build if you need
|
||||
# cross-platform coverage.
|
||||
# See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Install lcov
|
||||
run: |
|
||||
mkdir -p "$LCOV_ROOT"
|
||||
wget https://github.com/linux-test-project/lcov/releases/download/v1.15/lcov-1.15.tar.gz --output-document="$LCOV_ROOT/lcov.tar.gz"
|
||||
tar -xf "$LCOV_ROOT/lcov.tar.gz" --strip-components=1 -C "$LCOV_ROOT"
|
||||
echo "$LCOV_ROOT/bin" >> $GITHUB_PATH
|
||||
shell: bash
|
||||
|
||||
- name: Configure CMake
|
||||
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
|
||||
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
|
||||
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DBUILDER_ENABLE_PROFILING=true
|
||||
|
||||
- name: Build
|
||||
# Build your program with the given configuration
|
||||
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
|
||||
|
||||
- name: Run Unit Tests
|
||||
working-directory: ${{github.workspace}}/build
|
||||
run: ctest --verbose
|
||||
|
||||
- name: Generate code coverage report
|
||||
working-directory: ${{github.workspace}}/build
|
||||
run: |
|
||||
lcov --directory . --capture --output-file coverage.info
|
||||
lcov --remove coverage.info '/usr/*' "${{github.workspace}}/test/*" "${{github.workspace}}/external/*" --output-file coverage.info
|
||||
lcov --list coverage.info
|
||||
|
||||
- uses: coverallsapp/github-action@9ba913c152ae4be1327bfb9085dc806cedb44057
|
||||
name: Upload code coverage report to Coveralls
|
||||
with:
|
||||
path-to-lcov: ${{github.workspace}}/build/coverage.info
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
name: PlatformIO
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
platformio:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
example:
|
||||
- AltPinSerial
|
||||
- Basic_IO
|
||||
- Bench
|
||||
- Callbacks
|
||||
- Chaining
|
||||
- DualMerger
|
||||
- ErrorCallback
|
||||
- Input
|
||||
- RPN_NRPN
|
||||
- SimpleSynth
|
||||
- CustomBaudRate
|
||||
board:
|
||||
- uno
|
||||
- due
|
||||
- zero
|
||||
- leonardo
|
||||
- micro
|
||||
- nanoatmega328
|
||||
- megaatmega2560
|
||||
- teensy2
|
||||
- teensy30
|
||||
- teensy31
|
||||
- teensylc
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||
restore-keys: ${{ runner.os }}-pip-
|
||||
- name: Cache PlatformIO
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.platformio
|
||||
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
- name: Install PlatformIO
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install --upgrade platformio
|
||||
pip install "click!=8.0.2" # See platformio/platformio-core#4078
|
||||
- name: Run PlatformIO
|
||||
run: pio ci --lib="." --board="${{matrix.board}}"
|
||||
env:
|
||||
PLATFORMIO_CI_SRC: examples/${{ matrix.example }}
|
||||
|
|
@ -3,3 +3,8 @@
|
|||
logs/
|
||||
build/
|
||||
.vscode/.cmaketools.json
|
||||
src/.DS_Store
|
||||
examples/.DS_Store
|
||||
.DS_Store
|
||||
test/xcode
|
||||
.development
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
[submodule "external/google-test"]
|
||||
path = external/google-test
|
||||
url = https://github.com/google/googletest.git
|
||||
[submodule "external/midi-usb"]
|
||||
path = external/midi-usb
|
||||
url = https://github.com/arduino-libraries/MIDIUSB.git
|
||||
|
|
|
|||
95
.travis.yml
95
.travis.yml
|
|
@ -1,95 +0,0 @@
|
|||
# Kudos to these guys:
|
||||
# https://github.com/Return-To-The-Roots/s25client/blob/master/.travis.yml
|
||||
# http://docs.platformio.org/en/stable/ci/travis.html
|
||||
|
||||
sudo: false
|
||||
language: python
|
||||
|
||||
os:
|
||||
- linux
|
||||
|
||||
python:
|
||||
- "2.7"
|
||||
|
||||
# Cache PlatformIO packages using Travis CI container-based infrastructure
|
||||
cache:
|
||||
directories:
|
||||
- "~/.platformio"
|
||||
|
||||
env:
|
||||
global:
|
||||
- BUILD_TYPE=Debug
|
||||
matrix:
|
||||
- BUILD_UNIT_TESTS=1
|
||||
- PLATFORMIO_CI_SRC=examples/Basic_IO
|
||||
- PLATFORMIO_CI_SRC=examples/Bench
|
||||
- PLATFORMIO_CI_SRC=examples/Callbacks
|
||||
- PLATFORMIO_CI_SRC=examples/DualMerger
|
||||
- PLATFORMIO_CI_SRC=examples/Input
|
||||
- PLATFORMIO_CI_SRC=examples/MidiUSB REQUIRES_USB=1
|
||||
- PLATFORMIO_CI_SRC=examples/RPN_NRPN
|
||||
- PLATFORMIO_CI_SRC=examples/SimpleSynth
|
||||
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-4.8
|
||||
- cmake
|
||||
|
||||
install:
|
||||
- |
|
||||
if [ "${BUILD_UNIT_TESTS}" ]; then
|
||||
# GCov 4.6 cannot handle the file structure
|
||||
export CXX="g++-4.8"
|
||||
export GCOV="gcov-4.8"
|
||||
|
||||
# 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"
|
||||
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"
|
||||
tar xf "$LCOV_ROOT/lcov.tar.gz" --strip-components=1 -C $LCOV_ROOT
|
||||
export PATH="$LCOV_ROOT/bin:$PATH"
|
||||
which lcov
|
||||
|
||||
# Install coveralls tool
|
||||
gem install coveralls-lcov
|
||||
export GENERATE_COVERAGE=1
|
||||
else
|
||||
# Install PlatformIO
|
||||
pip install -U platformio
|
||||
fi
|
||||
|
||||
script:
|
||||
# Build unit tests & generate code coverage
|
||||
- |
|
||||
if [ "${BUILD_UNIT_TESTS}" ]; then
|
||||
mkdir build && cd build
|
||||
cmake -DCMAKE_CXX_COMPILER=$COMPILER -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DBUILDER_ENABLE_PROFILING=${GENERATE_COVERAGE} --generator="Unix Makefiles" ..
|
||||
make all
|
||||
ctest --verbose
|
||||
fi
|
||||
|
||||
# Build current example
|
||||
- |
|
||||
if [ ! "${BUILD_UNIT_TESTS}" ]; then
|
||||
if [ "${REQUIRES_USB}" ]; then
|
||||
platformio ci --lib="." --lib=external/midi-usb --board="due" --board="dueUSB" --board="zero" --board="zeroUSB" --board="leonardo"
|
||||
else
|
||||
platformio ci --lib="." --board=uno --board="due" --board="zero" --board="leonardo" --board="micro" --board="nanoatmega328" --board="megaatmega2560" --board="teensy20" --board="teensy20pp" --board="teensy30" --board="teensy31"
|
||||
fi
|
||||
fi
|
||||
|
||||
after_success:
|
||||
- |
|
||||
if [ "${GENERATE_COVERAGE}" ]; then
|
||||
# Generate code coverage information & send to Coveralls
|
||||
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 --list coverage.info
|
||||
coveralls-lcov --repo-token ${COVERALLS_TOKEN} coverage.info
|
||||
fi
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"board": "arduino:avr:leonardo"
|
||||
}
|
||||
|
|
@ -6,26 +6,57 @@
|
|||
"/Applications/Arduino.app/Contents/Java/hardware/tools/avr/include",
|
||||
"/Applications/Arduino.app/Contents/Java/hardware/arduino/avr/cores/arduino"
|
||||
],
|
||||
"browse" : {
|
||||
"limitSymbolsToIncludedHeaders" : true,
|
||||
"databaseFilename" : ""
|
||||
}
|
||||
"browse": {
|
||||
"limitSymbolsToIncludedHeaders": true,
|
||||
"databaseFilename": "",
|
||||
"path": [
|
||||
"/Applications/Arduino.app/Contents/Java/hardware/tools/avr/include",
|
||||
"/Applications/Arduino.app/Contents/Java/hardware/arduino/avr/cores/arduino"
|
||||
]
|
||||
},
|
||||
"intelliSenseMode": "clang-x64",
|
||||
"macFrameworkPath": [
|
||||
"/System/Library/Frameworks",
|
||||
"/Library/Frameworks"
|
||||
],
|
||||
"compilerPath": "/usr/bin/clang",
|
||||
"cStandard": "c11",
|
||||
"cppStandard": "c++17"
|
||||
},
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": ["/usr/include"],
|
||||
"browse" : {
|
||||
"limitSymbolsToIncludedHeaders" : true,
|
||||
"databaseFilename" : ""
|
||||
}
|
||||
"includePath": [
|
||||
"/usr/include"
|
||||
],
|
||||
"browse": {
|
||||
"limitSymbolsToIncludedHeaders": true,
|
||||
"databaseFilename": "",
|
||||
"path": [
|
||||
"/usr/include"
|
||||
]
|
||||
},
|
||||
"intelliSenseMode": "clang-x64",
|
||||
"compilerPath": "/usr/bin/clang",
|
||||
"cStandard": "c11",
|
||||
"cppStandard": "c++17"
|
||||
},
|
||||
{
|
||||
"name": "Win32",
|
||||
"includePath": ["c:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include"],
|
||||
"browse" : {
|
||||
"limitSymbolsToIncludedHeaders" : true,
|
||||
"databaseFilename" : ""
|
||||
}
|
||||
"includePath": [
|
||||
"c:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include"
|
||||
],
|
||||
"browse": {
|
||||
"limitSymbolsToIncludedHeaders": true,
|
||||
"databaseFilename": "",
|
||||
"path": [
|
||||
"c:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include"
|
||||
]
|
||||
},
|
||||
"intelliSenseMode": "msvc-x64",
|
||||
"compilerPath": "/usr/bin/clang",
|
||||
"cStandard": "c11",
|
||||
"cppStandard": "c++17"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
|
|
@ -1,4 +1,14 @@
|
|||
// 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",
|
||||
"system_error": "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"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1,17 +1,29 @@
|
|||
# Contributing Guidelines
|
||||
|
||||
First, thanks for your help ! :+1:
|
||||
|
||||
## Branches
|
||||
|
||||
Please base your Pull Requests off the `master` branch.
|
||||
|
||||
## Requirements
|
||||
|
||||
Requirements to build and run the unit tests:
|
||||
- CMake 2.8 or later
|
||||
- GCC / Clang with C++11 support
|
||||
|
||||
- CMake 2.8 or later
|
||||
- GCC / Clang with C++11 support (GCC 4.8 or higher)
|
||||
|
||||
## Setup
|
||||
|
||||
Pull Google Test / Google Mock subrepository:
|
||||
|
||||
```
|
||||
$ git init submodules
|
||||
$ git submodule init
|
||||
$ git submodule update
|
||||
```
|
||||
|
||||
Create build directory, run CMake, build and run unit tests:
|
||||
|
||||
```
|
||||
$ mkdir build && cd build
|
||||
$ cmake ..
|
||||
|
|
|
|||
151
README.md
151
README.md
|
|
@ -1,61 +1,142 @@
|
|||
# Arduino MIDI Library
|
||||
|
||||
[](https://travis-ci.org/FortySevenEffects/arduino_midi_library)
|
||||
[](https://coveralls.io/github/FortySevenEffects/arduino_midi_library)
|
||||
[](https://github.com/FortySevenEffects/arduino_midi_library/releases/latest)
|
||||
[](LICENSE)
|
||||
[](https://github.com/FortySevenEffects/arduino_midi_library/actions/workflows/cmake.yml)
|
||||
[](https://github.com/FortySevenEffects/arduino_midi_library/actions/workflows/platformio.yml)
|
||||
[](https://coveralls.io/github/FortySevenEffects/arduino_midi_library)
|
||||
|
||||
This library enables MIDI I/O communications on the Arduino serial ports.
|
||||
This library adds MIDI I/O communications to an Arduino board.
|
||||
|
||||
### 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..).
|
||||
* OMNI input reading (read all channels).
|
||||
* Software Thru, with message filtering.
|
||||
* [Callbacks](http://playground.arduino.cc/Main/MIDILibraryCallbacks) to handle input messages more easily.
|
||||
* Last received message is saved until a new one arrives.
|
||||
* Configurable: [overridable template-based settings](https://github.com/FortySevenEffects/arduino_midi_library/wiki/Using-custom-Settings).
|
||||
* Create more than one MIDI port for mergers/splitters applications.
|
||||
* Use any serial port, hardware or software.
|
||||
|
||||
- **New** : MIDI over USB, Bluetooth, IP & AppleMIDI (see [Transports](#other-transport-mechanisms)).
|
||||
- **New** : Active Sensing support
|
||||
- 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..).
|
||||
- OMNI input reading (read all channels).
|
||||
- Software Thru, with message filtering.
|
||||
- [Callbacks](https://github.com/FortySevenEffects/arduino_midi_library/wiki/Using-Callbacks) to handle input messages more easily.
|
||||
- Last received message is saved until a new one arrives.
|
||||
- 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
|
||||
|
||||
1. Use Arduino's Library Manager to install the library.
|
||||
1. Use the Arduino Library Manager to install the library.
|
||||

|
||||
|
||||
2. Start coding:
|
||||
```c++
|
||||
#include <MIDI.h>
|
||||
|
||||
// Created and binds the MIDI interface to the default hardware Serial port
|
||||
MIDI_CREATE_DEFAULT_INSTANCE();
|
||||
```c++
|
||||
#include <MIDI.h>
|
||||
|
||||
void setup()
|
||||
{
|
||||
MIDI.begin(MIDI_CHANNEL_OMNI); // Listen to all incoming messages
|
||||
}
|
||||
// Create and bind the MIDI interface to the default hardware Serial port
|
||||
MIDI_CREATE_DEFAULT_INSTANCE();
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Send note 42 with velocity 127 on channel 1
|
||||
MIDI.sendNoteOn(42, 127, 1);
|
||||
void setup()
|
||||
{
|
||||
MIDI.begin(MIDI_CHANNEL_OMNI); // Listen to all incoming messages
|
||||
}
|
||||
|
||||
// Read incoming messages
|
||||
MIDI.read();
|
||||
}
|
||||
```
|
||||
void loop()
|
||||
{
|
||||
// Send note 42 with velocity 127 on channel 1
|
||||
MIDI.sendNoteOn(42, 127, 1);
|
||||
|
||||
// Read incoming messages
|
||||
MIDI.read();
|
||||
}
|
||||
```
|
||||
|
||||
3. Read the [documentation](#documentation) or watch the awesome video tutorials from [Notes & Volts](https://www.youtube.com/playlist?list=PL4_gPbvyebyH2xfPXePHtx8gK5zPBrVkg).
|
||||
|
||||
## Documentation
|
||||
|
||||
- [Doxygen Extended Documentation](http://fortyseveneffects.github.io/arduino_midi_library/).
|
||||
- [GitHub wiki](https://github.com/FortySevenEffects/arduino_midi_library/wiki).
|
||||
- [Doxygen Extended Documentation](https://fortyseveneffects.github.io/arduino_midi_library/).
|
||||
- [GitHub wiki](https://github.com/FortySevenEffects/arduino_midi_library/wiki).
|
||||
|
||||
## Contact
|
||||
## USB Migration (4.x to 5.x)
|
||||
|
||||
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).
|
||||
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.
|
||||
|
||||
You can also get informations about bug fixes and updates on my twitter account: [@fortysevenfx](http://twitter.com/fortysevenfx).
|
||||
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.x`:
|
||||
|
||||
```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.
|
||||
|
||||
### Differences between Serial & other transports
|
||||
|
||||
- Software Thru is enabled by default on Serial, but not on other transports.
|
||||
|
||||
## Contact & Contribution
|
||||
|
||||
To report a bug, contribute, discuss on usage, or request support, please [discuss it here](https://github.com/FortySevenEffects/arduino_midi_library/discussions/new).
|
||||
|
||||
You can also contact me on Twitter: [@fortysevenfx](https://twitter.com/fortysevenfx).
|
||||
|
||||
## Contributors
|
||||
|
||||
Special thanks to all who have contributed to this open-source project !
|
||||
|
||||
- [@lathoub](https://github.com/lathoub)
|
||||
- [@jarosz](https://github.com/jarosz)
|
||||
- [@ivankravets](https://github.com/ivankravets)
|
||||
- [@insolace](https://github.com/insolace)
|
||||
- [@softegg](https://github.com/softegg)
|
||||
- [@per1234](https://github.com/per1234)
|
||||
- [@LnnrtS](https://github.com/LnnrtS)
|
||||
- [@DavidMenting](https://github.com/DavidMenting)
|
||||
- [@Rolel](https://github.com/Rolel)
|
||||
- [@kant](https://github.com/kant)
|
||||
- [@paul-emile-element](https://github.com/paul-emile-element)
|
||||
- [@muxa](https://github.com/muxa)
|
||||
|
||||
You want to help ? Check out the [contribution guidelines](./CONTRIBUTING.md).
|
||||
|
||||
## License
|
||||
|
||||
MIT © 2016 [Francois Best](http://fortyseveneffects.com)
|
||||
MIT © 2009 - present [Francois Best](https://francoisbest.com)
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
#### Changelog
|
||||
* 11/06/2014 : Version 4.2 released. Bug fix for SysEx, overridable template settings.
|
||||
* 16/04/2014 : Version 4.1 released. Bug fixes regarding running status.
|
||||
* 13/02/2014 : Version 4.0 released. Moved to GitHub, added multiple instances & software serial support, and a few bug fixes.
|
||||
* 29/01/2012 : Version 3.2 released. Release notes are [here](http://sourceforge.net/news/?group_id=265194).
|
||||
* 06/05/2011 : Version 3.1 released. Added [callback](http://playground.arduino.cc/Main/MIDILibraryCallbacks) support.
|
||||
* 06/03/2011 : Version 3.0 released. Project is now hosted on [SourceForge](http://sourceforge.net/projects/arduinomidilib).
|
||||
* 14/12/2009 : Version 2.5 released.
|
||||
* 28/07/2009 : Version 2.0 released.
|
||||
* 28/03/2009 : Simplified version of MIDI.begin, Fast mode is now on by default.
|
||||
* 08/03/2009 : Thru method operational. Added some features to enable thru.
|
||||
|
||||
- 20/04/2020 : Version 5.0 released. Separation of transports by [@lathoub](https://github.com/lathoub), adds Active Sensing.
|
||||
- 11/06/2014 : Version 4.2 released. Bug fix for SysEx, overridable template settings.
|
||||
- 16/04/2014 : Version 4.1 released. Bug fixes regarding running status.
|
||||
- 13/02/2014 : Version 4.0 released. Moved to GitHub, added multiple instances & software serial support, and a few bug fixes.
|
||||
- 29/01/2012 : Version 3.2 released. Release notes are [here](http://sourceforge.net/news/?group_id=265194).
|
||||
- 06/05/2011 : Version 3.1 released. Added [callback](http://playground.arduino.cc/Main/MIDILibraryCallbacks) support.
|
||||
- 06/03/2011 : Version 3.0 released. Project is now hosted on [SourceForge](http://sourceforge.net/projects/arduinomidilib).
|
||||
- 14/12/2009 : Version 2.5 released.
|
||||
- 28/07/2009 : Version 2.0 released.
|
||||
- 28/03/2009 : Simplified version of MIDI.begin, Fast mode is now on by default.
|
||||
- 08/03/2009 : Thru method operational. Added some features to enable thru.
|
||||
|
|
|
|||
|
|
@ -8,7 +8,18 @@ macro(setup_builder)
|
|||
|
||||
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)
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -O0")
|
||||
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")
|
||||
|
||||
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
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = "Version 4.3.1"
|
||||
PROJECT_NUMBER = "Version 5.0.2"
|
||||
|
||||
# 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
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
// Examples
|
||||
|
||||
/*!
|
||||
\example MIDI_Basic_IO.ino
|
||||
\example Basic_IO.ino
|
||||
This example shows how to perform simple input and output MIDI. \n
|
||||
\n
|
||||
When any message arrives to the Arduino, the LED is turned on,
|
||||
|
|
@ -29,15 +29,15 @@
|
|||
*/
|
||||
|
||||
/*!
|
||||
\example MIDI_Callbacks.ino
|
||||
\example Callbacks.ino
|
||||
This example shows how to use callbacks for easier MIDI input handling. \n
|
||||
*/
|
||||
|
||||
/*!
|
||||
\example MIDI_Bench.ino
|
||||
\example MIDI_DualMerger.ino
|
||||
\example MIDI_Input.ino
|
||||
\example MIDI_SimpleSynth.ino
|
||||
\example Bench.ino
|
||||
\example DualMerger.ino
|
||||
\example Input.ino
|
||||
\example SimpleSynth.ino
|
||||
*/
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -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 behaviour, 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,37 @@
|
|||
#include <MIDI.h>
|
||||
|
||||
// Simple tutorial on how to receive and send MIDI messages
|
||||
// on a different serial port, using SoftwareSerial.
|
||||
// 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) || defined(_VARIANT_ARDUINO_ZERO_)
|
||||
/* example not relevant for this hardware (SoftwareSerial not supported) */
|
||||
MIDI_CREATE_DEFAULT_INSTANCE();
|
||||
#else
|
||||
#include <SoftwareSerial.h>
|
||||
using Transport = MIDI_NAMESPACE::SerialMIDI<SoftwareSerial>;
|
||||
int rxPin = 18;
|
||||
int txPin = 19;
|
||||
SoftwareSerial mySerial = SoftwareSerial(rxPin, txPin);
|
||||
Transport serialMIDI(mySerial);
|
||||
MIDI_NAMESPACE::MidiInterface<Transport> MIDI((Transport&)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();
|
||||
|
||||
static const unsigned ledPin = 13; // LED pin on Arduino Uno
|
||||
|
||||
void setup()
|
||||
{
|
||||
pinMode(ledPin, OUTPUT);
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
MIDI.begin(4); // Launch MIDI and listen to channel 4
|
||||
}
|
||||
|
||||
|
|
@ -18,10 +16,10 @@ void loop()
|
|||
{
|
||||
if (MIDI.read()) // If we have received a message
|
||||
{
|
||||
digitalWrite(ledPin, HIGH);
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
MIDI.sendNoteOn(42, 127, 1); // Send a Note (pitch 42, velo 127 on channel 1)
|
||||
delay(1000); // Wait for a second
|
||||
MIDI.sendNoteOff(42, 0, 1); // Stop the note
|
||||
digitalWrite(ledPin, LOW);
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,8 +71,8 @@ void setup()
|
|||
midiBench.setHandleNoteOn(handleNoteOn);
|
||||
midiBench.begin();
|
||||
|
||||
while(!Serial);
|
||||
Serial.begin(115200);
|
||||
while(!Serial);
|
||||
Serial.println("Arduino Ready");
|
||||
|
||||
midiBench.sendNoteOn(69,127,1);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ MIDI_CREATE_DEFAULT_INSTANCE();
|
|||
// This function will be automatically called when a NoteOn is received.
|
||||
// It must be a void-returning function with the correct parameters,
|
||||
// see documentation here:
|
||||
// http://arduinomidilib.fortyseveneffects.com/a00022.html
|
||||
// https://github.com/FortySevenEffects/arduino_midi_library/wiki/Using-Callbacks
|
||||
|
||||
void handleNoteOn(byte channel, byte pitch, byte velocity)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
#include <MIDI.h>
|
||||
|
||||
MIDI_CREATE_DEFAULT_INSTANCE();
|
||||
|
||||
void setup()
|
||||
{
|
||||
pinMode(2, INPUT);
|
||||
|
||||
MIDI // chaining MIDI commands - order is from top to bottom (turnThruOff,... begin)
|
||||
.turnThruOff()
|
||||
// using a lamdba function for this callbacks
|
||||
.setHandleNoteOn([](byte channel, byte note, byte velocity)
|
||||
{
|
||||
// Do whatever you want when a note is pressed.
|
||||
|
||||
// Try to keep your callbacks short (no delays ect)
|
||||
// otherwise it would slow down the loop() and have a bad impact
|
||||
// on real-time performance.
|
||||
})
|
||||
.setHandleNoteOff([](byte channel, byte note, byte velocity)
|
||||
{
|
||||
// Do something when the note is released.
|
||||
// Note that NoteOn messages with 0 velocity are interpreted as NoteOffs.
|
||||
})
|
||||
.begin(MIDI_CHANNEL_OMNI); // Initiate MIDI communications, listen to all channels
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Call MIDI.read the fastest you can for real-time performance.
|
||||
MIDI.read();
|
||||
|
||||
if (digitalRead(2))
|
||||
MIDI // chained sendNoteOn commands
|
||||
.sendNoteOn(42, 127, 1)
|
||||
.sendNoteOn(40, 54, 1);
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
#include <MIDI.h>
|
||||
|
||||
// Override the default MIDI baudrate to
|
||||
// a decoding program such as Hairless MIDI (set baudrate to 115200)
|
||||
struct CustomBaudRateSettings : public MIDI_NAMESPACE::DefaultSerialSettings {
|
||||
static const long BaudRate = 115200;
|
||||
};
|
||||
|
||||
#if defined(ARDUINO_SAM_DUE) || defined(USBCON) || defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MKL26Z64__)
|
||||
// Leonardo, Due and other USB boards use Serial1 by default.
|
||||
MIDI_NAMESPACE::SerialMIDI<HardwareSerial, CustomBaudRateSettings> serialMIDI(Serial1);
|
||||
MIDI_NAMESPACE::MidiInterface<MIDI_NAMESPACE::SerialMIDI<HardwareSerial, CustomBaudRateSettings>> MIDI((MIDI_NAMESPACE::SerialMIDI<HardwareSerial, CustomBaudRateSettings>&)serialMIDI);
|
||||
#else
|
||||
MIDI_NAMESPACE::SerialMIDI<HardwareSerial, CustomBaudRateSettings> serialMIDI(Serial);
|
||||
MIDI_NAMESPACE::MidiInterface<MIDI_NAMESPACE::SerialMIDI<HardwareSerial, CustomBaudRateSettings>> MIDI((MIDI_NAMESPACE::SerialMIDI<HardwareSerial, CustomBaudRateSettings>&)serialMIDI);
|
||||
#endif
|
||||
|
||||
void setup() {
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
MIDI.begin(MIDI_CHANNEL_OMNI);
|
||||
}
|
||||
|
||||
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,12 +6,17 @@
|
|||
// A out = A in + B in
|
||||
// B out = B in + A in
|
||||
|
||||
#ifdef ARDUINO_SAM_DUE
|
||||
#if defined(ARDUINO_SAM_DUE)
|
||||
MIDI_CREATE_INSTANCE(HardwareSerial, Serial, midiA);
|
||||
MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, midiB);
|
||||
#elif defined(ARDUINO_SAMD_ZERO)
|
||||
MIDI_CREATE_INSTANCE(HardwareSerial, SerialUSB, midiA);
|
||||
MIDI_CREATE_INSTANCE(Serial_, SerialUSB, midiA);
|
||||
MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, midiB);
|
||||
#elif defined(USBCON) || defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MKL26Z64__)
|
||||
#include <SoftwareSerial.h>
|
||||
SoftwareSerial softSerial(2,3);
|
||||
MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, midiA);
|
||||
MIDI_CREATE_INSTANCE(SoftwareSerial, softSerial, midiB);
|
||||
#else
|
||||
#include <SoftwareSerial.h>
|
||||
SoftwareSerial softSerial(2,3);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
#include <MIDI.h>
|
||||
|
||||
// Before running the program below, make sure you set
|
||||
// UseReceiverActiveSensing (optionally UseSenderActiveSensing) in Settings.h to true
|
||||
|
||||
MIDI_CREATE_DEFAULT_INSTANCE();
|
||||
|
||||
void handleError(int8_t err)
|
||||
{
|
||||
digitalWrite(LED_BUILTIN, (err == 0)? LOW : HIGH);
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
|
||||
MIDI.setHandleError(handleError);
|
||||
MIDI.begin(1);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
MIDI.read();
|
||||
}
|
||||
|
|
@ -1,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 ecd530865cefdfa7dea58e84f6aa1b548950363d
|
||||
Subproject commit 703bd9caab50b139428cea1aaff9974ebee5742e
|
||||
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 0a1ef7498dad7904d2a54530616f418dcba9197c
|
||||
23
keywords.txt
23
keywords.txt
|
|
@ -29,6 +29,14 @@ sendSongPosition KEYWORD2
|
|||
sendSongSelect KEYWORD2
|
||||
sendTuneRequest KEYWORD2
|
||||
sendRealTime KEYWORD2
|
||||
sendCommon KEYWORD2
|
||||
sendClock KEYWORD2
|
||||
sendStart KEYWORD2
|
||||
sendStop KEYWORD2
|
||||
sendTick KEYWORD2
|
||||
sendContinue KEYWORD2
|
||||
sendActiveSensing KEYWORD2
|
||||
sendSystemReset KEYWORD2
|
||||
beginRpn KEYWORD2
|
||||
sendRpnValue KEYWORD2
|
||||
sendRpnIncrement KEYWORD2
|
||||
|
|
@ -77,8 +85,8 @@ setHandleSystemReset KEYWORD2
|
|||
getTypeFromStatusByte KEYWORD2
|
||||
getChannelFromStatusByte KEYWORD2
|
||||
isChannelMessage KEYWORD2
|
||||
encodeSysEx KEYWORD2
|
||||
decodeSysEx KEYWORD2
|
||||
encodeSysEx KEYWORD2
|
||||
decodeSysEx KEYWORD2
|
||||
|
||||
|
||||
#######################################
|
||||
|
|
@ -138,7 +146,18 @@ GeneralPurposeController1 LITERAL1
|
|||
GeneralPurposeController2 LITERAL1
|
||||
GeneralPurposeController3 LITERAL1
|
||||
GeneralPurposeController4 LITERAL1
|
||||
BankSelectLSB LITERAL1
|
||||
ModulationWheelLSB LITERAL1
|
||||
BreathControllerLSB LITERAL1
|
||||
FootControllerLSB LITERAL1
|
||||
PortamentoTimeLSB LITERAL1
|
||||
DataEntryLSB LITERAL1
|
||||
ChannelVolumeLSB LITERAL1
|
||||
BalanceLSB LITERAL1
|
||||
PanLSB LITERAL1
|
||||
ExpressionControllerLSB LITERAL1
|
||||
EffectControl1LSB LITERAL1
|
||||
EffectControl2LSB LITERAL1
|
||||
Sustain LITERAL1
|
||||
Portamento LITERAL1
|
||||
Sostenuto LITERAL1
|
||||
|
|
|
|||
46
library.json
46
library.json
|
|
@ -1,25 +1,23 @@
|
|||
{
|
||||
"name": "MIDI Library",
|
||||
"version": "4.3.1",
|
||||
"keywords": "midi",
|
||||
"description": "Enables MIDI I/O communications on the Arduino serial ports",
|
||||
"license": "MIT",
|
||||
"authors":
|
||||
{
|
||||
"name": "Francois Best",
|
||||
"email": "francois.best@fortyseveneffects.com",
|
||||
"url": "https://github.com/Franky47",
|
||||
"maintainer": true
|
||||
},
|
||||
"repository":
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/FortySevenEffects/arduino_midi_library.git",
|
||||
"branch": "master"
|
||||
},
|
||||
"downloadUrl": "https://github.com/FortySevenEffects/arduino_midi_library/releases/tag/4.3.1",
|
||||
"include": "src",
|
||||
"examples": "examples/*/*.ino",
|
||||
"frameworks": "arduino",
|
||||
"platforms": ["atmelavr", "atmelsam", "teensy"]
|
||||
}
|
||||
"name": "MIDI Library",
|
||||
"version": "5.0.2",
|
||||
"keywords": "midi",
|
||||
"description": "Enables MIDI I/O communications on the Arduino serial ports",
|
||||
"license": "MIT",
|
||||
"authors": {
|
||||
"name": "Francois Best",
|
||||
"email": "contact@francoisbest.com",
|
||||
"url": "https://github.com/Franky47",
|
||||
"maintainer": true
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/FortySevenEffects/arduino_midi_library.git",
|
||||
"branch": "master"
|
||||
},
|
||||
"export": {
|
||||
"include": ["src", "examples"]
|
||||
},
|
||||
"frameworks": "arduino",
|
||||
"platforms": ["atmelavr", "atmelsam", "teensy"]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
name=MIDI Library
|
||||
version=4.3.1
|
||||
author=Forty Seven Effects
|
||||
maintainer=Francois Best <francois.best@fortyseveneffects.com>
|
||||
version=5.0.2
|
||||
author=Francois Best, lathoub
|
||||
maintainer=Francois Best <contact@francoisbest.com>
|
||||
sentence=MIDI I/Os for Arduino
|
||||
paragraph=Read & send MIDI messages to interface with your controllers and synths
|
||||
category=Communication
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
|
|
@ -1,15 +1,15 @@
|
|||
increase_warning_level()
|
||||
|
||||
project(midi)
|
||||
|
||||
add_library(midi STATIC
|
||||
midi_Namespace.h
|
||||
midi_Defs.h
|
||||
midi_Message.h
|
||||
midi_Platform.h
|
||||
midi_Settings.h
|
||||
midi_RingBuffer.h
|
||||
midi_RingBuffer.hpp
|
||||
midi_UsbTransport.h
|
||||
midi_UsbTransport.hpp
|
||||
MIDI.cpp
|
||||
MIDI.hpp
|
||||
MIDI.h
|
||||
serialMIDI.h
|
||||
)
|
||||
|
|
|
|||
30
src/MIDI.cpp
30
src/MIDI.cpp
|
|
@ -37,12 +37,16 @@ BEGIN_MIDI_NAMESPACE
|
|||
data you want to send.
|
||||
\param inData The data to encode.
|
||||
\param outSysEx The output buffer where to store the encoded message.
|
||||
\param inLength The lenght of the input buffer.
|
||||
\return The lenght of the encoded output buffer.
|
||||
\param inLength The length of the input buffer.
|
||||
\param inFlipHeaderBits True for Korg and other who store MSB in reverse order
|
||||
\return The length of the encoded output buffer.
|
||||
@see decodeSysEx
|
||||
Code inspired from Ruin & Wesen's SysEx encoder/decoder - http://ruinwesen.com
|
||||
*/
|
||||
unsigned encodeSysEx(const byte* inData, byte* outSysEx, unsigned inLength)
|
||||
unsigned encodeSysEx(const byte* inData,
|
||||
byte* outSysEx,
|
||||
unsigned inLength,
|
||||
bool inFlipHeaderBits)
|
||||
{
|
||||
unsigned outLength = 0; // Num bytes in output array.
|
||||
byte count = 0; // Num 7bytes in a block.
|
||||
|
|
@ -54,7 +58,7 @@ unsigned encodeSysEx(const byte* inData, byte* outSysEx, unsigned inLength)
|
|||
const byte msb = data >> 7;
|
||||
const byte body = data & 0x7f;
|
||||
|
||||
outSysEx[0] |= (msb << (6 - count));
|
||||
outSysEx[0] |= (msb << (inFlipHeaderBits ? count : (6 - count)));
|
||||
outSysEx[1 + count] = body;
|
||||
|
||||
if (count++ == 6)
|
||||
|
|
@ -73,13 +77,17 @@ unsigned encodeSysEx(const byte* inData, byte* outSysEx, unsigned inLength)
|
|||
127 without breaking the MIDI protocol. Use this static method to reassemble
|
||||
your received message.
|
||||
\param inSysEx The SysEx data received from MIDI in.
|
||||
\param outData The output buffer where to store the decrypted message.
|
||||
\param inLength The lenght of the input buffer.
|
||||
\return The lenght of the output buffer.
|
||||
\param outData The output buffer where to store the decrypted message.
|
||||
\param inLength The length of the input buffer.
|
||||
\param inFlipHeaderBits True for Korg and other who store MSB in reverse order
|
||||
\return The length of the output buffer.
|
||||
@see encodeSysEx @see getSysExArrayLength
|
||||
Code inspired from Ruin & Wesen's SysEx encoder/decoder - http://ruinwesen.com
|
||||
*/
|
||||
unsigned decodeSysEx(const byte* inSysEx, byte* outData, unsigned inLength)
|
||||
unsigned decodeSysEx(const byte* inSysEx,
|
||||
byte* outData,
|
||||
unsigned inLength,
|
||||
bool inFlipHeaderBits)
|
||||
{
|
||||
unsigned count = 0;
|
||||
byte msbStorage = 0;
|
||||
|
|
@ -94,8 +102,10 @@ unsigned decodeSysEx(const byte* inSysEx, byte* outData, unsigned inLength)
|
|||
}
|
||||
else
|
||||
{
|
||||
const byte body = inSysEx[i];
|
||||
const byte msb = ((msbStorage >> byteIndex--) & 1) << 7;
|
||||
const byte body = inSysEx[i];
|
||||
const byte shift = inFlipHeaderBits ? 6 - byteIndex : byteIndex;
|
||||
const byte msb = byte(((msbStorage >> shift) & 1) << 7);
|
||||
byteIndex--;
|
||||
outData[count++] = msb | body;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
211
src/MIDI.h
211
src/MIDI.h
|
|
@ -2,7 +2,7 @@
|
|||
* @file MIDI.h
|
||||
* Project Arduino MIDI Library
|
||||
* @brief MIDI Library for the Arduino
|
||||
* @author Francois Best
|
||||
* @author Francois Best, lathoub
|
||||
* @date 24/02/11
|
||||
* @license MIT - Copyright (c) 2015 Francois Best
|
||||
*
|
||||
|
|
@ -28,105 +28,128 @@
|
|||
#pragma once
|
||||
|
||||
#include "midi_Defs.h"
|
||||
#include "midi_Platform.h"
|
||||
#include "midi_Settings.h"
|
||||
#include "midi_Message.h"
|
||||
|
||||
#include "serialMIDI.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
BEGIN_MIDI_NAMESPACE
|
||||
|
||||
#define MIDI_LIBRARY_VERSION 0x050000
|
||||
#define MIDI_LIBRARY_VERSION_MAJOR 5
|
||||
#define MIDI_LIBRARY_VERSION_MINOR 0
|
||||
#define MIDI_LIBRARY_VERSION_PATCH 0
|
||||
|
||||
/*! \brief The main class for MIDI handling.
|
||||
It is templated over the type of serial port to provide abstraction from
|
||||
the hardware interface, meaning you can use HardwareSerial, SoftwareSerial
|
||||
or ak47's Uart classes. The only requirement is that the class implements
|
||||
the begin, read, write and available methods.
|
||||
*/
|
||||
template<class SerialPort, class _Settings = DefaultSettings>
|
||||
template<class Transport, class _Settings = DefaultSettings, class _Platform = DefaultPlatform>
|
||||
class MidiInterface
|
||||
{
|
||||
public:
|
||||
typedef _Settings Settings;
|
||||
typedef _Platform Platform;
|
||||
typedef Message<Settings::SysExMaxSize> MidiMessage;
|
||||
|
||||
public:
|
||||
inline MidiInterface(SerialPort& inSerial);
|
||||
inline MidiInterface(Transport&);
|
||||
inline ~MidiInterface();
|
||||
|
||||
public:
|
||||
void begin(Channel inChannel = 1);
|
||||
MidiInterface& begin(Channel inChannel = 1);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// MIDI Output
|
||||
|
||||
public:
|
||||
inline void sendNoteOn(DataByte inNoteNumber,
|
||||
inline MidiInterface& sendNoteOn(DataByte inNoteNumber,
|
||||
DataByte inVelocity,
|
||||
Channel inChannel);
|
||||
|
||||
inline void sendNoteOff(DataByte inNoteNumber,
|
||||
inline MidiInterface& sendNoteOff(DataByte inNoteNumber,
|
||||
DataByte inVelocity,
|
||||
Channel inChannel);
|
||||
|
||||
inline void sendProgramChange(DataByte inProgramNumber,
|
||||
inline MidiInterface& sendProgramChange(DataByte inProgramNumber,
|
||||
Channel inChannel);
|
||||
|
||||
inline void sendControlChange(DataByte inControlNumber,
|
||||
inline MidiInterface& sendControlChange(DataByte inControlNumber,
|
||||
DataByte inControlValue,
|
||||
Channel inChannel);
|
||||
|
||||
inline void sendPitchBend(int inPitchValue, Channel inChannel);
|
||||
inline void sendPitchBend(double inPitchValue, Channel inChannel);
|
||||
inline MidiInterface& sendPitchBend(int inPitchValue, Channel inChannel);
|
||||
inline MidiInterface& sendPitchBend(double inPitchValue, Channel inChannel);
|
||||
|
||||
inline void sendPolyPressure(DataByte inNoteNumber,
|
||||
inline MidiInterface& sendPolyPressure(DataByte inNoteNumber,
|
||||
DataByte inPressure,
|
||||
Channel inChannel) __attribute__ ((deprecated));
|
||||
|
||||
inline void sendAfterTouch(DataByte inPressure,
|
||||
inline MidiInterface& sendAfterTouch(DataByte inPressure,
|
||||
Channel inChannel);
|
||||
inline void sendAfterTouch(DataByte inNoteNumber,
|
||||
inline MidiInterface& sendAfterTouch(DataByte inNoteNumber,
|
||||
DataByte inPressure,
|
||||
Channel inChannel);
|
||||
|
||||
inline void sendSysEx(unsigned inLength,
|
||||
inline MidiInterface& sendSysEx(unsigned inLength,
|
||||
const byte* inArray,
|
||||
bool inArrayContainsBoundaries = false);
|
||||
|
||||
inline void sendTimeCodeQuarterFrame(DataByte inTypeNibble,
|
||||
inline MidiInterface& sendTimeCodeQuarterFrame(DataByte inTypeNibble,
|
||||
DataByte inValuesNibble);
|
||||
inline void sendTimeCodeQuarterFrame(DataByte inData);
|
||||
inline MidiInterface& sendTimeCodeQuarterFrame(DataByte inData);
|
||||
|
||||
inline void sendSongPosition(unsigned inBeats);
|
||||
inline void sendSongSelect(DataByte inSongNumber);
|
||||
inline void sendTuneRequest();
|
||||
inline void sendRealTime(MidiType inType);
|
||||
inline MidiInterface& sendSongPosition(unsigned inBeats);
|
||||
inline MidiInterface& sendSongSelect(DataByte inSongNumber);
|
||||
inline MidiInterface& sendTuneRequest();
|
||||
|
||||
inline void beginRpn(unsigned inNumber,
|
||||
inline MidiInterface& sendCommon(MidiType inType, unsigned = 0);
|
||||
|
||||
inline MidiInterface& sendClock() { return sendRealTime(Clock); };
|
||||
inline MidiInterface& sendStart() { return sendRealTime(Start); };
|
||||
inline MidiInterface& sendStop() { return sendRealTime(Stop); };
|
||||
inline MidiInterface& sendTick() { return sendRealTime(Tick); };
|
||||
inline MidiInterface& sendContinue() { return sendRealTime(Continue); };
|
||||
inline MidiInterface& sendActiveSensing() { return sendRealTime(ActiveSensing); };
|
||||
inline MidiInterface& sendSystemReset() { return sendRealTime(SystemReset); };
|
||||
|
||||
inline MidiInterface& sendRealTime(MidiType inType);
|
||||
|
||||
inline MidiInterface& beginRpn(unsigned inNumber,
|
||||
Channel inChannel);
|
||||
inline void sendRpnValue(unsigned inValue,
|
||||
inline MidiInterface& sendRpnValue(unsigned inValue,
|
||||
Channel inChannel);
|
||||
inline void sendRpnValue(byte inMsb,
|
||||
inline MidiInterface& sendRpnValue(byte inMsb,
|
||||
byte inLsb,
|
||||
Channel inChannel);
|
||||
inline void sendRpnIncrement(byte inAmount,
|
||||
inline MidiInterface& sendRpnIncrement(byte inAmount,
|
||||
Channel inChannel);
|
||||
inline void sendRpnDecrement(byte inAmount,
|
||||
inline MidiInterface& sendRpnDecrement(byte inAmount,
|
||||
Channel inChannel);
|
||||
inline void endRpn(Channel inChannel);
|
||||
inline MidiInterface& endRpn(Channel inChannel);
|
||||
|
||||
inline void beginNrpn(unsigned inNumber,
|
||||
inline MidiInterface& beginNrpn(unsigned inNumber,
|
||||
Channel inChannel);
|
||||
inline void sendNrpnValue(unsigned inValue,
|
||||
inline MidiInterface& sendNrpnValue(unsigned inValue,
|
||||
Channel inChannel);
|
||||
inline void sendNrpnValue(byte inMsb,
|
||||
inline MidiInterface& sendNrpnValue(byte inMsb,
|
||||
byte inLsb,
|
||||
Channel inChannel);
|
||||
inline void sendNrpnIncrement(byte inAmount,
|
||||
inline MidiInterface& sendNrpnIncrement(byte inAmount,
|
||||
Channel inChannel);
|
||||
inline void sendNrpnDecrement(byte inAmount,
|
||||
inline MidiInterface& sendNrpnDecrement(byte inAmount,
|
||||
Channel inChannel);
|
||||
inline void endNrpn(Channel inChannel);
|
||||
inline MidiInterface& endNrpn(Channel inChannel);
|
||||
|
||||
inline MidiInterface& send(const MidiMessage&);
|
||||
|
||||
public:
|
||||
void send(MidiType inType,
|
||||
MidiInterface& send(MidiType inType,
|
||||
DataByte inData1,
|
||||
DataByte inData2,
|
||||
Channel inChannel);
|
||||
|
|
@ -149,7 +172,7 @@ public:
|
|||
|
||||
public:
|
||||
inline Channel getInputChannel() const;
|
||||
inline void setInputChannel(Channel inChannel);
|
||||
inline MidiInterface& setInputChannel(Channel inChannel);
|
||||
|
||||
public:
|
||||
static inline MidiType getTypeFromStatusByte(byte inStatus);
|
||||
|
|
@ -160,48 +183,54 @@ public:
|
|||
// Input Callbacks
|
||||
|
||||
public:
|
||||
inline void setHandleNoteOff(void (*fptr)(byte channel, byte note, byte velocity));
|
||||
inline void setHandleNoteOn(void (*fptr)(byte channel, byte note, byte velocity));
|
||||
inline void setHandleAfterTouchPoly(void (*fptr)(byte channel, byte note, byte pressure));
|
||||
inline void setHandleControlChange(void (*fptr)(byte channel, byte number, byte value));
|
||||
inline void setHandleProgramChange(void (*fptr)(byte channel, byte number));
|
||||
inline void setHandleAfterTouchChannel(void (*fptr)(byte channel, byte pressure));
|
||||
inline void setHandlePitchBend(void (*fptr)(byte channel, int bend));
|
||||
inline void setHandleSystemExclusive(void (*fptr)(byte * array, unsigned size));
|
||||
inline void setHandleTimeCodeQuarterFrame(void (*fptr)(byte data));
|
||||
inline void setHandleSongPosition(void (*fptr)(unsigned beats));
|
||||
inline void setHandleSongSelect(void (*fptr)(byte songnumber));
|
||||
inline void setHandleTuneRequest(void (*fptr)(void));
|
||||
inline void setHandleClock(void (*fptr)(void));
|
||||
inline void setHandleStart(void (*fptr)(void));
|
||||
inline void setHandleContinue(void (*fptr)(void));
|
||||
inline void setHandleStop(void (*fptr)(void));
|
||||
inline void setHandleActiveSensing(void (*fptr)(void));
|
||||
inline void setHandleSystemReset(void (*fptr)(void));
|
||||
inline MidiInterface& setHandleMessage(void (*fptr)(const MidiMessage&)) { mMessageCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandleError(ErrorCallback fptr) { mErrorCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandleNoteOff(NoteOffCallback fptr) { mNoteOffCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandleNoteOn(NoteOnCallback fptr) { mNoteOnCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandleAfterTouchPoly(AfterTouchPolyCallback fptr) { mAfterTouchPolyCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandleControlChange(ControlChangeCallback fptr) { mControlChangeCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandleProgramChange(ProgramChangeCallback fptr) { mProgramChangeCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandleAfterTouchChannel(AfterTouchChannelCallback fptr) { mAfterTouchChannelCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandlePitchBend(PitchBendCallback fptr) { mPitchBendCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandleSystemExclusive(SystemExclusiveCallback fptr) { mSystemExclusiveCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandleTimeCodeQuarterFrame(TimeCodeQuarterFrameCallback fptr) { mTimeCodeQuarterFrameCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandleSongPosition(SongPositionCallback fptr) { mSongPositionCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandleSongSelect(SongSelectCallback fptr) { mSongSelectCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandleTuneRequest(TuneRequestCallback fptr) { mTuneRequestCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandleClock(ClockCallback fptr) { mClockCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandleStart(StartCallback fptr) { mStartCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandleTick(TickCallback fptr) { mTickCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandleContinue(ContinueCallback fptr) { mContinueCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandleStop(StopCallback fptr) { mStopCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandleActiveSensing(ActiveSensingCallback fptr) { mActiveSensingCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandleSystemReset(SystemResetCallback fptr) { mSystemResetCallback = fptr; return *this; };
|
||||
|
||||
inline void disconnectCallbackFromType(MidiType inType);
|
||||
inline MidiInterface& disconnectCallbackFromType(MidiType inType);
|
||||
|
||||
private:
|
||||
void launchCallback();
|
||||
|
||||
void (*mNoteOffCallback)(byte channel, byte note, byte velocity);
|
||||
void (*mNoteOnCallback)(byte channel, byte note, byte velocity);
|
||||
void (*mAfterTouchPolyCallback)(byte channel, byte note, byte velocity);
|
||||
void (*mControlChangeCallback)(byte channel, byte, byte);
|
||||
void (*mProgramChangeCallback)(byte channel, byte);
|
||||
void (*mAfterTouchChannelCallback)(byte channel, byte);
|
||||
void (*mPitchBendCallback)(byte channel, int);
|
||||
void (*mSystemExclusiveCallback)(byte * array, unsigned size);
|
||||
void (*mTimeCodeQuarterFrameCallback)(byte data);
|
||||
void (*mSongPositionCallback)(unsigned beats);
|
||||
void (*mSongSelectCallback)(byte songnumber);
|
||||
void (*mTuneRequestCallback)(void);
|
||||
void (*mClockCallback)(void);
|
||||
void (*mStartCallback)(void);
|
||||
void (*mContinueCallback)(void);
|
||||
void (*mStopCallback)(void);
|
||||
void (*mActiveSensingCallback)(void);
|
||||
void (*mSystemResetCallback)(void);
|
||||
void (*mMessageCallback)(const MidiMessage& message) = nullptr;
|
||||
ErrorCallback mErrorCallback = nullptr;
|
||||
NoteOffCallback mNoteOffCallback = nullptr;
|
||||
NoteOnCallback mNoteOnCallback = nullptr;
|
||||
AfterTouchPolyCallback mAfterTouchPolyCallback = nullptr;
|
||||
ControlChangeCallback mControlChangeCallback = nullptr;
|
||||
ProgramChangeCallback mProgramChangeCallback = nullptr;
|
||||
AfterTouchChannelCallback mAfterTouchChannelCallback = nullptr;
|
||||
PitchBendCallback mPitchBendCallback = nullptr;
|
||||
SystemExclusiveCallback mSystemExclusiveCallback = nullptr;
|
||||
TimeCodeQuarterFrameCallback mTimeCodeQuarterFrameCallback = nullptr;
|
||||
SongPositionCallback mSongPositionCallback = nullptr;
|
||||
SongSelectCallback mSongSelectCallback = nullptr;
|
||||
TuneRequestCallback mTuneRequestCallback = nullptr;
|
||||
ClockCallback mClockCallback = nullptr;
|
||||
StartCallback mStartCallback = nullptr;
|
||||
TickCallback mTickCallback = nullptr;
|
||||
ContinueCallback mContinueCallback = nullptr;
|
||||
StopCallback mStopCallback = nullptr;
|
||||
ActiveSensingCallback mActiveSensingCallback = nullptr;
|
||||
SystemResetCallback mSystemResetCallback = nullptr;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// MIDI Soft Thru
|
||||
|
|
@ -210,38 +239,52 @@ public:
|
|||
inline Thru::Mode getFilterMode() const;
|
||||
inline bool getThruState() const;
|
||||
|
||||
inline void turnThruOn(Thru::Mode inThruFilterMode = Thru::Full);
|
||||
inline void turnThruOff();
|
||||
inline void setThruFilterMode(Thru::Mode inThruFilterMode);
|
||||
inline MidiInterface& turnThruOn(Thru::Mode inThruFilterMode = Thru::Full);
|
||||
inline MidiInterface& turnThruOff();
|
||||
inline MidiInterface& setThruFilterMode(Thru::Mode inThruFilterMode);
|
||||
|
||||
private:
|
||||
void thruFilter(byte inChannel);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// MIDI Parsing
|
||||
|
||||
private:
|
||||
bool parse();
|
||||
inline void handleNullVelocityNoteOnAsNoteOff();
|
||||
inline bool inputFilter(Channel inChannel);
|
||||
inline void resetInput();
|
||||
inline void updateLastSentTime();
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Transport
|
||||
|
||||
public:
|
||||
Transport* getTransport() { return &mTransport; };
|
||||
|
||||
private:
|
||||
typedef Message<Settings::SysExMaxSize> MidiMessage;
|
||||
Transport& mTransport;
|
||||
|
||||
private:
|
||||
SerialPort& mSerial;
|
||||
// -------------------------------------------------------------------------
|
||||
// Internal variables
|
||||
|
||||
private:
|
||||
Channel mInputChannel;
|
||||
StatusByte mRunningStatus_RX;
|
||||
StatusByte mRunningStatus_TX;
|
||||
byte mPendingMessage[3];
|
||||
unsigned mPendingMessageExpectedLenght;
|
||||
unsigned mPendingMessageExpectedLength;
|
||||
unsigned mPendingMessageIndex;
|
||||
unsigned mCurrentRpnNumber;
|
||||
unsigned mCurrentNrpnNumber;
|
||||
bool mThruActivated : 1;
|
||||
Thru::Mode mThruFilterMode : 7;
|
||||
MidiMessage mMessage;
|
||||
|
||||
unsigned long mLastMessageSentTime;
|
||||
unsigned long mLastMessageReceivedTime;
|
||||
unsigned long mSenderActiveSensingPeriodicity;
|
||||
bool mReceiverActiveSensingActivated;
|
||||
int8_t mLastError;
|
||||
|
||||
private:
|
||||
inline StatusByte getStatus(MidiType inType,
|
||||
|
|
@ -250,8 +293,14 @@ private:
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
unsigned encodeSysEx(const byte* inData, byte* outSysEx, unsigned inLenght);
|
||||
unsigned decodeSysEx(const byte* inSysEx, byte* outData, unsigned inLenght);
|
||||
unsigned encodeSysEx(const byte* inData,
|
||||
byte* outSysEx,
|
||||
unsigned inLength,
|
||||
bool inFlipHeaderBits = false);
|
||||
unsigned decodeSysEx(const byte* inSysEx,
|
||||
byte* outData,
|
||||
unsigned inLength,
|
||||
bool inFlipHeaderBits = false);
|
||||
|
||||
END_MIDI_NAMESPACE
|
||||
|
||||
|
|
|
|||
903
src/MIDI.hpp
903
src/MIDI.hpp
File diff suppressed because it is too large
Load Diff
127
src/midi_Defs.h
127
src/midi_Defs.h
|
|
@ -2,7 +2,7 @@
|
|||
* @file midi_Defs.h
|
||||
* Project Arduino MIDI Library
|
||||
* @brief MIDI Library for the Arduino - Definitions
|
||||
* @author Francois Best
|
||||
* @author Francois Best, lathoub
|
||||
* @date 24/02/11
|
||||
* @license MIT - Copyright (c) 2015 Francois Best
|
||||
*
|
||||
|
|
@ -38,11 +38,6 @@ typedef uint8_t byte;
|
|||
|
||||
BEGIN_MIDI_NAMESPACE
|
||||
|
||||
#define MIDI_LIBRARY_VERSION 0x040300
|
||||
#define MIDI_LIBRARY_VERSION_MAJOR 4
|
||||
#define MIDI_LIBRARY_VERSION_MINOR 3
|
||||
#define MIDI_LIBRARY_VERSION_PATCH 0
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#define MIDI_CHANNEL_OMNI 0
|
||||
|
|
@ -51,6 +46,10 @@ BEGIN_MIDI_NAMESPACE
|
|||
#define MIDI_PITCHBEND_MIN -8192
|
||||
#define MIDI_PITCHBEND_MAX 8191
|
||||
|
||||
/*! Receiving Active Sensing
|
||||
*/
|
||||
static const uint16_t ActiveSensingTimeout = 300;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Type definitions
|
||||
|
||||
|
|
@ -59,28 +58,65 @@ typedef byte DataByte;
|
|||
typedef byte Channel;
|
||||
typedef byte FilterMode;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Errors
|
||||
static const uint8_t ErrorParse = 0;
|
||||
static const uint8_t ErrorActiveSensingTimeout = 1;
|
||||
static const uint8_t WarningSplitSysEx = 2;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Aliasing
|
||||
|
||||
using ErrorCallback = void (*)(int8_t);
|
||||
using NoteOffCallback = void (*)(Channel channel, byte note, byte velocity);
|
||||
using NoteOnCallback = void (*)(Channel channel, byte note, byte velocity);
|
||||
using AfterTouchPolyCallback = void (*)(Channel channel, byte note, byte velocity);
|
||||
using ControlChangeCallback = void (*)(Channel channel, byte, byte);
|
||||
using ProgramChangeCallback = void (*)(Channel channel, byte);
|
||||
using AfterTouchChannelCallback = void (*)(Channel channel, byte);
|
||||
using PitchBendCallback = void (*)(Channel channel, int);
|
||||
using SystemExclusiveCallback = void (*)(byte * array, unsigned size);
|
||||
using TimeCodeQuarterFrameCallback = void (*)(byte data);
|
||||
using SongPositionCallback = void (*)(unsigned beats);
|
||||
using SongSelectCallback = void (*)(byte songnumber);
|
||||
using TuneRequestCallback = void (*)(void);
|
||||
using ClockCallback = void (*)(void);
|
||||
using StartCallback = void (*)(void);
|
||||
using TickCallback = void (*)(void);
|
||||
using ContinueCallback = void (*)(void);
|
||||
using StopCallback = void (*)(void);
|
||||
using ActiveSensingCallback = void (*)(void);
|
||||
using SystemResetCallback = void (*)(void);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/*! Enumeration of MIDI types */
|
||||
enum MidiType
|
||||
enum MidiType: uint8_t
|
||||
{
|
||||
InvalidType = 0x00, ///< For notifying errors
|
||||
NoteOff = 0x80, ///< Note Off
|
||||
NoteOn = 0x90, ///< Note On
|
||||
AfterTouchPoly = 0xA0, ///< Polyphonic AfterTouch
|
||||
ControlChange = 0xB0, ///< Control Change / Channel Mode
|
||||
ProgramChange = 0xC0, ///< Program Change
|
||||
AfterTouchChannel = 0xD0, ///< Channel (monophonic) AfterTouch
|
||||
PitchBend = 0xE0, ///< Pitch Bend
|
||||
NoteOff = 0x80, ///< Channel Message - Note Off
|
||||
NoteOn = 0x90, ///< Channel Message - Note On
|
||||
AfterTouchPoly = 0xA0, ///< Channel Message - Polyphonic AfterTouch
|
||||
ControlChange = 0xB0, ///< Channel Message - Control Change / Channel Mode
|
||||
ProgramChange = 0xC0, ///< Channel Message - Program Change
|
||||
AfterTouchChannel = 0xD0, ///< Channel Message - Channel (monophonic) AfterTouch
|
||||
PitchBend = 0xE0, ///< Channel Message - Pitch Bend
|
||||
SystemExclusive = 0xF0, ///< System Exclusive
|
||||
SystemExclusiveStart = SystemExclusive, ///< System Exclusive Start
|
||||
TimeCodeQuarterFrame = 0xF1, ///< System Common - MIDI Time Code Quarter Frame
|
||||
SongPosition = 0xF2, ///< System Common - Song Position Pointer
|
||||
SongSelect = 0xF3, ///< System Common - Song Select
|
||||
Undefined_F4 = 0xF4,
|
||||
Undefined_F5 = 0xF5,
|
||||
TuneRequest = 0xF6, ///< System Common - Tune Request
|
||||
SystemExclusiveEnd = 0xF7, ///< System Exclusive End
|
||||
Clock = 0xF8, ///< System Real Time - Timing Clock
|
||||
Undefined_F9 = 0xF9,
|
||||
Tick = Undefined_F9, ///< System Real Time - Timing Tick (1 tick = 10 milliseconds)
|
||||
Start = 0xFA, ///< System Real Time - Start
|
||||
Continue = 0xFB, ///< System Real Time - Continue
|
||||
Stop = 0xFC, ///< System Real Time - Stop
|
||||
Undefined_FD = 0xFD,
|
||||
ActiveSensing = 0xFE, ///< System Real Time - Active Sensing
|
||||
SystemReset = 0xFF, ///< System Real Time - System Reset
|
||||
};
|
||||
|
|
@ -99,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.
|
||||
See the detailed controllers numbers & description here:
|
||||
http://www.somascape.org/midi/tech/spec.html#ctrlnums
|
||||
*/
|
||||
enum MidiControlChangeNumber
|
||||
enum MidiControlChangeNumber: uint8_t
|
||||
{
|
||||
// High resolution Continuous Controllers MSB (+32 for LSB) ----------------
|
||||
BankSelect = 0,
|
||||
|
|
@ -139,8 +164,22 @@ enum MidiControlChangeNumber
|
|||
GeneralPurposeController2 = 17,
|
||||
GeneralPurposeController3 = 18,
|
||||
GeneralPurposeController4 = 19,
|
||||
|
||||
// CC20 to CC31 undefined
|
||||
BankSelectLSB = 32,
|
||||
ModulationWheelLSB = 33,
|
||||
BreathControllerLSB = 34,
|
||||
// CC35 undefined
|
||||
FootControllerLSB = 36,
|
||||
PortamentoTimeLSB = 37,
|
||||
DataEntryLSB = 38,
|
||||
ChannelVolumeLSB = 39,
|
||||
BalanceLSB = 40,
|
||||
// CC41 undefined
|
||||
PanLSB = 42,
|
||||
ExpressionControllerLSB = 43,
|
||||
EffectControl1LSB = 44,
|
||||
EffectControl2LSB = 45,
|
||||
// CC46 to CC63 undefined
|
||||
|
||||
// Switches ----------------------------------------------------------------
|
||||
Sustain = 64,
|
||||
|
|
@ -178,6 +217,7 @@ enum MidiControlChangeNumber
|
|||
NRPNMSB = 99, ///< Non-Registered Parameter Number (MSB)
|
||||
RPNLSB = 100, ///< Registered Parameter Number (LSB)
|
||||
RPNMSB = 101, ///< Registered Parameter Number (MSB)
|
||||
// CC102 to CC119 undefined
|
||||
|
||||
// Channel Mode messages ---------------------------------------------------
|
||||
AllSoundOff = 120,
|
||||
|
|
@ -192,7 +232,7 @@ enum MidiControlChangeNumber
|
|||
|
||||
struct RPN
|
||||
{
|
||||
enum RegisteredParameterNumbers
|
||||
enum RegisteredParameterNumbers: uint16_t
|
||||
{
|
||||
PitchBendSensitivity = 0x0000,
|
||||
ChannelFineTuning = 0x0001,
|
||||
|
|
@ -204,35 +244,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(ARDUINO_SAM_DUE) || defined(USBCON)
|
||||
// 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
|
||||
|
||||
/*! \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
|
||||
|
|
|
|||
|
|
@ -29,6 +29,9 @@
|
|||
|
||||
#include "midi_Namespace.h"
|
||||
#include "midi_Defs.h"
|
||||
#ifndef ARDUINO
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
BEGIN_MIDI_NAMESPACE
|
||||
|
||||
|
|
@ -43,7 +46,7 @@ struct Message
|
|||
*/
|
||||
inline Message()
|
||||
: channel(0)
|
||||
, type(midi::InvalidType)
|
||||
, type(MIDI_NAMESPACE::InvalidType)
|
||||
, data1(0)
|
||||
, data2(0)
|
||||
, valid(false)
|
||||
|
|
@ -51,6 +54,20 @@ struct Message
|
|||
memset(sysexArray, 0, sSysExMaxSize * sizeof(DataByte));
|
||||
}
|
||||
|
||||
inline Message(const Message& inOther)
|
||||
: channel(inOther.channel)
|
||||
, type(inOther.type)
|
||||
, data1(inOther.data1)
|
||||
, data2(inOther.data2)
|
||||
, valid(inOther.valid)
|
||||
, length(inOther.length)
|
||||
{
|
||||
if (type == midi::SystemExclusive)
|
||||
{
|
||||
memcpy(sysexArray, inOther.sysexArray, sSysExMaxSize * sizeof(DataByte));
|
||||
}
|
||||
}
|
||||
|
||||
/*! The maximum size for the System Exclusive array.
|
||||
*/
|
||||
static const unsigned sSysExMaxSize = SysExMaxSize;
|
||||
|
|
@ -88,11 +105,27 @@ struct Message
|
|||
*/
|
||||
bool valid;
|
||||
|
||||
/*! Total Length of the message.
|
||||
*/
|
||||
unsigned length;
|
||||
|
||||
inline unsigned getSysExSize() const
|
||||
{
|
||||
const unsigned size = unsigned(data2) << 8 | data1;
|
||||
return size > sSysExMaxSize ? sSysExMaxSize : size;
|
||||
}
|
||||
inline bool isSystemRealTime () const
|
||||
{
|
||||
return (type & 0xf8) == 0xf8;
|
||||
}
|
||||
inline bool isSystemCommon () const
|
||||
{
|
||||
return (type & 0xf8) == 0xf0;
|
||||
}
|
||||
inline bool isChannelMessage () const
|
||||
{
|
||||
return (type & 0xf0) != 0xf0;
|
||||
}
|
||||
};
|
||||
|
||||
END_MIDI_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
/*!
|
||||
* @file midi_RingBuffer.h
|
||||
* @file midi_Platform.h
|
||||
* Project Arduino MIDI Library
|
||||
* @brief MIDI Library for Arduino - Ring Buffer
|
||||
* @author Francois Best
|
||||
* @date 10/10/2016
|
||||
* @license MIT - Copyright (c) 2016 Francois Best
|
||||
* @brief MIDI Library for the Arduino - Platform
|
||||
* @license MIT - Copyright (c) 2015 Francois Best
|
||||
* @author lathoub
|
||||
* @date 22/03/20
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
@ -27,36 +27,25 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "midi_Namespace.h"
|
||||
#include "midi_Defs.h"
|
||||
|
||||
BEGIN_MIDI_NAMESPACE
|
||||
|
||||
template<typename DataType, int Size>
|
||||
class RingBuffer
|
||||
#if ARDUINO
|
||||
|
||||
// DefaultPlatform is the Arduino Platform
|
||||
struct DefaultPlatform
|
||||
{
|
||||
public:
|
||||
RingBuffer();
|
||||
~RingBuffer();
|
||||
|
||||
public:
|
||||
int getLength() const;
|
||||
bool isEmpty() const;
|
||||
|
||||
public:
|
||||
void write(DataType inData);
|
||||
void write(const DataType* inData, int inSize);
|
||||
void clear();
|
||||
|
||||
public:
|
||||
DataType read();
|
||||
void read(DataType* outData, int inSize);
|
||||
|
||||
private:
|
||||
DataType mData[Size];
|
||||
DataType* mWriteHead;
|
||||
DataType* mReadHead;
|
||||
static unsigned long now() { return ::millis(); };
|
||||
};
|
||||
|
||||
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
|
||||
|
|
@ -38,18 +38,19 @@ BEGIN_MIDI_NAMESPACE
|
|||
macro to create your instance. The settings you don't override will keep their
|
||||
default value. Eg:
|
||||
\code{.cpp}
|
||||
struct MySettings : public midi::DefaultSettings
|
||||
struct MySettings : public MIDI_NAMESPACE::DefaultSettings
|
||||
{
|
||||
static const unsigned SysExMaxSize = 1024; // Accept SysEx messages up to 1024 bytes long.
|
||||
};
|
||||
|
||||
MIDI_CREATE_CUSTOM_INSTANCE(HardwareSerial, Serial2, midi, MySettings);
|
||||
MIDI_CREATE_CUSTOM_INSTANCE(HardwareSerial, Serial2, MIDI, MySettings);
|
||||
\endcode
|
||||
*/
|
||||
struct DefaultSettings
|
||||
{
|
||||
/*! Running status enables short messages when sending multiple values
|
||||
of the same type and channel.\n
|
||||
Must be disabled to send USB MIDI messages to a computer
|
||||
Warning: does not work with some hardware, enable with caution.
|
||||
*/
|
||||
static const bool UseRunningStatus = false;
|
||||
|
|
@ -66,16 +67,38 @@ struct DefaultSettings
|
|||
*/
|
||||
static const bool Use1ByteParsing = true;
|
||||
|
||||
/*! Override the default MIDI baudrate to transmit over USB serial, to
|
||||
a decoding program such as Hairless MIDI (set baudrate to 115200)\n
|
||||
http://projectgus.github.io/hairless-midiserial/
|
||||
*/
|
||||
static const long BaudRate = 31250;
|
||||
|
||||
/*! Maximum size of SysEx receivable. Decrease to save RAM if you don't expect
|
||||
to receive SysEx, or adjust accordingly.
|
||||
*/
|
||||
static const unsigned SysExMaxSize = 128;
|
||||
|
||||
/*! Global switch to turn on/off sender ActiveSensing
|
||||
Set to true to send ActiveSensing
|
||||
Set to false will not send ActiveSensing message (will also save memory)
|
||||
*/
|
||||
static const bool UseSenderActiveSensing = false;
|
||||
|
||||
/*! Global switch to turn on/off receiver ActiveSensing
|
||||
Set to true to check for message timeouts (via ErrorCallback)
|
||||
Set to false will not check if chained device are still alive (if they use ActiveSensing) (will also save memory)
|
||||
*/
|
||||
static const bool UseReceiverActiveSensing = false;
|
||||
|
||||
/*! Active Sensing is intended to be sent
|
||||
repeatedly by the sender to tell the receiver that a connection is alive. Use
|
||||
of this message is optional. When initially received, the
|
||||
receiver will expect to receive another Active Sensing
|
||||
message each 300ms (max), and if it does not then it will
|
||||
assume that the connection has been terminated. At
|
||||
termination, the receiver will turn off all voices and return to
|
||||
normal (non- active sensing) operation.
|
||||
|
||||
Typical value is 250 (ms) - an Active Sensing command is send every 250ms.
|
||||
(All Roland devices send Active Sensing every 250ms)
|
||||
|
||||
Setting this field to 0 will disable sending MIDI active sensing.
|
||||
*/
|
||||
static const uint16_t SenderActiveSensingPeriodicity = 0;
|
||||
};
|
||||
|
||||
END_MIDI_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -1,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,130 @@
|
|||
/*!
|
||||
* @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:
|
||||
static const bool thruActivated = true;
|
||||
|
||||
void begin()
|
||||
{
|
||||
// Initialise the Serial port
|
||||
#if defined(AVR_CAKE)
|
||||
mSerial. template open<Settings::BaudRate>();
|
||||
#else
|
||||
mSerial.begin(Settings::BaudRate);
|
||||
#endif
|
||||
}
|
||||
|
||||
void end()
|
||||
{
|
||||
mSerial.end();
|
||||
}
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
END_MIDI_NAMESPACE
|
||||
|
||||
/*! \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
|
||||
|
||||
/*! \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_NAMESPACE::SerialMIDI<Type> serial##Name(SerialPort);\
|
||||
MIDI_NAMESPACE::MidiInterface<MIDI_NAMESPACE::SerialMIDI<Type>, Settings> Name((MIDI_NAMESPACE::SerialMIDI<Type>&)serial##Name);
|
||||
|
|
@ -4,8 +4,11 @@ add_library(test-mocks STATIC
|
|||
test-mocks.cpp
|
||||
test-mocks.h
|
||||
test-mocks_Namespace.h
|
||||
test-mocks_Defs.h
|
||||
test-mocks_SerialMock.cpp
|
||||
test-mocks_SerialMock.hpp
|
||||
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
|
||||
|
||||
#include "test-mocks.h"
|
||||
#include "test-mocks_Defs.h"
|
||||
#include <inttypes.h>
|
||||
|
||||
BEGIN_TEST_MOCKS_NAMESPACE
|
||||
|
||||
|
|
@ -32,8 +32,6 @@ private:
|
|||
DataType* mReadHead;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
template<int BufferSize>
|
||||
class SerialMock
|
||||
{
|
||||
|
|
@ -44,14 +42,14 @@ public:
|
|||
public: // Arduino Serial API
|
||||
void begin(int inBaudrate);
|
||||
int available() const;
|
||||
void write(uint8 inData);
|
||||
uint8 read();
|
||||
void write(uint8_t inData);
|
||||
uint8_t read();
|
||||
|
||||
public: // Test Helpers API
|
||||
void moveTxToRx(); // Simulate loopback
|
||||
|
||||
public:
|
||||
typedef RingBuffer<uint8, BufferSize> Buffer;
|
||||
typedef RingBuffer<uint8_t, BufferSize> Buffer;
|
||||
Buffer mTxBuffer;
|
||||
Buffer mRxBuffer;
|
||||
int mBaudrate;
|
||||
|
|
|
|||
|
|
@ -126,13 +126,13 @@ int SerialMock<BufferSize>::available() const
|
|||
}
|
||||
|
||||
template<int BufferSize>
|
||||
void SerialMock<BufferSize>::write(uint8 inData)
|
||||
void SerialMock<BufferSize>::write(uint8_t inData)
|
||||
{
|
||||
mTxBuffer.write(inData);
|
||||
}
|
||||
|
||||
template<int BufferSize>
|
||||
uint8 SerialMock<BufferSize>::read()
|
||||
uint8_t SerialMock<BufferSize>::read()
|
||||
{
|
||||
return mRxBuffer.read();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,13 +3,12 @@ include(CMakeToolsHelpers OPTIONAL)
|
|||
project(unit-tests)
|
||||
|
||||
include_directories(
|
||||
${unit-tests_SOURCE_DIR}
|
||||
${gtest_SOURCE_DIR}/include
|
||||
${gmock_SOURCE_DIR}/include
|
||||
"${unit-tests_SOURCE_DIR}"
|
||||
"${gtest_SOURCE_DIR}/include"
|
||||
"${gmock_SOURCE_DIR}/include"
|
||||
)
|
||||
|
||||
add_executable(unit-tests
|
||||
|
||||
unit-tests.cpp
|
||||
unit-tests.h
|
||||
unit-tests_Namespace.h
|
||||
|
|
@ -18,12 +17,10 @@ add_executable(unit-tests
|
|||
tests/unit-tests_Settings.cpp
|
||||
tests/unit-tests_Settings.h
|
||||
tests/unit-tests_SysExCodec.cpp
|
||||
tests/unit-tests_SerialMock.cpp
|
||||
tests/unit-tests_MidiInput.cpp
|
||||
tests/unit-tests_MidiInputCallbacks.cpp
|
||||
tests/unit-tests_MidiOutput.cpp
|
||||
tests/unit-tests_MidiThru.cpp
|
||||
tests/unit-tests_MidiUsb.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(unit-tests
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@ BEGIN_UNNAMED_NAMESPACE
|
|||
using namespace testing;
|
||||
USING_NAMESPACE_UNIT_TESTS
|
||||
typedef test_mocks::SerialMock<32> SerialMock;
|
||||
typedef midi::MidiInterface<SerialMock> MidiInterface;
|
||||
typedef midi::SerialMIDI<SerialMock> Transport;
|
||||
typedef midi::MidiInterface<Transport> MidiInterface;
|
||||
|
||||
template<unsigned Size>
|
||||
struct VariableSysExSettings : midi::DefaultSettings
|
||||
|
|
@ -53,7 +54,6 @@ TEST(MidiInput, getTypeFromStatusByte)
|
|||
}
|
||||
EXPECT_EQ(MidiInterface::getTypeFromStatusByte(0xf4), midi::InvalidType);
|
||||
EXPECT_EQ(MidiInterface::getTypeFromStatusByte(0xf5), midi::InvalidType);
|
||||
EXPECT_EQ(MidiInterface::getTypeFromStatusByte(0xf9), midi::InvalidType);
|
||||
EXPECT_EQ(MidiInterface::getTypeFromStatusByte(0xfd), midi::InvalidType);
|
||||
}
|
||||
|
||||
|
|
@ -93,7 +93,8 @@ TEST(MidiInput, isChannelMessage)
|
|||
TEST(MidiInput, begin)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
// Default channel
|
||||
midi.begin();
|
||||
|
|
@ -109,7 +110,8 @@ TEST(MidiInput, begin)
|
|||
TEST(MidiInput, initInputChannel)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
EXPECT_EQ(midi.getInputChannel(), 0);
|
||||
midi.setInputChannel(12);
|
||||
|
|
@ -119,7 +121,9 @@ TEST(MidiInput, initInputChannel)
|
|||
TEST(MidiInput, initMessage)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
EXPECT_EQ(midi.getType(), midi::InvalidType);
|
||||
EXPECT_EQ(midi.getChannel(), 0);
|
||||
EXPECT_EQ(midi.getData1(), 0);
|
||||
|
|
@ -131,7 +135,9 @@ TEST(MidiInput, initMessage)
|
|||
TEST(MidiInput, channelFiltering)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
static const unsigned rxSize = 3;
|
||||
static const byte rxData[rxSize] = { 0x9b, 12, 34 };
|
||||
midi.begin(4); // Mistmatching channel
|
||||
|
|
@ -144,7 +150,9 @@ TEST(MidiInput, channelFiltering)
|
|||
TEST(MidiInput, noRxData)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
midi.begin();
|
||||
EXPECT_EQ(midi.read(), false);
|
||||
}
|
||||
|
|
@ -152,7 +160,9 @@ TEST(MidiInput, noRxData)
|
|||
TEST(MidiInput, inputDisabled)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
static const unsigned rxSize = 3;
|
||||
static const byte rxData[rxSize] = { 0x9b, 12, 34 };
|
||||
midi.begin(MIDI_CHANNEL_OFF); // Invalid channel
|
||||
|
|
@ -165,10 +175,12 @@ TEST(MidiInput, inputDisabled)
|
|||
TEST(MidiInput, multiByteParsing)
|
||||
{
|
||||
typedef VariableSettings<false, false> Settings;
|
||||
typedef midi::MidiInterface<SerialMock, Settings> MultiByteMidiInterface;
|
||||
typedef midi::MidiInterface<Transport, Settings> MultiByteMidiInterface;
|
||||
|
||||
SerialMock serial;
|
||||
MultiByteMidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MultiByteMidiInterface midi(transport);
|
||||
|
||||
static const unsigned rxSize = 3;
|
||||
static const byte rxData[rxSize] = { 0x9b, 12, 34 };
|
||||
midi.begin(12);
|
||||
|
|
@ -179,7 +191,9 @@ TEST(MidiInput, multiByteParsing)
|
|||
TEST(MidiInput, noteOn)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
static const unsigned rxSize = 10;
|
||||
static const byte rxData[rxSize] = {
|
||||
0x9b, 12, 34,
|
||||
|
|
@ -230,7 +244,9 @@ TEST(MidiInput, noteOn)
|
|||
TEST(MidiInput, noteOff)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
static const unsigned rxSize = 8;
|
||||
static const byte rxData[rxSize] = {
|
||||
0x8b, 12, 34,
|
||||
|
|
@ -272,7 +288,9 @@ TEST(MidiInput, noteOff)
|
|||
TEST(MidiInput, programChange)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
static const unsigned rxSize = 6;
|
||||
static const byte rxData[rxSize] = {
|
||||
0xc3, 12, 34,
|
||||
|
|
@ -316,7 +334,9 @@ TEST(MidiInput, programChange)
|
|||
TEST(MidiInput, controlChange)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
static const unsigned rxSize = 8;
|
||||
static const byte rxData[rxSize] = {
|
||||
0xbb, 12, 34,
|
||||
|
|
@ -358,7 +378,9 @@ TEST(MidiInput, controlChange)
|
|||
TEST(MidiInput, pitchBend)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
static const unsigned rxSize = 8;
|
||||
static const byte rxData[rxSize] = {
|
||||
0xeb, 12, 34,
|
||||
|
|
@ -400,7 +422,9 @@ TEST(MidiInput, pitchBend)
|
|||
TEST(MidiInput, afterTouchPoly)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
static const unsigned rxSize = 8;
|
||||
static const byte rxData[rxSize] = {
|
||||
0xab, 12, 34,
|
||||
|
|
@ -442,7 +466,9 @@ TEST(MidiInput, afterTouchPoly)
|
|||
TEST(MidiInput, afterTouchChannel)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
static const unsigned rxSize = 6;
|
||||
static const byte rxData[rxSize] = {
|
||||
0xd3, 12, 34,
|
||||
|
|
@ -487,10 +513,12 @@ TEST(MidiInput, sysExWithinBufferSize)
|
|||
{
|
||||
typedef VariableSysExSettings<1024> Settings;
|
||||
typedef test_mocks::SerialMock<2048> LargerSerialMock;
|
||||
typedef midi::MidiInterface<LargerSerialMock, Settings> LargerMidiInterface;
|
||||
typedef midi::SerialMIDI<LargerSerialMock> LargerTransport;
|
||||
typedef midi::MidiInterface<LargerTransport, Settings> LargerMidiInterface;
|
||||
|
||||
LargerSerialMock serial;
|
||||
LargerMidiInterface midi(serial);
|
||||
LargerTransport transport(serial);
|
||||
LargerMidiInterface midi(transport);
|
||||
|
||||
// Short Frame < 256
|
||||
{
|
||||
|
|
@ -553,10 +581,11 @@ TEST(MidiInput, sysExWithinBufferSize)
|
|||
TEST(MidiInput, sysExOverBufferSize)
|
||||
{
|
||||
typedef VariableSysExSettings<8> Settings;
|
||||
typedef midi::MidiInterface<SerialMock, Settings> SmallMidiInterface;
|
||||
typedef midi::MidiInterface<Transport, Settings> SmallMidiInterface;
|
||||
|
||||
SerialMock serial;
|
||||
SmallMidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
SmallMidiInterface midi(transport);
|
||||
|
||||
static const unsigned frameLength = 15;
|
||||
static const byte frame[frameLength] = {
|
||||
|
|
@ -566,17 +595,29 @@ TEST(MidiInput, sysExOverBufferSize)
|
|||
midi.begin();
|
||||
serial.mRxBuffer.write(frame, frameLength);
|
||||
|
||||
for (unsigned i = 0; i < frameLength - 1; ++i)
|
||||
{
|
||||
EXPECT_EQ(midi.read(), false);
|
||||
}
|
||||
EXPECT_EQ(midi.read(), false);
|
||||
EXPECT_EQ(midi.read(), false); // start sysex f0
|
||||
EXPECT_EQ(midi.read(), false); // H
|
||||
EXPECT_EQ(midi.read(), false); // e
|
||||
EXPECT_EQ(midi.read(), false); // l
|
||||
EXPECT_EQ(midi.read(), false); // l
|
||||
EXPECT_EQ(midi.read(), false); // o
|
||||
EXPECT_EQ(midi.read(), false); // , message send and buffer cleared.
|
||||
EXPECT_EQ(midi.read(), false); // start sysex
|
||||
EXPECT_EQ(midi.read(), false); // (space)
|
||||
EXPECT_EQ(midi.read(), false); // W
|
||||
EXPECT_EQ(midi.read(), false); // o
|
||||
EXPECT_EQ(midi.read(), false); // r
|
||||
EXPECT_EQ(midi.read(), false); // l
|
||||
EXPECT_EQ(midi.read(), false); // d
|
||||
EXPECT_EQ(midi.read(), true); // end sysex
|
||||
}
|
||||
|
||||
TEST(MidiInput, mtcQuarterFrame)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
static const unsigned rxSize = 4;
|
||||
static const byte rxData[rxSize] = {
|
||||
0xf1, 12,
|
||||
|
|
@ -606,7 +647,9 @@ TEST(MidiInput, mtcQuarterFrame)
|
|||
TEST(MidiInput, songPosition)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
static const unsigned rxSize = 6;
|
||||
static const byte rxData[rxSize] = {
|
||||
0xf2, 12, 34,
|
||||
|
|
@ -638,7 +681,9 @@ TEST(MidiInput, songPosition)
|
|||
TEST(MidiInput, songSelect)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
static const unsigned rxSize = 4;
|
||||
static const byte rxData[rxSize] = {
|
||||
0xf3, 12,
|
||||
|
|
@ -668,7 +713,9 @@ TEST(MidiInput, songSelect)
|
|||
TEST(MidiInput, tuneRequest)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
static const unsigned rxSize = 1;
|
||||
static const byte rxData[rxSize] = {
|
||||
0xf6
|
||||
|
|
@ -686,7 +733,9 @@ TEST(MidiInput, tuneRequest)
|
|||
TEST(MidiInput, realTime)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
static const unsigned rxSize = 8;
|
||||
static const byte rxData[rxSize] = {
|
||||
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
|
||||
|
|
@ -700,7 +749,11 @@ TEST(MidiInput, realTime)
|
|||
EXPECT_EQ(midi.getData1(), 0);
|
||||
EXPECT_EQ(midi.getData2(), 0);
|
||||
|
||||
EXPECT_EQ(midi.read(), false); // 0xf9 = undefined
|
||||
EXPECT_EQ(midi.read(), true);
|
||||
EXPECT_EQ(midi.getType(), midi::Tick);
|
||||
EXPECT_EQ(midi.getChannel(), 0);
|
||||
EXPECT_EQ(midi.getData1(), 0);
|
||||
EXPECT_EQ(midi.getData2(), 0);
|
||||
|
||||
EXPECT_EQ(midi.read(), true);
|
||||
EXPECT_EQ(midi.getType(), midi::Start);
|
||||
|
|
@ -740,7 +793,8 @@ TEST(MidiInput, realTime)
|
|||
TEST(MidiInput, interleavedRealTime)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
// Interleaved Clocks between NoteOn / Off messages (with running status)
|
||||
{
|
||||
|
|
@ -754,6 +808,7 @@ TEST(MidiInput, interleavedRealTime)
|
|||
};
|
||||
midi.begin(12);
|
||||
serial.mRxBuffer.write(rxData, rxSize);
|
||||
|
||||
EXPECT_EQ(midi.read(), false);
|
||||
EXPECT_EQ(midi.read(), false);
|
||||
|
||||
|
|
@ -816,6 +871,7 @@ TEST(MidiInput, interleavedRealTime)
|
|||
};
|
||||
midi.begin(12);
|
||||
serial.mRxBuffer.write(rxData, rxSize);
|
||||
|
||||
EXPECT_EQ(midi.read(), false);
|
||||
EXPECT_EQ(midi.read(), false);
|
||||
EXPECT_EQ(midi.read(), false);
|
||||
|
|
@ -841,13 +897,16 @@ TEST(MidiInput, strayEox)
|
|||
{
|
||||
// A stray End of Exclusive will reset the parser, but should it ?
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
static const unsigned rxSize = 4;
|
||||
static const byte rxData[rxSize] = {
|
||||
0x8b, 42, 0xf7, 12
|
||||
};
|
||||
midi.begin(MIDI_CHANNEL_OMNI);
|
||||
serial.mRxBuffer.write(rxData, rxSize);
|
||||
|
||||
EXPECT_EQ(midi.read(), false);
|
||||
EXPECT_EQ(midi.read(), false);
|
||||
EXPECT_EQ(midi.read(), false);
|
||||
|
|
@ -857,18 +916,20 @@ TEST(MidiInput, strayEox)
|
|||
TEST(MidiInput, strayUndefinedOneByteParsing)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
static const unsigned rxSize = 13;
|
||||
static const byte rxData[rxSize] = {
|
||||
0xbb, 12, 0xf9, 34,
|
||||
0xbb, 12, 0xfd, 34,
|
||||
12, 0,
|
||||
42, 0xfd, 127,
|
||||
0xf9,
|
||||
0xfd,
|
||||
42, 0xfd, 0
|
||||
};
|
||||
midi.begin(12);
|
||||
serial.mRxBuffer.write(rxData, rxSize);
|
||||
|
||||
EXPECT_EQ(midi.read(), false);
|
||||
EXPECT_EQ(midi.read(), false);
|
||||
EXPECT_EQ(midi.read(), false); // Invalid, should not reset parser
|
||||
|
|
@ -907,17 +968,19 @@ TEST(MidiInput, strayUndefinedOneByteParsing)
|
|||
TEST(MidiInput, strayUndefinedMultiByteParsing)
|
||||
{
|
||||
typedef VariableSettings<false, false> Settings;
|
||||
typedef midi::MidiInterface<SerialMock, Settings> MultiByteMidiInterface;
|
||||
typedef midi::MidiInterface<Transport, Settings> MultiByteMidiInterface;
|
||||
|
||||
SerialMock serial;
|
||||
MultiByteMidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MultiByteMidiInterface midi(transport);
|
||||
|
||||
static const unsigned rxSize = 4;
|
||||
static const byte rxData[rxSize] = {
|
||||
0xbb, 12, 0xf9, 34,
|
||||
0xbb, 12, 0xfd, 34,
|
||||
};
|
||||
midi.begin(12);
|
||||
serial.mRxBuffer.write(rxData, rxSize);
|
||||
|
||||
EXPECT_EQ(midi.read(), true);
|
||||
EXPECT_EQ(midi.getType(), midi::ControlChange);
|
||||
EXPECT_EQ(midi.getChannel(), 12);
|
||||
|
|
|
|||
|
|
@ -21,8 +21,10 @@ struct VariableSysExSettings : midi::DefaultSettings
|
|||
};
|
||||
|
||||
typedef test_mocks::SerialMock<256> SerialMock;
|
||||
typedef midi::SerialMIDI<SerialMock> Transport;
|
||||
|
||||
typedef VariableSysExSettings<256> Settings;
|
||||
typedef midi::MidiInterface<SerialMock, Settings> MidiInterface;
|
||||
typedef midi::MidiInterface<Transport, Settings> MidiInterface;
|
||||
|
||||
MidiInterface* midi;
|
||||
|
||||
|
|
@ -30,7 +32,8 @@ class MidiInputCallbacks : public Test
|
|||
{
|
||||
public:
|
||||
MidiInputCallbacks()
|
||||
: mMidi(mSerial)
|
||||
: mTransport(mSerial)
|
||||
, mMidi(mTransport)
|
||||
{
|
||||
}
|
||||
virtual ~MidiInputCallbacks()
|
||||
|
|
@ -50,6 +53,7 @@ protected:
|
|||
|
||||
protected:
|
||||
SerialMock mSerial;
|
||||
Transport mTransport;
|
||||
MidiInterface mMidi;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,8 @@ using namespace testing;
|
|||
USING_NAMESPACE_UNIT_TESTS;
|
||||
|
||||
typedef test_mocks::SerialMock<32> SerialMock;
|
||||
typedef midi::MidiInterface<SerialMock> MidiInterface;
|
||||
typedef midi::SerialMIDI<SerialMock> Transport;
|
||||
typedef midi::MidiInterface<Transport> MidiInterface;
|
||||
|
||||
typedef std::vector<uint8_t> Buffer;
|
||||
|
||||
|
|
@ -24,7 +25,8 @@ typedef std::vector<uint8_t> Buffer;
|
|||
TEST(MidiOutput, sendInvalid)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
midi.begin();
|
||||
midi.send(midi::NoteOn, 42, 42, 42); // Invalid channel > OFF
|
||||
|
|
@ -40,7 +42,9 @@ TEST(MidiOutput, sendInvalid)
|
|||
TEST(MidiOutput, sendGenericSingle)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
buffer.resize(3);
|
||||
|
||||
|
|
@ -54,10 +58,12 @@ TEST(MidiOutput, sendGenericSingle)
|
|||
TEST(MidiOutput, sendGenericWithRunningStatus)
|
||||
{
|
||||
typedef VariableSettings<true, false> Settings;
|
||||
typedef midi::MidiInterface<SerialMock, Settings> RsMidiInterface;
|
||||
typedef midi::MidiInterface<Transport, Settings> RsMidiInterface;
|
||||
|
||||
SerialMock serial;
|
||||
RsMidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
RsMidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
buffer.resize(5);
|
||||
|
||||
|
|
@ -74,10 +80,12 @@ TEST(MidiOutput, sendGenericWithRunningStatus)
|
|||
TEST(MidiOutput, sendGenericWithoutRunningStatus)
|
||||
{
|
||||
typedef VariableSettings<false, true> Settings; // No running status
|
||||
typedef midi::MidiInterface<SerialMock, Settings> NoRsMidiInterface;
|
||||
typedef midi::MidiInterface<Transport, Settings> NoRsMidiInterface;
|
||||
|
||||
SerialMock serial;
|
||||
NoRsMidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
NoRsMidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
buffer.resize(6);
|
||||
|
||||
|
|
@ -103,7 +111,9 @@ TEST(MidiOutput, sendGenericWithoutRunningStatus)
|
|||
TEST(MidiOutput, sendGenericBreakingRunningStatus)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
buffer.resize(6);
|
||||
|
||||
|
|
@ -118,7 +128,9 @@ TEST(MidiOutput, sendGenericBreakingRunningStatus)
|
|||
TEST(MidiOutput, sendGenericRealTimeShortcut)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
buffer.resize(6);
|
||||
|
||||
|
|
@ -140,7 +152,9 @@ TEST(MidiOutput, sendGenericRealTimeShortcut)
|
|||
TEST(MidiOutput, sendNoteOn)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
buffer.resize(6);
|
||||
|
||||
|
|
@ -155,7 +169,9 @@ TEST(MidiOutput, sendNoteOn)
|
|||
TEST(MidiOutput, sendNoteOff)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
buffer.resize(6);
|
||||
|
||||
|
|
@ -170,7 +186,9 @@ TEST(MidiOutput, sendNoteOff)
|
|||
TEST(MidiOutput, sendProgramChange)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
buffer.resize(4);
|
||||
|
||||
|
|
@ -185,7 +203,9 @@ TEST(MidiOutput, sendProgramChange)
|
|||
TEST(MidiOutput, sendControlChange)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
buffer.resize(6);
|
||||
|
||||
|
|
@ -200,7 +220,9 @@ TEST(MidiOutput, sendControlChange)
|
|||
TEST(MidiOutput, sendPitchBend)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
|
||||
// Int signature - arbitrary values
|
||||
|
|
@ -257,7 +279,9 @@ TEST(MidiOutput, sendPolyPressure)
|
|||
// This test is kept for coverage until removal of sendPolyPressure.
|
||||
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
buffer.resize(6);
|
||||
|
||||
|
|
@ -272,7 +296,9 @@ TEST(MidiOutput, sendPolyPressure)
|
|||
TEST(MidiOutput, sendAfterTouchMono)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
buffer.resize(4);
|
||||
|
||||
|
|
@ -287,7 +313,9 @@ TEST(MidiOutput, sendAfterTouchMono)
|
|||
TEST(MidiOutput, sendAfterTouchPoly)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
buffer.resize(6);
|
||||
|
||||
|
|
@ -302,10 +330,13 @@ TEST(MidiOutput, sendAfterTouchPoly)
|
|||
TEST(MidiOutput, sendSysEx)
|
||||
{
|
||||
typedef test_mocks::SerialMock<1024> LargeSerialMock;
|
||||
typedef midi::MidiInterface<LargeSerialMock> LargeMidiInterface;
|
||||
typedef midi::SerialMIDI<LargeSerialMock> LargeTransport;
|
||||
typedef midi::MidiInterface<LargeTransport> LargeMidiInterface;
|
||||
|
||||
LargeSerialMock serial;
|
||||
LargeMidiInterface midi(serial);
|
||||
LargeTransport transport(serial);
|
||||
LargeMidiInterface midi((LargeTransport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
|
||||
// Short frame
|
||||
|
|
@ -384,7 +415,9 @@ TEST(MidiOutput, sendSysEx)
|
|||
TEST(MidiOutput, sendTimeCodeQuarterFrame)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
|
||||
// Separate Nibbles
|
||||
|
|
@ -418,7 +451,9 @@ TEST(MidiOutput, sendTimeCodeQuarterFrame)
|
|||
TEST(MidiOutput, sendSongPosition)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
buffer.resize(6);
|
||||
|
||||
|
|
@ -434,7 +469,9 @@ TEST(MidiOutput, sendSongPosition)
|
|||
TEST(MidiOutput, sendSongSelect)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
buffer.resize(4);
|
||||
|
||||
|
|
@ -449,7 +486,9 @@ TEST(MidiOutput, sendSongSelect)
|
|||
TEST(MidiOutput, sendTuneRequest)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
buffer.resize(1);
|
||||
|
||||
|
|
@ -463,7 +502,9 @@ TEST(MidiOutput, sendTuneRequest)
|
|||
TEST(MidiOutput, sendRealTime)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
|
||||
// Test valid RealTime messages
|
||||
|
|
@ -509,10 +550,12 @@ TEST(MidiOutput, sendRealTime)
|
|||
TEST(MidiOutput, RPN)
|
||||
{
|
||||
typedef VariableSettings<true, true> Settings;
|
||||
typedef midi::MidiInterface<SerialMock, Settings> RsMidiInterface;
|
||||
typedef midi::MidiInterface<Transport, Settings> RsMidiInterface;
|
||||
|
||||
SerialMock serial;
|
||||
RsMidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
RsMidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
|
||||
// 14-bit Value Single Frame
|
||||
|
|
@ -625,10 +668,12 @@ TEST(MidiOutput, RPN)
|
|||
TEST(MidiOutput, NRPN)
|
||||
{
|
||||
typedef VariableSettings<true, true> Settings;
|
||||
typedef midi::MidiInterface<SerialMock, Settings> RsMidiInterface;
|
||||
typedef midi::MidiInterface<Transport, Settings> RsMidiInterface;
|
||||
|
||||
SerialMock serial;
|
||||
RsMidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
RsMidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
|
||||
// 14-bit Value Single Frame
|
||||
|
|
@ -741,10 +786,12 @@ TEST(MidiOutput, NRPN)
|
|||
TEST(MidiOutput, runningStatusCancellation)
|
||||
{
|
||||
typedef VariableSettings<true, false> Settings;
|
||||
typedef midi::MidiInterface<SerialMock, Settings> RsMidiInterface;
|
||||
typedef midi::MidiInterface<Transport, Settings> RsMidiInterface;
|
||||
|
||||
SerialMock serial;
|
||||
RsMidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
RsMidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
|
||||
static const unsigned sysExLength = 13;
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@ BEGIN_UNNAMED_NAMESPACE
|
|||
using namespace testing;
|
||||
USING_NAMESPACE_UNIT_TESTS
|
||||
typedef test_mocks::SerialMock<32> SerialMock;
|
||||
typedef midi::MidiInterface<SerialMock> MidiInterface;
|
||||
typedef midi::SerialMIDI<SerialMock> Transport;
|
||||
typedef midi::MidiInterface<Transport> MidiInterface;
|
||||
typedef std::vector<byte> Buffer;
|
||||
|
||||
template<unsigned Size>
|
||||
|
|
@ -28,7 +29,8 @@ struct VariableSysExSettings : midi::DefaultSettings
|
|||
TEST(MidiThru, defaultValues)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
EXPECT_EQ(midi.getThruState(), true);
|
||||
EXPECT_EQ(midi.getFilterMode(), midi::Thru::Full);
|
||||
|
|
@ -40,7 +42,8 @@ TEST(MidiThru, defaultValues)
|
|||
TEST(MidiThru, beginEnablesThru)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
midi.turnThruOff();
|
||||
EXPECT_EQ(midi.getThruState(), false);
|
||||
|
|
@ -53,7 +56,8 @@ TEST(MidiThru, beginEnablesThru)
|
|||
TEST(MidiThru, setGet)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
midi.turnThruOff();
|
||||
EXPECT_EQ(midi.getThruState(), false);
|
||||
|
|
@ -86,7 +90,8 @@ TEST(MidiThru, setGet)
|
|||
TEST(MidiThru, off)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
midi.begin(MIDI_CHANNEL_OMNI);
|
||||
midi.turnThruOff();
|
||||
|
|
@ -106,7 +111,9 @@ TEST(MidiThru, off)
|
|||
TEST(MidiThru, full)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
|
||||
midi.begin(MIDI_CHANNEL_OMNI);
|
||||
|
|
@ -148,7 +155,9 @@ TEST(MidiThru, full)
|
|||
TEST(MidiThru, sameChannel)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
|
||||
midi.begin(12);
|
||||
|
|
@ -177,7 +186,9 @@ TEST(MidiThru, sameChannel)
|
|||
TEST(MidiThru, sameChannelOmni) // Acts like full
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
|
||||
midi.begin(MIDI_CHANNEL_OMNI);
|
||||
|
|
@ -219,7 +230,9 @@ TEST(MidiThru, sameChannelOmni) // Acts like full
|
|||
TEST(MidiThru, differentChannel)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
|
||||
midi.begin(12);
|
||||
|
|
@ -248,7 +261,9 @@ TEST(MidiThru, differentChannel)
|
|||
TEST(MidiThru, differentChannelOmni) // Acts like off
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
|
||||
midi.begin(MIDI_CHANNEL_OMNI);
|
||||
|
|
@ -276,10 +291,12 @@ TEST(MidiThru, differentChannelOmni) // Acts like off
|
|||
TEST(MidiThru, multiByteThru)
|
||||
{
|
||||
typedef VariableSettings<false, false> MultiByteParsing;
|
||||
typedef midi::MidiInterface<SerialMock, MultiByteParsing> MultiByteMidiInterface;
|
||||
typedef midi::MidiInterface<Transport, MultiByteParsing> MultiByteMidiInterface;
|
||||
|
||||
SerialMock serial;
|
||||
MultiByteMidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MultiByteMidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
|
||||
midi.begin(MIDI_CHANNEL_OMNI);
|
||||
|
|
@ -305,10 +322,12 @@ TEST(MidiThru, multiByteThru)
|
|||
TEST(MidiThru, withTxRunningStatus)
|
||||
{
|
||||
typedef VariableSettings<true, true> Settings;
|
||||
typedef midi::MidiInterface<SerialMock, Settings> RsMidiInterface;
|
||||
typedef midi::MidiInterface<Transport, Settings> RsMidiInterface;
|
||||
|
||||
SerialMock serial;
|
||||
RsMidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
RsMidiInterface midi((Transport&)transport);
|
||||
|
||||
Buffer buffer;
|
||||
|
||||
midi.begin(MIDI_CHANNEL_OMNI);
|
||||
|
|
@ -348,7 +367,8 @@ TEST(MidiThru, withTxRunningStatus)
|
|||
TEST(MidiThru, invalidMode)
|
||||
{
|
||||
SerialMock serial;
|
||||
MidiInterface midi(serial);
|
||||
Transport transport(serial);
|
||||
MidiInterface midi((Transport&)transport);
|
||||
|
||||
midi.begin(MIDI_CHANNEL_OMNI);
|
||||
midi.setThruFilterMode(midi::Thru::Mode(42));
|
||||
|
|
|
|||
|
|
@ -1,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::HandleNullVelocityNoteOnAsNoteOff;
|
||||
const bool DefaultSettings::Use1ByteParsing;
|
||||
const long DefaultSettings::BaudRate;
|
||||
const unsigned DefaultSettings::SysExMaxSize;
|
||||
|
||||
END_MIDI_NAMESPACE
|
||||
|
|
@ -19,7 +18,6 @@ TEST(Settings, hasTheRightDefaultValues)
|
|||
EXPECT_EQ(midi::DefaultSettings::UseRunningStatus, false);
|
||||
EXPECT_EQ(midi::DefaultSettings::HandleNullVelocityNoteOnAsNoteOff, true);
|
||||
EXPECT_EQ(midi::DefaultSettings::Use1ByteParsing, true);
|
||||
EXPECT_EQ(midi::DefaultSettings::BaudRate, 31250);
|
||||
EXPECT_EQ(midi::DefaultSettings::SysExMaxSize, unsigned(128));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,115 +11,171 @@ BEGIN_UNNAMED_NAMESPACE
|
|||
|
||||
using namespace testing;
|
||||
|
||||
TEST(SysExCodec, Encoder)
|
||||
TEST(SysExCodec, EncoderAscii)
|
||||
{
|
||||
// ASCII content
|
||||
{
|
||||
const byte input[] = "Hello, World!";
|
||||
byte buffer[16];
|
||||
memset(buffer, 0, 16 * sizeof(byte));
|
||||
const unsigned encodedSize = midi::encodeSysEx(input, buffer, 13);
|
||||
EXPECT_EQ(encodedSize, unsigned(15));
|
||||
const byte expected[16] = {
|
||||
0, 'H', 'e', 'l', 'l', 'o', ',', ' ',
|
||||
0, 'W', 'o', 'r', 'l', 'd', '!', 0,
|
||||
};
|
||||
EXPECT_THAT(buffer, Each(Le(0x7f))); // All elements are <= 127
|
||||
EXPECT_THAT(buffer, ContainerEq(expected));
|
||||
}
|
||||
// Non-ASCII content
|
||||
{
|
||||
const byte input[] = {
|
||||
182, 236, 167, 177, 61, 91, 120, // 01111000 -> 120
|
||||
107, 94, 209, 87, 94 // 000100xx -> 16
|
||||
};
|
||||
byte buffer[16];
|
||||
memset(buffer, 0, 16 * sizeof(byte));
|
||||
const unsigned encodedSize = midi::encodeSysEx(input, buffer, 12);
|
||||
EXPECT_EQ(encodedSize, unsigned(14));
|
||||
const byte expected[16] = {
|
||||
// MSB Data
|
||||
120, 54, 108, 39, 49, 61, 91, 120,
|
||||
16, 107, 94, 81, 87, 94, 0, 0,
|
||||
};
|
||||
EXPECT_THAT(buffer, Each(Le(0x7f))); // All elements are <= 127
|
||||
EXPECT_THAT(buffer, ContainerEq(expected));
|
||||
}
|
||||
const byte input[] = "Hello, World!";
|
||||
byte buffer[16];
|
||||
memset(buffer, 0, 16 * sizeof(byte));
|
||||
const unsigned encodedSize = midi::encodeSysEx(input, buffer, 13);
|
||||
EXPECT_EQ(encodedSize, unsigned(15));
|
||||
const byte expected[16] = {
|
||||
0, 'H', 'e', 'l', 'l', 'o', ',', ' ',
|
||||
0, 'W', 'o', 'r', 'l', 'd', '!', 0,
|
||||
};
|
||||
EXPECT_THAT(buffer, Each(Le(0x7f))); // All elements are <= 127
|
||||
EXPECT_THAT(buffer, ContainerEq(expected));
|
||||
}
|
||||
|
||||
TEST(SysExCodec, Decoder)
|
||||
TEST(SysExCodec, EncoderNonAscii)
|
||||
{
|
||||
// ASCII content
|
||||
{
|
||||
const byte input[] = {
|
||||
0, 'H', 'e', 'l', 'l', 'o', ',', ' ',
|
||||
0, 'W', 'o', 'r', 'l', 'd', '!',
|
||||
};
|
||||
byte buffer[16];
|
||||
memset(buffer, 0, 16 * sizeof(byte));
|
||||
const unsigned decodedSize = midi::decodeSysEx(input, buffer, 15);
|
||||
EXPECT_EQ(decodedSize, unsigned(13));
|
||||
const byte expected[16] = {
|
||||
'H', 'e', 'l', 'l', 'o', ',', ' ', 'W',
|
||||
'o', 'r', 'l', 'd', '!', 0, 0, 0,
|
||||
};
|
||||
EXPECT_THAT(buffer, Each(Le(0x7f))); // All elements are <= 127
|
||||
EXPECT_THAT(buffer, ContainerEq(expected));
|
||||
}
|
||||
// Non-ASCII content
|
||||
{
|
||||
const byte input[] = {
|
||||
// MSB Data
|
||||
120, 54, 108, 39, 49, 61, 91, 120,
|
||||
16, 107, 94, 81, 87, 94,
|
||||
};
|
||||
byte buffer[16];
|
||||
memset(buffer, 0, 16 * sizeof(byte));
|
||||
const unsigned encodedSize = midi::decodeSysEx(input, buffer, 14);
|
||||
EXPECT_EQ(encodedSize, unsigned(12));
|
||||
const byte expected[16] = {
|
||||
182, 236, 167, 177, 61, 91, 120,
|
||||
107, 94, 209, 87, 94, 0, 0,
|
||||
0, 0,
|
||||
};
|
||||
EXPECT_THAT(input, Each(Le(0x7f))); // All elements are <= 127
|
||||
EXPECT_THAT(buffer, ContainerEq(expected));
|
||||
}
|
||||
const byte input[] = {
|
||||
182, 236, 167, 177, 61, 91, 120, // 01111000 -> 120
|
||||
107, 94, 209, 87, 94 // 000100xx -> 16
|
||||
};
|
||||
byte buffer[16];
|
||||
memset(buffer, 0, 16 * sizeof(byte));
|
||||
const unsigned encodedSize = midi::encodeSysEx(input, buffer, 12);
|
||||
EXPECT_EQ(encodedSize, unsigned(14));
|
||||
const byte expected[16] = {
|
||||
// MSB Data
|
||||
120, 54, 108, 39, 49, 61, 91, 120,
|
||||
16, 107, 94, 81, 87, 94, 0, 0,
|
||||
};
|
||||
EXPECT_THAT(buffer, Each(Le(0x7f))); // All elements are <= 127
|
||||
EXPECT_THAT(buffer, ContainerEq(expected));
|
||||
}
|
||||
|
||||
TEST(SysExCodec, Codec)
|
||||
TEST(SysExCodec, EncoderNonAsciiFlipHeader)
|
||||
{
|
||||
// ASCII content
|
||||
{
|
||||
const byte input[] = "Hello, World!";
|
||||
byte buffer1[16];
|
||||
byte buffer2[16];
|
||||
memset(buffer1, 0, 16 * sizeof(byte));
|
||||
memset(buffer2, 0, 16 * sizeof(byte));
|
||||
const unsigned encodedSize = midi::encodeSysEx(input, buffer1, 13);
|
||||
EXPECT_EQ(encodedSize, unsigned(15));
|
||||
const unsigned decodedSize = midi::decodeSysEx(buffer1, buffer2, encodedSize);
|
||||
EXPECT_EQ(decodedSize, unsigned(13));
|
||||
EXPECT_STREQ(reinterpret_cast<const char*>(buffer2),
|
||||
reinterpret_cast<const char*>(input));
|
||||
}
|
||||
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, DecoderAscii)
|
||||
{
|
||||
const byte input[] = {
|
||||
0, 'H', 'e', 'l', 'l', 'o', ',', ' ',
|
||||
0, 'W', 'o', 'r', 'l', 'd', '!',
|
||||
};
|
||||
byte buffer[16];
|
||||
memset(buffer, 0, 16 * sizeof(byte));
|
||||
const unsigned decodedSize = midi::decodeSysEx(input, buffer, 15);
|
||||
EXPECT_EQ(decodedSize, unsigned(13));
|
||||
const byte expected[16] = {
|
||||
'H', 'e', 'l', 'l', 'o', ',', ' ', 'W',
|
||||
'o', 'r', 'l', 'd', '!', 0, 0, 0,
|
||||
};
|
||||
EXPECT_THAT(buffer, Each(Le(0x7f))); // All elements are <= 127
|
||||
EXPECT_THAT(buffer, ContainerEq(expected));
|
||||
}
|
||||
|
||||
// Non-ASCII content
|
||||
{
|
||||
const byte input[] = {
|
||||
// MSB Data
|
||||
182, 236, 167, 177, 61, 91, 120,
|
||||
107, 94, 209, 87, 94
|
||||
};
|
||||
byte buffer1[14];
|
||||
byte buffer2[12];
|
||||
memset(buffer1, 0, 14 * sizeof(byte));
|
||||
memset(buffer2, 0, 12 * sizeof(byte));
|
||||
const unsigned encodedSize = midi::encodeSysEx(input, buffer1, 12);
|
||||
EXPECT_EQ(encodedSize, unsigned(14));
|
||||
const unsigned decodedSize = midi::decodeSysEx(buffer1, buffer2, encodedSize);
|
||||
EXPECT_EQ(decodedSize, unsigned(12));
|
||||
EXPECT_THAT(buffer2, ContainerEq(input));
|
||||
}
|
||||
TEST(SysExCodec, DecoderNonAscii)
|
||||
{
|
||||
const byte input[] = {
|
||||
// MSB Data
|
||||
120, 54, 108, 39, 49, 61, 91, 120,
|
||||
16, 107, 94, 81, 87, 94,
|
||||
};
|
||||
byte buffer[16];
|
||||
memset(buffer, 0, 16 * sizeof(byte));
|
||||
const unsigned encodedSize = midi::decodeSysEx(input, buffer, 14);
|
||||
EXPECT_EQ(encodedSize, unsigned(12));
|
||||
const byte expected[16] = {
|
||||
182, 236, 167, 177, 61, 91, 120,
|
||||
107, 94, 209, 87, 94, 0, 0,
|
||||
0, 0,
|
||||
};
|
||||
EXPECT_THAT(input, Each(Le(0x7f))); // All elements are <= 127
|
||||
EXPECT_THAT(buffer, ContainerEq(expected));
|
||||
}
|
||||
|
||||
TEST(SysExCodec, DecoderNonAsciiFlipHeader)
|
||||
{
|
||||
const byte input[] = {
|
||||
// MSB Data
|
||||
15, 54, 108, 39, 49, 61, 91, 120,
|
||||
4, 107, 94, 81, 87, 94,
|
||||
};
|
||||
byte buffer[16];
|
||||
memset(buffer, 0, 16 * sizeof(byte));
|
||||
const unsigned encodedSize = midi::decodeSysEx(input, buffer, 14, true);
|
||||
EXPECT_EQ(encodedSize, unsigned(12));
|
||||
const byte expected[16] = {
|
||||
182, 236, 167, 177, 61, 91, 120,
|
||||
107, 94, 209, 87, 94, 0, 0,
|
||||
0, 0,
|
||||
};
|
||||
EXPECT_THAT(input, Each(Le(0x7f))); // All elements are <= 127
|
||||
EXPECT_THAT(buffer, ContainerEq(expected));
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
TEST(SysExCodec, CodecAscii)
|
||||
{
|
||||
const byte input[] = "Hello, World!";
|
||||
byte buffer1[16];
|
||||
byte buffer2[16];
|
||||
memset(buffer1, 0, 16 * sizeof(byte));
|
||||
memset(buffer2, 0, 16 * sizeof(byte));
|
||||
const unsigned encodedSize = midi::encodeSysEx(input, buffer1, 13);
|
||||
EXPECT_EQ(encodedSize, unsigned(15));
|
||||
const unsigned decodedSize = midi::decodeSysEx(buffer1, buffer2, encodedSize);
|
||||
EXPECT_EQ(decodedSize, unsigned(13));
|
||||
EXPECT_STREQ(reinterpret_cast<const char*>(buffer2),
|
||||
reinterpret_cast<const char*>(input));
|
||||
}
|
||||
|
||||
TEST(SysExCodec, CodecNonAscii)
|
||||
{
|
||||
const byte input[] = {
|
||||
// MSB Data
|
||||
182, 236, 167, 177, 61, 91, 120,
|
||||
107, 94, 209, 87, 94
|
||||
};
|
||||
byte buffer1[14];
|
||||
byte buffer2[12];
|
||||
memset(buffer1, 0, 14 * sizeof(byte));
|
||||
memset(buffer2, 0, 12 * sizeof(byte));
|
||||
const unsigned encodedSize = midi::encodeSysEx(input, buffer1, 12);
|
||||
EXPECT_EQ(encodedSize, unsigned(14));
|
||||
const unsigned decodedSize = midi::decodeSysEx(buffer1, buffer2, encodedSize);
|
||||
EXPECT_EQ(decodedSize, unsigned(12));
|
||||
EXPECT_THAT(buffer2, ContainerEq(input));
|
||||
}
|
||||
|
||||
TEST(SysExCodec, CodecNonAsciiFlipHeader)
|
||||
{
|
||||
const byte input[] = {
|
||||
// MSB Data
|
||||
182, 236, 167, 177, 61, 91, 120,
|
||||
107, 94, 209, 87, 94
|
||||
};
|
||||
byte buffer1[14];
|
||||
byte buffer2[12];
|
||||
memset(buffer1, 0, 14 * sizeof(byte));
|
||||
memset(buffer2, 0, 12 * sizeof(byte));
|
||||
const unsigned encodedSize = midi::encodeSysEx(input, buffer1, 12, true);
|
||||
EXPECT_EQ(encodedSize, unsigned(14));
|
||||
const unsigned decodedSize = midi::decodeSysEx(buffer1, buffer2, encodedSize, true);
|
||||
EXPECT_EQ(decodedSize, unsigned(12));
|
||||
EXPECT_THAT(buffer2, ContainerEq(input));
|
||||
}
|
||||
|
||||
END_UNNAMED_NAMESPACE
|
||||
|
|
|
|||
Loading…
Reference in New Issue