Compare commits

...

137 Commits
4.3 ... master

Author SHA1 Message Date
lathoub 2d64cc3c2f
Update CustomBaudRate.ino
override DefaultSerialSettings to override BaudRate (and not DefaultSettings )
2022-01-11 08:00:48 +01:00
lathoub 7c0d716641
added CustomBaudRate example (#262)
* added CustomBaudRate example

- added customer baudrate example
- fixed old refs to examples in Doxygen

* fixed compile error for boards that have no Serial
2022-01-11 07:24:58 +01:00
François Best 8f8c7cfcc6
doc: Add @muxa to the contributors list 2021-11-30 09:22:26 +01:00
Mikhail Diatchenko 8e9805fc92
feat: Added missing MidiControlChangeNumber definitions (#260)
* Added missing MidiControlChangeNumber definitions
* Fixed duplicate enum
* Added keywords for new definitions
2021-11-29 10:54:16 +01:00
François Best 1944aca891
chore: Add @paul-emile-element as contributor 2021-11-03 15:06:11 +01:00
Paul 663b24b0b5
fix: Updated send(midiMessage&) to better handle system real time (#250)
* updated send(midiMessage&) to better handle system real time,
sysex and other system common messages

* use fully qualified function names as requested

Co-authored-by: Element <paul-emile.element@windriver.com>
2021-11-03 15:04:52 +01:00
lathoub be557c1f4b Update MIDI.h
added return value (missed by PR)
2021-10-10 17:04:46 +02:00
lathoub 50e33c8b4a
Merge pull request #247 from FortySevenEffects/chaining
chaining for all commands, callbacks and setters
2021-10-10 16:47:07 +02:00
lathoub 417beca1c7 Update platformio.yml
added Chaining example
2021-10-10 15:48:29 +02:00
lathoub c9d3b9b592 no chaining for private functions, added example 2021-10-10 15:33:28 +02:00
François Best c7922927e5
chore: Fix PlatformIO checks
See platformio/platformio-core#4078
2021-10-10 14:01:47 +02:00
lathoub 892f65a9ee Update MIDI.hpp 2021-10-10 12:16:15 +02:00
lathoub e1035a03f7 Update MIDI.hpp
fixed errors (return -> return *this where needed)
2021-10-10 12:13:30 +02:00
lathoub 2012e2a84a chaining for all commands, callbacks and setters 2021-10-10 12:04:08 +02:00
Francois Best b4daa697a9 doc: Update badges with CI status 2021-08-10 16:26:57 +02:00
Francois Best d9873560ad chore: Improve coverage blind spots 2021-08-10 16:21:18 +02:00
François Best bf80e99d54
chore: Move CI to GitHub Actions
- Build and run unit tests with CMake
- Track code coverage with Coveralls
- Build examples on officially supported boards
- Removed TravisCI configuration

Closes #233.
2021-08-10 16:12:51 +02:00
François Best 2f03d9b29d
chore: Checkout submodules in CI 2021-08-09 22:06:09 +02:00
François Best d2f11d02e2
chore: Add CMake CI 2021-08-09 22:03:59 +02:00
Francois Best 9f5317f299 chore: Config 2021-08-06 09:35:54 +02:00
Francois Best f356c99ca2 chore: Allow copying Messages
This is ground work for the `map` Thru function
in PR #232.
2021-08-06 09:35:54 +02:00
Francois Best 7ca289d84e chore: Fix internal method casing 2021-08-06 09:35:54 +02:00
François Best 0d605dc8a7
doc: Update contributors
Added @kant for PR #230
2021-08-01 20:02:40 +02:00
Darío Hereñú 3f0a2d3fdb Minor fix (line 65) 2021-08-01 20:00:28 +02:00
lathoub d501f4bb3d end method for Serial Transport
The Transport layer is started, but could never be stopped.
This change will allow the underlying library to call the end() method in the Transport layers (all other Transport layer have the end() method implemented)

Next step is to call the Transport end() method, when ending the MIDI instance
2021-06-08 20:36:38 +02:00
François Best d9149d19df
chore: Better description for Discussions 2020-12-09 14:04:49 +01:00
François Best a93fb27a1c
chore: Add link to Discussions in issue templates 2020-12-09 11:39:42 +01:00
François Best d967c0c389
chore: Disable generic issues
General community-related Q&A is moved to Discussions
2020-12-09 11:34:22 +01:00
François Best d3c361033d
chore: Suggest using Discussions first 2020-12-09 11:28:26 +01:00
François Best 33b294624a chore: Add Feature Request template
Also redirect issues to discussions for project help.
2020-12-09 11:26:09 +01:00
François Best 10ef10bfde feat: Add issue template for bug report 2020-12-09 11:20:27 +01:00
Felix Uhl da8ca5e69a Update search term for library manager 2020-09-16 16:39:29 +02:00
Felix Uhl e292cf61b0 Update library manager screenshot 2020-09-16 16:39:29 +02:00
stfufane 150cecd450 Fix sendPitchBend multiplication 2020-06-08 11:39:16 +02:00
lathoub ff3052ceb4 fix bug in MIDI_CREATE_CUSTOM_INSTANCE
- MIDI Setting in MIDI_CREATE_CUSTOM_INSTANCE, but Setting for SerialMIDI
- MACRO outside of Namespace
2020-05-16 15:51:03 +02:00
Francois Best e5ee620139 doc: Add contributor 2020-04-28 07:34:38 +02:00
Francois Best 0d9f6f4731 chore: Release 5.0.2
Includes fix for missing MIDI_CREATE_CUSTOM_INSTANCE,
see #150.
2020-04-28 07:31:42 +02:00
Rolel 42 80dfb8333c [FIX] Repair missing MIDI_CREATE_CUSTOM_INSTANCE
The MIDI_CREATE_CUSTOM_INSTANCE function was removed with 5.0 branch. This commit brings it back.
2020-04-28 07:28:24 +02:00
Francois Best d0110e4866 doc: Thru is off by default in other transports 2020-04-24 07:10:21 +02:00
Francois Best ce57d26d2c doc: Update example 2020-04-24 07:10:02 +02:00
Francois Best 47ce2acc16 chore: Update version & package metadata 2020-04-24 06:52:25 +02:00
Francois Best 1375b0b6aa doc: Update URL 2020-04-24 06:52:02 +02:00
Francois Best 116dba12eb chore: Update compiler config file 2020-04-24 06:49:55 +02:00
Francois Best aa4912b587 chore: Update version in documentation 2020-04-24 06:47:49 +02:00
Francois Best c0a66516f6
thruActivated as a property of the Transport layer (#148)
* thruActivated as a property of the Transport layer

* thruActivated defaults to true

Co-authored-by: lathoub <lathoub@gmail.com>
2020-04-24 06:44:59 +02:00
lathoub a5e31f15a4
thruActivated defaults to true 2020-04-23 22:14:59 +02:00
lathoub 99a981be5e thruActivated as a property of the Transport layer 2020-04-23 22:08:15 +02:00
Francois Best 419c74adfe doc: Add AppleMIDI & release notes 2020-04-20 17:33:46 +02:00
Francois Best 5e9a0165d9 docs: Contributions 2020-04-20 17:30:03 +02:00
Francois Best d600656f04 Merge branch dev into master 2020-04-20 17:09:02 +02:00
Francois Best 804e59669e
Merge pull request #95 from FortySevenEffects/feat/4.4.0
v5.0.0
2020-04-20 17:02:01 +02:00
Francois Best fc360d60b3 chore: Remove Google test coverage 2020-04-20 16:47:36 +02:00
Francois Best b384278b29 chore: Ignore edge cases for coverage 2020-04-20 15:36:12 +02:00
Francois Best ae49d3037d chore: Ignore external coverage 2020-04-20 15:31:26 +02:00
Francois Best 2d6bdd6dc2 doc: Move Documentation section up 2020-04-20 15:22:41 +02:00
Francois Best c2d17ec429 chore: Update lcov to latest available version 2020-04-20 15:22:18 +02:00
lathoub c1d2f476b8
Update unit-tests_MidiInput.cpp 2020-04-20 14:31:51 +02:00
lathoub 45fb2df88f
listen on channel 1 by default
Listening to all channels by default breaks backward compatibility
2020-04-20 14:17:43 +02:00
lathoub 05487c5415
Example not relevant for Due and ZERO as they lack support for SoftwareSerial 2020-04-20 14:11:58 +02:00
lathoub e06e3677f0
bug fix: HardwareSerial => SoftwareSerial 2020-04-20 13:09:39 +02:00
lathoub c5330945ee
Delete altPinSerialMIDI.h 2020-04-20 13:09:01 +02:00
lathoub 1e14162bf4
rewrote AltPinSerial to use SoftwareSerial 2020-04-20 13:08:49 +02:00
lathoub 9d43a8370e
added AltPinSerial example 2020-04-19 21:37:39 +02:00
lathoub b457f6db7c added USB Migration and other Transport mechanisms 2020-04-17 22:09:06 +02:00
lathoub be85c7b3e0 SerialUSB is of type Serial_, not HardwareSerial 2020-04-17 22:05:49 +02:00
Francois Best 23c53cafe1 fix: Remove USB-based Teensys from CI 2020-04-17 08:41:16 +02:00
Francois Best f8707ed49a chore: Add all Teensy boards to CI 2020-04-17 08:22:05 +02:00
Francois Best a9664ef4a4 fix: Use SysEx size in Settings 2020-04-17 08:15:42 +02:00
Francois Best 7a96fec0b5 chore: Update Google Test & remove USBMIDI 2020-04-17 08:15:01 +02:00
lathoub 2c657a38d1
Added support for Active Sensing and SysEx command segments (v4.4.0) (#138)
* stuff to ignore list

* Update midi_Defs.h

* added support for ActiveSensing

From: https://www.midi.org/specifications/item/table-1-summary-of-midi-message

Active Sensing. This message is intended to be sent repeatedly to tell the receiver that a connection is alive. Use of this message is optional. When initially received, the receiver will expect to receive another Active Sensing message each 300ms (max), and if it does not then it will assume that the connection has been terminated. At termination, the receiver will turn off all voices and return to normal (non- active sensing) operation.

* replaced ActiveSensing with Sender Active Sensing

Receiver active Sensing is not implemented (yet)

* added support for receiving SysEx command segments

Very long SysEx mesaages are cut in to multiple command segments
Where a normal SysEx starts with F0 and ends with F7, the first segment will start with F0 and end with F0, the middle section (optional) start with F7 and ends with F7 - the last segments starts with F7 and ends with F0

* lift and shift of the Serial code into a seperate class, allowing for other serializers

lift and shift of the Serial code into a seperate class, allowing for other serializers as AppleMIDI, USBMIDI, ipMIDI, BLE-MIDI

* added Platform class to abstract millis()

* add MidiType to beginTransmission

Avoids reparsing of the stream in the transport layer, in order to get the MidiType

* active sensing defaults to false, to avoid spamming devices

* set ActiveSensing Periodicity in ms

Gives more control over the bool value. Typical value is 300 (ms) - an Active Sensing command is send every 300ms; or 0 (zero) to disable sending ActiveSensing

* added namespace reference

* renamed Encoder -> Transport, added MidiType to beginTransmission in serialMIDI

* added callback for Message

before the specific callback are called, a generic mMessage callback can be fired to inform the user that 'a' message has been received.

* added send(MidiMessage), added (untested) bridge example

added send(MidiMessage) for Bridge application (that convert MIDI transport x into MIDI transport y), avoiding parsing entry a stream, setting up all callback - whilst this allows for passing the content, without to much processing/parsing.

Had to move mPendingMessageExpectedLenght into MidiMessage to avoid parsing the data again, just to know the size

Added Bridge example (untested)

* changed based on Franky47's feedback

- send: pass the message as a const ref, to avoid copies
- add mSerial.begin (with Baudrate - added Settings)
- ThruActivated defaults to true
- class name serialMIDI => SerialMIDI

* return reference to Transport layer

* return a *pointer* (not a ref) to the transport layer

* mPendingMessageExpectedLength as before

mMessage.length is reset to 0 before the callback, so bring back mPendingMessageExpectedLength as before, and set mMessage.length (and not reset it)

* DefaultPlatform for Arduino

* strong typing Channel in the callbacks

* aliasing for callbacks (and default initializers

* cleanup setHandleMessage

unfortunately, not using aliases yet (too complex)

* Fixed "FML" case: fall down here with an overflown SysEx..

Splitting larger incoming messages into smaller SysEx packets - using an RrtpMidi trick:
            //   first:  0xF0 .... 0xF0
            //   midlle: 0xF7 .... 0xF0
            //   last:   0xF7 .... 0xF7

see: https://tools.ietf.org/html/rfc4695#section-3.2

(Understanding this is not part of the original MIDI spec, but does allow for receiving very very large SysEx messages on a small footprint (does require some 'handy' parsing))

SysExMaxSize in Settings can be reduced significatly (16bytes works fine - pending use case)

* + receiver ActiveSensing, + error Callback

1) Active Sensing:
Once an ActiveSensing message is received, the system checks for timeouts: if no message is received within the specified 300ms (see in _Defs), an error is set and the checks for timeout stop.

2) added a callback for errors. 2 errors are defined: parse error and ActiveSensing timeout

* cleanup of basic example

use LED_BUILTIN

* + Manufacturer System Exclusive ID (incomplete)

* + noteValues

* added SendCommon, consistent with SendRealTime

including:

sendClock, sendStart, sendStop, sendContinue, sendActiveSensing, sendSystemReset

* UseSenderActiveSensing & UseReceiverActiveSensing to enable/disable Active Sensing

UseSenderActiveSensing & UseReceiverActiveSensing in Settings are global switches to turn on/off ActiveSensing (and save memory)

* use #defined value, not the literal

* cleanup

* removed deprecated MidiFilterMode (to be removed for v5)

* getting ready for v5

* prepare for v5

* updating authors

* Removed USB examples

* added header

* removed typedef

when instanciating multiple instances of SerialMIDI, a redefinition error accors because of typing of the serial##Name.
Fix: removed the typdef, a bit harder to read, but avoided complex #ifdef

* move bridge example to other Transport mechanisms

* Update Bench.ino

* Create NoteNames.ino

demonstrate use of MIDI_NAMESPACE::NoteValues[inNote].strptr

* moved #version to MIDI.h

#version of the library does not belong in general MIDI definitions
(making midi_Defs.h as generic as possible - usable on other platforms)

* adding comment section

* shorter syntax using iif

* moved code to avoid doc clash

* added Tick (0xF9)

* Simplified NoteValues

Need need for extra index (that is the same as the noteName anyway)

* Removed Undefined_F9 (Tick) as an invalid token (so it valid now)

* removed references to USB in the test scripts

* setting the CMake env

* removed USB references

* struggling with travis

* LCOV_EXCL_LINE in sendCommon

* order of initialization

* reorder variables for initialisation

* extending platforms

* adding boards (but not the Zero)

* fixing cmake

* moved RingBuffer to SerialMock

* fix cmake removing RingBuffer

* Update CMakeLists.txt

* using bitwire operators (works on all platforms)

* Update midi_Platform.h

* removed NoteNames

* simplify test (will be rolled back later)

* Update unit-tests_MidiInput.cpp

* Update unit-tests_MidiInput.cpp

* Revert "Update midi_Platform.h"

This reverts commit bd2f6476b2.

* bring in other Platform (remove usb)

* added BaudRate

* Revert "using bitwire operators (works on all platforms)"

This reverts commit 122ebe1dc3.

* Revert "moved code to avoid doc clash"

This reverts commit ef878344cd.

* restored after very funcky commits and rollbacks (Sorry!)

* add Transport layer

* removed SerialMock test

* Update unit-tests_MidiInput.cpp

* Update unit-tests_MidiInput.cpp

* Update unit-tests_MidiInput.cpp

* Update unit-tests_MidiInput.cpp

* fixed MidiInterface<SerialMock => MidiInterface<Transport

* SerialMIDI should not aware of the channel

* Update unit-tests_MidiThru.cpp

* Update midi_Defs.h

* avoid shadow parameters and buf fix

* Update CMakeLists.txt

* Update unit-tests_MidiOutput.cpp

* Update midi_Settings.h

* Update unit-tests_MidiInput.cpp

* Update unit-tests_MidiInput.cpp

* Update unit-tests_MidiInput.cpp

* tmp removed teensy, bug fix sendCommon (unsigned, not byte)

* Update unit-tests_MidiInput.cpp

* fix for Leonardo

* Update DualMerger.ino

* adding tests_MidiInputCallbacks

* Update unit-tests_MidiInputCallbacks.cpp

* preparing to release 5.0.0

* added Alternative Pin for Serial port example

* default listen on all channel as in #96

* Update unit-tests_MidiInput.cpp

Co-authored-by: lathoub <lathoub@gmail.com>
2020-04-08 10:36:10 +02:00
Francois Best cab564b995
Merge pull request #125 from lathoub/patch-1
changed default size of enums (int) to a smaller type
2019-08-29 12:28:05 +02:00
Francois Best 2ffbdef8da
Merge pull request #124 from insolace/master
::send ignores realtime messages, quick fix
2019-08-22 08:52:06 +02:00
Eric Bateman 843a9e5d8d
Delete .DS_Store 2019-08-21 23:36:22 -07:00
lathoub f067883dd8
changed default size of enums (int) to a smaller type
Easily save over 200 bytes for the library by using the smallest type for these MIDI types.
2019-08-18 06:52:50 +02:00
Eric Bateman dac0862657 Update MIDI.hpp 2019-08-11 00:58:17 -07:00
Eric Bateman d688030c14 debugging 2019-08-11 00:34:40 -07:00
Francois Best 96b7fd4537 chore: Config file update 2018-11-07 12:09:47 +01:00
Francois Best b3ab309781 doc: Update Readme
Fix typos, add USB support
2018-11-07 12:09:37 +01:00
Francois Best faa7bade0b cleanup: Dedupe RingBuffer implementation in mocks 2018-11-07 12:08:12 +01:00
Francois Best a9e0db5b73 fix: Test examples in CI 2018-11-06 16:58:05 +01:00
Francois Best 39d13e8ac4 feat: Add MIDI USB test sketches 2018-11-06 16:55:51 +01:00
Francois Best 5835806832 fix: Constify 2018-11-06 16:55:08 +01:00
Francois Best 347b67a877 fix: Point back to original MIDIUSB repo
Now that arduino-libraries/MIDIUSB#47 has been merged.
2018-11-06 12:47:26 +01:00
Francois Best 0e9e505543 doc: Note the importance of Running Status being disabled for USB 2018-11-04 14:17:30 +01:00
Francois Best 67a13be6c6 fix: Use USB packet interface in the transport layer 2018-11-04 14:17:07 +01:00
Francois Best 5ccf0159a2 feat: Serialise USB MIDI packets into the serial RX buffer 2018-11-04 10:07:21 +01:00
Francois Best 1ccd7c3ce8 feat: Add SysEx support for USB MIDI 2018-11-03 21:47:37 +01:00
Francois Best 5b96487362 feat: Compose TX USB MIDI packets from serial buffer 2018-11-03 18:59:20 +01:00
Francois Best 3f15b733e4 feat: Get CIN from status byte
Removed unused implementation of UsbMidiEventPacket
2018-11-03 18:58:45 +01:00
Francois Best a34087c92c feat: Add peek and pop methods 2018-11-03 18:56:42 +01:00
Francois Best 9a0907ea7f chore: Point MIDI-USB submodule to own fork for unit testing 2018-11-03 18:56:11 +01:00
Francois Best b9397337d2 doc: Update links
[skip ci]
2018-10-11 11:45:46 +02:00
Francois Best db0f65a46e fix: Unnamed namespace macro is not available here 2018-10-11 11:37:40 +02:00
Francois Best 42b98a78cf refactor: Avoid redundant call 2018-10-11 10:33:07 +02:00
Francois Best 04ae12d9ad chore: Add VSCode config files & editor settings 2018-10-11 10:32:26 +02:00
Francois Best 83ad031ee6 fix: Add tests and fix RingBuffer implementation 2018-10-11 10:31:23 +02:00
Francois Best a44d1e7c1c
Merge pull request #98 from jarosz/master
Corrected typo.
2018-07-11 20:57:23 +02:00
Jacek Roszkowski e486667d8a
Corrected typo: Lenght - Length 2018-06-22 20:47:13 +02:00
Jacek Roszkowski 58474673b4
Corrected typo: Lenght - Length 2018-06-22 20:44:12 +02:00
Jacek Roszkowski 2e8be813c4
Corrected typo: Lenght - Length 2018-06-22 20:43:21 +02:00
Jacek Roszkowski 98f7bb8831
Corrected typo: Lenght - Length 2018-06-22 20:40:43 +02:00
Francois Best ba6e16442b Merge master into feat/4.4.0 2018-03-10 18:51:47 +01:00
Francois Best 1cd638361e chore: Update VSCode C++ helper file 2018-03-10 18:43:15 +01:00
Francois Best 561def7c06
Merge pull request #81 from LnnrtS/fixedWarnings
fix: Implicit conversion & sign comparison compiler warnings

- Increase warning level for sources
- Fix implicit conversion & sign comparison warnings
2018-03-10 18:41:36 +01:00
Francois Best 33bd77dd13 fix: Fix more sign / implicit type conversion warnings 2018-03-10 17:59:17 +01:00
Francois Best c5833214a1 feat: Increase warning level for sources
Don't do it globally as externals may have warnings we can't do much about.
2018-03-10 17:44:16 +01:00
Francois Best d9cad6034f chore: Upgrade Google Test to release-1.8.0 2018-03-10 17:10:47 +01:00
Francois Best 064c9d9568 fix: Issue link in documentation
[ci skip]
2018-03-10 17:07:55 +01:00
Francois Best 1c01effbd9 feat: Handle Korg-style of flipping SysEx data header bits
Closes #92
2018-03-10 16:58:17 +01:00
Francois Best 9b9905fb2a chore: Bump version to 4.4.0 2018-03-10 15:44:46 +01:00
Francois Best 4f9e629471 Merge branch 'master' into dev 2018-01-09 08:40:14 +01:00
Francois Best 63caf9a564
Merge pull request #88 from per1234/keywords-separator
Use correct separator in keywords.txt
2017-12-14 11:42:36 +01:00
per1234 ad652d3191
Use correct separator in keywords.txt
The Arduino IDE currently requires the use of a tab separator between the name and identifier. Without this tab the keyword is not highlighted.

Reference: https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5:-Library-specification#keywords
2017-12-13 14:56:35 -08:00
Francois Best ed72e06755 chore: auto-update VSCode C++ support file 2017-10-08 09:50:39 +02:00
Francois Best d292b68eaa fix: correct sequence of commands for submodules 2017-10-08 09:49:36 +02:00
Francois Best 43fcb370ed Merge branch 'master' into dev 2017-10-08 09:40:18 +02:00
Francois Best 7809235676 Added screenshot of the library manager 2017-08-25 15:33:31 +02:00
Francois Best 2a1e4a86b3 Added library manager screenshot 2017-08-25 15:29:07 +02:00
Lennart 3396ec9429 fixed some warnings when compiling with -Wconversion and -Wsign-conversion 2017-07-18 10:37:49 +02:00
Francois Best 724a1caecd Fix non-Arduino builds. 2017-04-07 09:39:52 +02:00
Francois Best 03d73c2b09 Changed def to match updates to cake library (FortySevenEffects/cake) 2017-04-07 09:37:49 +02:00
Francois Best 3a31a366e4 Changed def to match updates to cake library (FortySevenEffects/cake) 2017-01-07 14:40:27 +01:00
Francois Best 9a4b8b6c86 Merge branch 'master' into dev. 2016-11-04 23:27:01 +01:00
Francois Best 77bb518f19 Using recommended default HW serial port.
Relates to #65.
2016-11-04 23:22:45 +01:00
Francois Best de51bcfa34 Merge pull request #63 from datomusic/master
Added default serial port for Teensy 3.0/3.1/3.2 and Teensy LC
2016-11-04 21:11:58 +01:00
Francois Best e615065dc2 Merge pull request #64 from ivankravets/patch-4
Fix library manifest for @PlatformIO
2016-11-04 13:34:28 +01:00
Ivan Kravets de608f874f Fix library manifest for @PlatformIO 2016-11-04 13:45:47 +02:00
David Menting 32489bc0ea Added default serial port for Teensy 3.0/3.1/3.2 and Teensy LC 2016-11-04 12:36:21 +01:00
Francois Best ce42efc7c6 Updated doc and tag URL. 2016-11-04 10:53:54 +01:00
Francois Best 82f5dca265 Bumped version to 4.3.1, fixing Arduino lib file.
Removed redundant version mentions in sources.
2016-11-04 10:53:18 +01:00
Francois Best ce659116b7 Updated subs. 2016-11-04 07:19:23 +01:00
Francois Best 6b295e6a47 Merge branch 'master' into dev. 2016-11-04 07:15:12 +01:00
Francois Best 2a1e86dbaf Maintaining only one doc location. 2016-11-02 20:22:23 +01:00
Francois Best 7aaa7d4e24 Merge pull request #44 from softegg/patch-1
For Arduino IDE happiness / workiness
2016-06-09 12:14:14 +02:00
SoftEgg f6b4282821 For Arduino IDE happiness / workiness
If you want to use the directory structure as-is, this file is necessary.
2016-06-09 02:47:15 -07:00
Francois Best 8a856e1f9d Merge remote-tracking branch 'origin/Franky47-patch-1' into dev 2015-02-27 15:09:57 +01:00
Francois Best 3eb65db1a4 Fixed #30 2015-02-27 14:54:04 +01:00
62 changed files with 2121 additions and 1705 deletions

9
.editorconfig Normal file
View File

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

66
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,66 @@
---
name: Bug report
about: Report something that does not work as intended
title: ''
labels: bug
assignees: ''
---
<!--
Before opening an issue, check if your problem already has been solved by looking in:
- The existing issues: https://github.com/FortySevenEffects/arduino_midi_library/issues
- The discussions: https://github.com/FortySevenEffects/arduino_midi_library/discussions
Consider opening a discussion instead of an issue if you need help with your project:
https://github.com/FortySevenEffects/arduino_midi_library/discussions/new
-->
## Context
Please answer a few questions to help us understand your problem better and guide you to a solution:
<!-- Tip: place the letter x in the checkboxes to tick them:
- [ ] Unticked checkbox
- [x] Ticked checkbox
You can also tick them by clicking after you've submitted your issue.
-->
- What board are you using ?
- `example: Arduino Leonardo`
- _Please list any shields or other **relevant** hardware you're using_
- What version of the Arduino IDE are you using ?
- `example: 1.8.5`
- How are you using MIDI ?
- [ ] Hardware Serial (DIN plugs)
- [ ] USB
- [ ] Other (please specify)
- Is your problem related to:
- [ ] MIDI Input (reading messages from other devices)
- [ ] MIDI Output (sending messages to other devices)
- How comfortable are you with code ?
- [ ] Complete beginner
- [ ] I've done basic projects
- [ ] I know my way around C/C++
- [ ] Advanced / professional
## Describe your project and what you expect to happen:
<!--
Example: When I press a switch on my pedalboard, it sends a SysEx message that I'd like to receive on my Arduino.
Note: Attachments (circuit diagrams, code examples) are most welcome and will help us understand your needs better and find a suitable solution for your issue.
-->
## Describe your problem (what does not work):
<!--
Example: I cannot receive SysEx messages coming from my AxeFX 2
-->
## Steps to reproduce
<!--
Please list the steps you took to hit the problem, so we can try and reproduce it.
-->

5
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: Discussions
url: https://github.com/FortySevenEffects/arduino_midi_library/discussions
about: Not a bug or a feature request ? Discuss your problem, ask for help or show what you've built in Discussions.

View File

@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: new feature
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

59
.github/workflows/cmake.yml vendored Normal file
View File

@ -0,0 +1,59 @@
name: CMake
on:
push:
pull_request:
branches: [ master ]
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
BUILD_TYPE: Debug
GENERATE_COVERAGE: true
LCOV_ROOT: ${{github.workspace}}/lcov
jobs:
build:
# The CMake configure and build commands are platform agnostic and should work equally
# well on Windows or Mac. You can convert this to a matrix build if you need
# cross-platform coverage.
# See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
submodules: recursive
- name: Install lcov
run: |
mkdir -p "$LCOV_ROOT"
wget https://github.com/linux-test-project/lcov/releases/download/v1.15/lcov-1.15.tar.gz --output-document="$LCOV_ROOT/lcov.tar.gz"
tar -xf "$LCOV_ROOT/lcov.tar.gz" --strip-components=1 -C "$LCOV_ROOT"
echo "$LCOV_ROOT/bin" >> $GITHUB_PATH
shell: bash
- name: Configure CMake
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DBUILDER_ENABLE_PROFILING=true
- name: Build
# Build your program with the given configuration
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
- name: Run Unit Tests
working-directory: ${{github.workspace}}/build
run: ctest --verbose
- name: Generate code coverage report
working-directory: ${{github.workspace}}/build
run: |
lcov --directory . --capture --output-file coverage.info
lcov --remove coverage.info '/usr/*' "${{github.workspace}}/test/*" "${{github.workspace}}/external/*" --output-file coverage.info
lcov --list coverage.info
- uses: coverallsapp/github-action@9ba913c152ae4be1327bfb9085dc806cedb44057
name: Upload code coverage report to Coveralls
with:
path-to-lcov: ${{github.workspace}}/build/coverage.info
github-token: ${{ secrets.GITHUB_TOKEN }}

62
.github/workflows/platformio.yml vendored Normal file
View File

@ -0,0 +1,62 @@
name: PlatformIO
on:
push:
branches: [master]
pull_request:
branches: [ master ]
jobs:
platformio:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
example:
- AltPinSerial
- Basic_IO
- Bench
- Callbacks
- Chaining
- DualMerger
- ErrorCallback
- Input
- RPN_NRPN
- SimpleSynth
- CustomBaudRate
board:
- uno
- due
- zero
- leonardo
- micro
- nanoatmega328
- megaatmega2560
- teensy2
- teensy30
- teensy31
- teensylc
steps:
- uses: actions/checkout@v2
- name: Cache pip
uses: actions/cache@v2
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: ${{ runner.os }}-pip-
- name: Cache PlatformIO
uses: actions/cache@v2
with:
path: ~/.platformio
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
- name: Set up Python
uses: actions/setup-python@v2
- name: Install PlatformIO
run: |
python -m pip install --upgrade pip
pip install --upgrade platformio
pip install "click!=8.0.2" # See platformio/platformio-core#4078
- name: Run PlatformIO
run: pio ci --lib="." --board="${{matrix.board}}"
env:
PLATFORMIO_CI_SRC: examples/${{ matrix.example }}

5
.gitignore vendored
View File

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

3
.gitmodules vendored
View File

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

View File

@ -1,95 +0,0 @@
# Kudos to these guys:
# https://github.com/Return-To-The-Roots/s25client/blob/master/.travis.yml
# http://docs.platformio.org/en/stable/ci/travis.html
sudo: false
language: python
os:
- linux
python:
- "2.7"
# Cache PlatformIO packages using Travis CI container-based infrastructure
cache:
directories:
- "~/.platformio"
env:
global:
- BUILD_TYPE=Debug
matrix:
- BUILD_UNIT_TESTS=1
- PLATFORMIO_CI_SRC=examples/Basic_IO
- PLATFORMIO_CI_SRC=examples/Bench
- PLATFORMIO_CI_SRC=examples/Callbacks
- PLATFORMIO_CI_SRC=examples/DualMerger
- PLATFORMIO_CI_SRC=examples/Input
- PLATFORMIO_CI_SRC=examples/MidiUSB REQUIRES_USB=1
- PLATFORMIO_CI_SRC=examples/RPN_NRPN
- PLATFORMIO_CI_SRC=examples/SimpleSynth
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-4.8
- cmake
install:
- |
if [ "${BUILD_UNIT_TESTS}" ]; then
# GCov 4.6 cannot handle the file structure
export CXX="g++-4.8"
export GCOV="gcov-4.8"
# Install newer lcov (1.9 seems to fail: http://gronlier.fr/blog/2015/01/adding-code-coverage-to-your-c-project/)
export LCOV_ROOT="$HOME/lcov"
mkdir -p "$LCOV_ROOT"
wget http://ftp.de.debian.org/debian/pool/main/l/lcov/lcov_1.12.orig.tar.gz --output-document="$LCOV_ROOT/lcov.tar.gz"
tar xf "$LCOV_ROOT/lcov.tar.gz" --strip-components=1 -C $LCOV_ROOT
export PATH="$LCOV_ROOT/bin:$PATH"
which lcov
# Install coveralls tool
gem install coveralls-lcov
export GENERATE_COVERAGE=1
else
# Install PlatformIO
pip install -U platformio
fi
script:
# Build unit tests & generate code coverage
- |
if [ "${BUILD_UNIT_TESTS}" ]; then
mkdir build && cd build
cmake -DCMAKE_CXX_COMPILER=$COMPILER -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DBUILDER_ENABLE_PROFILING=${GENERATE_COVERAGE} --generator="Unix Makefiles" ..
make all
ctest --verbose
fi
# Build current example
- |
if [ ! "${BUILD_UNIT_TESTS}" ]; then
if [ "${REQUIRES_USB}" ]; then
platformio ci --lib="." --lib=external/midi-usb --board="due" --board="dueUSB" --board="zero" --board="zeroUSB" --board="leonardo"
else
platformio ci --lib="." --board=uno --board="due" --board="zero" --board="leonardo" --board="micro" --board="nanoatmega328" --board="megaatmega2560" --board="teensy20" --board="teensy20pp" --board="teensy30" --board="teensy31"
fi
fi
after_success:
- |
if [ "${GENERATE_COVERAGE}" ]; then
# Generate code coverage information & send to Coveralls
lcov --gcov-tool $GCOV --directory . --capture --output-file coverage.info
lcov --gcov-tool $GCOV --remove coverage.info 'test/*' '/usr/*' 'external/*' --output-file coverage.info
lcov --list coverage.info
coveralls-lcov --repo-token ${COVERALLS_TOKEN} coverage.info
fi
notifications:
email: false

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

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

View File

@ -6,26 +6,57 @@
"/Applications/Arduino.app/Contents/Java/hardware/tools/avr/include",
"/Applications/Arduino.app/Contents/Java/hardware/arduino/avr/cores/arduino"
],
"browse" : {
"limitSymbolsToIncludedHeaders" : true,
"databaseFilename" : ""
}
"browse": {
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": "",
"path": [
"/Applications/Arduino.app/Contents/Java/hardware/tools/avr/include",
"/Applications/Arduino.app/Contents/Java/hardware/arduino/avr/cores/arduino"
]
},
"intelliSenseMode": "clang-x64",
"macFrameworkPath": [
"/System/Library/Frameworks",
"/Library/Frameworks"
],
"compilerPath": "/usr/bin/clang",
"cStandard": "c11",
"cppStandard": "c++17"
},
{
"name": "Linux",
"includePath": ["/usr/include"],
"browse" : {
"limitSymbolsToIncludedHeaders" : true,
"databaseFilename" : ""
}
"includePath": [
"/usr/include"
],
"browse": {
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": "",
"path": [
"/usr/include"
]
},
"intelliSenseMode": "clang-x64",
"compilerPath": "/usr/bin/clang",
"cStandard": "c11",
"cppStandard": "c++17"
},
{
"name": "Win32",
"includePath": ["c:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include"],
"browse" : {
"limitSymbolsToIncludedHeaders" : true,
"databaseFilename" : ""
}
"includePath": [
"c:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include"
],
"browse": {
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": "",
"path": [
"c:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include"
]
},
"intelliSenseMode": "msvc-x64",
"compilerPath": "/usr/bin/clang",
"cStandard": "c11",
"cppStandard": "c++17"
}
]
}
],
"version": 4
}

