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