16
.vscode/settings.json vendored
View File

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

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

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

View File

@ -1,17 +1,29 @@
# Contributing Guidelines
First, thanks for your help ! :+1:
## Branches
Please base your Pull Requests off the `master` branch.
## Requirements
Requirements to build and run the unit tests:
- CMake 2.8 or later
- GCC / Clang with C++11 support
- CMake 2.8 or later
- GCC / Clang with C++11 support (GCC 4.8 or higher)
## Setup
Pull Google Test / Google Mock subrepository:
```
$ git init submodules
$ git submodule init
$ git submodule update
```
Create build directory, run CMake, build and run unit tests:
```
$ mkdir build && cd build
$ cmake ..

151
README.md
View File

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

View File

@ -1,11 +1,13 @@
#### Changelog
* 11/06/2014 : Version 4.2 released. Bug fix for SysEx, overridable template settings.
* 16/04/2014 : Version 4.1 released. Bug fixes regarding running status.
* 13/02/2014 : Version 4.0 released. Moved to GitHub, added multiple instances & software serial support, and a few bug fixes.
* 29/01/2012 : Version 3.2 released. Release notes are [here](http://sourceforge.net/news/?group_id=265194).
* 06/05/2011 : Version 3.1 released. Added [callback](http://playground.arduino.cc/Main/MIDILibraryCallbacks) support.
* 06/03/2011 : Version 3.0 released. Project is now hosted on [SourceForge](http://sourceforge.net/projects/arduinomidilib).
* 14/12/2009 : Version 2.5 released.
* 28/07/2009 : Version 2.0 released.
* 28/03/2009 : Simplified version of MIDI.begin, Fast mode is now on by default.
* 08/03/2009 : Thru method operational. Added some features to enable thru.
- 20/04/2020 : Version 5.0 released. Separation of transports by [@lathoub](https://github.com/lathoub), adds Active Sensing.
- 11/06/2014 : Version 4.2 released. Bug fix for SysEx, overridable template settings.
- 16/04/2014 : Version 4.1 released. Bug fixes regarding running status.
- 13/02/2014 : Version 4.0 released. Moved to GitHub, added multiple instances & software serial support, and a few bug fixes.
- 29/01/2012 : Version 3.2 released. Release notes are [here](http://sourceforge.net/news/?group_id=265194).
- 06/05/2011 : Version 3.1 released. Added [callback](http://playground.arduino.cc/Main/MIDILibraryCallbacks) support.
- 06/03/2011 : Version 3.0 released. Project is now hosted on [SourceForge](http://sourceforge.net/projects/arduinomidilib).
- 14/12/2009 : Version 2.5 released.
- 28/07/2009 : Version 2.0 released.
- 28/03/2009 : Simplified version of MIDI.begin, Fast mode is now on by default.
- 08/03/2009 : Thru method operational. Added some features to enable thru.

View File

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

View File

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

View File

@ -12,7 +12,7 @@
// Examples
/*!
\example MIDI_Basic_IO.ino
\example Basic_IO.ino
This example shows how to perform simple input and output MIDI. \n
\n
When any message arrives to the Arduino, the LED is turned on,
@ -29,15 +29,15 @@
*/
/*!
\example MIDI_Callbacks.ino
\example Callbacks.ino
This example shows how to use callbacks for easier MIDI input handling. \n
*/
/*!
\example MIDI_Bench.ino
\example MIDI_DualMerger.ino
\example MIDI_Input.ino
\example MIDI_SimpleSynth.ino
\example Bench.ino
\example DualMerger.ino
\example Input.ino
\example SimpleSynth.ino
*/
// -----------------------------------------------------------------------------

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

@ -0,0 +1,87 @@
# SysEx Encoding & Decoding
There are various ways of encoding & decoding arbitrary 8-bit wide data into
SysEx, which is 7-bit wide.
The [official documentation](http://www.somascape.org/midi/tech/spec.html#nusx_fd)
for FileDump data exchanges states the following:
> The 8-bit file data needs to be converted to 7-bit form,
> with the result that every 7 bytes of file data translates
> to 8 bytes in the MIDI stream.
>
> For each group of 7 bytes (of file data) the top bit from each
> is used to construct an eigth byte, which is sent first.
> So:
> ```
> AAAAaaaa BBBBbbbb CCCCcccc DDDDdddd EEEEeeee FFFFffff GGGGgggg
> ```
> becomes:
> ```
> 0ABCDEFG 0AAAaaaa 0BBBbbbb 0CCCcccc 0DDDdddd 0EEEeeee 0FFFffff 0GGGgggg
> ```
>
> The final group may have less than 7 bytes, and is coded as follows
> (e.g. with 3 bytes in the final group):
> ```
> 0ABC0000 0AAAaaaa 0BBBbbbb 0CCCcccc
> ```
## SysEx encoding / decoding functions
The MIDI library supplies two functions to do this, `encodeSysEx` and `decodeSysEx`.
Example usage:
```c++
#include <MIDI.h>
static const byte myData[12] = {
// Hex dump: CAFEBABE BAADF00D FACADE42
0xca, 0xfe, 0xba, 0xbe, 0xba, 0xad, 0xf0, 0x0d,
0xfa, 0xca, 0xde, 0x42
};
byte encoded[16];
const unsigned encodedSize = midi::encodeSysEx(myData, encoded, 12);
// Encoded hex dump: 07 4a 7e 3a 3e 3a 2d 70 07 0d 7a 4a 5e 42
byte decoded[12];
const unsigned decoded = midi::decodeSysEx(encoded, decoded, encodedSize);
```
## Special case for Korg devices
Korg apparently uses another convention for their SysEx encoding / decoding,
where:
```
AAAAaaaa BBBBbbbb CCCCcccc DDDDdddd EEEEeeee FFFFffff GGGGgggg
```
becomes:
```
0GFEDCBA 0AAAaaaa 0BBBbbbb 0CCCcccc 0DDDdddd 0EEEeeee 0FFFffff 0GGGgggg
```
The order of the bits in the "header" byte is reversed.
To follow this 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).

View File

@ -0,0 +1,37 @@
#include <MIDI.h>
// Simple tutorial on how to receive and send MIDI messages
// on a different serial port, using SoftwareSerial.
// Here, when receiving any message on channel 4, the Arduino
// will blink a led and play back a note for 1 second.
#if defined(ARDUINO_SAM_DUE) || defined(SAMD_SERIES) || defined(_VARIANT_ARDUINO_ZERO_)
/* example not relevant for this hardware (SoftwareSerial not supported) */
MIDI_CREATE_DEFAULT_INSTANCE();
#else
#include <SoftwareSerial.h>
using Transport = MIDI_NAMESPACE::SerialMIDI<SoftwareSerial>;
int rxPin = 18;
int txPin = 19;
SoftwareSerial mySerial = SoftwareSerial(rxPin, txPin);
Transport serialMIDI(mySerial);
MIDI_NAMESPACE::MidiInterface<Transport> MIDI((Transport&)serialMIDI);
#endif
void setup()
{
pinMode(LED_BUILTIN, OUTPUT);
MIDI.begin(4); // Launch MIDI and listen to channel 4
}
void loop()
{
if (MIDI.read()) // If we have received a message
{
digitalWrite(LED_BUILTIN, HIGH);
MIDI.sendNoteOn(42, 127, 1); // Send a Note (pitch 42, velo 127 on channel 1)
delay(1000); // Wait for a second
MIDI.sendNoteOff(42, 0, 1); // Stop the note
digitalWrite(LED_BUILTIN, LOW);
}
}

View File

@ -6,11 +6,9 @@
MIDI_CREATE_DEFAULT_INSTANCE();
static const unsigned ledPin = 13; // LED pin on Arduino Uno
void setup()
{
pinMode(ledPin, OUTPUT);
pinMode(LED_BUILTIN, OUTPUT);
MIDI.begin(4); // Launch MIDI and listen to channel 4
}
@ -18,10 +16,10 @@ void loop()
{
if (MIDI.read()) // If we have received a message
{
digitalWrite(ledPin, HIGH);
digitalWrite(LED_BUILTIN, HIGH);
MIDI.sendNoteOn(42, 127, 1); // Send a Note (pitch 42, velo 127 on channel 1)
delay(1000); // Wait for a second
MIDI.sendNoteOff(42, 0, 1); // Stop the note
digitalWrite(ledPin, LOW);
digitalWrite(LED_BUILTIN, LOW);
}
}

View File

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

View File

@ -7,7 +7,7 @@ MIDI_CREATE_DEFAULT_INSTANCE();
// This function will be automatically called when a NoteOn is received.
// It must be a void-returning function with the correct parameters,
// see documentation here:
// http://arduinomidilib.fortyseveneffects.com/a00022.html
// https://github.com/FortySevenEffects/arduino_midi_library/wiki/Using-Callbacks
void handleNoteOn(byte channel, byte pitch, byte velocity)
{

View File

@ -0,0 +1,37 @@
#include <MIDI.h>
MIDI_CREATE_DEFAULT_INSTANCE();
void setup()
{
pinMode(2, INPUT);
MIDI // chaining MIDI commands - order is from top to bottom (turnThruOff,... begin)
.turnThruOff()
// using a lamdba function for this callbacks
.setHandleNoteOn([](byte channel, byte note, byte velocity)
{
// Do whatever you want when a note is pressed.
// Try to keep your callbacks short (no delays ect)
// otherwise it would slow down the loop() and have a bad impact
// on real-time performance.
})
.setHandleNoteOff([](byte channel, byte note, byte velocity)
{
// Do something when the note is released.
// Note that NoteOn messages with 0 velocity are interpreted as NoteOffs.
})
.begin(MIDI_CHANNEL_OMNI); // Initiate MIDI communications, listen to all channels
}
void loop()
{
// Call MIDI.read the fastest you can for real-time performance.
MIDI.read();
if (digitalRead(2))
MIDI // chained sendNoteOn commands
.sendNoteOn(42, 127, 1)
.sendNoteOn(40, 54, 1);
}

View File

@ -0,0 +1,32 @@
#include <MIDI.h>
// Override the default MIDI baudrate to
// a decoding program such as Hairless MIDI (set baudrate to 115200)
struct CustomBaudRateSettings : public MIDI_NAMESPACE::DefaultSerialSettings {
static const long BaudRate = 115200;
};
#if defined(ARDUINO_SAM_DUE) || defined(USBCON) || defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MKL26Z64__)
// Leonardo, Due and other USB boards use Serial1 by default.
MIDI_NAMESPACE::SerialMIDI<HardwareSerial, CustomBaudRateSettings> serialMIDI(Serial1);
MIDI_NAMESPACE::MidiInterface<MIDI_NAMESPACE::SerialMIDI<HardwareSerial, CustomBaudRateSettings>> MIDI((MIDI_NAMESPACE::SerialMIDI<HardwareSerial, CustomBaudRateSettings>&)serialMIDI);
#else
MIDI_NAMESPACE::SerialMIDI<HardwareSerial, CustomBaudRateSettings> serialMIDI(Serial);
MIDI_NAMESPACE::MidiInterface<MIDI_NAMESPACE::SerialMIDI<HardwareSerial, CustomBaudRateSettings>> MIDI((MIDI_NAMESPACE::SerialMIDI<HardwareSerial, CustomBaudRateSettings>&)serialMIDI);
#endif
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
MIDI.begin(MIDI_CHANNEL_OMNI);
}
void loop() {
if (MIDI.read()) // If we have received a message
{
digitalWrite(LED_BUILTIN, HIGH);
MIDI.sendNoteOn(42, 127, 1); // Send a Note (pitch 42, velo 127 on channel 1)
delay(1000); // Wait for a second
MIDI.sendNoteOff(42, 0, 1); // Stop the note
digitalWrite(LED_BUILTIN, LOW);
}
}

View File

@ -6,12 +6,17 @@
// A out = A in + B in
// B out = B in + A in
#ifdef ARDUINO_SAM_DUE
#if defined(ARDUINO_SAM_DUE)
MIDI_CREATE_INSTANCE(HardwareSerial, Serial, midiA);
MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, midiB);
#elif defined(ARDUINO_SAMD_ZERO)
MIDI_CREATE_INSTANCE(HardwareSerial, SerialUSB, midiA);
MIDI_CREATE_INSTANCE(Serial_, SerialUSB, midiA);
MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, midiB);
#elif defined(USBCON) || defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MKL26Z64__)
#include <SoftwareSerial.h>
SoftwareSerial softSerial(2,3);
MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, midiA);
MIDI_CREATE_INSTANCE(SoftwareSerial, softSerial, midiB);
#else
#include <SoftwareSerial.h>
SoftwareSerial softSerial(2,3);

View File

@ -0,0 +1,25 @@
#include <MIDI.h>
// Before running the program below, make sure you set
// UseReceiverActiveSensing (optionally UseSenderActiveSensing) in Settings.h to true
MIDI_CREATE_DEFAULT_INSTANCE();
void handleError(int8_t err)
{
digitalWrite(LED_BUILTIN, (err == 0)? LOW : HIGH);
}
void setup()
{
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
MIDI.setHandleError(handleError);
MIDI.begin(1);
}
void loop()
{
MIDI.read();
}

View File

@ -1,45 +0,0 @@
#include <MIDI.h>
#if defined(USBCON)
#include <midi_UsbTransport.h>
static const unsigned sUsbTransportBufferSize = 16;
typedef midi::UsbTransport<sUsbTransportBufferSize> UsbTransport;
UsbTransport sUsbTransport;
MIDI_CREATE_INSTANCE(UsbTransport, sUsbTransport, MIDI);
#else // No USB available, fallback to Serial
MIDI_CREATE_DEFAULT_INSTANCE();
#endif
// --
void handleNoteOn(byte inChannel, byte inNumber, byte inVelocity)
{
Serial.print("NoteOn ");
Serial.print(inNumber);
Serial.print("\tvelocity: ");
Serial.println(inVelocity);
}
void handleNoteOff(byte inChannel, byte inNumber, byte inVelocity)
{
Serial.print("NoteOff ");
Serial.print(inNumber);
Serial.print("\tvelocity: ");
Serial.println(inVelocity);
}
void setup() {
Serial.begin(115200);
while (!Serial);
MIDI.begin();
MIDI.setHandleNoteOn(handleNoteOn);
MIDI.setHandleNoteOff(handleNoteOff);
Serial.println("Arduino ready.");
}
void loop() {
MIDI.read();
}

@ -1 +1 @@
Subproject commit ecd530865cefdfa7dea58e84f6aa1b548950363d
Subproject commit 703bd9caab50b139428cea1aaff9974ebee5742e

1
external/midi-usb vendored

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

View File

@ -29,6 +29,14 @@ sendSongPosition KEYWORD2
sendSongSelect KEYWORD2
sendTuneRequest KEYWORD2
sendRealTime KEYWORD2
sendCommon KEYWORD2
sendClock KEYWORD2
sendStart KEYWORD2
sendStop KEYWORD2
sendTick KEYWORD2
sendContinue KEYWORD2
sendActiveSensing KEYWORD2
sendSystemReset KEYWORD2
beginRpn KEYWORD2
sendRpnValue KEYWORD2
sendRpnIncrement KEYWORD2
@ -77,8 +85,8 @@ setHandleSystemReset KEYWORD2
getTypeFromStatusByte KEYWORD2
getChannelFromStatusByte KEYWORD2
isChannelMessage KEYWORD2
encodeSysEx KEYWORD2
decodeSysEx KEYWORD2
encodeSysEx KEYWORD2
decodeSysEx KEYWORD2
#######################################
@ -138,7 +146,18 @@ GeneralPurposeController1 LITERAL1
GeneralPurposeController2 LITERAL1
GeneralPurposeController3 LITERAL1
GeneralPurposeController4 LITERAL1
BankSelectLSB LITERAL1
ModulationWheelLSB LITERAL1
BreathControllerLSB LITERAL1
FootControllerLSB LITERAL1
PortamentoTimeLSB LITERAL1
DataEntryLSB LITERAL1
ChannelVolumeLSB LITERAL1
BalanceLSB LITERAL1
PanLSB LITERAL1
ExpressionControllerLSB LITERAL1
EffectControl1LSB LITERAL1
EffectControl2LSB LITERAL1
Sustain LITERAL1
Portamento LITERAL1
Sostenuto LITERAL1

View File

@ -1,25 +1,23 @@
{
"name": "MIDI Library",
"version": "4.3",
"keywords": "midi",
"description": "Enables MIDI I/O communications on the Arduino serial ports",
"license": "MIT",
"authors":
{
"name": "Francois Best",
"email": "francois.best@fortyseveneffects.com",
"url": "https://github.com/Franky47",
"maintainer": true
},
"repository":
{
"type": "git",
"url": "https://github.com/FortySevenEffects/arduino_midi_library.git",
"branch": "master"
},
"downloadUrl": "https://github.com/FortySevenEffects/arduino_midi_library/releases/tag/4.3",
"include": "src",
"examples": "examples/*/*.ino",
"frameworks": "arduino",
"platforms": ["atmelavr", "atmelsam", "teensy"]
}
"name": "MIDI Library",
"version": "5.0.2",
"keywords": "midi",
"description": "Enables MIDI I/O communications on the Arduino serial ports",
"license": "MIT",
"authors": {
"name": "Francois Best",
"email": "contact@francoisbest.com",
"url": "https://github.com/Franky47",
"maintainer": true
},
"repository": {
"type": "git",
"url": "https://github.com/FortySevenEffects/arduino_midi_library.git",
"branch": "master"
},
"export": {
"include": ["src", "examples"]
},
"frameworks": "arduino",
"platforms": ["atmelavr", "atmelsam", "teensy"]
}

View File

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

BIN
res/library-manager.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

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

View File

@ -2,7 +2,6 @@
* @file MIDI.cpp
* Project Arduino MIDI Library
* @brief MIDI Library for the Arduino
* @version 4.3
* @author Francois Best
* @date 24/02/11
* @license MIT - Copyright (c) 2015 Francois Best
@ -38,12 +37,16 @@ BEGIN_MIDI_NAMESPACE
data you want to send.
\param inData The data to encode.
\param outSysEx The output buffer where to store the encoded message.
\param inLength The lenght of the input buffer.
\return The lenght of the encoded output buffer.
\param inLength The length of the input buffer.
\param inFlipHeaderBits True for Korg and other who store MSB in reverse order
\return The length of the encoded output buffer.
@see decodeSysEx
Code inspired from Ruin & Wesen's SysEx encoder/decoder - http://ruinwesen.com
*/
unsigned encodeSysEx(const byte* inData, byte* outSysEx, unsigned inLength)
unsigned encodeSysEx(const byte* inData,
byte* outSysEx,
unsigned inLength,
bool inFlipHeaderBits)
{
unsigned outLength = 0; // Num bytes in output array.
byte count = 0; // Num 7bytes in a block.
@ -55,7 +58,7 @@ unsigned encodeSysEx(const byte* inData, byte* outSysEx, unsigned inLength)
const byte msb = data >> 7;
const byte body = data & 0x7f;
outSysEx[0] |= (msb << (6 - count));
outSysEx[0] |= (msb << (inFlipHeaderBits ? count : (6 - count)));
outSysEx[1 + count] = body;
if (count++ == 6)
@ -74,13 +77,17 @@ unsigned encodeSysEx(const byte* inData, byte* outSysEx, unsigned inLength)
127 without breaking the MIDI protocol. Use this static method to reassemble
your received message.
\param inSysEx The SysEx data received from MIDI in.
\param outData The output buffer where to store the decrypted message.
\param inLength The lenght of the input buffer.
\return The lenght of the output buffer.
\param outData The output buffer where to store the decrypted message.
\param inLength The length of the input buffer.
\param inFlipHeaderBits True for Korg and other who store MSB in reverse order
\return The length of the output buffer.
@see encodeSysEx @see getSysExArrayLength
Code inspired from Ruin & Wesen's SysEx encoder/decoder - http://ruinwesen.com
*/
unsigned decodeSysEx(const byte* inSysEx, byte* outData, unsigned inLength)
unsigned decodeSysEx(const byte* inSysEx,
byte* outData,
unsigned inLength,
bool inFlipHeaderBits)
{
unsigned count = 0;
byte msbStorage = 0;
@ -95,8 +102,10 @@ unsigned decodeSysEx(const byte* inSysEx, byte* outData, unsigned inLength)
}
else
{
const byte body = inSysEx[i];
const byte msb = ((msbStorage >> byteIndex--) & 1) << 7;
const byte body = inSysEx[i];
const byte shift = inFlipHeaderBits ? 6 - byteIndex : byteIndex;
const byte msb = byte(((msbStorage >> shift) & 1) << 7);
byteIndex--;
outData[count++] = msb | body;
}
}

View File

@ -2,8 +2,7 @@
* @file MIDI.h
* Project Arduino MIDI Library
* @brief MIDI Library for the Arduino
* @version 4.3
* @author Francois Best
* @author Francois Best, lathoub
* @date 24/02/11
* @license MIT - Copyright (c) 2015 Francois Best
*
@ -29,105 +28,128 @@
#pragma once
#include "midi_Defs.h"
#include "midi_Platform.h"
#include "midi_Settings.h"
#include "midi_Message.h"
#include "serialMIDI.h"
// -----------------------------------------------------------------------------
BEGIN_MIDI_NAMESPACE
#define MIDI_LIBRARY_VERSION 0x050000
#define MIDI_LIBRARY_VERSION_MAJOR 5
#define MIDI_LIBRARY_VERSION_MINOR 0
#define MIDI_LIBRARY_VERSION_PATCH 0
/*! \brief The main class for MIDI handling.
It is templated over the type of serial port to provide abstraction from
the hardware interface, meaning you can use HardwareSerial, SoftwareSerial
or ak47's Uart classes. The only requirement is that the class implements
the begin, read, write and available methods.
*/
template<class SerialPort, class _Settings = DefaultSettings>
template<class Transport, class _Settings = DefaultSettings, class _Platform = DefaultPlatform>
class MidiInterface
{
public:
typedef _Settings Settings;
typedef _Platform Platform;
typedef Message<Settings::SysExMaxSize> MidiMessage;
public:
inline MidiInterface(SerialPort& inSerial);
inline MidiInterface(Transport&);
inline ~MidiInterface();
public:
void begin(Channel inChannel = 1);
MidiInterface& begin(Channel inChannel = 1);
// -------------------------------------------------------------------------
// MIDI Output
public:
inline void sendNoteOn(DataByte inNoteNumber,
inline MidiInterface& sendNoteOn(DataByte inNoteNumber,
DataByte inVelocity,
Channel inChannel);
inline void sendNoteOff(DataByte inNoteNumber,
inline MidiInterface& sendNoteOff(DataByte inNoteNumber,
DataByte inVelocity,
Channel inChannel);
inline void sendProgramChange(DataByte inProgramNumber,
inline MidiInterface& sendProgramChange(DataByte inProgramNumber,
Channel inChannel);
inline void sendControlChange(DataByte inControlNumber,
inline MidiInterface& sendControlChange(DataByte inControlNumber,
DataByte inControlValue,
Channel inChannel);
inline void sendPitchBend(int inPitchValue, Channel inChannel);
inline void sendPitchBend(double inPitchValue, Channel inChannel);
inline MidiInterface& sendPitchBend(int inPitchValue, Channel inChannel);
inline MidiInterface& sendPitchBend(double inPitchValue, Channel inChannel);
inline void sendPolyPressure(DataByte inNoteNumber,
inline MidiInterface& sendPolyPressure(DataByte inNoteNumber,
DataByte inPressure,
Channel inChannel) __attribute__ ((deprecated));
inline void sendAfterTouch(DataByte inPressure,
inline MidiInterface& sendAfterTouch(DataByte inPressure,
Channel inChannel);
inline void sendAfterTouch(DataByte inNoteNumber,
inline MidiInterface& sendAfterTouch(DataByte inNoteNumber,
DataByte inPressure,
Channel inChannel);
inline void sendSysEx(unsigned inLength,
inline MidiInterface& sendSysEx(unsigned inLength,
const byte* inArray,
bool inArrayContainsBoundaries = false);
inline void sendTimeCodeQuarterFrame(DataByte inTypeNibble,
inline MidiInterface& sendTimeCodeQuarterFrame(DataByte inTypeNibble,
DataByte inValuesNibble);
inline void sendTimeCodeQuarterFrame(DataByte inData);
inline MidiInterface& sendTimeCodeQuarterFrame(DataByte inData);
inline void sendSongPosition(unsigned inBeats);
inline void sendSongSelect(DataByte inSongNumber);
inline void sendTuneRequest();
inline void sendRealTime(MidiType inType);
inline MidiInterface& sendSongPosition(unsigned inBeats);
inline MidiInterface& sendSongSelect(DataByte inSongNumber);
inline MidiInterface& sendTuneRequest();
inline void beginRpn(unsigned inNumber,
inline MidiInterface& sendCommon(MidiType inType, unsigned = 0);
inline MidiInterface& sendClock() { return sendRealTime(Clock); };
inline MidiInterface& sendStart() { return sendRealTime(Start); };
inline MidiInterface& sendStop() { return sendRealTime(Stop); };
inline MidiInterface& sendTick() { return sendRealTime(Tick); };
inline MidiInterface& sendContinue() { return sendRealTime(Continue); };
inline MidiInterface& sendActiveSensing() { return sendRealTime(ActiveSensing); };
inline MidiInterface& sendSystemReset() { return sendRealTime(SystemReset); };
inline MidiInterface& sendRealTime(MidiType inType);
inline MidiInterface& beginRpn(unsigned inNumber,
Channel inChannel);
inline void sendRpnValue(unsigned inValue,
inline MidiInterface& sendRpnValue(unsigned inValue,
Channel inChannel);
inline void sendRpnValue(byte inMsb,
inline MidiInterface& sendRpnValue(byte inMsb,
byte inLsb,
Channel inChannel);
inline void sendRpnIncrement(byte inAmount,
inline MidiInterface& sendRpnIncrement(byte inAmount,
Channel inChannel);
inline void sendRpnDecrement(byte inAmount,
inline MidiInterface& sendRpnDecrement(byte inAmount,
Channel inChannel);
inline void endRpn(Channel inChannel);
inline MidiInterface& endRpn(Channel inChannel);
inline void beginNrpn(unsigned inNumber,
inline MidiInterface& beginNrpn(unsigned inNumber,
Channel inChannel);
inline void sendNrpnValue(unsigned inValue,
inline MidiInterface& sendNrpnValue(unsigned inValue,
Channel inChannel);
inline void sendNrpnValue(byte inMsb,
inline MidiInterface& sendNrpnValue(byte inMsb,
byte inLsb,
Channel inChannel);
inline void sendNrpnIncrement(byte inAmount,
inline MidiInterface& sendNrpnIncrement(byte inAmount,
Channel inChannel);
inline void sendNrpnDecrement(byte inAmount,
inline MidiInterface& sendNrpnDecrement(byte inAmount,
Channel inChannel);
inline void endNrpn(Channel inChannel);
inline MidiInterface& endNrpn(Channel inChannel);
inline MidiInterface& send(const MidiMessage&);
public:
void send(MidiType inType,
MidiInterface& send(MidiType inType,
DataByte inData1,
DataByte inData2,
Channel inChannel);
@ -150,7 +172,7 @@ public:
public:
inline Channel getInputChannel() const;
inline void setInputChannel(Channel inChannel);
inline MidiInterface& setInputChannel(Channel inChannel);
public:
static inline MidiType getTypeFromStatusByte(byte inStatus);
@ -161,48 +183,54 @@ public:
// Input Callbacks
public:
inline void setHandleNoteOff(void (*fptr)(byte channel, byte note, byte velocity));
inline void setHandleNoteOn(void (*fptr)(byte channel, byte note, byte velocity));
inline void setHandleAfterTouchPoly(void (*fptr)(byte channel, byte note, byte pressure));
inline void setHandleControlChange(void (*fptr)(byte channel, byte number, byte value));
inline void setHandleProgramChange(void (*fptr)(byte channel, byte number));
inline void setHandleAfterTouchChannel(void (*fptr)(byte channel, byte pressure));
inline void setHandlePitchBend(void (*fptr)(byte channel, int bend));
inline void setHandleSystemExclusive(void (*fptr)(byte * array, unsigned size));
inline void setHandleTimeCodeQuarterFrame(void (*fptr)(byte data));
inline void setHandleSongPosition(void (*fptr)(unsigned beats));
inline void setHandleSongSelect(void (*fptr)(byte songnumber));
inline void setHandleTuneRequest(void (*fptr)(void));
inline void setHandleClock(void (*fptr)(void));
inline void setHandleStart(void (*fptr)(void));
inline void setHandleContinue(void (*fptr)(void));
inline void setHandleStop(void (*fptr)(void));
inline void setHandleActiveSensing(void (*fptr)(void));
inline void setHandleSystemReset(void (*fptr)(void));
inline MidiInterface& setHandleMessage(void (*fptr)(const MidiMessage&)) { mMessageCallback = fptr; return *this; };
inline MidiInterface& setHandleError(ErrorCallback fptr) { mErrorCallback = fptr; return *this; };
inline MidiInterface& setHandleNoteOff(NoteOffCallback fptr) { mNoteOffCallback = fptr; return *this; };
inline MidiInterface& setHandleNoteOn(NoteOnCallback fptr) { mNoteOnCallback = fptr; return *this; };
inline MidiInterface& setHandleAfterTouchPoly(AfterTouchPolyCallback fptr) { mAfterTouchPolyCallback = fptr; return *this; };
inline MidiInterface& setHandleControlChange(ControlChangeCallback fptr) { mControlChangeCallback = fptr; return *this; };
inline MidiInterface& setHandleProgramChange(ProgramChangeCallback fptr) { mProgramChangeCallback = fptr; return *this; };
inline MidiInterface& setHandleAfterTouchChannel(AfterTouchChannelCallback fptr) { mAfterTouchChannelCallback = fptr; return *this; };
inline MidiInterface& setHandlePitchBend(PitchBendCallback fptr) { mPitchBendCallback = fptr; return *this; };
inline MidiInterface& setHandleSystemExclusive(SystemExclusiveCallback fptr) { mSystemExclusiveCallback = fptr; return *this; };
inline MidiInterface& setHandleTimeCodeQuarterFrame(TimeCodeQuarterFrameCallback fptr) { mTimeCodeQuarterFrameCallback = fptr; return *this; };
inline MidiInterface& setHandleSongPosition(SongPositionCallback fptr) { mSongPositionCallback = fptr; return *this; };
inline MidiInterface& setHandleSongSelect(SongSelectCallback fptr) { mSongSelectCallback = fptr; return *this; };
inline MidiInterface& setHandleTuneRequest(TuneRequestCallback fptr) { mTuneRequestCallback = fptr; return *this; };
inline MidiInterface& setHandleClock(ClockCallback fptr) { mClockCallback = fptr; return *this; };
inline MidiInterface& setHandleStart(StartCallback fptr) { mStartCallback = fptr; return *this; };
inline MidiInterface& setHandleTick(TickCallback fptr) { mTickCallback = fptr; return *this; };
inline MidiInterface& setHandleContinue(ContinueCallback fptr) { mContinueCallback = fptr; return *this; };
inline MidiInterface& setHandleStop(StopCallback fptr) { mStopCallback = fptr; return *this; };
inline MidiInterface& setHandleActiveSensing(ActiveSensingCallback fptr) { mActiveSensingCallback = fptr; return *this; };
inline MidiInterface& setHandleSystemReset(SystemResetCallback fptr) { mSystemResetCallback = fptr; return *this; };
inline void disconnectCallbackFromType(MidiType inType);
inline MidiInterface& disconnectCallbackFromType(MidiType inType);
private:
void launchCallback();
void (*mNoteOffCallback)(byte channel, byte note, byte velocity);
void (*mNoteOnCallback)(byte channel, byte note, byte velocity);
void (*mAfterTouchPolyCallback)(byte channel, byte note, byte velocity);
void (*mControlChangeCallback)(byte channel, byte, byte);
void (*mProgramChangeCallback)(byte channel, byte);
void (*mAfterTouchChannelCallback)(byte channel, byte);
void (*mPitchBendCallback)(byte channel, int);
void (*mSystemExclusiveCallback)(byte * array, unsigned size);
void (*mTimeCodeQuarterFrameCallback)(byte data);
void (*mSongPositionCallback)(unsigned beats);
void (*mSongSelectCallback)(byte songnumber);
void (*mTuneRequestCallback)(void);
void (*mClockCallback)(void);
void (*mStartCallback)(void);
void (*mContinueCallback)(void);
void (*mStopCallback)(void);
void (*mActiveSensingCallback)(void);
void (*mSystemResetCallback)(void);
void (*mMessageCallback)(const MidiMessage& message) = nullptr;
ErrorCallback mErrorCallback = nullptr;
NoteOffCallback mNoteOffCallback = nullptr;
NoteOnCallback mNoteOnCallback = nullptr;
AfterTouchPolyCallback mAfterTouchPolyCallback = nullptr;
ControlChangeCallback mControlChangeCallback = nullptr;
ProgramChangeCallback mProgramChangeCallback = nullptr;
AfterTouchChannelCallback mAfterTouchChannelCallback = nullptr;
PitchBendCallback mPitchBendCallback = nullptr;
SystemExclusiveCallback mSystemExclusiveCallback = nullptr;
TimeCodeQuarterFrameCallback mTimeCodeQuarterFrameCallback = nullptr;
SongPositionCallback mSongPositionCallback = nullptr;
SongSelectCallback mSongSelectCallback = nullptr;
TuneRequestCallback mTuneRequestCallback = nullptr;
ClockCallback mClockCallback = nullptr;
StartCallback mStartCallback = nullptr;
TickCallback mTickCallback = nullptr;
ContinueCallback mContinueCallback = nullptr;
StopCallback mStopCallback = nullptr;
ActiveSensingCallback mActiveSensingCallback = nullptr;
SystemResetCallback mSystemResetCallback = nullptr;
// -------------------------------------------------------------------------
// MIDI Soft Thru
@ -211,38 +239,52 @@ public:
inline Thru::Mode getFilterMode() const;
inline bool getThruState() const;
inline void turnThruOn(Thru::Mode inThruFilterMode = Thru::Full);
inline void turnThruOff();
inline void setThruFilterMode(Thru::Mode inThruFilterMode);
inline MidiInterface& turnThruOn(Thru::Mode inThruFilterMode = Thru::Full);
inline MidiInterface& turnThruOff();
inline MidiInterface& setThruFilterMode(Thru::Mode inThruFilterMode);
private:
void thruFilter(byte inChannel);
// -------------------------------------------------------------------------
// MIDI Parsing
private:
bool parse();
inline void handleNullVelocityNoteOnAsNoteOff();
inline bool inputFilter(Channel inChannel);
inline void resetInput();
inline void updateLastSentTime();
// -------------------------------------------------------------------------
// Transport
public:
Transport* getTransport() { return &mTransport; };
private:
typedef Message<Settings::SysExMaxSize> MidiMessage;
Transport& mTransport;
private:
SerialPort& mSerial;
// -------------------------------------------------------------------------
// Internal variables
private:
Channel mInputChannel;
StatusByte mRunningStatus_RX;
StatusByte mRunningStatus_TX;
byte mPendingMessage[3];
unsigned mPendingMessageExpectedLenght;
unsigned mPendingMessageExpectedLength;
unsigned mPendingMessageIndex;
unsigned mCurrentRpnNumber;
unsigned mCurrentNrpnNumber;
bool mThruActivated : 1;
Thru::Mode mThruFilterMode : 7;
MidiMessage mMessage;
unsigned long mLastMessageSentTime;
unsigned long mLastMessageReceivedTime;
unsigned long mSenderActiveSensingPeriodicity;
bool mReceiverActiveSensingActivated;
int8_t mLastError;
private:
inline StatusByte getStatus(MidiType inType,
@ -251,8 +293,14 @@ private:
// -----------------------------------------------------------------------------
unsigned encodeSysEx(const byte* inData, byte* outSysEx, unsigned inLenght);
unsigned decodeSysEx(const byte* inSysEx, byte* outData, unsigned inLenght);
unsigned encodeSysEx(const byte* inData,
byte* outSysEx,
unsigned inLength,
bool inFlipHeaderBits = false);
unsigned decodeSysEx(const byte* inSysEx,
byte* outData,
unsigned inLength,
bool inFlipHeaderBits = false);
END_MIDI_NAMESPACE

File diff suppressed because it is too large Load Diff

View File

@ -2,8 +2,7 @@
* @file midi_Defs.h
* Project Arduino MIDI Library
* @brief MIDI Library for the Arduino - Definitions
* @version 4.3
* @author Francois Best
* @author Francois Best, lathoub
* @date 24/02/11
* @license MIT - Copyright (c) 2015 Francois Best
*
@ -39,11 +38,6 @@ typedef uint8_t byte;
BEGIN_MIDI_NAMESPACE
#define MIDI_LIBRARY_VERSION 0x040300
#define MIDI_LIBRARY_VERSION_MAJOR 4
#define MIDI_LIBRARY_VERSION_MINOR 3
#define MIDI_LIBRARY_VERSION_PATCH 0
// -----------------------------------------------------------------------------
#define MIDI_CHANNEL_OMNI 0
@ -52,6 +46,10 @@ BEGIN_MIDI_NAMESPACE
#define MIDI_PITCHBEND_MIN -8192
#define MIDI_PITCHBEND_MAX 8191
/*! Receiving Active Sensing
*/
static const uint16_t ActiveSensingTimeout = 300;
// -----------------------------------------------------------------------------
// Type definitions
@ -60,28 +58,65 @@ typedef byte DataByte;
typedef byte Channel;
typedef byte FilterMode;
// -----------------------------------------------------------------------------
// Errors
static const uint8_t ErrorParse = 0;
static const uint8_t ErrorActiveSensingTimeout = 1;
static const uint8_t WarningSplitSysEx = 2;
// -----------------------------------------------------------------------------
// Aliasing
using ErrorCallback = void (*)(int8_t);
using NoteOffCallback = void (*)(Channel channel, byte note, byte velocity);
using NoteOnCallback = void (*)(Channel channel, byte note, byte velocity);
using AfterTouchPolyCallback = void (*)(Channel channel, byte note, byte velocity);
using ControlChangeCallback = void (*)(Channel channel, byte, byte);
using ProgramChangeCallback = void (*)(Channel channel, byte);
using AfterTouchChannelCallback = void (*)(Channel channel, byte);
using PitchBendCallback = void (*)(Channel channel, int);
using SystemExclusiveCallback = void (*)(byte * array, unsigned size);
using TimeCodeQuarterFrameCallback = void (*)(byte data);
using SongPositionCallback = void (*)(unsigned beats);
using SongSelectCallback = void (*)(byte songnumber);
using TuneRequestCallback = void (*)(void);
using ClockCallback = void (*)(void);
using StartCallback = void (*)(void);
using TickCallback = void (*)(void);
using ContinueCallback = void (*)(void);
using StopCallback = void (*)(void);
using ActiveSensingCallback = void (*)(void);
using SystemResetCallback = void (*)(void);
// -----------------------------------------------------------------------------
/*! Enumeration of MIDI types */
enum MidiType
enum MidiType: uint8_t
{
InvalidType = 0x00, ///< For notifying errors
NoteOff = 0x80, ///< Note Off
NoteOn = 0x90, ///< Note On
AfterTouchPoly = 0xA0, ///< Polyphonic AfterTouch
ControlChange = 0xB0, ///< Control Change / Channel Mode
ProgramChange = 0xC0, ///< Program Change
AfterTouchChannel = 0xD0, ///< Channel (monophonic) AfterTouch
PitchBend = 0xE0, ///< Pitch Bend
NoteOff = 0x80, ///< Channel Message - Note Off
NoteOn = 0x90, ///< Channel Message - Note On
AfterTouchPoly = 0xA0, ///< Channel Message - Polyphonic AfterTouch
ControlChange = 0xB0, ///< Channel Message - Control Change / Channel Mode
ProgramChange = 0xC0, ///< Channel Message - Program Change
AfterTouchChannel = 0xD0, ///< Channel Message - Channel (monophonic) AfterTouch
PitchBend = 0xE0, ///< Channel Message - Pitch Bend
SystemExclusive = 0xF0, ///< System Exclusive
SystemExclusiveStart = SystemExclusive, ///< System Exclusive Start
TimeCodeQuarterFrame = 0xF1, ///< System Common - MIDI Time Code Quarter Frame
SongPosition = 0xF2, ///< System Common - Song Position Pointer
SongSelect = 0xF3, ///< System Common - Song Select
Undefined_F4 = 0xF4,
Undefined_F5 = 0xF5,
TuneRequest = 0xF6, ///< System Common - Tune Request
SystemExclusiveEnd = 0xF7, ///< System Exclusive End
Clock = 0xF8, ///< System Real Time - Timing Clock
Undefined_F9 = 0xF9,
Tick = Undefined_F9, ///< System Real Time - Timing Tick (1 tick = 10 milliseconds)
Start = 0xFA, ///< System Real Time - Start
Continue = 0xFB, ///< System Real Time - Continue
Stop = 0xFC, ///< System Real Time - Stop
Undefined_FD = 0xFD,
ActiveSensing = 0xFE, ///< System Real Time - Active Sensing
SystemReset = 0xFF, ///< System Real Time - System Reset
};
@ -100,24 +135,13 @@ struct Thru
};
};
/*! Deprecated: use Thru::Mode instead.
Will be removed in v5.0.
*/
enum __attribute__ ((deprecated)) MidiFilterMode
{
Off = Thru::Off,
Full = Thru::Full,
SameChannel = Thru::SameChannel,
DifferentChannel = Thru::DifferentChannel,
};
// -----------------------------------------------------------------------------
/*! \brief Enumeration of Control Change command numbers.
See the detailed controllers numbers & description here:
http://www.somascape.org/midi/tech/spec.html#ctrlnums
*/
enum MidiControlChangeNumber
enum MidiControlChangeNumber: uint8_t
{
// High resolution Continuous Controllers MSB (+32 for LSB) ----------------
BankSelect = 0,
@ -140,8 +164,22 @@ enum MidiControlChangeNumber
GeneralPurposeController2 = 17,
GeneralPurposeController3 = 18,
GeneralPurposeController4 = 19,
// CC20 to CC31 undefined
BankSelectLSB = 32,
ModulationWheelLSB = 33,
BreathControllerLSB = 34,
// CC35 undefined
FootControllerLSB = 36,
PortamentoTimeLSB = 37,
DataEntryLSB = 38,
ChannelVolumeLSB = 39,
BalanceLSB = 40,
// CC41 undefined
PanLSB = 42,
ExpressionControllerLSB = 43,
EffectControl1LSB = 44,
EffectControl2LSB = 45,
// CC46 to CC63 undefined
// Switches ----------------------------------------------------------------
Sustain = 64,
@ -179,6 +217,7 @@ enum MidiControlChangeNumber
NRPNMSB = 99, ///< Non-Registered Parameter Number (MSB)
RPNLSB = 100, ///< Registered Parameter Number (LSB)
RPNMSB = 101, ///< Registered Parameter Number (MSB)
// CC102 to CC119 undefined
// Channel Mode messages ---------------------------------------------------
AllSoundOff = 120,
@ -193,7 +232,7 @@ enum MidiControlChangeNumber
struct RPN
{
enum RegisteredParameterNumbers
enum RegisteredParameterNumbers: uint16_t
{
PitchBendSensitivity = 0x0000,
ChannelFineTuning = 0x0001,
@ -205,35 +244,4 @@ struct RPN
};
};
// -----------------------------------------------------------------------------
/*! \brief Create an instance of the library attached to a serial port.
You can use HardwareSerial or SoftwareSerial for the serial port.
Example: MIDI_CREATE_INSTANCE(HardwareSerial, Serial2, midi2);
Then call midi2.begin(), midi2.read() etc..
*/
#define MIDI_CREATE_INSTANCE(Type, SerialPort, Name) \
midi::MidiInterface<Type> Name((Type&)SerialPort);
#if defined(ARDUINO_SAM_DUE) || defined(USBCON)
// Leonardo, Due and other USB boards use Serial1 by default.
#define MIDI_CREATE_DEFAULT_INSTANCE() \
MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI);
#else
/*! \brief Create an instance of the library with default name, serial port
and settings, for compatibility with sketches written with pre-v4.2 MIDI Lib,
or if you don't bother using custom names, serial port or settings.
*/
#define MIDI_CREATE_DEFAULT_INSTANCE() \
MIDI_CREATE_INSTANCE(HardwareSerial, Serial, MIDI);
#endif
/*! \brief Create an instance of the library attached to a serial port with
custom settings.
@see DefaultSettings
@see MIDI_CREATE_INSTANCE
*/
#define MIDI_CREATE_CUSTOM_INSTANCE(Type, SerialPort, Name, Settings) \
midi::MidiInterface<Type, Settings> Name((Type&)SerialPort);
END_MIDI_NAMESPACE

View File

@ -2,7 +2,6 @@
* @file midi_Message.h
* Project Arduino MIDI Library
* @brief MIDI Library for the Arduino - Message struct definition
* @version 4.3
* @author Francois Best
* @date 11/06/14
* @license MIT - Copyright (c) 2015 Francois Best
@ -30,6 +29,9 @@
#include "midi_Namespace.h"
#include "midi_Defs.h"
#ifndef ARDUINO
#include <string.h>
#endif
BEGIN_MIDI_NAMESPACE
@ -44,7 +46,7 @@ struct Message
*/
inline Message()
: channel(0)
, type(midi::InvalidType)
, type(MIDI_NAMESPACE::InvalidType)
, data1(0)
, data2(0)
, valid(false)
@ -52,6 +54,20 @@ struct Message
memset(sysexArray, 0, sSysExMaxSize * sizeof(DataByte));
}
inline Message(const Message& inOther)
: channel(inOther.channel)
, type(inOther.type)
, data1(inOther.data1)
, data2(inOther.data2)
, valid(inOther.valid)
, length(inOther.length)
{
if (type == midi::SystemExclusive)
{
memcpy(sysexArray, inOther.sysexArray, sSysExMaxSize * sizeof(DataByte));
}
}
/*! The maximum size for the System Exclusive array.
*/
static const unsigned sSysExMaxSize = SysExMaxSize;
@ -89,11 +105,27 @@ struct Message
*/
bool valid;
/*! Total Length of the message.
*/
unsigned length;
inline unsigned getSysExSize() const
{
const unsigned size = unsigned(data2) << 8 | data1;
return size > sSysExMaxSize ? sSysExMaxSize : size;
}
inline bool isSystemRealTime () const
{
return (type & 0xf8) == 0xf8;
}
inline bool isSystemCommon () const
{
return (type & 0xf8) == 0xf0;
}
inline bool isChannelMessage () const
{
return (type & 0xf0) != 0xf0;
}
};
END_MIDI_NAMESPACE

View File

@ -2,7 +2,6 @@
* @file midi_Namespace.h
* Project Arduino MIDI Library
* @brief MIDI Library for the Arduino - Namespace declaration
* @version 4.3
* @author Francois Best
* @date 24/02/11
* @license MIT - Copyright (c) 2015 Francois Best

View File

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

View File

@ -1,122 +0,0 @@
/*!
* @file midi_RingBuffer.hpp
* Project Arduino MIDI Library
* @brief MIDI Library for Arduino - Ring Buffer
* @version 4.3
* @author Francois Best
* @date 10/10/2016
* @license MIT - Copyright (c) 2016 Francois Best
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#pragma once
BEGIN_MIDI_NAMESPACE
template<typename DataType, int Size>
RingBuffer<DataType, Size>::RingBuffer()
: mWriteHead(mData)
, mReadHead(mData)
{
memset(mData, DataType(0), Size * sizeof(DataType));
}
template<typename DataType, int Size>
RingBuffer<DataType, Size>::~RingBuffer()
{
}
// -----------------------------------------------------------------------------
template<typename DataType, int Size>
int RingBuffer<DataType, Size>::getLength() const
{
if (mReadHead == mWriteHead)
{
return 0;
}
else if (mWriteHead > mReadHead)
{
return int(mWriteHead - mReadHead);
}
else
{
return int(mWriteHead - mData) + Size - int(mReadHead - mData);
}
}
template<typename DataType, int Size>
bool RingBuffer<DataType, Size>::isEmpty() const
{
return mReadHead == mWriteHead;
}
// -----------------------------------------------------------------------------
template<typename DataType, int Size>
void RingBuffer<DataType, Size>::write(DataType inData)
{
*mWriteHead++ = inData;
if (mWriteHead >= mData + Size)
{
mWriteHead = mData;
}
}
template<typename DataType, int Size>
void RingBuffer<DataType, Size>::write(const DataType* inData, int inSize)
{
for (int i = 0; i < inSize; ++i)
{
write(inData[i]);
}
}
template<typename DataType, int Size>
void RingBuffer<DataType, Size>::clear()
{
memset(mData, DataType(0), Size * sizeof(DataType));
mReadHead = mData;
mWriteHead = mData;
}
// -----------------------------------------------------------------------------
template<typename DataType, int Size>
DataType RingBuffer<DataType, Size>::read()
{
const DataType data = *mReadHead++;
if (mReadHead >= mData + Size)
{
mReadHead = mData;
}
return data;
}
template<typename DataType, int Size>
void RingBuffer<DataType, Size>::read(DataType* outData, int inSize)
{
for (int i = 0; i < inSize; ++i)
{
outData[i] = read();
}
}
END_MIDI_NAMESPACE

View File

@ -2,7 +2,6 @@
* @file midi_Settings.h
* Project Arduino MIDI Library
* @brief MIDI Library for the Arduino - Settings
* @version 4.3
* @author Francois Best
* @date 24/02/11
* @license MIT - Copyright (c) 2015 Francois Best
@ -39,18 +38,19 @@ BEGIN_MIDI_NAMESPACE
macro to create your instance. The settings you don't override will keep their
default value. Eg:
\code{.cpp}
struct MySettings : public midi::DefaultSettings
struct MySettings : public MIDI_NAMESPACE::DefaultSettings
{
static const unsigned SysExMaxSize = 1024; // Accept SysEx messages up to 1024 bytes long.
};
MIDI_CREATE_CUSTOM_INSTANCE(HardwareSerial, Serial2, midi, MySettings);
MIDI_CREATE_CUSTOM_INSTANCE(HardwareSerial, Serial2, MIDI, MySettings);
\endcode
*/
struct DefaultSettings
{
/*! Running status enables short messages when sending multiple values
of the same type and channel.\n
Must be disabled to send USB MIDI messages to a computer
Warning: does not work with some hardware, enable with caution.
*/
static const bool UseRunningStatus = false;
@ -67,16 +67,38 @@ struct DefaultSettings
*/
static const bool Use1ByteParsing = true;
/*! Override the default MIDI baudrate to transmit over USB serial, to
a decoding program such as Hairless MIDI (set baudrate to 115200)\n
http://projectgus.github.io/hairless-midiserial/
*/
static const long BaudRate = 31250;
/*! Maximum size of SysEx receivable. Decrease to save RAM if you don't expect
to receive SysEx, or adjust accordingly.
*/
static const unsigned SysExMaxSize = 128;
/*! Global switch to turn on/off sender ActiveSensing
Set to true to send ActiveSensing
Set to false will not send ActiveSensing message (will also save memory)
*/
static const bool UseSenderActiveSensing = false;
/*! Global switch to turn on/off receiver ActiveSensing
Set to true to check for message timeouts (via ErrorCallback)
Set to false will not check if chained device are still alive (if they use ActiveSensing) (will also save memory)
*/
static const bool UseReceiverActiveSensing = false;
/*! Active Sensing is intended to be sent
repeatedly by the sender to tell the receiver that a connection is alive. Use
of this message is optional. When initially received, the
receiver will expect to receive another Active Sensing
message each 300ms (max), and if it does not then it will
assume that the connection has been terminated. At
termination, the receiver will turn off all voices and return to
normal (non- active sensing) operation.
Typical value is 250 (ms) - an Active Sensing command is send every 250ms.
(All Roland devices send Active Sensing every 250ms)
Setting this field to 0 will disable sending MIDI active sensing.
*/
static const uint16_t SenderActiveSensingPeriodicity = 0;
};
END_MIDI_NAMESPACE

View File

@ -1,145 +0,0 @@
/*!
* @file midi_UsbDefs.h
* Project Arduino MIDI Library
* @brief MIDI Library for the Arduino - Definitions
* @version 4.3
* @author Francois Best
* @date 24/02/11
* @license MIT - Copyright (c) 2016 Francois Best
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#pragma once
#include "midi_Defs.h"
BEGIN_MIDI_NAMESPACE
struct CodeIndexNumbers
{
enum
{
reserved = 0x00,
misc = reserved,
cableEvent = 0x01,
systemCommon2Bytes = 0x02,
systemCommon3Bytes = 0x03,
sysExStart = 0x04,
sysExContinue = sysExStart,
systemCommon1Byte = 0x05,
sysExEnds1Byte = systemCommon1Byte,
sysExEnds2Bytes = 0x06,
sysExEnds3Bytes = 0x07,
noteOff = 0x08,
noteOn = 0x09,
polyPressure = 0x0A,
controlChange = 0x0B,
programChange = 0x0C,
channelPressure = 0x0D,
pitchBend = 0x0E,
singleByte = 0x0F,
};
static inline byte getSize(byte inCodeIndexNumber)
{
switch (inCodeIndexNumber)
{
case noteOn:
case noteOff:
case controlChange:
case pitchBend:
case polyPressure:
case systemCommon3Bytes:
case sysExEnds3Bytes:
case sysExStart:
return 3;
case programChange:
case channelPressure:
case systemCommon2Bytes:
case sysExEnds2Bytes:
return 2;
case systemCommon1Byte:
case singleByte:
return 1;
default:
break;
}
return 0; // Can be any length (1, 2 or 3).
}
};
// -----------------------------------------------------------------------------
struct UsbMidiEventPacket
{
public:
inline UsbMidiEventPacket()
{
memset(mData, 0, 4 * sizeof(byte));
}
public:
inline void setHeader(byte inCableNumber, byte inCodeIndexNumber)
{
const byte msb = (0x0f & inCableNumber) << 4;
const byte lsb = (0x0f & inCodeIndexNumber);
mData[0] = msb | lsb;
}
inline void setMidiData(const byte* inData)
{
mData[1] = *inData++;
mData[2] = *inData++;
mData[3] = *inData;
}
inline byte getCableNumber() const
{
return mData[0] >> 4;
}
inline byte getCodeIndexNumber() const
{
return mData[0] & 0x0f;
}
inline const byte* getMidiData() const
{
return mData + 1;
}
inline byte* getMidiData()
{
return mData + 1;
}
inline UsbMidiEventPacket& operator=(const byte* inData)
{
mData[0] = *inData++;
setMidiData(inData);
return *this;
}
public:
byte mData[4];
};
END_MIDI_NAMESPACE

View File

@ -1,73 +0,0 @@
/*!
* @file midi_UsbTransport.h
* Project Arduino MIDI Library
* @brief MIDI Library for the Arduino - Transport layer for USB MIDI
* @version 4.3
* @author Francois Best
* @date 10/10/2016
* @license MIT - Copyright (c) 2016 Francois Best
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#pragma once
#include "midi_Defs.h"
#include "midi_RingBuffer.h"
#include <MIDIUSB.h>
BEGIN_MIDI_NAMESPACE
template<unsigned BuffersSize>
class UsbTransport
{
public:
inline UsbTransport();
inline ~UsbTransport();
public: // Serial / Stream API required for template compatibility
inline void begin(unsigned inBaudrate);
inline unsigned available();
inline byte read();
inline void write(byte inData);
private:
inline bool pollUsbMidi();
inline void recomposeAndSendTxPackets();
inline void resetTx();
static inline byte encodePacketHeader(StatusByte inStatusByte);
static inline int getPacketLength(const midiEventPacket_t& inPacket);
private:
typedef RingBuffer<byte, BuffersSize> Buffer;
Buffer mTxBuffer;
Buffer mRxBuffer;
union TxPacket
{
byte mDataArray[4];
midiEventPacket_t mPacket;
};
TxPacket mCurrentTxPacket;
int mCurrentTxPacketByteIndex;
};
END_MIDI_NAMESPACE
#include "midi_UsbTransport.hpp"

View File

@ -1,181 +0,0 @@
/*!
* @file midi_UsbTransport.hpp
* Project Arduino MIDI Library
* @brief MIDI Library for the Arduino - Transport layer for USB MIDI
* @version 4.3
* @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 Normal file
View File

@ -0,0 +1,130 @@
/*!
* @file serialMIDI.h
* Project Arduino MIDI Library
* @brief MIDI Library for the Arduino - Platform
* @license MIT - Copyright (c) 2015 Francois Best
* @author lathoub, Francois Best
* @date 22/03/20
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#pragma once
#include "midi_Namespace.h"
BEGIN_MIDI_NAMESPACE
struct DefaultSerialSettings
{
/*! Override the default MIDI baudrate to transmit over USB serial, to
a decoding program such as Hairless MIDI (set baudrate to 115200)\n
http://projectgus.github.io/hairless-midiserial/
*/
static const long BaudRate = 31250;
};
template <class SerialPort, class _Settings = DefaultSerialSettings>
class SerialMIDI
{
typedef _Settings Settings;
public:
SerialMIDI(SerialPort& inSerial)
: mSerial(inSerial)
{
};
public:
static const bool thruActivated = true;
void begin()
{
// Initialise the Serial port
#if defined(AVR_CAKE)
mSerial. template open<Settings::BaudRate>();
#else
mSerial.begin(Settings::BaudRate);
#endif
}
void end()
{
mSerial.end();
}
bool beginTransmission(MidiType)
{
return true;
};
void write(byte value)
{
mSerial.write(value);
};
void endTransmission()
{
};
byte read()
{
return mSerial.read();
};
unsigned available()
{
return mSerial.available();
};
private:
SerialPort& mSerial;
};
END_MIDI_NAMESPACE
/*! \brief Create an instance of the library attached to a serial port.
You can use HardwareSerial or SoftwareSerial for the serial port.
Example: MIDI_CREATE_INSTANCE(HardwareSerial, Serial2, midi2);
Then call midi2.begin(), midi2.read() etc..
*/
#define MIDI_CREATE_INSTANCE(Type, SerialPort, Name) \
MIDI_NAMESPACE::SerialMIDI<Type> serial##Name(SerialPort);\
MIDI_NAMESPACE::MidiInterface<MIDI_NAMESPACE::SerialMIDI<Type>> Name((MIDI_NAMESPACE::SerialMIDI<Type>&)serial##Name);
#if defined(ARDUINO_SAM_DUE) || defined(USBCON) || defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MKL26Z64__)
// Leonardo, Due and other USB boards use Serial1 by default.
#define MIDI_CREATE_DEFAULT_INSTANCE() \
MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI);
#else
/*! \brief Create an instance of the library with default name, serial port
and settings, for compatibility with sketches written with pre-v4.2 MIDI Lib,
or if you don't bother using custom names, serial port or settings.
*/
#define MIDI_CREATE_DEFAULT_INSTANCE() \
MIDI_CREATE_INSTANCE(HardwareSerial, Serial, MIDI);
#endif
/*! \brief Create an instance of the library attached to a serial port with
custom settings.
@see DefaultSettings
@see MIDI_CREATE_INSTANCE
*/
#define MIDI_CREATE_CUSTOM_INSTANCE(Type, SerialPort, Name, Settings) \
MIDI_NAMESPACE::SerialMIDI<Type> serial##Name(SerialPort);\
MIDI_NAMESPACE::MidiInterface<MIDI_NAMESPACE::SerialMIDI<Type>, Settings> Name((MIDI_NAMESPACE::SerialMIDI<Type>&)serial##Name);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,75 +0,0 @@
#include "unit-tests.h"
#include <src/midi_UsbDefs.h>
BEGIN_MIDI_NAMESPACE
END_MIDI_NAMESPACE
// -----------------------------------------------------------------------------
BEGIN_UNNAMED_NAMESPACE
TEST(MidiUsb, codeIndexNumberSizes)
{
typedef midi::CodeIndexNumbers CIN;
EXPECT_EQ(CIN::getSize(CIN::reserved), 0);
EXPECT_EQ(CIN::getSize(CIN::misc), 0);
EXPECT_EQ(CIN::getSize(CIN::cableEvent), 0);
EXPECT_EQ(CIN::getSize(CIN::systemCommon2Bytes), 2);
EXPECT_EQ(CIN::getSize(CIN::systemCommon3Bytes), 3);
EXPECT_EQ(CIN::getSize(CIN::sysExStart), 3);
EXPECT_EQ(CIN::getSize(CIN::sysExContinue), 3);
EXPECT_EQ(CIN::getSize(CIN::systemCommon1Byte), 1);
EXPECT_EQ(CIN::getSize(CIN::sysExEnds1Byte), 1);
EXPECT_EQ(CIN::getSize(CIN::sysExEnds2Bytes), 2);
EXPECT_EQ(CIN::getSize(CIN::sysExEnds3Bytes), 3);
EXPECT_EQ(CIN::getSize(CIN::noteOff), 3);
EXPECT_EQ(CIN::getSize(CIN::noteOn), 3);
EXPECT_EQ(CIN::getSize(CIN::polyPressure), 3);
EXPECT_EQ(CIN::getSize(CIN::controlChange), 3);
EXPECT_EQ(CIN::getSize(CIN::programChange), 2);
EXPECT_EQ(CIN::getSize(CIN::channelPressure), 2);
EXPECT_EQ(CIN::getSize(CIN::pitchBend), 3);
EXPECT_EQ(CIN::getSize(CIN::singleByte), 1);
}
TEST(MidiUsb, UsbMidiEventPacket)
{
midi::UsbMidiEventPacket packet;
EXPECT_EQ(packet.mData[0], 0);
EXPECT_EQ(packet.mData[1], 0);
EXPECT_EQ(packet.mData[2], 0);
EXPECT_EQ(packet.mData[3], 0);
EXPECT_EQ(packet.getCableNumber(), 0);
EXPECT_EQ(packet.getCodeIndexNumber(), 0);
packet.setHeader(12, 7);
EXPECT_EQ(packet.mData[0], 0xc7);
EXPECT_EQ(packet.getCableNumber(), 12);
EXPECT_EQ(packet.getCodeIndexNumber(), 7);
const byte midiData[3] = { 12, 42, 47 };
packet.setMidiData(midiData);
EXPECT_EQ(packet.mData[0], 0xc7);
EXPECT_EQ(packet.mData[1], 12);
EXPECT_EQ(packet.mData[2], 42);
EXPECT_EQ(packet.mData[3], 47);
const byte fullData[4] = { 12, 34, 56, 78 };
packet = fullData;
EXPECT_EQ(packet.mData[0], 12);
EXPECT_EQ(packet.mData[1], 34);
EXPECT_EQ(packet.mData[2], 56);
EXPECT_EQ(packet.mData[3], 78);
const byte* midiDataConst = packet.getMidiData();
EXPECT_EQ(midiDataConst[0], 34);
EXPECT_EQ(midiDataConst[1], 56);
EXPECT_EQ(midiDataConst[2], 78);
byte* midiDataMutable = packet.getMidiData();
EXPECT_EQ(midiDataMutable[0], 34);
EXPECT_EQ(midiDataMutable[1], 56);
EXPECT_EQ(midiDataMutable[2], 78);
}
END_UNNAMED_NAMESPACE

View File

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

View File

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

View File

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