From 1d09cf3a0a4723b2b918d55d1a54be8f371f57ae Mon Sep 17 00:00:00 2001 From: Francois Best Date: Thu, 10 Apr 2014 14:32:08 +0200 Subject: [PATCH 001/138] USB defs. --- src/midi_USB.h | 106 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 src/midi_USB.h diff --git a/src/midi_USB.h b/src/midi_USB.h new file mode 100644 index 0000000..7ff7875 --- /dev/null +++ b/src/midi_USB.h @@ -0,0 +1,106 @@ +/*! + * @file midi_USB.h + * Project Arduino MIDI Library + * @brief MIDI Library for the Arduino - USB + * @version 4.1 + * @author Francois Best + * @date 24/02/11 + * @license GPL v3.0 - Copyright Forty Seven Effects 2014 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "midi_Namespace.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, + noteOn = 0x08, + noteOff = 0x09, + polyKeyPress = 0x0A, + controlChange = 0x0B, + programChange = 0x0C, + channelPressure = 0x0D, + pitchBend = 0x0E, + singleByte = 0x0F, + }; + + inline byte getSize(byte inCIN) + { + switch (inCIN) + { + case noteOn: + case noteOff: + case controlChange: + case pitchBend: + case polyKeyPress: + case systemCommon3Bytes: + case sysExEnds3Bytes: + return 3; + + case programChange: + case channelPressure: + case systemCommon2Bytes: + case sysExEnds2Bytes: + return 2; + + case systemCommon1Byte: + case singleByte: + return 1; + + default: + break; + } + return 0; + } +}; + +// ----------------------------------------------------------------------------- + +struct UsbMidiEvent +{ + union + { + uint32_t mRawData; + struct + { + byte mCableNumber:4; + byte mCodeIndexNumber:4; + byte mMidi[3]; + }; + byte[4] mDataArray; + }; +}; + +END_MIDI_NAMESPACE From c7d2ced229090eb9f30b649687c92875b65471f4 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Sun, 19 Apr 2015 18:28:53 +0200 Subject: [PATCH 002/138] Readme edits, removed arduino-playground (no longer used). --- README.md | 27 +++++++------- arduino-playground.md | 86 ------------------------------------------- 2 files changed, 14 insertions(+), 99 deletions(-) delete mode 100644 arduino-playground.md diff --git a/README.md b/README.md index 95780e6..4d0eb90 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ #Arduino MIDI Library v4.2 This library enables MIDI I/O communications on the Arduino serial ports. -The purpose of this library is not to make a big synthetizer out of an Arduino board, the application remains yours. However, it will help you interfacing it with other MIDI devices. +The purpose of this library is not to make a big synthesizer out of an Arduino board, the application remains yours. However, it will help you interfacing it with other MIDI devices. Download the latest version [here](https://github.com/FortySevenEffects/arduino_midi_library/releases/latest). ### Features -* Compatible with all Arduino boards (and clones with an AVR processor) +* 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. @@ -21,7 +21,7 @@ Download the latest version [here](https://github.com/FortySevenEffects/arduino_ * 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) +* 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. @@ -36,26 +36,27 @@ Download the latest version [here](https://github.com/FortySevenEffects/arduino_ ### What do I need to do? -* Download the library ([link](https://github.com/FortySevenEffects/arduino_midi_library/releases/latest)) -* Follow the installation instructions there: http://arduino.cc/en/Guide/Libraries +* Download the library ([link](https://github.com/FortySevenEffects/arduino_midi_library/releases/latest)). +* Follow the installation instructions - http://arduino.cc/en/Guide/Libraries. * Include the library in your sketch using the menu in the IDE, or type `#include ` * Create the MIDI instance using `MIDI_CREATE_DEFAULT_INSTANCE();` or take a look at the documentation for custom serial port, settings etc.. -You are now ready to use the library. Look at the reference page to learn how to use it, or the examples given. Just don't forget to enable the I/O communications with MIDI.begin... +You are now ready to use the library. Look at the documentation to learn how to use it, or checkout the examples installed with the Library. +You can also watch the awesome video tutorials from [Notes & Volts](https://www.youtube.com/playlist?list=PL4_gPbvyebyH2xfPXePHtx8gK5zPBrVkg). -##Reference +##Documentation -See the extended reference [here](http://arduinomidilib.fortyseveneffects.com) ([Mirror](http://fortyseveneffects.github.io/arduino_midi_library/)). +See the extended documentation [here](http://arduinomidilib.fortyseveneffects.com) ([Mirror](http://fortyseveneffects.github.io/arduino_midi_library/)). ### Using MIDI.begin In the `setup()` function of the Arduino, you must call the `MIDI.begin()` method. If you don't give any argument to this method, the input channel for MIDI in will be set to 1 (channels are going from 1 to 16, plus `MIDI_CHANNEL_OMNI to listen to all channels at the same time). This method will: -* Start the serial port at the MIDI baudrate (31250) -* Set the input channel at the argument given (if any, else 1) -* Enable Soft Thru, without filtering (everything at the input is sent back) +* Start the serial port at the MIDI baudrate (31250). +* Set the input channel at the argument given (if any, else 1). +* Enable Soft Thru, without filtering (everything at the input is sent back). @@ -63,14 +64,14 @@ This method will: The MIDI Thru allows you to redirect your incoming messages to the MIDI output. It replaces the need of a MIDI Thru connector, as it copies every valid incoming message from the input. For good performance, you might want to call read() in a fast loop, for low latency. -Incoming unread bytes/messages are kept in the Arduino serial buffer, in order not to flood it, check regularily with MIDI.read. See the reference for Thru explanations. +Incoming unread bytes/messages are kept in the Arduino serial buffer, in order not to flood it, check regularily with MIDI.read. See the documentation for Thru explanations. Thru is enabled by default, you can turn it off using appropriate methods. ### Hardware -Take a look at [the MIDI.org schematic](http://www.midi.org/techspecs/electrispec.php) +Take a look at [the MIDI.org schematic](http://www.midi.org/techspecs/electrispec.php). ## Contact diff --git a/arduino-playground.md b/arduino-playground.md deleted file mode 100644 index b68cd95..0000000 --- a/arduino-playground.md +++ /dev/null @@ -1,86 +0,0 @@ -!!MIDI Library v4.1 - -This library enables MIDI I/O communications on the Arduino serial ports. You can send and receive messages of all kinds (including System Exclusive, RealTime etc..). The purpose of this library is not to make a big synthetizer out of an Arduino board, the application remains yours. However, it will help you interfacing it with other MIDI devices. - -Download the latest version [[ https://github.com/FortySevenEffects/arduino_midi_library/releases/download/4.1/Arduino_MIDI_Library_v4.1.zip | here ]]. - -You can now follow the developments on [[ http://github.com/FortySevenEffects/arduino_midi_library/ | GitHub]]. - - -!!!!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. -* [[ http://playground.arduino.cc/Main/MIDILibraryCallbacks | Callbacks]] to handle input messages more easily. -* Last received message is saved until a new one arrives. -* Configurable: disable input or output if you don't need it, and get the pin back for IO use (and save some flash space). -* Create more than one MIDI port for mergers/splitters applications. -* Use any serial port, hardware or software. - - -!!!!Changelog: -* 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 [[ http://sourceforge.net/news/?group_id=265194 | here ]] -* 06/05/2011 : Version 3.1 released. Added [[ http://playground.arduino.cc/Main/MIDILibraryCallbacks | callback]] support. -* 06/03/2011 : Version 3.0 released. Project is now hosted on [[ http://sourceforge.net/projects/arduinomidilib/ | SourceForge]]. -* 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 operationnal. Added some features to enable thru. - -!!!!Warning: this library requires Arduino 1.0 or more recent versions. - - -!!!What do I need to do? - -* Download the library ([[ https://github.com/FortySevenEffects/arduino_midi_library/releases/download/4.1/Arduino_MIDI_Library_v4.1.zip | link ]]) -* Follow the installation instructions there: http://arduino.cc/en/Guide/Libraries -* Include the library in your sketch using the menu in the IDE, or type [@#include @] - -You are now ready to use the library. Look at the reference page to learn how to use it, or the examples given. Just don't forget to enable the I/O communications with MIDI.begin... - - -!!Reference - -See the extended reference [[ http://arduinomidilib.fortyseveneffects.com | here ]]. -Mirror: [[ http://fortyseveneffects.github.io/arduino_midi_library/ | GitHub ]]. - -To know how to use the callback feature, see the dedicated page [[ http://playground.arduino.cc/Main/MIDILibraryCallbacks | here]]. - - -!!A few things... - -!!!Using MIDI.begin - -In the setup() function of the Arduino, you must call the MIDI.begin method. If you don't give any argument to this method, the input channel for MIDI in will be set to 1 (channels are going from 1 to 16, plus MIDI_CHANNEL_OMNI to listen to all channels at the same time). - -This method will: -* Start the serial port at the MIDI baudrate (31250) -* Set the input channel at the argument given (if any, else 1) -* Enable Soft Thru, without filtering (everything at the input is sent back) - - - -!!!MIDI Thru - -The MIDI Thru allows you to redirect your incoming messages to the MIDI output. It replaces the need of a MIDI Thru connector, as it copies every valid incoming message from the input. For good performance, you might want to call read() in a fast loop, for low latency. - -Incoming unread bytes/messages are kept in the Arduino serial buffer, in order not to flood it, check regularily with MIDI.read. See the reference for Thru explanations. - -Thru is enabled by default, you can turn it off using appropriate methods. - - -!!!Hardware - -Take a look at [[ http://www.midi.org/techspecs/electrispec.php | the MIDI.org schematic ]] - - -!!Contact -if you have any comment or support request to make, feel free to contact me at francois.best{at}fortyseveneffects[dot]com. - -You can follow the developments on GitHub: -[[ http://github.com/FortySevenEffects/arduino_midi_library/tree/dev ]] - -You can also get informations about bug fixes and updates on my twitter account: @fortysevenfx. From fb693e724508cb8a473fa0bf1915101134206c34 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Thu, 13 Aug 2015 09:03:17 +0200 Subject: [PATCH 003/138] Changed license to MIT. --- README.md | 4 ++++ src/MIDI.cpp | 27 +++++++++++++++---------- src/MIDI.h | 27 +++++++++++++++---------- src/MIDI.hpp | 27 +++++++++++++++---------- src/midi_Defs.h | 27 +++++++++++++++---------- src/midi_Message.h | 27 +++++++++++++++---------- src/midi_Namespace.h | 27 +++++++++++++++---------- src/midi_Settings.h | 48 +++++++++++++++++++++++++------------------- 8 files changed, 127 insertions(+), 87 deletions(-) diff --git a/README.md b/README.md index 4d0eb90..60b3a64 100644 --- a/README.md +++ b/README.md @@ -78,3 +78,7 @@ Take a look at [the MIDI.org schematic](http://www.midi.org/techspecs/electrispe if you have any comment or support request to make, feel free to contact me: francois.best@fortyseveneffects.com You can also get informations about bug fixes and updates on my twitter account: [@fortysevenfx](http://twitter.com/fortysevenfx). + +## License + +MIT © 2015 [Francois Best](http://fortyseveneffects.com) diff --git a/src/MIDI.cpp b/src/MIDI.cpp index 0ed34b9..c117d5a 100644 --- a/src/MIDI.cpp +++ b/src/MIDI.cpp @@ -5,20 +5,25 @@ * @version 4.2 * @author Francois Best * @date 24/02/11 - * @license GPL v3.0 - Copyright Forty Seven Effects 2014 + * @license MIT - Copyright (c) 2015 Francois Best * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * 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: * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * 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. */ #include "MIDI.h" diff --git a/src/MIDI.h b/src/MIDI.h index d627c38..272e6b4 100644 --- a/src/MIDI.h +++ b/src/MIDI.h @@ -5,20 +5,25 @@ * @version 4.2 * @author Francois Best * @date 24/02/11 - * @license GPL v3.0 - Copyright Forty Seven Effects 2014 + * @license MIT - Copyright (c) 2015 Francois Best * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * 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: * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * 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 diff --git a/src/MIDI.hpp b/src/MIDI.hpp index 7e79d3c..ba6e6d0 100644 --- a/src/MIDI.hpp +++ b/src/MIDI.hpp @@ -5,20 +5,25 @@ * @version 4.2 * @author Francois Best * @date 24/02/11 - * @license GPL v3.0 - Copyright Forty Seven Effects 2014 + * @license MIT - Copyright (c) 2015 Francois Best * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * 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: * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * 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 diff --git a/src/midi_Defs.h b/src/midi_Defs.h index 3404797..b45e6d9 100644 --- a/src/midi_Defs.h +++ b/src/midi_Defs.h @@ -5,20 +5,25 @@ * @version 4.2 * @author Francois Best * @date 24/02/11 - * @license GPL v3.0 - Copyright Forty Seven Effects 2014 + * @license MIT - Copyright (c) 2015 Francois Best * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * 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: * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * 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 diff --git a/src/midi_Message.h b/src/midi_Message.h index 31ee3d1..1c3a3cd 100644 --- a/src/midi_Message.h +++ b/src/midi_Message.h @@ -5,20 +5,25 @@ * @version 4.2 * @author Francois Best * @date 11/06/14 - * @license GPL v3.0 - Copyright Forty Seven Effects 2014 + * @license MIT - Copyright (c) 2015 Francois Best * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * 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: * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * 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 diff --git a/src/midi_Namespace.h b/src/midi_Namespace.h index 4b93929..efd2395 100644 --- a/src/midi_Namespace.h +++ b/src/midi_Namespace.h @@ -5,20 +5,25 @@ * @version 4.2 * @author Francois Best * @date 24/02/11 - * @license GPL v3.0 - Copyright Forty Seven Effects 2014 + * @license MIT - Copyright (c) 2015 Francois Best * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * 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: * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * 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 diff --git a/src/midi_Settings.h b/src/midi_Settings.h index cf9a3dc..27e4be4 100644 --- a/src/midi_Settings.h +++ b/src/midi_Settings.h @@ -5,20 +5,25 @@ * @version 4.2 * @author Francois Best * @date 24/02/11 - * @license GPL v3.0 - Copyright Forty Seven Effects 2014 + * @license MIT - Copyright (c) 2015 Francois Best * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * 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: * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * 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 @@ -45,20 +50,21 @@ BEGIN_MIDI_NAMESPACE struct DefaultSettings { /*! Running status enables short messages when sending multiple values - of the same type and channel.\n - Set to 0 if you have troubles controlling your hardware. - */ + of the same type and channel.\n + Set to false if you have troubles controlling your hardware. + */ static const bool UseRunningStatus = true; - /* NoteOn with 0 velocity should be handled as NoteOf.\n - Set to 1 to get NoteOff events when receiving null-velocity NoteOn messages.\n - Set to 0 to get NoteOn events when receiving null-velocity NoteOn messages. - */ + /*! NoteOn with 0 velocity should be handled as NoteOf.\n + Set to true to get NoteOff events when receiving null-velocity NoteOn messages.\n + Set to false to get NoteOn events when receiving null-velocity NoteOn messages. + */ static const bool HandleNullVelocityNoteOnAsNoteOff = true; - // Setting this to 1 will make MIDI.read parse only one byte of data for each - // call when data is available. This can speed up your application if receiving - // a lot of traffic, but might induce MIDI Thru and treatment latency. + /*! Setting this to true will make MIDI.read parse only one byte of data for each + call when data is available. This can speed up your application if receiving + a lot of traffic, but might induce MIDI Thru and treatment latency. + */ static const bool Use1ByteParsing = true; /*! Override the default MIDI baudrate to transmit over USB serial, to From 219797524d75054bf397fbecbd633128a306aff4 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Sun, 3 Apr 2016 17:58:00 +0200 Subject: [PATCH 004/138] Fixed MIDI.read with input channel parameter. --- src/MIDI.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/MIDI.hpp b/src/MIDI.hpp index ba6e6d0..c57cc2b 100644 --- a/src/MIDI.hpp +++ b/src/MIDI.hpp @@ -797,8 +797,8 @@ inline bool MidiInterface::inputFilter(Channel inChannel) if (mMessage.type >= NoteOff && mMessage.type <= PitchBend) { // Then we need to know if we listen to it - if ((mMessage.channel == mInputChannel) || - (mInputChannel == MIDI_CHANNEL_OMNI)) + if ((mMessage.channel == inChannel) || + (inChannel == MIDI_CHANNEL_OMNI)) { return true; } From 79c01a27a4aad6fffb352134c9325f54bcad7662 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Sun, 3 Apr 2016 17:58:33 +0200 Subject: [PATCH 005/138] Added RPN/NRPN definitions. --- src/midi_Defs.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/midi_Defs.h b/src/midi_Defs.h index b45e6d9..e5e1170 100644 --- a/src/midi_Defs.h +++ b/src/midi_Defs.h @@ -122,6 +122,8 @@ enum MidiControlChangeNumber GeneralPurposeController3 = 18, GeneralPurposeController4 = 19, + DataEntryLSB = 38, + // Switches ---------------------------------------------------------------- Sustain = 64, Portamento = 65, @@ -152,6 +154,12 @@ enum MidiControlChangeNumber Effects3 = 93, ///< Chorus send level Effects4 = 94, ///< Celeste depth Effects5 = 95, ///< Phaser depth + DataIncrement = 96, + DataDecrement = 97, + NRPN = 98, ///< Non-Registered Parameter Number (LSB) + NRPNMSB = 99, ///< Non-Registered Parameter Number (MSB) + RPN = 100, ///< Registered Parameter Number (LSB) + RPNMSB = 101, ///< Registered Parameter Number (MSB) // Channel Mode messages --------------------------------------------------- AllSoundOff = 120, @@ -164,6 +172,24 @@ enum MidiControlChangeNumber PolyModeOn = 127 }; +struct RPN +{ +#define MIDI_MAKE_RPN(msb, lsb) msb << 7 + lsb + + enum RegisteredParameterNumbers + { + PitchBendSensitivity = MIDI_MAKE_RPN(0x00, 0x00), + ChannelFineTuning = MIDI_MAKE_RPN(0x00, 0x01), + ChannelCoarseTuning = MIDI_MAKE_RPN(0x00, 0x02), + SelectTuningProgram = MIDI_MAKE_RPN(0x00, 0x03), + SelectTuningBank = MIDI_MAKE_RPN(0x00, 0x04), + ModulationDepthRange = MIDI_MAKE_RPN(0x00, 0x05), + NullFunction = MIDI_MAKE_RPN(0x7f, 0x7f), + }; + +#undef MIDI_MAKE_RPN +}; + // ----------------------------------------------------------------------------- /*! \brief Create an instance of the library attached to a serial port. From 5b3e4ac0977a2a66ccb62e39f6c6c96aa6d3cdc4 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Sun, 24 Apr 2016 18:27:16 +0200 Subject: [PATCH 006/138] Fix warnings. --- src/midi_Defs.h | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/midi_Defs.h b/src/midi_Defs.h index e5e1170..b8f2985 100644 --- a/src/midi_Defs.h +++ b/src/midi_Defs.h @@ -174,20 +174,16 @@ enum MidiControlChangeNumber struct RPN { -#define MIDI_MAKE_RPN(msb, lsb) msb << 7 + lsb - enum RegisteredParameterNumbers { - PitchBendSensitivity = MIDI_MAKE_RPN(0x00, 0x00), - ChannelFineTuning = MIDI_MAKE_RPN(0x00, 0x01), - ChannelCoarseTuning = MIDI_MAKE_RPN(0x00, 0x02), - SelectTuningProgram = MIDI_MAKE_RPN(0x00, 0x03), - SelectTuningBank = MIDI_MAKE_RPN(0x00, 0x04), - ModulationDepthRange = MIDI_MAKE_RPN(0x00, 0x05), - NullFunction = MIDI_MAKE_RPN(0x7f, 0x7f), + PitchBendSensitivity = 0x0000, + ChannelFineTuning = 0x0001, + ChannelCoarseTuning = 0x0002, + SelectTuningProgram = 0x0003, + SelectTuningBank = 0x0004, + ModulationDepthRange = 0x0005, + NullFunction = (0x7f << 7) + 0x7f, }; - -#undef MIDI_MAKE_RPN }; // ----------------------------------------------------------------------------- From d48f371b96c2fa232e86287b7dc560ba09e73cad Mon Sep 17 00:00:00 2001 From: Francois Best Date: Tue, 26 Jul 2016 18:32:12 +0200 Subject: [PATCH 007/138] Fixed #48: created properties file for Arduino IDE. --- library.properties | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 library.properties diff --git a/library.properties b/library.properties new file mode 100644 index 0000000..e09d900 --- /dev/null +++ b/library.properties @@ -0,0 +1,10 @@ +name=MIDI Library +version=4.2.0 +author=Forty Seven Effects +maintainer=Francois Best +sentence=MIDI I/Os for Arduino +paragraph=Read & send MIDI messages to interface with your controllers and synths +category=Communication +url=https://github.com/FortySevenEffects/arduino_midi_library +architectures=* +includes=MIDI.h From 55f91d54aac28931e6a946229a18fdccea19c336 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Fri, 19 Aug 2016 14:58:39 +0200 Subject: [PATCH 008/138] Fix float pitch bend. --- src/MIDI.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MIDI.hpp b/src/MIDI.hpp index c57cc2b..12d0019 100644 --- a/src/MIDI.hpp +++ b/src/MIDI.hpp @@ -284,7 +284,7 @@ template void MidiInterface::sendPitchBend(double inPitchValue, Channel inChannel) { - const int value = inPitchValue * MIDI_PITCHBEND_MAX * Settings::Toto; + const int value = int(inPitchValue * double(MIDI_PITCHBEND_MAX)); sendPitchBend(value, inChannel); } From 40d20e3042de3612056a2f312106e10766370b03 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sat, 20 Aug 2016 22:01:02 +0300 Subject: [PATCH 009/138] Update version and name --- library.json | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/library.json b/library.json index a3b6065..15992bd 100644 --- a/library.json +++ b/library.json @@ -1,8 +1,9 @@ { - "name": "Arduino-MIDI", + "name": "MIDI Library", + "version": "4.2", "keywords": "midi", "description": "This library enables MIDI I/O communications on the Arduino serial ports", - "author": + "authors": { "name": "Francois Best", "email": "francois.best@fortyseveneffects.com", @@ -14,5 +15,7 @@ "url": "https://github.com/FortySevenEffects/arduino_midi_library.git" }, "include": "src", - "examples": "res/Examples/*/*.ino" + "examples": "res/Examples/*/*.ino", + "frameworks": "arduino", + "platforms": "atmelavr" } From d96b886bd5facfc7b81b06fa55cecdf1562dadd7 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Mon, 3 Oct 2016 10:17:34 -0700 Subject: [PATCH 010/138] Added include paths in VSCode. --- .vscode/c_cpp_properties.json | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 .vscode/c_cpp_properties.json diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..7c19b39 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,31 @@ +{ + "configurations": [ + { + "name": "Mac", + "includePath": [ + "/Applications/Arduino.app/Contents/Java/hardware/tools/avr/include", + "/Applications/Arduino.app/Contents/Java/hardware/arduino/avr/cores/arduino" + ], + "browse" : { + "limitSymbolsToIncludedHeaders" : true, + "databaseFilename" : "" + } + }, + { + "name": "Linux", + "includePath": ["/usr/include"], + "browse" : { + "limitSymbolsToIncludedHeaders" : true, + "databaseFilename" : "" + } + }, + { + "name": "Win32", + "includePath": ["c:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include"], + "browse" : { + "limitSymbolsToIncludedHeaders" : true, + "databaseFilename" : "" + } + } + ] +} From e4e5d8bfcc904896caa4895a0f77d6c163fbadbe Mon Sep 17 00:00:00 2001 From: Francois Best Date: Mon, 3 Oct 2016 10:18:01 -0700 Subject: [PATCH 011/138] Doc: remove noTone to keep osc active when using external envelopes. --- res/Examples/MIDI_SimpleSynth/MIDI_SimpleSynth.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/Examples/MIDI_SimpleSynth/MIDI_SimpleSynth.ino b/res/Examples/MIDI_SimpleSynth/MIDI_SimpleSynth.ino index c953885..d1ea184 100644 --- a/res/Examples/MIDI_SimpleSynth/MIDI_SimpleSynth.ino +++ b/res/Examples/MIDI_SimpleSynth/MIDI_SimpleSynth.ino @@ -39,7 +39,7 @@ void handleNotesChanged(bool isFirstNote = false) if (midiNotes.empty()) { handleGateChanged(false); - noTone(sAudioOutPin); + noTone(sAudioOutPin); // Remove to keep oscillator running during envelope release. } else { From 9bab7bd0df12ef2dd0031113ae3f7b93e5ee6561 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Mon, 3 Oct 2016 11:05:30 -0700 Subject: [PATCH 012/138] Added Travis support. --- .travis.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..6b2d327 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,10 @@ +language: c +sudo: false +before_install: + - source <(curl -SLs https://raw.githubusercontent.com/fortyseveneffects/travis-ci-arduino/master/install.sh) +script: + - build_main_platforms +notifications: + email: + on_success: change + on_failure: change From 69db8208961921df521db4d4e375250b970573b2 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Mon, 3 Oct 2016 11:09:02 -0700 Subject: [PATCH 013/138] Don't notify. --- .travis.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6b2d327..2238e5d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,4 @@ before_install: script: - build_main_platforms notifications: - email: - on_success: change - on_failure: change + email: false From 0275824e8638567dcfc06bfedff6870e439fdda5 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Mon, 3 Oct 2016 11:12:32 -0700 Subject: [PATCH 014/138] Come on Travis, do your thing. --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 2238e5d..ecd91eb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,11 @@ language: c sudo: false + before_install: - source <(curl -SLs https://raw.githubusercontent.com/fortyseveneffects/travis-ci-arduino/master/install.sh) + script: - build_main_platforms + notifications: email: false From 885bc6e87031ed301b4429ba6f420344c165d645 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Mon, 3 Oct 2016 11:19:15 -0700 Subject: [PATCH 015/138] Removed old file (using VSCode now). --- arduino_midi_library.sublime-project | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 arduino_midi_library.sublime-project diff --git a/arduino_midi_library.sublime-project b/arduino_midi_library.sublime-project deleted file mode 100644 index 2778d82..0000000 --- a/arduino_midi_library.sublime-project +++ /dev/null @@ -1,18 +0,0 @@ -{ - "folders": - [ - { - "path": ".", - "folder_exclude_patterns": [".*", "__pycache__"], - "file_exclude_patterns": [".*"] - } - ], - "build_systems": - [ - { - "name": "Arduino MIDI Library Validator", - "cmd": ["python3", "${project_path}/res/validate.py"], - "path": "/usr/local/bin:/usr/bin:/bin" - } - ] -} From 3a07cd0fce99af977c379fa857f249f162aa8673 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Mon, 3 Oct 2016 11:50:14 -0700 Subject: [PATCH 016/138] Fixed merger example on Zero. --- res/Examples/MIDI_DualMerger/MIDI_DualMerger.ino | 3 +++ 1 file changed, 3 insertions(+) diff --git a/res/Examples/MIDI_DualMerger/MIDI_DualMerger.ino b/res/Examples/MIDI_DualMerger/MIDI_DualMerger.ino index 740fa5b..c87ae53 100644 --- a/res/Examples/MIDI_DualMerger/MIDI_DualMerger.ino +++ b/res/Examples/MIDI_DualMerger/MIDI_DualMerger.ino @@ -9,6 +9,9 @@ #ifdef 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(HardwareSerial, Serial1, midiB); #else #include SoftwareSerial softSerial(2,3); From 210d3bd2aeaed61ca051450654a621ec127404f7 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Mon, 3 Oct 2016 12:04:44 -0700 Subject: [PATCH 017/138] Added badges and license file. --- LICENSE | 21 +++++++++++++++++++++ README.md | 6 +++++- 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f0d3c51 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +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. diff --git a/README.md b/README.md index 60b3a64..721b515 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,8 @@ -#Arduino MIDI Library v4.2 +# Arduino MIDI Library + +[![Build Status](https://travis-ci.org/FortySevenEffects/arduino_midi_library.svg?branch=master)](https://travis-ci.org/FortySevenEffects/arduino_midi_library) +[![GitHub release](https://img.shields.io/github/release/FortySevenEffects/arduino_midi_library.svg?maxAge=2592000)]() +[![License](https://img.shields.io/github/license/FortySevenEffects/arduino_midi_library.svg?maxAge=2592000)](LICENSE) This library enables MIDI I/O communications on the Arduino serial ports. The purpose of this library is not to make a big synthesizer out of an Arduino board, the application remains yours. However, it will help you interfacing it with other MIDI devices. From 3c1c65fd69fe9c77eebed49bce9aa3e9c17c8c4b Mon Sep 17 00:00:00 2001 From: Francois Best Date: Mon, 3 Oct 2016 12:06:03 -0700 Subject: [PATCH 018/138] Fix release link. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 721b515..9e3faca 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Arduino MIDI Library [![Build Status](https://travis-ci.org/FortySevenEffects/arduino_midi_library.svg?branch=master)](https://travis-ci.org/FortySevenEffects/arduino_midi_library) -[![GitHub release](https://img.shields.io/github/release/FortySevenEffects/arduino_midi_library.svg?maxAge=2592000)]() +[![GitHub release](https://img.shields.io/github/release/FortySevenEffects/arduino_midi_library.svg?maxAge=2592000)](https://github.com/FortySevenEffects/arduino_midi_library/releases/latest) [![License](https://img.shields.io/github/license/FortySevenEffects/arduino_midi_library.svg?maxAge=2592000)](LICENSE) This library enables MIDI I/O communications on the Arduino serial ports. From c6002871294a00cfdfcde8bc2f128aeb24acd2d5 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Mon, 3 Oct 2016 19:18:36 -0700 Subject: [PATCH 019/138] Added test library and CMake scaffolding. --- .vscode/.cmaketools.json | 3 + CMakeLists.txt | 5 + src/CMakeLists.txt | 11 ++ test/CMakeLists.txt | 2 + test/mocks/CMakeLists.txt | 11 ++ test/mocks/test-mocks.cpp | 5 + test/mocks/test-mocks.h | 7 ++ test/mocks/test-mocks_Defs.h | 10 ++ test/mocks/test-mocks_Namespace.h | 11 ++ test/mocks/test-mocks_SerialMock.cpp | 5 + test/mocks/test-mocks_SerialMock.h | 61 +++++++++++ test/mocks/test-mocks_SerialMock.hpp | 147 +++++++++++++++++++++++++++ test/runner/CMakeLists.txt | 9 ++ test/runner/test-runner.cpp | 5 + test/runner/test-runner.h | 7 ++ test/runner/test-runner_Main.cpp | 10 ++ test/runner/test-runner_Main.h | 7 ++ test/runner/test-runner_Namespace.h | 11 ++ 18 files changed, 327 insertions(+) create mode 100644 .vscode/.cmaketools.json create mode 100644 CMakeLists.txt create mode 100644 src/CMakeLists.txt create mode 100644 test/CMakeLists.txt create mode 100644 test/mocks/CMakeLists.txt create mode 100644 test/mocks/test-mocks.cpp create mode 100644 test/mocks/test-mocks.h create mode 100644 test/mocks/test-mocks_Defs.h create mode 100644 test/mocks/test-mocks_Namespace.h create mode 100644 test/mocks/test-mocks_SerialMock.cpp create mode 100644 test/mocks/test-mocks_SerialMock.h create mode 100644 test/mocks/test-mocks_SerialMock.hpp create mode 100644 test/runner/CMakeLists.txt create mode 100644 test/runner/test-runner.cpp create mode 100644 test/runner/test-runner.h create mode 100644 test/runner/test-runner_Main.cpp create mode 100644 test/runner/test-runner_Main.h create mode 100644 test/runner/test-runner_Namespace.h diff --git a/.vscode/.cmaketools.json b/.vscode/.cmaketools.json new file mode 100644 index 0000000..cd1a614 --- /dev/null +++ b/.vscode/.cmaketools.json @@ -0,0 +1,3 @@ +{ + "selectedBuildType": "Debug" +} diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..2f63516 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.3.0) +project(arduino_midi_library) + +add_subdirectory(src) +add_subdirectory(test) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..7dc7b16 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,11 @@ +project(midi) + +add_library(midi STATIC + midi_Namespace.h + midi_Defs.h + midi_Message.h + midi_Settings.h + MIDI.cpp + MIDI.hpp + MIDI.h +) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..3dcdacf --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(mocks) +add_subdirectory(runner) diff --git a/test/mocks/CMakeLists.txt b/test/mocks/CMakeLists.txt new file mode 100644 index 0000000..af82728 --- /dev/null +++ b/test/mocks/CMakeLists.txt @@ -0,0 +1,11 @@ +project(test-mocks) + +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 +) diff --git a/test/mocks/test-mocks.cpp b/test/mocks/test-mocks.cpp new file mode 100644 index 0000000..3b25fca --- /dev/null +++ b/test/mocks/test-mocks.cpp @@ -0,0 +1,5 @@ +#include "test-mocks.h" + +BEGIN_TEST_MOCKS_NAMESPACE + +END_TEST_MOCKS_NAMESPACE diff --git a/test/mocks/test-mocks.h b/test/mocks/test-mocks.h new file mode 100644 index 0000000..aeb3ede --- /dev/null +++ b/test/mocks/test-mocks.h @@ -0,0 +1,7 @@ +#pragma once + +#include "test-mocks_Namespace.h" + +BEGIN_TEST_MOCKS_NAMESPACE + +END_TEST_MOCKS_NAMESPACE diff --git a/test/mocks/test-mocks_Defs.h b/test/mocks/test-mocks_Defs.h new file mode 100644 index 0000000..9ed453a --- /dev/null +++ b/test/mocks/test-mocks_Defs.h @@ -0,0 +1,10 @@ +#pragma once + +#include "test-mocks.h" +#include + +BEGIN_TEST_MOCKS_NAMESPACE + +typedef uint8_t uint8; + +END_TEST_MOCKS_NAMESPACE diff --git a/test/mocks/test-mocks_Namespace.h b/test/mocks/test-mocks_Namespace.h new file mode 100644 index 0000000..99f971b --- /dev/null +++ b/test/mocks/test-mocks_Namespace.h @@ -0,0 +1,11 @@ +#pragma once + +#define TEST_MOCKS_NAMESPACE test_mocks +#define BEGIN_TEST_MOCKS_NAMESPACE namespace TEST_MOCKS_NAMESPACE { +#define END_TEST_MOCKS_NAMESPACE } + +#define USING_NAMESPACE_TEST_MOCKS using namespace TEST_MOCKS_NAMESPACE; + +BEGIN_TEST_MOCKS_NAMESPACE + +END_TEST_MOCKS_NAMESPACE diff --git a/test/mocks/test-mocks_SerialMock.cpp b/test/mocks/test-mocks_SerialMock.cpp new file mode 100644 index 0000000..d316788 --- /dev/null +++ b/test/mocks/test-mocks_SerialMock.cpp @@ -0,0 +1,5 @@ +#include "test-mocks_SerialMock.h" + +BEGIN_TEST_MOCKS_NAMESPACE + +END_TEST_MOCKS_NAMESPACE diff --git a/test/mocks/test-mocks_SerialMock.h b/test/mocks/test-mocks_SerialMock.h new file mode 100644 index 0000000..a934d2f --- /dev/null +++ b/test/mocks/test-mocks_SerialMock.h @@ -0,0 +1,61 @@ +#pragma once + +#include "test-mocks.h" +#include "test-mocks_Defs.h" + +BEGIN_TEST_MOCKS_NAMESPACE + +template +class RingBuffer +{ +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; +}; + +// ----------------------------------------------------------------------------- + +template +class SerialMock +{ +public: + SerialMock(); + ~SerialMock(); + +public: // Arduino Serial API + void begin(int inBaudrate); + int available() const; + void write(uint8 inData); + uint8 read(); + +public: // Test Helpers API + void moveTxToRx(); // Simulate loopback + +public: + typedef RingBuffer Buffer; + Buffer mTxBuffer; + Buffer mRxBuffer; + int mBaudrate; +}; + +END_TEST_MOCKS_NAMESPACE + +#include "test-mocks_SerialMock.hpp" diff --git a/test/mocks/test-mocks_SerialMock.hpp b/test/mocks/test-mocks_SerialMock.hpp new file mode 100644 index 0000000..082d47b --- /dev/null +++ b/test/mocks/test-mocks_SerialMock.hpp @@ -0,0 +1,147 @@ +#pragma once + +BEGIN_TEST_MOCKS_NAMESPACE + +template +RingBuffer::RingBuffer() + : mWriteHead(mData) + , mReadHead(mData) +{ + memset(mData, DataType(0), Size * sizeof(DataType)); +} + +template +RingBuffer::~RingBuffer() +{ +} + +// ----------------------------------------------------------------------------- + +template +int RingBuffer::getLength() const +{ + if (mReadHead == mWriteHead) + { + return 0; + } + else if (mWriteHead > mReadHead) + { + return mWriteHead - mReadHead; + } + else + { + return Size - mReadHead + mWriteHead; + } +} + +template +bool RingBuffer::isEmpty() const +{ + return mReadHead == mWriteHead; +} + +// ----------------------------------------------------------------------------- + +template +void RingBuffer::write(DataType inData) +{ + *mWriteHead++ = inData; + if (mWriteHead >= mData + Size) + { + mWriteHead = mData; + } +} + +template +void RingBuffer::write(const DataType* inData, int inSize) +{ + for (int i = 0; i < inSize; ++i) + { + write(inData[i]); + } +} + +template +void RingBuffer::clear() +{ + memset(mData, DataType(0), Size * sizeof(DataType)); + mReadHead = mData; + mWriteHead = mData; +} + +// ----------------------------------------------------------------------------- + +template +DataType RingBuffer::read() +{ + const DataType data = *mReadHead++; + if (mReadHead >= mData + Size) + { + mReadHead = mData; + } + return data; +} + +template +void RingBuffer::read(DataType* outData, int inSize) +{ + for (int i = 0; i < inSize; ++i) + { + outData[i] = read(); + } +} + +// ============================================================================= + +template +SerialMock::SerialMock() +{ +} + +template +SerialMock::~SerialMock() +{ +} + +// ----------------------------------------------------------------------------- + +template +void SerialMock::begin(int inBaudrate) +{ + mBaudrate = inBaudrate; + mTxBuffer.clear(); + mRxBuffer.clear(); +} + +template +int SerialMock::available() const +{ + return mRxBuffer.getSize(); +} + +template +void SerialMock::write(uint8 inData) +{ + mTxBuffer.write(inData); +} + +template +uint8 SerialMock::read() +{ + return mRxBuffer.read(); +} + +// ----------------------------------------------------------------------------- + +template +void SerialMock::moveTxToRx() +{ + mRxBuffer.clear(); + const int size = mTxBuffer.getSize(); + for (int i = 0; i < size; ++i) + { + mRxBuffer.write(mTxBuffer.read()); + } +} + +END_TEST_MOCKS_NAMESPACE diff --git a/test/runner/CMakeLists.txt b/test/runner/CMakeLists.txt new file mode 100644 index 0000000..50efab6 --- /dev/null +++ b/test/runner/CMakeLists.txt @@ -0,0 +1,9 @@ +project(test-runner) + +add_executable(test-runner + test-runner.cpp + test-runner.h + test-runner_Namespace.h + test-runner_Main.cpp + test-runner_Main.h +) diff --git a/test/runner/test-runner.cpp b/test/runner/test-runner.cpp new file mode 100644 index 0000000..29269a9 --- /dev/null +++ b/test/runner/test-runner.cpp @@ -0,0 +1,5 @@ +#include "test-runner.h" + +BEGIN_TEST_RUNNER_NAMESPACE + +END_TEST_RUNNER_NAMESPACE diff --git a/test/runner/test-runner.h b/test/runner/test-runner.h new file mode 100644 index 0000000..43b051e --- /dev/null +++ b/test/runner/test-runner.h @@ -0,0 +1,7 @@ +#pragma once + +#include "test-runner_Namespace.h" + +BEGIN_TEST_RUNNER_NAMESPACE + +END_TEST_RUNNER_NAMESPACE diff --git a/test/runner/test-runner_Main.cpp b/test/runner/test-runner_Main.cpp new file mode 100644 index 0000000..fe960a7 --- /dev/null +++ b/test/runner/test-runner_Main.cpp @@ -0,0 +1,10 @@ +#include "test-runner_Main.h" + +BEGIN_TEST_RUNNER_NAMESPACE + +END_TEST_RUNNER_NAMESPACE + +int main() +{ + return 0; +} diff --git a/test/runner/test-runner_Main.h b/test/runner/test-runner_Main.h new file mode 100644 index 0000000..826c393 --- /dev/null +++ b/test/runner/test-runner_Main.h @@ -0,0 +1,7 @@ +#pragma once + +#include "test-runner.h" + +BEGIN_TEST_RUNNER_NAMESPACE + +END_TEST_RUNNER_NAMESPACE diff --git a/test/runner/test-runner_Namespace.h b/test/runner/test-runner_Namespace.h new file mode 100644 index 0000000..839dbf3 --- /dev/null +++ b/test/runner/test-runner_Namespace.h @@ -0,0 +1,11 @@ +#pragma once + +#define TEST_RUNNER_NAMESPACE test_runner +#define BEGIN_TEST_RUNNER_NAMESPACE namespace TEST_RUNNER_NAMESPACE { +#define END_TEST_RUNNER_NAMESPACE } + +#define USING_NAMESPACE_TEST_RUNNER using namespace TEST_RUNNER_NAMESPACE; + +BEGIN_TEST_RUNNER_NAMESPACE + +END_TEST_RUNNER_NAMESPACE From a24d195f93bb53ac94dcf385cf4b15f197a47d5c Mon Sep 17 00:00:00 2001 From: Francois Best Date: Mon, 3 Oct 2016 20:17:49 -0700 Subject: [PATCH 020/138] Added root to include dirs. --- CMakeLists.txt | 3 +++ test/runner/test-runner_Main.cpp | 7 ++++++- test/runner/test-runner_Main.h | 2 ++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2f63516..65babf9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,8 @@ cmake_minimum_required(VERSION 3.3.0) project(arduino_midi_library) +set(ROOT_SOURCE_DIR ${PROJECT_SOURCE_DIR}) +include_directories(${ROOT_SOURCE_DIR}) + add_subdirectory(src) add_subdirectory(test) diff --git a/test/runner/test-runner_Main.cpp b/test/runner/test-runner_Main.cpp index fe960a7..d5cfa6b 100644 --- a/test/runner/test-runner_Main.cpp +++ b/test/runner/test-runner_Main.cpp @@ -2,9 +2,14 @@ BEGIN_TEST_RUNNER_NAMESPACE +bool run() +{ + return false; +} + END_TEST_RUNNER_NAMESPACE int main() { - return 0; + return TEST_RUNNER_NAMESPACE::run() ? 0 : 1; } diff --git a/test/runner/test-runner_Main.h b/test/runner/test-runner_Main.h index 826c393..690391c 100644 --- a/test/runner/test-runner_Main.h +++ b/test/runner/test-runner_Main.h @@ -5,3 +5,5 @@ BEGIN_TEST_RUNNER_NAMESPACE END_TEST_RUNNER_NAMESPACE + +int main(); From 3740624176e17daad062b3f5101a479d7030802b Mon Sep 17 00:00:00 2001 From: Francois Best Date: Mon, 3 Oct 2016 20:20:55 -0700 Subject: [PATCH 021/138] Added Google Test as sub for unit tests. --- .gitmodules | 3 +++ external/google-test | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 external/google-test diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..53d7ecd --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "external/google-test"] + path = external/google-test + url = https://github.com/google/googletest.git diff --git a/external/google-test b/external/google-test new file mode 160000 index 0000000..ecd5308 --- /dev/null +++ b/external/google-test @@ -0,0 +1 @@ +Subproject commit ecd530865cefdfa7dea58e84f6aa1b548950363d From 4bd4015f9dddf6fc45b79f1b63a109fb7f32e4b6 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Mon, 3 Oct 2016 20:34:43 -0700 Subject: [PATCH 022/138] Binding Google Test into CMake. --- CMakeLists.txt | 1 + external/CMakeLists.txt | 1 + test/runner/CMakeLists.txt | 6 ++++++ test/runner/test-runner_Main.cpp | 16 ++++------------ test/runner/test-runner_Main.h | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) create mode 100644 external/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 65babf9..0ca2c9a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,5 +4,6 @@ project(arduino_midi_library) set(ROOT_SOURCE_DIR ${PROJECT_SOURCE_DIR}) include_directories(${ROOT_SOURCE_DIR}) +add_subdirectory(external) add_subdirectory(src) add_subdirectory(test) diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt new file mode 100644 index 0000000..9a20729 --- /dev/null +++ b/external/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(google-test) diff --git a/test/runner/CMakeLists.txt b/test/runner/CMakeLists.txt index 50efab6..f619c7c 100644 --- a/test/runner/CMakeLists.txt +++ b/test/runner/CMakeLists.txt @@ -1,5 +1,7 @@ project(test-runner) +include_directories(${gtest_SOURCE_DIR}/include) + add_executable(test-runner test-runner.cpp test-runner.h @@ -7,3 +9,7 @@ add_executable(test-runner test-runner_Main.cpp test-runner_Main.h ) +target_link_libraries(test-runner + test-mocks + gtest +) diff --git a/test/runner/test-runner_Main.cpp b/test/runner/test-runner_Main.cpp index d5cfa6b..9691a61 100644 --- a/test/runner/test-runner_Main.cpp +++ b/test/runner/test-runner_Main.cpp @@ -1,15 +1,7 @@ #include "test-runner_Main.h" +#include -BEGIN_TEST_RUNNER_NAMESPACE - -bool run() -{ - return false; -} - -END_TEST_RUNNER_NAMESPACE - -int main() -{ - return TEST_RUNNER_NAMESPACE::run() ? 0 : 1; +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); } diff --git a/test/runner/test-runner_Main.h b/test/runner/test-runner_Main.h index 690391c..e875f19 100644 --- a/test/runner/test-runner_Main.h +++ b/test/runner/test-runner_Main.h @@ -6,4 +6,4 @@ BEGIN_TEST_RUNNER_NAMESPACE END_TEST_RUNNER_NAMESPACE -int main(); +int main(int argc, char **argv); From f5b51bd21102762640c06bddfd13e3c669077569 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Mon, 3 Oct 2016 21:40:21 -0700 Subject: [PATCH 023/138] This file is generated when CMake config changes. --- .gitignore | 1 + .vscode/.cmaketools.json | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) delete mode 100644 .vscode/.cmaketools.json diff --git a/.gitignore b/.gitignore index 6681cf4..b9e2962 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ *.pyc logs/ build/ +.vscode/.cmaketools.json diff --git a/.vscode/.cmaketools.json b/.vscode/.cmaketools.json deleted file mode 100644 index cd1a614..0000000 --- a/.vscode/.cmaketools.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "selectedBuildType": "Debug" -} From b5c2d8c12c710274c7411a35b3c066c920c5ff72 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Mon, 3 Oct 2016 21:41:05 -0700 Subject: [PATCH 024/138] Reworked unit tests. --- test/CMakeLists.txt | 2 +- test/runner/CMakeLists.txt | 15 ---- test/runner/test-runner.cpp | 5 -- test/runner/test-runner.h | 7 -- test/runner/test-runner_Main.h | 9 --- test/runner/test-runner_Namespace.h | 11 --- test/unit-tests/CMakeLists.txt | 22 ++++++ .../unit-tests.cpp} | 3 +- test/unit-tests/unit-tests.h | 8 ++ test/unit-tests/unit-tests_MidiMessage.cpp | 75 +++++++++++++++++++ test/unit-tests/unit-tests_Namespace.h | 13 ++++ 11 files changed, 120 insertions(+), 50 deletions(-) delete mode 100644 test/runner/CMakeLists.txt delete mode 100644 test/runner/test-runner.cpp delete mode 100644 test/runner/test-runner.h delete mode 100644 test/runner/test-runner_Main.h delete mode 100644 test/runner/test-runner_Namespace.h create mode 100644 test/unit-tests/CMakeLists.txt rename test/{runner/test-runner_Main.cpp => unit-tests/unit-tests.cpp} (66%) create mode 100644 test/unit-tests/unit-tests.h create mode 100644 test/unit-tests/unit-tests_MidiMessage.cpp create mode 100644 test/unit-tests/unit-tests_Namespace.h diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3dcdacf..c3d5866 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,2 +1,2 @@ add_subdirectory(mocks) -add_subdirectory(runner) +add_subdirectory(unit-tests) diff --git a/test/runner/CMakeLists.txt b/test/runner/CMakeLists.txt deleted file mode 100644 index f619c7c..0000000 --- a/test/runner/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -project(test-runner) - -include_directories(${gtest_SOURCE_DIR}/include) - -add_executable(test-runner - test-runner.cpp - test-runner.h - test-runner_Namespace.h - test-runner_Main.cpp - test-runner_Main.h -) -target_link_libraries(test-runner - test-mocks - gtest -) diff --git a/test/runner/test-runner.cpp b/test/runner/test-runner.cpp deleted file mode 100644 index 29269a9..0000000 --- a/test/runner/test-runner.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "test-runner.h" - -BEGIN_TEST_RUNNER_NAMESPACE - -END_TEST_RUNNER_NAMESPACE diff --git a/test/runner/test-runner.h b/test/runner/test-runner.h deleted file mode 100644 index 43b051e..0000000 --- a/test/runner/test-runner.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include "test-runner_Namespace.h" - -BEGIN_TEST_RUNNER_NAMESPACE - -END_TEST_RUNNER_NAMESPACE diff --git a/test/runner/test-runner_Main.h b/test/runner/test-runner_Main.h deleted file mode 100644 index e875f19..0000000 --- a/test/runner/test-runner_Main.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include "test-runner.h" - -BEGIN_TEST_RUNNER_NAMESPACE - -END_TEST_RUNNER_NAMESPACE - -int main(int argc, char **argv); diff --git a/test/runner/test-runner_Namespace.h b/test/runner/test-runner_Namespace.h deleted file mode 100644 index 839dbf3..0000000 --- a/test/runner/test-runner_Namespace.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#define TEST_RUNNER_NAMESPACE test_runner -#define BEGIN_TEST_RUNNER_NAMESPACE namespace TEST_RUNNER_NAMESPACE { -#define END_TEST_RUNNER_NAMESPACE } - -#define USING_NAMESPACE_TEST_RUNNER using namespace TEST_RUNNER_NAMESPACE; - -BEGIN_TEST_RUNNER_NAMESPACE - -END_TEST_RUNNER_NAMESPACE diff --git a/test/unit-tests/CMakeLists.txt b/test/unit-tests/CMakeLists.txt new file mode 100644 index 0000000..5b594e4 --- /dev/null +++ b/test/unit-tests/CMakeLists.txt @@ -0,0 +1,22 @@ +project(unit-tests) + +include_directories(${gtest_SOURCE_DIR}/include) + +add_executable(unit-tests + + unit-tests.cpp + unit-tests.h + unit-tests_Namespace.h + unit-tests_MidiMessage.cpp +) + +target_link_libraries(unit-tests + gtest + midi + test-mocks +) + +add_custom_command(TARGET unit-tests POST_BUILD + COMMAND ${unit-tests_BINARY_DIR}/unit-tests +) + diff --git a/test/runner/test-runner_Main.cpp b/test/unit-tests/unit-tests.cpp similarity index 66% rename from test/runner/test-runner_Main.cpp rename to test/unit-tests/unit-tests.cpp index 9691a61..5c8e3d8 100644 --- a/test/runner/test-runner_Main.cpp +++ b/test/unit-tests/unit-tests.cpp @@ -1,5 +1,4 @@ -#include "test-runner_Main.h" -#include +#include "unit-tests.h" int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); diff --git a/test/unit-tests/unit-tests.h b/test/unit-tests/unit-tests.h new file mode 100644 index 0000000..520206b --- /dev/null +++ b/test/unit-tests/unit-tests.h @@ -0,0 +1,8 @@ +#pragma once + +#include "unit-tests_Namespace.h" +#include + +BEGIN_UNIT_TESTS_NAMESPACE + +END_UNIT_TESTS_NAMESPACE diff --git a/test/unit-tests/unit-tests_MidiMessage.cpp b/test/unit-tests/unit-tests_MidiMessage.cpp new file mode 100644 index 0000000..79cfac1 --- /dev/null +++ b/test/unit-tests/unit-tests_MidiMessage.cpp @@ -0,0 +1,75 @@ +#include "unit-tests.h" +#include +#include + +BEGIN_UNNAMED_NAMESPACE + +TEST(MidiMessage, hasTheRightProperties) +{ + typedef midi::Message<42> Message; + const Message message = Message(); + EXPECT_EQ(message.channel, 0); + EXPECT_EQ(message.type, 0); + EXPECT_EQ(message.data1, 0); + EXPECT_EQ(message.data2, 0); + EXPECT_EQ(message.valid, false); + EXPECT_EQ(message.getSysExSize(), 0); +} + +template +inline void setSysExSize(Message& ioMessage, unsigned inSize) +{ + ioMessage.data2 = inSize >> 8; // MSB + ioMessage.data1 = inSize & 0xff; // LSB +} + +TEST(MidiMessage, getSysExSize) +{ + // Small message + { + typedef midi::Message<32> Message; + Message message = Message(); + ASSERT_EQ(Message::getSysExMaxSize(), 32); + ASSERT_EQ(message.getSysExMaxSize(), 32); + + const unsigned sizeUnder = 20; + setSysExSize(message, sizeUnder); + ASSERT_EQ(message.getSysExSize(), sizeUnder); + + const unsigned sizeOver = 64; + setSysExSize(message, sizeOver); + ASSERT_EQ(message.getSysExSize(), 32); + } + // Medium message + { + typedef midi::Message<256> Message; + Message message = Message(); + ASSERT_EQ(Message::getSysExMaxSize(), 256); + ASSERT_EQ(message.getSysExMaxSize(), 256); + + const unsigned sizeUnder = 200; + setSysExSize(message, sizeUnder); + ASSERT_EQ(message.getSysExSize(), sizeUnder); + + const unsigned sizeOver = 300; + setSysExSize(message, sizeOver); + ASSERT_EQ(message.getSysExSize(), 256); + } + // Large message + { + typedef midi::Message<1024> Message; + Message message = Message(); + ASSERT_EQ(Message::getSysExMaxSize(), 1024); + ASSERT_EQ(message.getSysExMaxSize(), 1024); + + const unsigned sizeUnder = 1000; + setSysExSize(message, sizeUnder); + ASSERT_EQ(message.getSysExSize(), sizeUnder); + + const unsigned sizeOver = 2000; + setSysExSize(message, sizeOver); + ASSERT_EQ(message.getSysExSize(), 1024); + } +} + +END_UNNAMED_NAMESPACE diff --git a/test/unit-tests/unit-tests_Namespace.h b/test/unit-tests/unit-tests_Namespace.h new file mode 100644 index 0000000..41ac829 --- /dev/null +++ b/test/unit-tests/unit-tests_Namespace.h @@ -0,0 +1,13 @@ +#pragma once + +#define UNIT_TESTS_NAMESPACE unit_tests +#define BEGIN_UNIT_TESTS_NAMESPACE namespace UNIT_TESTS_NAMESPACE { +#define END_UNIT_TESTS_NAMESPACE } +#define BEGIN_UNNAMED_NAMESPACE namespace { +#define END_UNNAMED_NAMESPACE } + +#define USING_NAMESPACE_UNIT_TESTS using namespace UNIT_TESTS_NAMESPACE; + +BEGIN_UNIT_TESTS_NAMESPACE + +END_UNIT_TESTS_NAMESPACE From c86d6f2e2636bcabfca340d134d69b5a362ce8d4 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Mon, 3 Oct 2016 21:41:13 -0700 Subject: [PATCH 025/138] Added testing facility. --- src/midi_Message.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/midi_Message.h b/src/midi_Message.h index 1c3a3cd..a292bc9 100644 --- a/src/midi_Message.h +++ b/src/midi_Message.h @@ -43,6 +43,13 @@ struct Message */ static const unsigned sSysExMaxSize = SysExMaxSize; + /*! Static method accessor for SysEx max size, used for unit tests. + */ + static inline unsigned getSysExMaxSize() + { + return SysExMaxSize; + } + /*! The MIDI channel on which the message was recieved. \n Value goes from 1 to 16. */ From 92c50d612a26a4ace4ecf76065d6ef04d29f99f2 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Mon, 3 Oct 2016 22:08:14 -0700 Subject: [PATCH 026/138] Removed this nonsense. --- src/midi_Message.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/midi_Message.h b/src/midi_Message.h index a292bc9..1c3a3cd 100644 --- a/src/midi_Message.h +++ b/src/midi_Message.h @@ -43,13 +43,6 @@ struct Message */ static const unsigned sSysExMaxSize = SysExMaxSize; - /*! Static method accessor for SysEx max size, used for unit tests. - */ - static inline unsigned getSysExMaxSize() - { - return SysExMaxSize; - } - /*! The MIDI channel on which the message was recieved. \n Value goes from 1 to 16. */ From 618f71658bb435215ab8ab79111551dc47985ea7 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Mon, 3 Oct 2016 22:08:45 -0700 Subject: [PATCH 027/138] Moved tests, added references to static stuff. --- test/unit-tests/CMakeLists.txt | 10 ++++--- .../{ => tests}/unit-tests_MidiMessage.cpp | 22 ++++++++++----- test/unit-tests/tests/unit-tests_Settings.cpp | 27 +++++++++++++++++++ 3 files changed, 49 insertions(+), 10 deletions(-) rename test/unit-tests/{ => tests}/unit-tests_MidiMessage.cpp (79%) create mode 100644 test/unit-tests/tests/unit-tests_Settings.cpp diff --git a/test/unit-tests/CMakeLists.txt b/test/unit-tests/CMakeLists.txt index 5b594e4..a9bcb79 100644 --- a/test/unit-tests/CMakeLists.txt +++ b/test/unit-tests/CMakeLists.txt @@ -1,13 +1,18 @@ project(unit-tests) -include_directories(${gtest_SOURCE_DIR}/include) +include_directories( + ${unit-tests_SOURCE_DIR} + ${gtest_SOURCE_DIR}/include +) add_executable(unit-tests unit-tests.cpp unit-tests.h unit-tests_Namespace.h - unit-tests_MidiMessage.cpp + + tests/unit-tests_MidiMessage.cpp + tests/unit-tests_Settings.cpp ) target_link_libraries(unit-tests @@ -19,4 +24,3 @@ target_link_libraries(unit-tests add_custom_command(TARGET unit-tests POST_BUILD COMMAND ${unit-tests_BINARY_DIR}/unit-tests ) - diff --git a/test/unit-tests/unit-tests_MidiMessage.cpp b/test/unit-tests/tests/unit-tests_MidiMessage.cpp similarity index 79% rename from test/unit-tests/unit-tests_MidiMessage.cpp rename to test/unit-tests/tests/unit-tests_MidiMessage.cpp index 79cfac1..13b0a02 100644 --- a/test/unit-tests/unit-tests_MidiMessage.cpp +++ b/test/unit-tests/tests/unit-tests_MidiMessage.cpp @@ -1,6 +1,17 @@ #include "unit-tests.h" #include -#include + +BEGIN_MIDI_NAMESPACE + +// Declare references: +// http://stackoverflow.com/questions/4891067/weird-undefined-symbols-of-static-constants-inside-a-struct-class + +template +const unsigned Message::sSysExMaxSize; + +END_MIDI_NAMESPACE + +// ----------------------------------------------------------------------------- BEGIN_UNNAMED_NAMESPACE @@ -28,9 +39,8 @@ TEST(MidiMessage, getSysExSize) // Small message { typedef midi::Message<32> Message; + ASSERT_EQ(Message::sSysExMaxSize, 32); Message message = Message(); - ASSERT_EQ(Message::getSysExMaxSize(), 32); - ASSERT_EQ(message.getSysExMaxSize(), 32); const unsigned sizeUnder = 20; setSysExSize(message, sizeUnder); @@ -43,9 +53,8 @@ TEST(MidiMessage, getSysExSize) // Medium message { typedef midi::Message<256> Message; + ASSERT_EQ(Message::sSysExMaxSize, 256); Message message = Message(); - ASSERT_EQ(Message::getSysExMaxSize(), 256); - ASSERT_EQ(message.getSysExMaxSize(), 256); const unsigned sizeUnder = 200; setSysExSize(message, sizeUnder); @@ -58,9 +67,8 @@ TEST(MidiMessage, getSysExSize) // Large message { typedef midi::Message<1024> Message; + ASSERT_EQ(Message::sSysExMaxSize, 1024); Message message = Message(); - ASSERT_EQ(Message::getSysExMaxSize(), 1024); - ASSERT_EQ(message.getSysExMaxSize(), 1024); const unsigned sizeUnder = 1000; setSysExSize(message, sizeUnder); diff --git a/test/unit-tests/tests/unit-tests_Settings.cpp b/test/unit-tests/tests/unit-tests_Settings.cpp new file mode 100644 index 0000000..49a3613 --- /dev/null +++ b/test/unit-tests/tests/unit-tests_Settings.cpp @@ -0,0 +1,27 @@ +#include "unit-tests.h" +#include + +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 + +// ----------------------------------------------------------------------------- + +BEGIN_UNNAMED_NAMESPACE + +TEST(Settings, hasTheRightDefaultValues) +{ + EXPECT_EQ(midi::DefaultSettings::UseRunningStatus, true); + EXPECT_EQ(midi::DefaultSettings::HandleNullVelocityNoteOnAsNoteOff, true); + EXPECT_EQ(midi::DefaultSettings::Use1ByteParsing, true); + EXPECT_EQ(midi::DefaultSettings::BaudRate, 31250); + EXPECT_EQ(midi::DefaultSettings::SysExMaxSize, 128); +} + +END_UNNAMED_NAMESPACE From 22d6bb8cf2b0a3ef64ff1f49f21c63e579c8dad7 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Mon, 3 Oct 2016 22:10:39 -0700 Subject: [PATCH 028/138] Restrict include. --- test/unit-tests/tests/unit-tests_MidiMessage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit-tests/tests/unit-tests_MidiMessage.cpp b/test/unit-tests/tests/unit-tests_MidiMessage.cpp index 13b0a02..1fb7272 100644 --- a/test/unit-tests/tests/unit-tests_MidiMessage.cpp +++ b/test/unit-tests/tests/unit-tests_MidiMessage.cpp @@ -1,5 +1,5 @@ #include "unit-tests.h" -#include +#include BEGIN_MIDI_NAMESPACE From d42acc0cbb4376c89ec16fde8e5f29865a6925f8 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Tue, 4 Oct 2016 01:00:12 -0700 Subject: [PATCH 029/138] Testing (and fixed) SysEx codec. Now conforms to Somascape specs. --- src/MIDI.cpp | 9 +- test/unit-tests/CMakeLists.txt | 3 + .../tests/unit-tests_SysExCodec.cpp | 103 ++++++++++++++++++ test/unit-tests/unit-tests.h | 1 + 4 files changed, 113 insertions(+), 3 deletions(-) create mode 100644 test/unit-tests/tests/unit-tests_SysExCodec.cpp diff --git a/src/MIDI.cpp b/src/MIDI.cpp index c117d5a..9d53668 100644 --- a/src/MIDI.cpp +++ b/src/MIDI.cpp @@ -55,7 +55,7 @@ unsigned encodeSysEx(const byte* inData, byte* outSysEx, unsigned inLength) const byte msb = data >> 7; const byte body = data & 0x7f; - outSysEx[0] |= (msb << count); + outSysEx[0] |= (msb << (6 - count)); outSysEx[1 + count] = body; if (count++ == 6) @@ -84,17 +84,20 @@ unsigned decodeSysEx(const byte* inSysEx, byte* outData, unsigned inLength) { unsigned count = 0; byte msbStorage = 0; + byte byteIndex = 0; for (unsigned i = 0; i < inLength; ++i) { if ((i % 8) == 0) { msbStorage = inSysEx[i]; + byteIndex = 6; } else { - outData[count++] = inSysEx[i] | ((msbStorage & 1) << 7); - msbStorage >>= 1; + const byte body = inSysEx[i]; + const byte msb = ((msbStorage >> byteIndex--) & 1) << 7; + outData[count++] = msb | body; } } return count; diff --git a/test/unit-tests/CMakeLists.txt b/test/unit-tests/CMakeLists.txt index a9bcb79..a77c826 100644 --- a/test/unit-tests/CMakeLists.txt +++ b/test/unit-tests/CMakeLists.txt @@ -3,6 +3,7 @@ project(unit-tests) include_directories( ${unit-tests_SOURCE_DIR} ${gtest_SOURCE_DIR}/include + ${gmock_SOURCE_DIR}/include ) add_executable(unit-tests @@ -13,10 +14,12 @@ add_executable(unit-tests tests/unit-tests_MidiMessage.cpp tests/unit-tests_Settings.cpp + tests/unit-tests_SysExCodec.cpp ) target_link_libraries(unit-tests gtest + gmock midi test-mocks ) diff --git a/test/unit-tests/tests/unit-tests_SysExCodec.cpp b/test/unit-tests/tests/unit-tests_SysExCodec.cpp new file mode 100644 index 0000000..f5c6335 --- /dev/null +++ b/test/unit-tests/tests/unit-tests_SysExCodec.cpp @@ -0,0 +1,103 @@ +#include "unit-tests.h" +#include + +BEGIN_MIDI_NAMESPACE + +END_MIDI_NAMESPACE + +// ----------------------------------------------------------------------------- + +BEGIN_UNNAMED_NAMESPACE + +using namespace testing; + +TEST(SysExCodec, Encoder) +{ + // ASCII content + { + const byte input[] = "Hello, World!"; + byte buffer[32]; + memset(buffer, 0, 32 * sizeof(byte)); + const unsigned encodedSize = midi::encodeSysEx(input, buffer, 13); + EXPECT_EQ(encodedSize, 15); + const byte expected[32] = { + 0, 'H', 'e', 'l', 'l', 'o', ',', ' ', + 0, 'W', 'o', 'r', 'l', 'd', '!', 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 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[32]; + memset(buffer, 0, 32 * sizeof(byte)); + const unsigned encodedSize = midi::encodeSysEx(input, buffer, 12); + EXPECT_EQ(encodedSize, 14); + const byte expected[32] = { + // MSB Data + 120, 54, 108, 39, 49, 61, 91, 120, + 16, 107, 94, 81, 87, 94, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + }; + EXPECT_THAT(buffer, Each(Le(0x7f))); // All elements are <= 127 + EXPECT_THAT(buffer, ContainerEq(expected)); + } +} + +TEST(SysExCodec, Decoder) +{ + // ASCII content + { + const byte input[] = { + 0, 'H', 'e', 'l', 'l', 'o', ',', ' ', + 0, 'W', 'o', 'r', 'l', 'd', '!', + }; + byte buffer[32]; + memset(buffer, 0, 32 * sizeof(byte)); + const unsigned decodedSize = midi::decodeSysEx(input, buffer, 15); + EXPECT_EQ(decodedSize, 13); + const byte expected[32] = { + 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', + 'o', 'r', 'l', 'd', '!', 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 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[32]; + memset(buffer, 0, 32 * sizeof(byte)); + const unsigned encodedSize = midi::decodeSysEx(input, buffer, 14); + EXPECT_EQ(encodedSize, 12); + const byte expected[32] = { + 182, 236, 167, 177, 61, 91, 120, + 107, 94, 209, 87, 94, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0 + }; + EXPECT_THAT(input, Each(Le(0x7f))); // All elements are <= 127 + EXPECT_THAT(buffer, ContainerEq(expected)); + } +} + +TEST(SysExCodec, Codec) +{ + +} + +END_UNNAMED_NAMESPACE diff --git a/test/unit-tests/unit-tests.h b/test/unit-tests/unit-tests.h index 520206b..b02f40c 100644 --- a/test/unit-tests/unit-tests.h +++ b/test/unit-tests/unit-tests.h @@ -2,6 +2,7 @@ #include "unit-tests_Namespace.h" #include +#include BEGIN_UNIT_TESTS_NAMESPACE From 51d25a831f62f8220e8134391bcc94c9cdaa6ea1 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Tue, 4 Oct 2016 01:11:39 -0700 Subject: [PATCH 030/138] Running test in Travis. --- .travis.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ecd91eb..4eeaeec 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ -language: c +language: cpp sudo: false before_install: @@ -6,6 +6,10 @@ before_install: script: - build_main_platforms + - mkdir build && cd build + - cmake .. + - make + - test/unit-tests/unit-tests notifications: email: false From 371d1adba972f9ea8fe922112884839a7f5c460c Mon Sep 17 00:00:00 2001 From: Francois Best Date: Tue, 4 Oct 2016 01:24:28 -0700 Subject: [PATCH 031/138] Disable auto-tests in post-build. --- test/unit-tests/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/unit-tests/CMakeLists.txt b/test/unit-tests/CMakeLists.txt index a77c826..3affcdc 100644 --- a/test/unit-tests/CMakeLists.txt +++ b/test/unit-tests/CMakeLists.txt @@ -24,6 +24,6 @@ target_link_libraries(unit-tests test-mocks ) -add_custom_command(TARGET unit-tests POST_BUILD - COMMAND ${unit-tests_BINARY_DIR}/unit-tests -) +# add_custom_command(TARGET unit-tests POST_BUILD +# COMMAND ${unit-tests_BINARY_DIR}/unit-tests +# ) From f483eb86e9b1460329a79704c6a87aafa38e8212 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Tue, 4 Oct 2016 01:24:39 -0700 Subject: [PATCH 032/138] Require lower CMake version for Travis. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0ca2c9a..b82f16c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.3.0) +cmake_minimum_required(VERSION 2.8.7) project(arduino_midi_library) set(ROOT_SOURCE_DIR ${PROJECT_SOURCE_DIR}) From 7268429235909689ce9268b45a90945eb65e290d Mon Sep 17 00:00:00 2001 From: Francois Best Date: Tue, 4 Oct 2016 09:54:46 -0700 Subject: [PATCH 033/138] More tests. --- CMakeLists.txt | 2 + test/mocks/test-mocks_SerialMock.hpp | 4 +- test/unit-tests/CMakeLists.txt | 4 ++ .../unit-tests/tests/unit-tests_MidiInput.cpp | 67 +++++++++++++++++++ .../tests/unit-tests_MidiOutput.cpp | 0 test/unit-tests/tests/unit-tests_MidiThru.cpp | 0 .../tests/unit-tests_SerialMock.cpp | 64 ++++++++++++++++++ 7 files changed, 139 insertions(+), 2 deletions(-) create mode 100644 test/unit-tests/tests/unit-tests_MidiInput.cpp create mode 100644 test/unit-tests/tests/unit-tests_MidiOutput.cpp create mode 100644 test/unit-tests/tests/unit-tests_MidiThru.cpp create mode 100644 test/unit-tests/tests/unit-tests_SerialMock.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b82f16c..e1d38a6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,8 @@ project(arduino_midi_library) set(ROOT_SOURCE_DIR ${PROJECT_SOURCE_DIR}) include_directories(${ROOT_SOURCE_DIR}) +set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + add_subdirectory(external) add_subdirectory(src) add_subdirectory(test) diff --git a/test/mocks/test-mocks_SerialMock.hpp b/test/mocks/test-mocks_SerialMock.hpp index 082d47b..8bd0999 100644 --- a/test/mocks/test-mocks_SerialMock.hpp +++ b/test/mocks/test-mocks_SerialMock.hpp @@ -26,11 +26,11 @@ int RingBuffer::getLength() const } else if (mWriteHead > mReadHead) { - return mWriteHead - mReadHead; + return int(mWriteHead - mReadHead); } else { - return Size - mReadHead + mWriteHead; + return int(mWriteHead - mData) + Size - int(mReadHead - mData); } } diff --git a/test/unit-tests/CMakeLists.txt b/test/unit-tests/CMakeLists.txt index 3affcdc..097f2f6 100644 --- a/test/unit-tests/CMakeLists.txt +++ b/test/unit-tests/CMakeLists.txt @@ -15,6 +15,10 @@ add_executable(unit-tests tests/unit-tests_MidiMessage.cpp tests/unit-tests_Settings.cpp tests/unit-tests_SysExCodec.cpp + tests/unit-tests_SerialMock.cpp + tests/unit-tests_MidiInput.cpp + tests/unit-tests_MidiOutput.cpp + tests/unit-tests_MidiThru.cpp ) target_link_libraries(unit-tests diff --git a/test/unit-tests/tests/unit-tests_MidiInput.cpp b/test/unit-tests/tests/unit-tests_MidiInput.cpp new file mode 100644 index 0000000..1c271f0 --- /dev/null +++ b/test/unit-tests/tests/unit-tests_MidiInput.cpp @@ -0,0 +1,67 @@ +#include "unit-tests.h" +#include +#include + +BEGIN_MIDI_NAMESPACE + +END_MIDI_NAMESPACE + +// ----------------------------------------------------------------------------- + +BEGIN_UNNAMED_NAMESPACE + +typedef test_mocks::SerialMock<32> SerialMock; +typedef midi::MidiInterface MidiInterface; + +TEST(MidiInput, getTypeFromStatusByte) +{ + // Channel Messages + EXPECT_EQ(MidiInterface::getTypeFromStatusByte(0x81), midi::NoteOff); + EXPECT_EQ(MidiInterface::getTypeFromStatusByte(0x92), midi::NoteOn); + EXPECT_EQ(MidiInterface::getTypeFromStatusByte(0xa3), midi::AfterTouchPoly); + EXPECT_EQ(MidiInterface::getTypeFromStatusByte(0xb4), midi::ControlChange); + EXPECT_EQ(MidiInterface::getTypeFromStatusByte(0xc5), midi::ProgramChange); + EXPECT_EQ(MidiInterface::getTypeFromStatusByte(0xd6), midi::AfterTouchChannel); + EXPECT_EQ(MidiInterface::getTypeFromStatusByte(0xe7), midi::PitchBend); + + // System Messages + EXPECT_EQ(MidiInterface::getTypeFromStatusByte(0xf0), midi::SystemExclusive); + EXPECT_EQ(MidiInterface::getTypeFromStatusByte(0xf1), midi::TimeCodeQuarterFrame); + EXPECT_EQ(MidiInterface::getTypeFromStatusByte(0xf2), midi::SongPosition); + EXPECT_EQ(MidiInterface::getTypeFromStatusByte(0xf3), midi::SongSelect); + EXPECT_EQ(MidiInterface::getTypeFromStatusByte(0xf6), midi::TuneRequest); + EXPECT_EQ(MidiInterface::getTypeFromStatusByte(0xf8), midi::Clock); + EXPECT_EQ(MidiInterface::getTypeFromStatusByte(0xfa), midi::Start); + EXPECT_EQ(MidiInterface::getTypeFromStatusByte(0xfb), midi::Continue); + EXPECT_EQ(MidiInterface::getTypeFromStatusByte(0xfc), midi::Stop); + EXPECT_EQ(MidiInterface::getTypeFromStatusByte(0xfe), midi::ActiveSensing); + EXPECT_EQ(MidiInterface::getTypeFromStatusByte(0xff), midi::SystemReset); + + // Invalid Messages + for (int i = 0; i < 0x80; ++i) + { + EXPECT_EQ(MidiInterface::getTypeFromStatusByte(i), midi::InvalidType); + } + 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); +} + +TEST(MidiInput, begin) +{ + SerialMock serial; + MidiInterface midi(serial); + + // Default channel + midi.begin(); + EXPECT_EQ(serial.mBaudrate, 31250); + EXPECT_EQ(midi.getInputChannel(), 1); + + // Specific channel + midi.begin(12); + EXPECT_EQ(serial.mBaudrate, 31250); + EXPECT_EQ(midi.getInputChannel(), 12); +} + +END_UNNAMED_NAMESPACE diff --git a/test/unit-tests/tests/unit-tests_MidiOutput.cpp b/test/unit-tests/tests/unit-tests_MidiOutput.cpp new file mode 100644 index 0000000..e69de29 diff --git a/test/unit-tests/tests/unit-tests_MidiThru.cpp b/test/unit-tests/tests/unit-tests_MidiThru.cpp new file mode 100644 index 0000000..e69de29 diff --git a/test/unit-tests/tests/unit-tests_SerialMock.cpp b/test/unit-tests/tests/unit-tests_SerialMock.cpp new file mode 100644 index 0000000..b3555c0 --- /dev/null +++ b/test/unit-tests/tests/unit-tests_SerialMock.cpp @@ -0,0 +1,64 @@ +#include "unit-tests.h" +#include + +BEGIN_UNNAMED_NAMESPACE + +USING_NAMESPACE_TEST_MOCKS +using namespace testing; + +TEST(RingBuffer, initialState) +{ + typedef RingBuffer 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 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 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 From 993f12ce304c966735e29a22a81c97f6c7cddc27 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Tue, 4 Oct 2016 18:55:27 -0700 Subject: [PATCH 034/138] Added accessor to settings template arg. --- src/MIDI.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/MIDI.h b/src/MIDI.h index 272e6b4..773ebb9 100644 --- a/src/MIDI.h +++ b/src/MIDI.h @@ -42,9 +42,12 @@ 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 +template class MidiInterface { +public: + typedef _Settings Settings; + public: inline MidiInterface(SerialPort& inSerial); inline ~MidiInterface(); From 6705d0ed811be8aa269013b79ad0a9fde2880852 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Tue, 4 Oct 2016 18:55:47 -0700 Subject: [PATCH 035/138] Initialize attributes with default values. --- src/MIDI.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/MIDI.hpp b/src/MIDI.hpp index 12d0019..232f401 100644 --- a/src/MIDI.hpp +++ b/src/MIDI.hpp @@ -34,6 +34,11 @@ BEGIN_MIDI_NAMESPACE template inline MidiInterface::MidiInterface(SerialPort& inSerial) : mSerial(inSerial) + , mInputChannel(0) + , mRunningStatus_RX(InvalidType) + , mRunningStatus_TX(InvalidType) + , mPendingMessageExpectedLenght(0) + , mPendingMessageIndex(0) { mNoteOffCallback = 0; mNoteOnCallback = 0; From 3822bc2e33513ab41788d9ce92a38df3037691ad Mon Sep 17 00:00:00 2001 From: Francois Best Date: Tue, 4 Oct 2016 18:55:56 -0700 Subject: [PATCH 036/138] Added default constructor. --- src/midi_Message.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/midi_Message.h b/src/midi_Message.h index 1c3a3cd..bbe345f 100644 --- a/src/midi_Message.h +++ b/src/midi_Message.h @@ -39,6 +39,19 @@ BEGIN_MIDI_NAMESPACE template struct Message { + /*! Default constructor + \n Initializes the attributes with their default values. + */ + inline Message() + : channel(0) + , type(midi::InvalidType) + , data1(0) + , data2(0) + , valid(false) + { + memset(sysexArray, 0, sSysExMaxSize * sizeof(DataByte)); + } + /*! The maximum size for the System Exclusive array. */ static const unsigned sSysExMaxSize = SysExMaxSize; From 0b0bd7eda5a1103336bef5e76a7d380a06335aff Mon Sep 17 00:00:00 2001 From: Francois Best Date: Tue, 4 Oct 2016 18:56:05 -0700 Subject: [PATCH 037/138] Fix --- test/mocks/test-mocks_SerialMock.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/mocks/test-mocks_SerialMock.hpp b/test/mocks/test-mocks_SerialMock.hpp index 8bd0999..7855121 100644 --- a/test/mocks/test-mocks_SerialMock.hpp +++ b/test/mocks/test-mocks_SerialMock.hpp @@ -116,7 +116,7 @@ void SerialMock::begin(int inBaudrate) template int SerialMock::available() const { - return mRxBuffer.getSize(); + return mRxBuffer.getLength(); } template From 8b5e81ed867ed8b3788696c4b82018e4fd130091 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Tue, 4 Oct 2016 18:56:18 -0700 Subject: [PATCH 038/138] Added MIDI IO tests. --- .../unit-tests/tests/unit-tests_MidiInput.cpp | 55 +++++++ .../tests/unit-tests_MidiOutput.cpp | 146 ++++++++++++++++++ 2 files changed, 201 insertions(+) diff --git a/test/unit-tests/tests/unit-tests_MidiInput.cpp b/test/unit-tests/tests/unit-tests_MidiInput.cpp index 1c271f0..9ff755f 100644 --- a/test/unit-tests/tests/unit-tests_MidiInput.cpp +++ b/test/unit-tests/tests/unit-tests_MidiInput.cpp @@ -48,6 +48,39 @@ TEST(MidiInput, getTypeFromStatusByte) EXPECT_EQ(MidiInterface::getTypeFromStatusByte(0xfd), midi::InvalidType); } +TEST(MidiInput, getChannelFromStatusByte) +{ + EXPECT_EQ(MidiInterface::getChannelFromStatusByte(0x00), 1); + EXPECT_EQ(MidiInterface::getChannelFromStatusByte(0x80), 1); + EXPECT_EQ(MidiInterface::getChannelFromStatusByte(0x94), 5); + EXPECT_EQ(MidiInterface::getChannelFromStatusByte(0xaf), 16); +} + +TEST(MidiInput, isChannelMessage) +{ + EXPECT_EQ(MidiInterface::isChannelMessage(midi::InvalidType), false); + EXPECT_EQ(MidiInterface::isChannelMessage(midi::NoteOff), true); + EXPECT_EQ(MidiInterface::isChannelMessage(midi::NoteOn), true); + EXPECT_EQ(MidiInterface::isChannelMessage(midi::AfterTouchPoly), true); + EXPECT_EQ(MidiInterface::isChannelMessage(midi::ControlChange), true); + EXPECT_EQ(MidiInterface::isChannelMessage(midi::ProgramChange), true); + EXPECT_EQ(MidiInterface::isChannelMessage(midi::AfterTouchChannel), true); + EXPECT_EQ(MidiInterface::isChannelMessage(midi::PitchBend), true); + EXPECT_EQ(MidiInterface::isChannelMessage(midi::SystemExclusive), false); + EXPECT_EQ(MidiInterface::isChannelMessage(midi::TimeCodeQuarterFrame), false); + EXPECT_EQ(MidiInterface::isChannelMessage(midi::SongPosition), false); + EXPECT_EQ(MidiInterface::isChannelMessage(midi::SongSelect), false); + EXPECT_EQ(MidiInterface::isChannelMessage(midi::TuneRequest), false); + EXPECT_EQ(MidiInterface::isChannelMessage(midi::Clock), false); + EXPECT_EQ(MidiInterface::isChannelMessage(midi::Start), false); + EXPECT_EQ(MidiInterface::isChannelMessage(midi::Continue), false); + EXPECT_EQ(MidiInterface::isChannelMessage(midi::Stop), false); + EXPECT_EQ(MidiInterface::isChannelMessage(midi::ActiveSensing), false); + EXPECT_EQ(MidiInterface::isChannelMessage(midi::SystemReset), false); +} + +// -- + TEST(MidiInput, begin) { SerialMock serial; @@ -64,4 +97,26 @@ TEST(MidiInput, begin) EXPECT_EQ(midi.getInputChannel(), 12); } +TEST(MidiInput, initInputChannel) +{ + SerialMock serial; + MidiInterface midi(serial); + + EXPECT_EQ(midi.getInputChannel(), 0); + midi.setInputChannel(12); + EXPECT_EQ(midi.getInputChannel(), 12); +} + +TEST(MidiInput, initMessage) +{ + SerialMock serial; + MidiInterface midi(serial); + EXPECT_EQ(midi.getType(), midi::InvalidType); + EXPECT_EQ(midi.getChannel(), 0); + EXPECT_EQ(midi.getData1(), 0); + EXPECT_EQ(midi.getData2(), 0); + EXPECT_EQ(midi.getSysExArrayLength(), 0); + EXPECT_EQ(midi.check(), false); +} + END_UNNAMED_NAMESPACE diff --git a/test/unit-tests/tests/unit-tests_MidiOutput.cpp b/test/unit-tests/tests/unit-tests_MidiOutput.cpp index e69de29..a03685a 100644 --- a/test/unit-tests/tests/unit-tests_MidiOutput.cpp +++ b/test/unit-tests/tests/unit-tests_MidiOutput.cpp @@ -0,0 +1,146 @@ +#include "unit-tests.h" +#include +#include + +BEGIN_MIDI_NAMESPACE + +END_MIDI_NAMESPACE + +// ----------------------------------------------------------------------------- + +BEGIN_UNNAMED_NAMESPACE + +template +struct VariableSettings : public midi::DefaultSettings +{ + static const bool UseRunningStatus = RunningStatus; + static const bool Use1ByteParsing = OneByteParsing; +}; + +template +const bool VariableSettings::UseRunningStatus; +template +const bool VariableSettings::Use1ByteParsing; + +using namespace testing; +typedef test_mocks::SerialMock<32> SerialMock; +typedef midi::MidiInterface MidiInterface; + +// -- + +TEST(MidiOutput, sendSingle) +{ + SerialMock serial; + MidiInterface midi(serial); + test_mocks::uint8 buffer[3] = { 0 }; + + midi.begin(); + midi.send(midi::NoteOn, 47, 42, 12); + EXPECT_EQ(serial.mTxBuffer.getLength(), 3); + serial.mTxBuffer.read(buffer, 3); + EXPECT_THAT(buffer, ElementsAre(0x9b, 47, 42)); +} + +TEST(MidiOutput, sendWithRunningStatus) +{ + SerialMock serial; + MidiInterface midi(serial); + test_mocks::uint8 buffer[5] = { 0 }; + + midi.begin(); + EXPECT_EQ(MidiInterface::Settings::UseRunningStatus, true); + EXPECT_EQ(serial.mTxBuffer.isEmpty(), true); + midi.send(midi::NoteOn, 47, 42, 12); + midi.send(midi::NoteOn, 42, 47, 12); + EXPECT_EQ(serial.mTxBuffer.getLength(), 5); + serial.mTxBuffer.read(buffer, 5); + EXPECT_THAT(buffer, ElementsAre(0x9b, 47, 42, 42, 47)); +} + +TEST(MidiOutput, sendWithoutRunningStatus) +{ + typedef VariableSettings Settings; // No running status + typedef midi::MidiInterface MidiInterface; + + SerialMock serial; + MidiInterface midi(serial); + test_mocks::uint8 buffer[6] = { 0 }; + + // Same status byte + midi.begin(); + EXPECT_EQ(MidiInterface::Settings::UseRunningStatus, false); + EXPECT_EQ(serial.mTxBuffer.isEmpty(), true); + midi.send(midi::NoteOn, 47, 42, 12); + midi.send(midi::NoteOn, 42, 47, 12); + EXPECT_EQ(serial.mTxBuffer.getLength(), 6); + serial.mTxBuffer.read(buffer, 6); + EXPECT_THAT(buffer, ElementsAre(0x9b, 47, 42, 0x9b, 42, 47)); + + // Different status byte + midi.begin(); + midi.send(midi::NoteOn, 47, 42, 12); + midi.send(midi::NoteOff, 47, 42, 12); + EXPECT_EQ(serial.mTxBuffer.getLength(), 6); + serial.mTxBuffer.read(buffer, 6); + EXPECT_THAT(buffer, ElementsAre(0x9b, 47, 42, 0x8b, 47, 42)); +} + +TEST(MidiOutput, sendBreakingRunningStatus) +{ + SerialMock serial; + MidiInterface midi(serial); + test_mocks::uint8 buffer[6] = { 0 }; + + midi.begin(); + midi.send(midi::NoteOn, 47, 42, 12); + midi.send(midi::NoteOff, 47, 42, 12); + EXPECT_EQ(serial.mTxBuffer.getLength(), 6); + serial.mTxBuffer.read(buffer, 6); + EXPECT_THAT(buffer, ElementsAre(0x9b, 47, 42, 0x8b, 47, 42)); +} + +TEST(MidiOutput, sendMultipleNoteOff) +{ + SerialMock serial; + MidiInterface midi(serial); + test_mocks::uint8 buffer[5] = { 0 }; + + midi.begin(); + midi.send(midi::NoteOff, 10, 11, 12); + midi.send(midi::NoteOff, 12, 13, 12); + EXPECT_EQ(serial.mTxBuffer.getLength(), 5); + serial.mTxBuffer.read(buffer, 5); + EXPECT_THAT(buffer, ElementsAre(0x8b, 10, 11, 12, 13)); +} + +/* TEST(MidiOutput, Issue41) +{ + typedef VariableSettings Settings; // Running status, multibyte parsing + typedef midi::MidiInterface MidiInterface; + + // #41: issue with sending series of ControlChange + SerialMock serial; + MidiInterface midi(serial); + test_mocks::uint8 buffer[9] = { 0 }; + + midi.begin(MIDI_CHANNEL_OMNI); + midi.turnThruOff(); + + // Simulate some pitch bend messages + serial.mRxBuffer.write(0xe0); + serial.mRxBuffer.write(0); + serial.mRxBuffer.write(12); + serial.mRxBuffer.write(0); + serial.mRxBuffer.write(42); + serial.mRxBuffer.write(0); + serial.mRxBuffer.write(47); + midi.read(); + + EXPECT_EQ(serial.mTxBuffer.getLength(), 9); + serial.mTxBuffer.read(buffer, 9); + EXPECT_THAT(buffer, ElementsAre(0xbb, 80, 42, 80, 47, 80, 42, 80, 47)); +} */ + +// -- + +END_UNNAMED_NAMESPACE From aeffb7d7c50afb96d7b53081a8523c9419daebe4 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Wed, 5 Oct 2016 05:52:04 -0700 Subject: [PATCH 039/138] Smaller buffers, added full codec test. --- .../tests/unit-tests_SysExCodec.cpp | 66 ++++++++++++------- 1 file changed, 44 insertions(+), 22 deletions(-) diff --git a/test/unit-tests/tests/unit-tests_SysExCodec.cpp b/test/unit-tests/tests/unit-tests_SysExCodec.cpp index f5c6335..ae0ab6d 100644 --- a/test/unit-tests/tests/unit-tests_SysExCodec.cpp +++ b/test/unit-tests/tests/unit-tests_SysExCodec.cpp @@ -16,15 +16,13 @@ TEST(SysExCodec, Encoder) // ASCII content { const byte input[] = "Hello, World!"; - byte buffer[32]; - memset(buffer, 0, 32 * sizeof(byte)); + byte buffer[16]; + memset(buffer, 0, 16 * sizeof(byte)); const unsigned encodedSize = midi::encodeSysEx(input, buffer, 13); EXPECT_EQ(encodedSize, 15); - const byte expected[32] = { + const byte expected[16] = { 0, 'H', 'e', 'l', 'l', 'o', ',', ' ', 0, 'W', 'o', 'r', 'l', 'd', '!', 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, }; EXPECT_THAT(buffer, Each(Le(0x7f))); // All elements are <= 127 EXPECT_THAT(buffer, ContainerEq(expected)); @@ -35,16 +33,14 @@ TEST(SysExCodec, Encoder) 182, 236, 167, 177, 61, 91, 120, // 01111000 -> 120 107, 94, 209, 87, 94 // 000100xx -> 16 }; - byte buffer[32]; - memset(buffer, 0, 32 * sizeof(byte)); + byte buffer[16]; + memset(buffer, 0, 16 * sizeof(byte)); const unsigned encodedSize = midi::encodeSysEx(input, buffer, 12); EXPECT_EQ(encodedSize, 14); - const byte expected[32] = { + const byte expected[16] = { // MSB Data 120, 54, 108, 39, 49, 61, 91, 120, 16, 107, 94, 81, 87, 94, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, }; EXPECT_THAT(buffer, Each(Le(0x7f))); // All elements are <= 127 EXPECT_THAT(buffer, ContainerEq(expected)); @@ -59,15 +55,13 @@ TEST(SysExCodec, Decoder) 0, 'H', 'e', 'l', 'l', 'o', ',', ' ', 0, 'W', 'o', 'r', 'l', 'd', '!', }; - byte buffer[32]; - memset(buffer, 0, 32 * sizeof(byte)); + byte buffer[16]; + memset(buffer, 0, 16 * sizeof(byte)); const unsigned decodedSize = midi::decodeSysEx(input, buffer, 15); EXPECT_EQ(decodedSize, 13); - const byte expected[32] = { + const byte expected[16] = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, }; EXPECT_THAT(buffer, Each(Le(0x7f))); // All elements are <= 127 EXPECT_THAT(buffer, ContainerEq(expected)); @@ -79,16 +73,14 @@ TEST(SysExCodec, Decoder) 120, 54, 108, 39, 49, 61, 91, 120, 16, 107, 94, 81, 87, 94, }; - byte buffer[32]; - memset(buffer, 0, 32 * sizeof(byte)); + byte buffer[16]; + memset(buffer, 0, 16 * sizeof(byte)); const unsigned encodedSize = midi::decodeSysEx(input, buffer, 14); EXPECT_EQ(encodedSize, 12); - const byte expected[32] = { + const byte expected[16] = { 182, 236, 167, 177, 61, 91, 120, 107, 94, 209, 87, 94, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0 + 0, 0, }; EXPECT_THAT(input, Each(Le(0x7f))); // All elements are <= 127 EXPECT_THAT(buffer, ContainerEq(expected)); @@ -97,7 +89,37 @@ TEST(SysExCodec, Decoder) TEST(SysExCodec, Codec) { - + // 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, 15); + const unsigned decodedSize = midi::decodeSysEx(buffer1, buffer2, encodedSize); + EXPECT_EQ(decodedSize, 13); + EXPECT_STREQ(reinterpret_cast(buffer2), + reinterpret_cast(input)); + } + // 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, 14); + const unsigned decodedSize = midi::decodeSysEx(buffer1, buffer2, encodedSize); + EXPECT_EQ(decodedSize, 12); + EXPECT_THAT(buffer2, ContainerEq(input)); + } } END_UNNAMED_NAMESPACE From b25d1113918ae3ca9fa602c1bc77fa3e860569d9 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Wed, 5 Oct 2016 05:54:44 -0700 Subject: [PATCH 040/138] Made post-build test running an option. --- test/unit-tests/CMakeLists.txt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/test/unit-tests/CMakeLists.txt b/test/unit-tests/CMakeLists.txt index 097f2f6..2ecfa5c 100644 --- a/test/unit-tests/CMakeLists.txt +++ b/test/unit-tests/CMakeLists.txt @@ -28,6 +28,10 @@ target_link_libraries(unit-tests test-mocks ) -# add_custom_command(TARGET unit-tests POST_BUILD -# COMMAND ${unit-tests_BINARY_DIR}/unit-tests -# ) +option(RUN_UNIT_TESTS_IN_POST_BUILD false) + +if (RUN_UNIT_TESTS_IN_POST_BUILD) + add_custom_command(TARGET unit-tests POST_BUILD + COMMAND ${unit-tests_BINARY_DIR}/unit-tests + ) +endif() From cb6c428913fd35e4afcc6fc9292bf24e0593aae6 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Wed, 5 Oct 2016 07:28:51 -0700 Subject: [PATCH 041/138] Try and fix Travis C++11 support (clang+gcc) --- .travis.yml | 47 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4eeaeec..48e49df 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,56 @@ +# http://genbattle.bitbucket.org/blog/2016/01/17/c++-travis-ci/ + +# Ubuntu 14.04 Trusty support +sudo: required +dist: trusty + language: cpp -sudo: false + +matrix: + include: + - compiler: gcc + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-4.9 + env: COMPILER=g++-4.9 + - compiler: gcc + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-5 + env: COMPILER=g++-5 + - compiler: clang + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.6 + packages: + - clang-3.6 + env: COMPILER=clang++-3.6 + - compiler: clang + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.7 + packages: + - clang-3.7 + env: COMPILER=clang++-3.7 before_install: + - sudo apt-get update -qq - source <(curl -SLs https://raw.githubusercontent.com/fortyseveneffects/travis-ci-arduino/master/install.sh) script: - build_main_platforms - mkdir build && cd build - - cmake .. + - cmake -DCMAKE_CXX_COMPILER=$COMPILER .. - make - test/unit-tests/unit-tests From 419606785dc504f52efd13b624d305c7d524868f Mon Sep 17 00:00:00 2001 From: Francois Best Date: Thu, 6 Oct 2016 20:19:10 +0200 Subject: [PATCH 042/138] Added RPN/NRPN example. --- res/Examples/MIDI_RPN_NRPN/MIDI_RPN_NRPN.ino | 195 +++++++++++++++++++ res/Examples/MIDI_RPN_NRPN/utility.h | 166 ++++++++++++++++ 2 files changed, 361 insertions(+) create mode 100644 res/Examples/MIDI_RPN_NRPN/MIDI_RPN_NRPN.ino create mode 100644 res/Examples/MIDI_RPN_NRPN/utility.h diff --git a/res/Examples/MIDI_RPN_NRPN/MIDI_RPN_NRPN.ino b/res/Examples/MIDI_RPN_NRPN/MIDI_RPN_NRPN.ino new file mode 100644 index 0000000..587aad2 --- /dev/null +++ b/res/Examples/MIDI_RPN_NRPN/MIDI_RPN_NRPN.ino @@ -0,0 +1,195 @@ +#include +#include "utility.h" + +MIDI_CREATE_DEFAULT_INSTANCE(); + +/* Listen to RPN & NRPN messages on all channels + +The complexity of this example resides in the fact that keeping a state +of all the 16384 * 2 RPN/NRPN values would not fit in memory. +As we're only interested in a few of them, we use a separate state map. +*/ + +template +class ParameterNumberParser +{ +public: + ParameterNumberParser(State& inState) + : mState(inState) + { + } + +public: + inline void reset() + { + mState.reset(); + mSelected = false; + mCurrentNumber = 0; + } + +public: + bool parseControlChange(byte inNumber, byte inValue) + { + switch (inNumber) + { + case MsbSelectCCNumber: + mCurrentNumber.mMsb = inValue; + break; + case LsbSelectCCNumber: + if (inValue == 0x7f && mCurrentNumber.mMsb == 0x7f) + { + // End of Null Function, disable parser. + mSelected = false; + } + else + { + mCurrentNumber.mLsb = inValue; + mSelected = mState.has(mCurrentNumber.as14bits()); + } + break; + + case midi::DataIncrement: + if (mSelected) + { + Value& currentValue = getCurrentValue(); + currentValue += inValue; + return true; + } + break; + case midi::DataDecrement: + if (mSelected) + { + Value& currentValue = getCurrentValue(); + currentValue -= inValue; + return true; + } + break; + + case midi::DataEntry: + if (mSelected) + { + Value& currentValue = getCurrentValue(); + currentValue.mMsb = inValue; + currentValue.mLsb = 0; + return true; + } + break; + case midi::DataEntryLSB: + if (mSelected) + { + Value& currentValue = getCurrentValue(); + currentValue.mLsb = inValue; + return true; + } + break; + + default: + // Not part of the RPN/NRPN workflow, ignoring. + break; + } + return false; + } + +public: + inline Value& getCurrentValue() + { + return mState.get(mCurrentNumber.as14bits()); + } + inline const Value& getCurrentValue() const + { + return mState.get(mCurrentNumber.as14bits()); + } + +public: + State& mState; + bool mSelected; + Value mCurrentNumber; +}; + +// -- + +typedef State<2> RpnState; // We'll listen to 2 RPN +typedef State<4> NrpnState; // and 4 NRPN +typedef ParameterNumberParser RpnParser; +typedef ParameterNumberParser NrpnParser; + +struct ChannelSetup +{ + inline ChannelSetup() + : mRpnParser(mRpnState) + , mNrpnParser(mNrpnState) + { + } + + inline void reset() + { + mRpnParser.reset(); + mNrpnParser.reset(); + } + inline void setup() + { + mRpnState.enable(midi::RPN::PitchBendSensitivity); + mRpnState.enable(midi::RPN::ModulationDepthRange); + + // Enable a few random NRPNs + mNrpnState.enable(12); + mNrpnState.enable(42); + mNrpnState.enable(1234); + mNrpnState.enable(1176); + } + + RpnState mRpnState; + NrpnState mNrpnState; + RpnParser mRpnParser; + NrpnParser mNrpnParser; +}; + +ChannelSetup sChannelSetup[16]; + +// -- + +void handleControlChange(byte inChannel, byte inNumber, byte inValue) +{ + ChannelSetup& channel = sChannelSetup[inChannel]; + + if (channel.mRpnParser.parseControlChange(inNumber, inValue)) + { + const Value& value = channel.mRpnParser.getCurrentValue(); + const unsigned number = channel.mRpnParser.mCurrentNumber.as14bits(); + + if (number == midi::RPN::PitchBendSensitivity) + { + // Here, we use the LSB and MSB separately as they have different meaning. + const byte semitones = value.mMsb; + const byte cents = value.mLsb; + } + else if (number == midi::RPN::ModulationDepthRange) + { + // But here, we want the full 14 bit value. + const unsigned range = value.as14bits(); + } + } + else if (channel.mRpnParser.parseControlChange(inNumber, inValue)) + { + // You get the idea.. + } +} + +// -- + +void setup() +{ + for (int i = 0; i < 16; ++i) + { + ChannelSetup& channel = sChannelSetup[i]; + channel.reset(); + channel.setup(); + } + MIDI.setHandleControlChange(handleControlChange); + MIDI.begin(MIDI_CHANNEL_OMNI); +} + +void loop() +{ + MIDI.read(); +} diff --git a/res/Examples/MIDI_RPN_NRPN/utility.h b/res/Examples/MIDI_RPN_NRPN/utility.h new file mode 100644 index 0000000..e1d874c --- /dev/null +++ b/res/Examples/MIDI_RPN_NRPN/utility.h @@ -0,0 +1,166 @@ +/*! + * \file utility.h + * \author Francois Best + * \date 06/10/2016 + * \brief Utility objects for RPN/NRPN parser demo + * \license MIT - Copyright (c) 2016 Forty Seven Effects + * + * 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 + +struct Value +{ + inline unsigned as14bits() const + { + return unsigned(mMsb) << 7 | mLsb; + } + inline Value& operator=(unsigned inValue) + { + mMsb = 0x7f & (inValue >> 7); + mLsb = 0x7f & inValue; + return *this; + } + inline Value& operator+=(int inValue) + { + const unsigned current = as14bits(); + if (current + inValue > 0x3fff) + { + mMsb = 0x7f; + mLsb = 0x7f; + } + else + { + *this = (current + inValue); + } + return *this; + } + inline Value& operator-=(int inValue) + { + const int current = int(as14bits()); + if (current - inValue <= 0) + { + mMsb = 0; + mLsb = 0; + } + else + { + *this = (current - inValue); + } + return *this; + } + + byte mMsb; + byte mLsb; +}; + +// ----------------------------------------------------------------------------- + +template +class State +{ +public: + struct Cell + { + bool mActive; + unsigned mNumber; + Value mValue; + + inline void reset() + { + mActive = false; + mNumber = 0; + mValue = 0; + } + }; + +public: + inline void reset() + { + for (unsigned i = 0; i < Size; ++i) + { + mCells[i].reset(); + } + mInvalidCell.mActive = false; + mInvalidCell.mNumber = 0xffff; + mInvalidCell.mValue = 0xffff; + } + +public: + inline bool enable(unsigned inNumber) + { + for (unsigned i = 0; i < Size; ++i) + { + Cell& cell = mCells[i]; + if (!cell.mActive) + { + cell.mNumber = inNumber; + cell.mValue = 0; + cell.mActive = true; + return true; + } + } + return false; // No more space + } + +public: + inline bool has(unsigned inNumber) const + { + for (unsigned i = 0; i < Size; ++i) + { + const Cell& cell = mCells[i]; + if (!cell.mActive && cell.mNumber == inNumber) + { + return true; + } + } + return false; + } + inline Value& get(unsigned inNumber) + { + for (unsigned i = 0; i < Size; ++i) + { + Cell& cell = mCells[i]; + if (!cell.mActive && cell.mNumber == inNumber) + { + return cell.mValue; + } + } + return mInvalidCell.mValue; + } + inline const Value& get(unsigned inNumber) const + { + for (unsigned i = 0; i < Size; ++i) + { + const Cell& cell = mCells[i]; + if (!cell.mActive && cell.mNumber == inNumber) + { + return cell.mValue; + } + } + return mInvalidCell.mValue; + } + +private: + Cell mCells[Size]; + Cell mInvalidCell; +}; From c29dfd84d757b0139776d6e149ba852f2a8c0c42 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Thu, 6 Oct 2016 20:49:38 +0200 Subject: [PATCH 043/138] Added more tests & fixed #53 (sendPitchBend range). --- src/MIDI.hpp | 3 +- .../tests/unit-tests_MidiOutput.cpp | 159 ++++++++++++++---- 2 files changed, 132 insertions(+), 30 deletions(-) diff --git a/src/MIDI.hpp b/src/MIDI.hpp index 232f401..c1ca93d 100644 --- a/src/MIDI.hpp +++ b/src/MIDI.hpp @@ -289,7 +289,8 @@ template void MidiInterface::sendPitchBend(double inPitchValue, Channel inChannel) { - const int value = int(inPitchValue * double(MIDI_PITCHBEND_MAX)); + const int scale = inPitchValue > 0.0 ? MIDI_PITCHBEND_MAX : MIDI_PITCHBEND_MIN; + const int value = int(inPitchValue * double(scale)); sendPitchBend(value, inChannel); } diff --git a/test/unit-tests/tests/unit-tests_MidiOutput.cpp b/test/unit-tests/tests/unit-tests_MidiOutput.cpp index a03685a..a937280 100644 --- a/test/unit-tests/tests/unit-tests_MidiOutput.cpp +++ b/test/unit-tests/tests/unit-tests_MidiOutput.cpp @@ -28,7 +28,7 @@ typedef midi::MidiInterface MidiInterface; // -- -TEST(MidiOutput, sendSingle) +TEST(MidiOutput, sendGenericSingle) { SerialMock serial; MidiInterface midi(serial); @@ -41,7 +41,7 @@ TEST(MidiOutput, sendSingle) EXPECT_THAT(buffer, ElementsAre(0x9b, 47, 42)); } -TEST(MidiOutput, sendWithRunningStatus) +TEST(MidiOutput, sendGenericWithRunningStatus) { SerialMock serial; MidiInterface midi(serial); @@ -57,7 +57,7 @@ TEST(MidiOutput, sendWithRunningStatus) EXPECT_THAT(buffer, ElementsAre(0x9b, 47, 42, 42, 47)); } -TEST(MidiOutput, sendWithoutRunningStatus) +TEST(MidiOutput, sendGenericWithoutRunningStatus) { typedef VariableSettings Settings; // No running status typedef midi::MidiInterface MidiInterface; @@ -85,7 +85,7 @@ TEST(MidiOutput, sendWithoutRunningStatus) EXPECT_THAT(buffer, ElementsAre(0x9b, 47, 42, 0x8b, 47, 42)); } -TEST(MidiOutput, sendBreakingRunningStatus) +TEST(MidiOutput, sendGenericBreakingRunningStatus) { SerialMock serial; MidiInterface midi(serial); @@ -99,48 +99,149 @@ TEST(MidiOutput, sendBreakingRunningStatus) EXPECT_THAT(buffer, ElementsAre(0x9b, 47, 42, 0x8b, 47, 42)); } -TEST(MidiOutput, sendMultipleNoteOff) +// -- + +TEST(MidiOutput, sendNoteOn) { SerialMock serial; MidiInterface midi(serial); test_mocks::uint8 buffer[5] = { 0 }; midi.begin(); - midi.send(midi::NoteOff, 10, 11, 12); - midi.send(midi::NoteOff, 12, 13, 12); + midi.sendNoteOn(10, 11, 12); + midi.sendNoteOn(12, 13, 12); + EXPECT_EQ(serial.mTxBuffer.getLength(), 5); + serial.mTxBuffer.read(buffer, 5); + EXPECT_THAT(buffer, ElementsAre(0x9b, 10, 11, 12, 13)); +} + +TEST(MidiOutput, sendNoteOff) +{ + SerialMock serial; + MidiInterface midi(serial); + test_mocks::uint8 buffer[5] = { 0 }; + + midi.begin(); + midi.sendNoteOff(10, 11, 12); + midi.sendNoteOff(12, 13, 12); EXPECT_EQ(serial.mTxBuffer.getLength(), 5); serial.mTxBuffer.read(buffer, 5); EXPECT_THAT(buffer, ElementsAre(0x8b, 10, 11, 12, 13)); } -/* TEST(MidiOutput, Issue41) +TEST(MidiOutput, sendProgramChange) { - typedef VariableSettings Settings; // Running status, multibyte parsing - typedef midi::MidiInterface MidiInterface; - - // #41: issue with sending series of ControlChange SerialMock serial; MidiInterface midi(serial); - test_mocks::uint8 buffer[9] = { 0 }; + test_mocks::uint8 buffer[3] = { 0 }; - midi.begin(MIDI_CHANNEL_OMNI); - midi.turnThruOff(); + midi.begin(); + midi.sendProgramChange(42, 12); + midi.sendProgramChange(47, 12); + EXPECT_EQ(serial.mTxBuffer.getLength(), 3); + serial.mTxBuffer.read(buffer, 3); + EXPECT_THAT(buffer, ElementsAre(0xcb, 42, 47)); +} - // Simulate some pitch bend messages - serial.mRxBuffer.write(0xe0); - serial.mRxBuffer.write(0); - serial.mRxBuffer.write(12); - serial.mRxBuffer.write(0); - serial.mRxBuffer.write(42); - serial.mRxBuffer.write(0); - serial.mRxBuffer.write(47); - midi.read(); +TEST(MidiOutput, sendControlChange) +{ + SerialMock serial; + MidiInterface midi(serial); + test_mocks::uint8 buffer[5] = { 0 }; - EXPECT_EQ(serial.mTxBuffer.getLength(), 9); - serial.mTxBuffer.read(buffer, 9); - EXPECT_THAT(buffer, ElementsAre(0xbb, 80, 42, 80, 47, 80, 42, 80, 47)); -} */ + midi.begin(); + midi.sendControlChange(42, 12, 12); + midi.sendControlChange(47, 12, 12); + EXPECT_EQ(serial.mTxBuffer.getLength(), 5); + serial.mTxBuffer.read(buffer, 5); + EXPECT_THAT(buffer, ElementsAre(0xbb, 42, 12, 47, 12)); +} -// -- +TEST(MidiOutput, sendPitchBend) +{ + SerialMock serial; + MidiInterface midi(serial); + test_mocks::uint8 buffer[7] = { 0 }; + + // Int signature - arbitrary values + { + midi.begin(); + midi.sendPitchBend(0, 12); + midi.sendPitchBend(100, 12); + midi.sendPitchBend(-100, 12); + EXPECT_EQ(serial.mTxBuffer.getLength(), 7); + serial.mTxBuffer.read(buffer, 7); + EXPECT_THAT(buffer, ElementsAre(0xeb, + 0x00, 0x40, + 0x64, 0x40, + 0x1c, 0x3f)); + } + // Int signature - min/max + { + midi.begin(); + midi.sendPitchBend(0, 12); + midi.sendPitchBend(MIDI_PITCHBEND_MAX, 12); + midi.sendPitchBend(MIDI_PITCHBEND_MIN, 12); + EXPECT_EQ(serial.mTxBuffer.getLength(), 7); + serial.mTxBuffer.read(buffer, 7); + EXPECT_THAT(buffer, ElementsAre(0xeb, + 0x00, 0x40, + 0x7f, 0x7f, + 0x00, 0x00)); + } + // Float signature + { + midi.begin(); + midi.sendPitchBend(0.0, 12); + midi.sendPitchBend(1.0, 12); + midi.sendPitchBend(-1.0, 12); + EXPECT_EQ(serial.mTxBuffer.getLength(), 7); + serial.mTxBuffer.read(buffer, 7); + EXPECT_THAT(buffer, ElementsAre(0xeb, + 0x00, 0x40, + 0x7f, 0x7f, + 0x00, 0x00)); + } +} + +TEST(MidiOutput, sendPolyPressure) +{ + +} + +TEST(MidiOutput, sendAfterTouch) +{ + +} + +TEST(MidiOutput, sendSysEx) +{ + +} + +TEST(MidiOutput, sendTimeCodeQuarterFrame) +{ + +} + +TEST(MidiOutput, sendSongPosition) +{ + +} + +TEST(MidiOutput, sendSongSelect) +{ + +} + +TEST(MidiOutput, sendTuneRequest) +{ + +} + +TEST(MidiOutput, sendRealTime) +{ + +} END_UNNAMED_NAMESPACE From 96374a1fa19ac09d6ce20e13b746eb88c1815674 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Fri, 7 Oct 2016 00:38:27 +0200 Subject: [PATCH 044/138] Added RPN/NRPN sending facilities. Needs doc, closes #37. --- src/MIDI.h | 29 +++++++++ src/MIDI.hpp | 158 ++++++++++++++++++++++++++++++++++++++++++++++++ src/midi_Defs.h | 6 +- 3 files changed, 190 insertions(+), 3 deletions(-) diff --git a/src/MIDI.h b/src/MIDI.h index 773ebb9..09961a2 100644 --- a/src/MIDI.h +++ b/src/MIDI.h @@ -97,6 +97,33 @@ public: inline void sendTuneRequest(); inline void sendRealTime(MidiType inType); + inline void beginRpn(unsigned inNumber, + Channel inChannel); + inline void sendRpnValue(unsigned inValue, + Channel inChannel); + inline void sendRpnValue(byte inMsb, + byte inLsb, + Channel inChannel); + inline void sendRpnIncrement(byte inAmount, + Channel inChannel); + inline void sendRpnDecrement(byte inAmount, + Channel inChannel); + inline void endRpn(Channel inChannel); + + inline void beginNrpn(unsigned inNumber, + Channel inChannel); + inline void sendNrpnValue(unsigned inValue, + Channel inChannel); + inline void sendNrpnValue(byte inMsb, + byte inLsb, + Channel inChannel); + inline void sendNrpnIncrement(byte inAmount, + Channel inChannel); + inline void sendNrpnDecrement(byte inAmount, + Channel inChannel); + inline void endNrpn(Channel inChannel); + + public: void send(MidiType inType, DataByte inData1, @@ -210,6 +237,8 @@ private: byte mPendingMessage[3]; unsigned mPendingMessageExpectedLenght; unsigned mPendingMessageIndex; + unsigned mCurrentRpnNumber; + unsigned mCurrentNrpnNumber; MidiMessage mMessage; private: diff --git a/src/MIDI.hpp b/src/MIDI.hpp index c1ca93d..28e672e 100644 --- a/src/MIDI.hpp +++ b/src/MIDI.hpp @@ -438,6 +438,164 @@ void MidiInterface::sendRealTime(MidiType inType) } } +/*! \brief Start a Registered Parameter Number frame. + \param inNumber The 14-bit number of the RPN you want to select. + \param inChannel The channel on which the message will be sent (1 to 16). +*/ +template +inline void MidiInterface::beginRpn(unsigned inNumber, + Channel inChannel) +{ + if (mCurrentRpnNumber != inNumber) + { + const byte numMsb = 0x7f & (inNumber >> 7); + const byte numLsb = 0x7f & inNumber; + sendControlChange(RPNLSB, numLsb, inChannel); + sendControlChange(RPNMSB, numMsb, inChannel); + mCurrentRpnNumber = inNumber; + } +} + +/*! \brief Send a 14-bit value for the currently selected RPN number. + \param inValue The 14-bit value of the selected RPN. + \param inChannel The channel on which the message will be sent (1 to 16). +*/ +template +inline void MidiInterface::sendRpnValue(unsigned inValue, + Channel inChannel) +{; + const byte valMsb = 0x7f & (inValue >> 7); + const byte valLsb = 0x7f & inValue; + sendControlChange(DataEntryLSB, valLsb, inChannel); + sendControlChange(DataEntryMSB, valMsb, inChannel); +} + +/*! \brief Send separate MSB/LSB values for the currently selected RPN number. + \param inMsb The MSB part of the value to send. Meaning depends on RPN number. + \param inLsb The LSB part of the value to send. Meaning depends on RPN number. + \param inChannel The channel on which the message will be sent (1 to 16). +*/ +template +inline void MidiInterface::sendRpnValue(byte inMsb, + byte inLsb, + Channel inChannel) +{ + sendControlChange(DataEntryLSB, inLsb, inChannel); + sendControlChange(DataEntryMSB, inMsb, inChannel); +} + +/* \brief Increment the value of the currently selected RPN number by the specified amount. + \param inAmount The amount to add to the currently selected RPN value. +*/ +template +inline void MidiInterface::sendRpnIncrement(byte inAmount, + Channel inChannel) +{ + sendControlChange(DataIncrement, inAmount, inChannel); +} + +/* \brief Decrement the value of the currently selected RPN number by the specified amount. + \param inAmount The amount to subtract to the currently selected RPN value. +*/ +template +inline void MidiInterface::sendRpnDecrement(byte inAmount, + Channel inChannel) +{ + sendControlChange(DataDecrement, inAmount, inChannel); +} + +/*! \brief Terminate an RPN frame. +This will send a Null Function to deselect the currently selected RPN. + \param inChannel The channel on which the message will be sent (1 to 16). +*/ +template +inline void MidiInterface::endRpn(Channel inChannel) +{ + sendControlChange(RPNLSB, 0x7f, inChannel); + sendControlChange(RPNMSB, 0x7f, inChannel); + mCurrentRpnNumber = 0xffff; +} + + + +/*! \brief Start a Non-Registered Parameter Number frame. + \param inNumber The 14-bit number of the NRPN you want to select. + \param inChannel The channel on which the message will be sent (1 to 16). +*/ +template +inline void MidiInterface::beginNrpn(unsigned inNumber, + Channel inChannel) +{ + if (mCurrentNrpnNumber != inNumber) + { + const byte numMsb = 0x7f & (inNumber >> 7); + const byte numLsb = 0x7f & inNumber; + sendControlChange(NRPNLSB, numLsb, inChannel); + sendControlChange(NRPNMSB, numMsb, inChannel); + mCurrentNrpnNumber = inNumber; + } +} + +/*! \brief Send a 14-bit value for the currently selected NRPN number. + \param inValue The 14-bit value of the selected NRPN. + \param inChannel The channel on which the message will be sent (1 to 16). +*/ +template +inline void MidiInterface::sendNrpnValue(unsigned inValue, + Channel inChannel) +{; + const byte valMsb = 0x7f & (inValue >> 7); + const byte valLsb = 0x7f & inValue; + sendControlChange(DataEntryLSB, valLsb, inChannel); + sendControlChange(DataEntryMSB, valMsb, inChannel); +} + +/*! \brief Send separate MSB/LSB values for the currently selected NRPN number. + \param inMsb The MSB part of the value to send. Meaning depends on NRPN number. + \param inLsb The LSB part of the value to send. Meaning depends on NRPN number. + \param inChannel The channel on which the message will be sent (1 to 16). +*/ +template +inline void MidiInterface::sendNrpnValue(byte inMsb, + byte inLsb, + Channel inChannel) +{ + sendControlChange(DataEntryLSB, inLsb, inChannel); + sendControlChange(DataEntryMSB, inMsb, inChannel); +} + +/* \brief Increment the value of the currently selected NRPN number by the specified amount. + \param inAmount The amount to add to the currently selected NRPN value. +*/ +template +inline void MidiInterface::sendNrpnIncrement(byte inAmount, + Channel inChannel) +{ + sendControlChange(DataIncrement, inAmount, inChannel); +} + +/* \brief Decrement the value of the currently selected NRPN number by the specified amount. + \param inAmount The amount to subtract to the currently selected NRPN value. +*/ +template +inline void MidiInterface::sendNrpnDecrement(byte inAmount, + Channel inChannel) +{ + sendControlChange(DataDecrement, inAmount, inChannel); +} + +/*! \brief Terminate an NRPN frame. +This will send a Null Function to deselect the currently selected NRPN. + \param inChannel The channel on which the message will be sent (1 to 16). +*/ +template +inline void MidiInterface::endNrpn(Channel inChannel) +{ + sendControlChange(NRPNLSB, 0x7f, inChannel); + sendControlChange(NRPNMSB, 0x7f, inChannel); + mCurrentNrpnNumber = 0xffff; +} + /*! @} */ // End of doc group MIDI Output // ----------------------------------------------------------------------------- diff --git a/src/midi_Defs.h b/src/midi_Defs.h index b8f2985..6ddb326 100644 --- a/src/midi_Defs.h +++ b/src/midi_Defs.h @@ -107,7 +107,7 @@ enum MidiControlChangeNumber // CC3 undefined FootController = 4, PortamentoTime = 5, - DataEntry = 6, + DataEntryMSB = 6, ChannelVolume = 7, Balance = 8, // CC9 undefined @@ -156,9 +156,9 @@ enum MidiControlChangeNumber Effects5 = 95, ///< Phaser depth DataIncrement = 96, DataDecrement = 97, - NRPN = 98, ///< Non-Registered Parameter Number (LSB) + NRPNLSB = 98, ///< Non-Registered Parameter Number (LSB) NRPNMSB = 99, ///< Non-Registered Parameter Number (MSB) - RPN = 100, ///< Registered Parameter Number (LSB) + RPNLSB = 100, ///< Registered Parameter Number (LSB) RPNMSB = 101, ///< Registered Parameter Number (MSB) // Channel Mode messages --------------------------------------------------- From a8e5b0ba15b68ac646ea8f58d9ab2e590e2e0b54 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Fri, 7 Oct 2016 00:44:03 +0200 Subject: [PATCH 045/138] Added example of RPN sequence. --- res/Examples/MIDI_RPN_NRPN/MIDI_RPN_NRPN.ino | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/res/Examples/MIDI_RPN_NRPN/MIDI_RPN_NRPN.ino b/res/Examples/MIDI_RPN_NRPN/MIDI_RPN_NRPN.ino index 587aad2..17155cd 100644 --- a/res/Examples/MIDI_RPN_NRPN/MIDI_RPN_NRPN.ino +++ b/res/Examples/MIDI_RPN_NRPN/MIDI_RPN_NRPN.ino @@ -192,4 +192,14 @@ void setup() void loop() { MIDI.read(); + + // Send a RPN sequence (Pitch Bend sensitivity) on channel 1 + { + const midi::Channel channel = 1; + const byte semitones = 12; + const byte cents = 42; + MIDI.startRpn(midi::PitchBendSensitivity, channel); + MIDI.sendRpnValue(semitones, cents, channel); + MIDI.endRpn(channel); + } } From 489b49b862ec3a5bfb10781505eda6157a66dfb2 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Fri, 7 Oct 2016 00:49:50 +0200 Subject: [PATCH 046/138] Fix thruFilter bug from #45. --- src/MIDI.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/MIDI.hpp b/src/MIDI.hpp index 28e672e..26c76bd 100644 --- a/src/MIDI.hpp +++ b/src/MIDI.hpp @@ -1289,8 +1289,8 @@ void MidiInterface::thruFilter(Channel inChannel) // First, check if the received message is Channel if (mMessage.type >= NoteOff && mMessage.type <= PitchBend) { - const bool filter_condition = ((mMessage.channel == mInputChannel) || - (mInputChannel == MIDI_CHANNEL_OMNI)); + const bool filter_condition = ((mMessage.channel == inChannel) || + (inChannel == MIDI_CHANNEL_OMNI)); // Now let's pass it to the output switch (mThruFilterMode) From 154b87f8d30d0dcd2542336209bf855955bda843 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Fri, 7 Oct 2016 00:51:53 +0200 Subject: [PATCH 047/138] Fix example. --- res/Examples/MIDI_RPN_NRPN/MIDI_RPN_NRPN.ino | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/res/Examples/MIDI_RPN_NRPN/MIDI_RPN_NRPN.ino b/res/Examples/MIDI_RPN_NRPN/MIDI_RPN_NRPN.ino index 17155cd..97c626e 100644 --- a/res/Examples/MIDI_RPN_NRPN/MIDI_RPN_NRPN.ino +++ b/res/Examples/MIDI_RPN_NRPN/MIDI_RPN_NRPN.ino @@ -65,7 +65,7 @@ public: } break; - case midi::DataEntry: + case midi::DataEntryMSB: if (mSelected) { Value& currentValue = getCurrentValue(); @@ -110,8 +110,8 @@ public: typedef State<2> RpnState; // We'll listen to 2 RPN typedef State<4> NrpnState; // and 4 NRPN -typedef ParameterNumberParser RpnParser; -typedef ParameterNumberParser NrpnParser; +typedef ParameterNumberParser RpnParser; +typedef ParameterNumberParser NrpnParser; struct ChannelSetup { From dc478a36567a25fe61571116dc9a7eda8ddf9a00 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Fri, 7 Oct 2016 00:58:23 +0200 Subject: [PATCH 048/138] Re-fix example. --- res/Examples/MIDI_RPN_NRPN/MIDI_RPN_NRPN.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/Examples/MIDI_RPN_NRPN/MIDI_RPN_NRPN.ino b/res/Examples/MIDI_RPN_NRPN/MIDI_RPN_NRPN.ino index 97c626e..69e0569 100644 --- a/res/Examples/MIDI_RPN_NRPN/MIDI_RPN_NRPN.ino +++ b/res/Examples/MIDI_RPN_NRPN/MIDI_RPN_NRPN.ino @@ -198,7 +198,7 @@ void loop() const midi::Channel channel = 1; const byte semitones = 12; const byte cents = 42; - MIDI.startRpn(midi::PitchBendSensitivity, channel); + MIDI.beginRpn(midi::RPN::PitchBendSensitivity, channel); MIDI.sendRpnValue(semitones, cents, channel); MIDI.endRpn(channel); } From bc0308223c6778d83514b680db7368cc351168d3 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Fri, 7 Oct 2016 00:58:35 +0200 Subject: [PATCH 049/138] Initialise new attributes. --- src/MIDI.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/MIDI.hpp b/src/MIDI.hpp index 26c76bd..200580b 100644 --- a/src/MIDI.hpp +++ b/src/MIDI.hpp @@ -39,6 +39,8 @@ inline MidiInterface::MidiInterface(SerialPort& inSerial) , mRunningStatus_TX(InvalidType) , mPendingMessageExpectedLenght(0) , mPendingMessageIndex(0) + , mCurrentRpnNumber(0xffff) + , mCurrentNrpnNumber(0xffff) { mNoteOffCallback = 0; mNoteOnCallback = 0; @@ -94,6 +96,9 @@ void MidiInterface::begin(Channel inChannel) mPendingMessageIndex = 0; mPendingMessageExpectedLenght = 0; + mCurrentRpnNumber = 0xffff; + mCurrentNrpnNumber = 0xffff; + mMessage.valid = false; mMessage.type = InvalidType; mMessage.channel = 0; From a7d6d803a1e0e64a30c5e99ca30fcc008026c79e Mon Sep 17 00:00:00 2001 From: Francois Best Date: Fri, 7 Oct 2016 09:12:48 +0200 Subject: [PATCH 050/138] Enabled CMake target debugging. (requires CMake Tools extension for VSCode) --- .vscode/settings.json | 4 ++++ test/unit-tests/CMakeLists.txt | 2 ++ 2 files changed, 6 insertions(+) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..b305399 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,4 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "cmake.experimental.enableTargetDebugging": true +} diff --git a/test/unit-tests/CMakeLists.txt b/test/unit-tests/CMakeLists.txt index 2ecfa5c..9d02706 100644 --- a/test/unit-tests/CMakeLists.txt +++ b/test/unit-tests/CMakeLists.txt @@ -1,3 +1,5 @@ +include(CMakeToolsHelpers OPTIONAL) + project(unit-tests) include_directories( From 34b37f75e8a66b4ad75ec321367e68c82f609a93 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Fri, 7 Oct 2016 09:50:37 +0200 Subject: [PATCH 051/138] Fixed order of DataEntry bytes (MSB first). --- src/MIDI.hpp | 8 +-- .../tests/unit-tests_MidiOutput.cpp | 49 +++++++++++++++++++ 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/src/MIDI.hpp b/src/MIDI.hpp index 200580b..570c759 100644 --- a/src/MIDI.hpp +++ b/src/MIDI.hpp @@ -471,8 +471,8 @@ inline void MidiInterface::sendRpnValue(unsigned inValue, {; const byte valMsb = 0x7f & (inValue >> 7); const byte valLsb = 0x7f & inValue; - sendControlChange(DataEntryLSB, valLsb, inChannel); sendControlChange(DataEntryMSB, valMsb, inChannel); + sendControlChange(DataEntryLSB, valLsb, inChannel); } /*! \brief Send separate MSB/LSB values for the currently selected RPN number. @@ -485,8 +485,8 @@ inline void MidiInterface::sendRpnValue(byte inMsb, byte inLsb, Channel inChannel) { - sendControlChange(DataEntryLSB, inLsb, inChannel); sendControlChange(DataEntryMSB, inMsb, inChannel); + sendControlChange(DataEntryLSB, inLsb, inChannel); } /* \brief Increment the value of the currently selected RPN number by the specified amount. @@ -551,8 +551,8 @@ inline void MidiInterface::sendNrpnValue(unsigned inValue, {; const byte valMsb = 0x7f & (inValue >> 7); const byte valLsb = 0x7f & inValue; - sendControlChange(DataEntryLSB, valLsb, inChannel); sendControlChange(DataEntryMSB, valMsb, inChannel); + sendControlChange(DataEntryLSB, valLsb, inChannel); } /*! \brief Send separate MSB/LSB values for the currently selected NRPN number. @@ -565,8 +565,8 @@ inline void MidiInterface::sendNrpnValue(byte inMsb, byte inLsb, Channel inChannel) { - sendControlChange(DataEntryLSB, inLsb, inChannel); sendControlChange(DataEntryMSB, inMsb, inChannel); + sendControlChange(DataEntryLSB, inLsb, inChannel); } /* \brief Increment the value of the currently selected NRPN number by the specified amount. diff --git a/test/unit-tests/tests/unit-tests_MidiOutput.cpp b/test/unit-tests/tests/unit-tests_MidiOutput.cpp index a937280..bdcb0c0 100644 --- a/test/unit-tests/tests/unit-tests_MidiOutput.cpp +++ b/test/unit-tests/tests/unit-tests_MidiOutput.cpp @@ -244,4 +244,53 @@ TEST(MidiOutput, sendRealTime) } +TEST(MidiOutput, RPN) +{ + SerialMock serial; + MidiInterface midi(serial); + std::vector buffer; + + // 14-bit Value Single Frame + { + buffer.clear(); + buffer.resize(13); + + midi.begin(); + midi.beginRpn(1242, 12); + midi.sendRpnValue(12345, 12); + midi.endRpn(12); + + EXPECT_EQ(serial.mTxBuffer.getLength(), 13); + serial.mTxBuffer.read(&buffer[0], 13); + EXPECT_THAT(buffer, ElementsAreArray({0xbb, + 0x64, 0x5a, + 0x65, 0x09, + 0x06, 0x60, + 0x26, 0x39, + 0x64, 0x7f, + 0x65, 0x7f})); + } + // MSB/LSB Single Frame + { + + } + // Increment Single Frame + { + + } + // Decrement Single Frame + { + + } + // Multi Frame + { + + } +} + +TEST(MidiOutput, NRPN) +{ + +} + END_UNNAMED_NAMESPACE From e65d5b6b4c14ea84dbe85600fa5a1fade6201328 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Fri, 7 Oct 2016 09:59:08 +0200 Subject: [PATCH 052/138] Added more RPN/NRPN tests. --- .../tests/unit-tests_MidiOutput.cpp | 177 ++++++++++++++++++ 1 file changed, 177 insertions(+) diff --git a/test/unit-tests/tests/unit-tests_MidiOutput.cpp b/test/unit-tests/tests/unit-tests_MidiOutput.cpp index bdcb0c0..95eef19 100644 --- a/test/unit-tests/tests/unit-tests_MidiOutput.cpp +++ b/test/unit-tests/tests/unit-tests_MidiOutput.cpp @@ -272,25 +272,202 @@ TEST(MidiOutput, RPN) } // MSB/LSB Single Frame { + buffer.clear(); + buffer.resize(13); + midi.begin(); + midi.beginRpn(1242, 12); + midi.sendRpnValue(12, 42, 12); + midi.endRpn(12); + + EXPECT_EQ(serial.mTxBuffer.getLength(), 13); + serial.mTxBuffer.read(&buffer[0], 13); + EXPECT_THAT(buffer, ElementsAreArray({0xbb, + 0x64, 0x5a, + 0x65, 0x09, + 0x06, 0x0c, + 0x26, 0x2a, + 0x64, 0x7f, + 0x65, 0x7f})); } // Increment Single Frame { + buffer.clear(); + buffer.resize(11); + midi.begin(); + midi.beginRpn(1242, 12); + midi.sendRpnIncrement(42, 12); + midi.endRpn(12); + + EXPECT_EQ(serial.mTxBuffer.getLength(), 11); + serial.mTxBuffer.read(&buffer[0], 11); + EXPECT_THAT(buffer, ElementsAreArray({0xbb, + 0x64, 0x5a, + 0x65, 0x09, + 0x60, 0x2a, + 0x64, 0x7f, + 0x65, 0x7f})); } // Decrement Single Frame { + buffer.clear(); + buffer.resize(11); + midi.begin(); + midi.beginRpn(1242, 12); + midi.sendRpnDecrement(42, 12); + midi.endRpn(12); + + EXPECT_EQ(serial.mTxBuffer.getLength(), 11); + serial.mTxBuffer.read(&buffer[0], 11); + EXPECT_THAT(buffer, ElementsAreArray({0xbb, + 0x64, 0x5a, + 0x65, 0x09, + 0x61, 0x2a, + 0x64, 0x7f, + 0x65, 0x7f})); } // Multi Frame { + buffer.clear(); + buffer.resize(21); + midi.begin(); + midi.beginRpn(1242, 12); + midi.sendRpnValue(12345, 12); + midi.sendRpnValue(12, 42, 12); + midi.sendRpnIncrement(42, 12); + midi.sendRpnDecrement(42, 12); + midi.endRpn(12); + + EXPECT_EQ(serial.mTxBuffer.getLength(), 21); + serial.mTxBuffer.read(&buffer[0], 21); + EXPECT_THAT(buffer, ElementsAreArray({0xbb, + 0x64, 0x5a, + 0x65, 0x09, + 0x06, 0x60, + 0x26, 0x39, + 0x06, 0x0c, + 0x26, 0x2a, + 0x60, 0x2a, + 0x61, 0x2a, + 0x64, 0x7f, + 0x65, 0x7f})); } } TEST(MidiOutput, NRPN) { + SerialMock serial; + MidiInterface midi(serial); + std::vector buffer; + // 14-bit Value Single Frame + { + buffer.clear(); + buffer.resize(13); + + midi.begin(); + midi.beginNrpn(1242, 12); + midi.sendNrpnValue(12345, 12); + midi.endNrpn(12); + + EXPECT_EQ(serial.mTxBuffer.getLength(), 13); + serial.mTxBuffer.read(&buffer[0], 13); + EXPECT_THAT(buffer, ElementsAreArray({0xbb, + 0x62, 0x5a, + 0x63, 0x09, + 0x06, 0x60, + 0x26, 0x39, + 0x62, 0x7f, + 0x63, 0x7f})); + } + // MSB/LSB Single Frame + { + buffer.clear(); + buffer.resize(13); + + midi.begin(); + midi.beginNrpn(1242, 12); + midi.sendNrpnValue(12, 42, 12); + midi.endNrpn(12); + + EXPECT_EQ(serial.mTxBuffer.getLength(), 13); + serial.mTxBuffer.read(&buffer[0], 13); + EXPECT_THAT(buffer, ElementsAreArray({0xbb, + 0x62, 0x5a, + 0x63, 0x09, + 0x06, 0x0c, + 0x26, 0x2a, + 0x62, 0x7f, + 0x63, 0x7f})); + } + // Increment Single Frame + { + buffer.clear(); + buffer.resize(11); + + midi.begin(); + midi.beginNrpn(1242, 12); + midi.sendNrpnIncrement(42, 12); + midi.endNrpn(12); + + EXPECT_EQ(serial.mTxBuffer.getLength(), 11); + serial.mTxBuffer.read(&buffer[0], 11); + EXPECT_THAT(buffer, ElementsAreArray({0xbb, + 0x62, 0x5a, + 0x63, 0x09, + 0x60, 0x2a, + 0x62, 0x7f, + 0x63, 0x7f})); + } + // Decrement Single Frame + { + buffer.clear(); + buffer.resize(11); + + midi.begin(); + midi.beginNrpn(1242, 12); + midi.sendNrpnDecrement(42, 12); + midi.endNrpn(12); + + EXPECT_EQ(serial.mTxBuffer.getLength(), 11); + serial.mTxBuffer.read(&buffer[0], 11); + EXPECT_THAT(buffer, ElementsAreArray({0xbb, + 0x62, 0x5a, + 0x63, 0x09, + 0x61, 0x2a, + 0x62, 0x7f, + 0x63, 0x7f})); + } + // Multi Frame + { + buffer.clear(); + buffer.resize(21); + + midi.begin(); + midi.beginNrpn(1242, 12); + midi.sendNrpnValue(12345, 12); + midi.sendNrpnValue(12, 42, 12); + midi.sendNrpnIncrement(42, 12); + midi.sendNrpnDecrement(42, 12); + midi.endNrpn(12); + + EXPECT_EQ(serial.mTxBuffer.getLength(), 21); + serial.mTxBuffer.read(&buffer[0], 21); + EXPECT_THAT(buffer, ElementsAreArray({0xbb, + 0x62, 0x5a, + 0x63, 0x09, + 0x06, 0x60, + 0x26, 0x39, + 0x06, 0x0c, + 0x26, 0x2a, + 0x60, 0x2a, + 0x61, 0x2a, + 0x62, 0x7f, + 0x63, 0x7f})); + } } END_UNNAMED_NAMESPACE From 527a7c8e9d4e4252a152020e6048dc98fb0b0ae1 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Fri, 7 Oct 2016 10:04:05 +0200 Subject: [PATCH 053/138] Using vector buffers & initializer-list expectancies. --- .../tests/unit-tests_MidiOutput.cpp | 103 +++++++++++------- 1 file changed, 61 insertions(+), 42 deletions(-) diff --git a/test/unit-tests/tests/unit-tests_MidiOutput.cpp b/test/unit-tests/tests/unit-tests_MidiOutput.cpp index 95eef19..d62ca91 100644 --- a/test/unit-tests/tests/unit-tests_MidiOutput.cpp +++ b/test/unit-tests/tests/unit-tests_MidiOutput.cpp @@ -26,26 +26,30 @@ using namespace testing; typedef test_mocks::SerialMock<32> SerialMock; typedef midi::MidiInterface MidiInterface; +typedef std::vector Buffer; + // -- TEST(MidiOutput, sendGenericSingle) { SerialMock serial; MidiInterface midi(serial); - test_mocks::uint8 buffer[3] = { 0 }; + Buffer buffer; + buffer.resize(3); midi.begin(); midi.send(midi::NoteOn, 47, 42, 12); EXPECT_EQ(serial.mTxBuffer.getLength(), 3); - serial.mTxBuffer.read(buffer, 3); - EXPECT_THAT(buffer, ElementsAre(0x9b, 47, 42)); + serial.mTxBuffer.read(&buffer[0], 3); + EXPECT_THAT(buffer, ElementsAreArray({0x9b, 47, 42})); } TEST(MidiOutput, sendGenericWithRunningStatus) { SerialMock serial; MidiInterface midi(serial); - test_mocks::uint8 buffer[5] = { 0 }; + Buffer buffer; + buffer.resize(5); midi.begin(); EXPECT_EQ(MidiInterface::Settings::UseRunningStatus, true); @@ -53,8 +57,8 @@ TEST(MidiOutput, sendGenericWithRunningStatus) midi.send(midi::NoteOn, 47, 42, 12); midi.send(midi::NoteOn, 42, 47, 12); EXPECT_EQ(serial.mTxBuffer.getLength(), 5); - serial.mTxBuffer.read(buffer, 5); - EXPECT_THAT(buffer, ElementsAre(0x9b, 47, 42, 42, 47)); + serial.mTxBuffer.read(&buffer[0], 5); + EXPECT_THAT(buffer, ElementsAreArray({0x9b, 47, 42, 42, 47})); } TEST(MidiOutput, sendGenericWithoutRunningStatus) @@ -64,7 +68,8 @@ TEST(MidiOutput, sendGenericWithoutRunningStatus) SerialMock serial; MidiInterface midi(serial); - test_mocks::uint8 buffer[6] = { 0 }; + Buffer buffer; + buffer.resize(6); // Same status byte midi.begin(); @@ -73,30 +78,31 @@ TEST(MidiOutput, sendGenericWithoutRunningStatus) midi.send(midi::NoteOn, 47, 42, 12); midi.send(midi::NoteOn, 42, 47, 12); EXPECT_EQ(serial.mTxBuffer.getLength(), 6); - serial.mTxBuffer.read(buffer, 6); - EXPECT_THAT(buffer, ElementsAre(0x9b, 47, 42, 0x9b, 42, 47)); + serial.mTxBuffer.read(&buffer[0], 6); + EXPECT_THAT(buffer, ElementsAreArray({0x9b, 47, 42, 0x9b, 42, 47})); // Different status byte midi.begin(); midi.send(midi::NoteOn, 47, 42, 12); midi.send(midi::NoteOff, 47, 42, 12); EXPECT_EQ(serial.mTxBuffer.getLength(), 6); - serial.mTxBuffer.read(buffer, 6); - EXPECT_THAT(buffer, ElementsAre(0x9b, 47, 42, 0x8b, 47, 42)); + serial.mTxBuffer.read(&buffer[0], 6); + EXPECT_THAT(buffer, ElementsAreArray({0x9b, 47, 42, 0x8b, 47, 42})); } TEST(MidiOutput, sendGenericBreakingRunningStatus) { SerialMock serial; MidiInterface midi(serial); - test_mocks::uint8 buffer[6] = { 0 }; + Buffer buffer; + buffer.resize(6); midi.begin(); midi.send(midi::NoteOn, 47, 42, 12); midi.send(midi::NoteOff, 47, 42, 12); EXPECT_EQ(serial.mTxBuffer.getLength(), 6); - serial.mTxBuffer.read(buffer, 6); - EXPECT_THAT(buffer, ElementsAre(0x9b, 47, 42, 0x8b, 47, 42)); + serial.mTxBuffer.read(&buffer[0], 6); + EXPECT_THAT(buffer, ElementsAreArray({0x9b, 47, 42, 0x8b, 47, 42})); } // -- @@ -105,102 +111,115 @@ TEST(MidiOutput, sendNoteOn) { SerialMock serial; MidiInterface midi(serial); - test_mocks::uint8 buffer[5] = { 0 }; + Buffer buffer; + buffer.resize(5); midi.begin(); midi.sendNoteOn(10, 11, 12); midi.sendNoteOn(12, 13, 12); EXPECT_EQ(serial.mTxBuffer.getLength(), 5); - serial.mTxBuffer.read(buffer, 5); - EXPECT_THAT(buffer, ElementsAre(0x9b, 10, 11, 12, 13)); + serial.mTxBuffer.read(&buffer[0], 5); + EXPECT_THAT(buffer, ElementsAreArray({0x9b, 10, 11, 12, 13})); } TEST(MidiOutput, sendNoteOff) { SerialMock serial; MidiInterface midi(serial); - test_mocks::uint8 buffer[5] = { 0 }; + Buffer buffer; + buffer.resize(5); midi.begin(); midi.sendNoteOff(10, 11, 12); midi.sendNoteOff(12, 13, 12); EXPECT_EQ(serial.mTxBuffer.getLength(), 5); - serial.mTxBuffer.read(buffer, 5); - EXPECT_THAT(buffer, ElementsAre(0x8b, 10, 11, 12, 13)); + serial.mTxBuffer.read(&buffer[0], 5); + EXPECT_THAT(buffer, ElementsAreArray({0x8b, 10, 11, 12, 13})); } TEST(MidiOutput, sendProgramChange) { SerialMock serial; MidiInterface midi(serial); - test_mocks::uint8 buffer[3] = { 0 }; + Buffer buffer; + buffer.resize(3); midi.begin(); midi.sendProgramChange(42, 12); midi.sendProgramChange(47, 12); EXPECT_EQ(serial.mTxBuffer.getLength(), 3); - serial.mTxBuffer.read(buffer, 3); - EXPECT_THAT(buffer, ElementsAre(0xcb, 42, 47)); + serial.mTxBuffer.read(&buffer[0], 3); + EXPECT_THAT(buffer, ElementsAreArray({0xcb, 42, 47})); } TEST(MidiOutput, sendControlChange) { SerialMock serial; MidiInterface midi(serial); - test_mocks::uint8 buffer[5] = { 0 }; + Buffer buffer; + buffer.resize(5); midi.begin(); midi.sendControlChange(42, 12, 12); midi.sendControlChange(47, 12, 12); EXPECT_EQ(serial.mTxBuffer.getLength(), 5); - serial.mTxBuffer.read(buffer, 5); - EXPECT_THAT(buffer, ElementsAre(0xbb, 42, 12, 47, 12)); + serial.mTxBuffer.read(&buffer[0], 5); + EXPECT_THAT(buffer, ElementsAreArray({0xbb, 42, 12, 47, 12})); } TEST(MidiOutput, sendPitchBend) { SerialMock serial; MidiInterface midi(serial); - test_mocks::uint8 buffer[7] = { 0 }; + Buffer buffer; // Int signature - arbitrary values { + buffer.clear(); + buffer.resize(7); + midi.begin(); midi.sendPitchBend(0, 12); midi.sendPitchBend(100, 12); midi.sendPitchBend(-100, 12); EXPECT_EQ(serial.mTxBuffer.getLength(), 7); - serial.mTxBuffer.read(buffer, 7); - EXPECT_THAT(buffer, ElementsAre(0xeb, - 0x00, 0x40, - 0x64, 0x40, - 0x1c, 0x3f)); + serial.mTxBuffer.read(&buffer[0], 7); + EXPECT_THAT(buffer, ElementsAreArray({0xeb, + 0x00, 0x40, + 0x64, 0x40, + 0x1c, 0x3f})); } // Int signature - min/max { + buffer.clear(); + buffer.resize(7); + midi.begin(); midi.sendPitchBend(0, 12); midi.sendPitchBend(MIDI_PITCHBEND_MAX, 12); midi.sendPitchBend(MIDI_PITCHBEND_MIN, 12); EXPECT_EQ(serial.mTxBuffer.getLength(), 7); - serial.mTxBuffer.read(buffer, 7); - EXPECT_THAT(buffer, ElementsAre(0xeb, - 0x00, 0x40, - 0x7f, 0x7f, - 0x00, 0x00)); + serial.mTxBuffer.read(&buffer[0], 7); + EXPECT_THAT(buffer, ElementsAreArray({0xeb, + 0x00, 0x40, + 0x7f, 0x7f, + 0x00, 0x00})); } // Float signature { + buffer.clear(); + buffer.resize(7); + midi.begin(); midi.sendPitchBend(0.0, 12); midi.sendPitchBend(1.0, 12); midi.sendPitchBend(-1.0, 12); EXPECT_EQ(serial.mTxBuffer.getLength(), 7); - serial.mTxBuffer.read(buffer, 7); - EXPECT_THAT(buffer, ElementsAre(0xeb, - 0x00, 0x40, - 0x7f, 0x7f, - 0x00, 0x00)); + serial.mTxBuffer.read(&buffer[0], 7); + EXPECT_THAT(buffer, ElementsAreArray({0xeb, + 0x00, 0x40, + 0x7f, 0x7f, + 0x00, 0x00})); } } From 886658c6a43fd7cb98baa1b6bdd2c899aca5000e Mon Sep 17 00:00:00 2001 From: Francois Best Date: Fri, 7 Oct 2016 11:34:56 +0200 Subject: [PATCH 054/138] Added coveralls-cmake sub. --- .gitmodules | 3 +++ external/coveralls-cmake | 1 + 2 files changed, 4 insertions(+) create mode 160000 external/coveralls-cmake diff --git a/.gitmodules b/.gitmodules index 53d7ecd..af8a698 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "external/google-test"] path = external/google-test url = https://github.com/google/googletest.git +[submodule "external/coveralls-cmake"] + path = external/coveralls-cmake + url = https://github.com/JoakimSoderberg/coveralls-cmake.git diff --git a/external/coveralls-cmake b/external/coveralls-cmake new file mode 160000 index 0000000..e37d5b8 --- /dev/null +++ b/external/coveralls-cmake @@ -0,0 +1 @@ +Subproject commit e37d5b8674dab235185b07ad9208c88d84f81823 From dd700fd49f76413770de4cf88cf2679191b07eee Mon Sep 17 00:00:00 2001 From: Francois Best Date: Fri, 7 Oct 2016 14:46:31 +0200 Subject: [PATCH 055/138] Using CTest for unit tests. --- .travis.yml | 4 ++-- CMakeLists.txt | 4 +++- test/unit-tests/CMakeLists.txt | 8 +------- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index 48e49df..320e87d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -50,9 +50,9 @@ before_install: script: - build_main_platforms - mkdir build && cd build - - cmake -DCMAKE_CXX_COMPILER=$COMPILER .. + - cmake -DCMAKE_CXX_COMPILER=$COMPILER -DCMAKE_BUILD_TYPE=Debug .. - make - - test/unit-tests/unit-tests + - ctest -V notifications: email: false diff --git a/CMakeLists.txt b/CMakeLists.txt index e1d38a6..a65df53 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,9 @@ project(arduino_midi_library) set(ROOT_SOURCE_DIR ${PROJECT_SOURCE_DIR}) include_directories(${ROOT_SOURCE_DIR}) -set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + +enable_testing() add_subdirectory(external) add_subdirectory(src) diff --git a/test/unit-tests/CMakeLists.txt b/test/unit-tests/CMakeLists.txt index 9d02706..c4cddd3 100644 --- a/test/unit-tests/CMakeLists.txt +++ b/test/unit-tests/CMakeLists.txt @@ -30,10 +30,4 @@ target_link_libraries(unit-tests test-mocks ) -option(RUN_UNIT_TESTS_IN_POST_BUILD false) - -if (RUN_UNIT_TESTS_IN_POST_BUILD) - add_custom_command(TARGET unit-tests POST_BUILD - COMMAND ${unit-tests_BINARY_DIR}/unit-tests - ) -endif() +add_test(unit-tests ${unit-tests_BINARY_DIR}/unit-tests --gtest_color=yes) From f26071fb8a47855ea9584702df3670b825b3469e Mon Sep 17 00:00:00 2001 From: Francois Best Date: Fri, 7 Oct 2016 15:06:45 +0200 Subject: [PATCH 056/138] Revert "Added coveralls-cmake sub." This reverts commit 886658c6a43fd7cb98baa1b6bdd2c899aca5000e. --- .gitmodules | 3 --- external/coveralls-cmake | 1 - 2 files changed, 4 deletions(-) delete mode 160000 external/coveralls-cmake diff --git a/.gitmodules b/.gitmodules index af8a698..53d7ecd 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ [submodule "external/google-test"] path = external/google-test url = https://github.com/google/googletest.git -[submodule "external/coveralls-cmake"] - path = external/coveralls-cmake - url = https://github.com/JoakimSoderberg/coveralls-cmake.git diff --git a/external/coveralls-cmake b/external/coveralls-cmake deleted file mode 160000 index e37d5b8..0000000 --- a/external/coveralls-cmake +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e37d5b8674dab235185b07ad9208c88d84f81823 From 34b1b11ad097cc7328b63163334b7fb40dadb526 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Sat, 8 Oct 2016 02:36:15 +0200 Subject: [PATCH 057/138] Moved stuff to builder. Added code coverage. --- .travis.yml | 30 ++++++++++++++++++++++++++++-- CMakeLists.txt | 9 +++------ builder/CMakeLists.txt | 15 +++++++++++++++ 3 files changed, 46 insertions(+), 8 deletions(-) create mode 100644 builder/CMakeLists.txt diff --git a/.travis.yml b/.travis.yml index 320e87d..ba53431 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,6 @@ +# Kudos to these guys: # http://genbattle.bitbucket.org/blog/2016/01/17/c++-travis-ci/ +# https://github.com/ticapix/arduino-toolbox/blob/master/.travis.yml # Ubuntu 14.04 Trusty support sudo: required @@ -45,14 +47,38 @@ matrix: before_install: - sudo apt-get update -qq + - sudo apt-get install lcov - source <(curl -SLs https://raw.githubusercontent.com/fortyseveneffects/travis-ci-arduino/master/install.sh) +install: + # Install lcov from source + - wget http://ftp.fr.debian.org/debian/pool/main/l/lcov/lcov_1.11.orig.tar.gz + - tar xf lcov_1.11.orig.tar.gz + - sudo make -C lcov-1.11/ install + - gem install coveralls-lcov + - lcov --version + +before_script: + # init coverage to 0 (optional) + - lcov --directory . --zerocounters + script: + # Build examples with Arduino IDE on each available platform / board - build_main_platforms + + # Build and run unit tests with regular C++ compiler - mkdir build && cd build - cmake -DCMAKE_CXX_COMPILER=$COMPILER -DCMAKE_BUILD_TYPE=Debug .. - - make - - ctest -V + - make all + - ctest --verbose + +after_success: + # Generate code coverage information & send to Coveralls + - cd build + - lcov --directory . --capture --output-file coverage.info + - lcov --remove coverage.info 'test/*' '/usr/*' 'external/*' --output-file coverage.info + - lcov --list coverage.info + - coveralls-lcov --repo-token ${COVERALLS_TOKEN} coverage.info notifications: email: false diff --git a/CMakeLists.txt b/CMakeLists.txt index a65df53..a06c2e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,12 +1,9 @@ cmake_minimum_required(VERSION 2.8.7) -project(arduino_midi_library) +project(arduino_midi_library CXX) -set(ROOT_SOURCE_DIR ${PROJECT_SOURCE_DIR}) -include_directories(${ROOT_SOURCE_DIR}) +add_subdirectory(builder) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") - -enable_testing() +setup_builder() add_subdirectory(external) add_subdirectory(src) diff --git a/builder/CMakeLists.txt b/builder/CMakeLists.txt new file mode 100644 index 0000000..684103b --- /dev/null +++ b/builder/CMakeLists.txt @@ -0,0 +1,15 @@ + +macro(setup_builder) + enable_testing() + + set(ROOT_SOURCE_DIR ${PROJECT_SOURCE_DIR} CACHE INTERNAL "Repository root directory") + set(ROOT_BINARY_DIR "${ROOT_SOURCE_DIR}/build") + + include_directories(${ROOT_SOURCE_DIR}) + + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall -W -Wshadow -Wunused-variable -Wunused-parameter -Wunused-function -Wunused -Wno-system-headers -Wno-deprecated -Woverloaded-virtual") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -O0") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} --coverage") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + +endmacro() From 530e983dea06f47c3fefdc6b3683ae32977eab34 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Sat, 8 Oct 2016 02:36:24 +0200 Subject: [PATCH 058/138] Added contributing guidelines (wip). --- CONTRIBUTING.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..9270a8a --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,20 @@ +## Requirements + +Requirements to build and run the unit tests: +- CMake 2.8 or later +- GCC / Clang with C++11 support + +## Setup + +Pull Google Test / Google Mock subrepository: +``` +$ git init submodules +``` + +Create build directory, run CMake, build and run unit tests: +``` +$ mkdir build && cd build +$ cmake .. +$ make +$ ctest --verbose +``` From 8372ee92d7b8c07eaf509721a9bbef33b73a5c00 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Sat, 8 Oct 2016 02:37:07 +0200 Subject: [PATCH 059/138] Added build & run target for unit tests. --- test/unit-tests/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/unit-tests/CMakeLists.txt b/test/unit-tests/CMakeLists.txt index c4cddd3..e784749 100644 --- a/test/unit-tests/CMakeLists.txt +++ b/test/unit-tests/CMakeLists.txt @@ -31,3 +31,7 @@ target_link_libraries(unit-tests ) add_test(unit-tests ${unit-tests_BINARY_DIR}/unit-tests --gtest_color=yes) +add_custom_target(build-and-run-unit-tests + COMMAND ${CMAKE_CTEST_COMMAND} -V + DEPENDS unit-tests +) From cb34be646cc64eb6ae117c13322e8740af8f4e58 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Sat, 8 Oct 2016 02:37:18 +0200 Subject: [PATCH 060/138] Added test for PolyPressure. --- test/unit-tests/tests/unit-tests_MidiOutput.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/unit-tests/tests/unit-tests_MidiOutput.cpp b/test/unit-tests/tests/unit-tests_MidiOutput.cpp index d62ca91..47890ea 100644 --- a/test/unit-tests/tests/unit-tests_MidiOutput.cpp +++ b/test/unit-tests/tests/unit-tests_MidiOutput.cpp @@ -225,7 +225,17 @@ TEST(MidiOutput, sendPitchBend) TEST(MidiOutput, sendPolyPressure) { + SerialMock serial; + MidiInterface midi(serial); + Buffer buffer; + buffer.resize(5); + midi.begin(); + midi.sendPolyPressure(42, 12, 12); + midi.sendPolyPressure(47, 12, 12); + EXPECT_EQ(serial.mTxBuffer.getLength(), 5); + serial.mTxBuffer.read(&buffer[0], 5); + EXPECT_THAT(buffer, ElementsAreArray({0xab, 42, 12, 47, 12})); } TEST(MidiOutput, sendAfterTouch) From 9cbce11523bc64f60462ab2a8c334452d55fc87f Mon Sep 17 00:00:00 2001 From: Francois Best Date: Sun, 9 Oct 2016 18:40:26 +0200 Subject: [PATCH 061/138] Install lcov from apt, fix path. --- .travis.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index ba53431..3d92fa3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -47,14 +47,14 @@ matrix: before_install: - sudo apt-get update -qq - - sudo apt-get install lcov - source <(curl -SLs https://raw.githubusercontent.com/fortyseveneffects/travis-ci-arduino/master/install.sh) install: # Install lcov from source - - wget http://ftp.fr.debian.org/debian/pool/main/l/lcov/lcov_1.11.orig.tar.gz - - tar xf lcov_1.11.orig.tar.gz - - sudo make -C lcov-1.11/ install + # - wget http://ftp.fr.debian.org/debian/pool/main/l/lcov/lcov_1.11.orig.tar.gz + # - tar xf lcov_1.11.orig.tar.gz + # - sudo make -C lcov-1.11/ install + - sudo apt-get install lcov - gem install coveralls-lcov - lcov --version @@ -74,7 +74,6 @@ script: after_success: # Generate code coverage information & send to Coveralls - - cd build - lcov --directory . --capture --output-file coverage.info - lcov --remove coverage.info 'test/*' '/usr/*' 'external/*' --output-file coverage.info - lcov --list coverage.info From 766961b2f32a60eafcc3cf9c54c98c9fe8c02397 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Sun, 9 Oct 2016 18:40:51 +0200 Subject: [PATCH 062/138] Added code coverage badge. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9e3faca..0670245 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # 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=2592000)](https://coveralls.io/github/FortySevenEffects/arduino_midi_library) [![GitHub release](https://img.shields.io/github/release/FortySevenEffects/arduino_midi_library.svg?maxAge=2592000)](https://github.com/FortySevenEffects/arduino_midi_library/releases/latest) [![License](https://img.shields.io/github/license/FortySevenEffects/arduino_midi_library.svg?maxAge=2592000)](LICENSE) From 4009b2a15b877f8ad448ae12c3bbe1c68dba14c4 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Sun, 9 Oct 2016 19:04:59 +0200 Subject: [PATCH 063/138] Testing lcov and gcov updates. --- .travis.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3d92fa3..a7ef90a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -51,12 +51,13 @@ before_install: install: # Install lcov from source - # - wget http://ftp.fr.debian.org/debian/pool/main/l/lcov/lcov_1.11.orig.tar.gz - # - tar xf lcov_1.11.orig.tar.gz - # - sudo make -C lcov-1.11/ install - - sudo apt-get install lcov + - wget http://ftp.fr.debian.org/debian/pool/main/l/lcov/lcov_1.12.orig.tar.gz + - tar xf lcov_1.11.orig.tar.gz + - sudo make -C lcov-1.11/ install + - sudo apt-get install ggcov - gem install coveralls-lcov - lcov --version + - gcov --version before_script: # init coverage to 0 (optional) @@ -74,6 +75,7 @@ script: after_success: # Generate code coverage information & send to Coveralls + - pwd - lcov --directory . --capture --output-file coverage.info - lcov --remove coverage.info 'test/*' '/usr/*' 'external/*' --output-file coverage.info - lcov --list coverage.info From 016f18df4bb96fedad472893d844b170761c2a81 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Sun, 9 Oct 2016 19:10:31 +0200 Subject: [PATCH 064/138] Fixy. --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index a7ef90a..a748798 100644 --- a/.travis.yml +++ b/.travis.yml @@ -52,8 +52,8 @@ before_install: install: # Install lcov from source - wget http://ftp.fr.debian.org/debian/pool/main/l/lcov/lcov_1.12.orig.tar.gz - - tar xf lcov_1.11.orig.tar.gz - - sudo make -C lcov-1.11/ install + - tar xf lcov_1.12.orig.tar.gz + - sudo make -C lcov-1.12/ install - sudo apt-get install ggcov - gem install coveralls-lcov - lcov --version @@ -65,7 +65,7 @@ before_script: script: # Build examples with Arduino IDE on each available platform / board - - build_main_platforms + # - build_main_platforms # Build and run unit tests with regular C++ compiler - mkdir build && cd build From 63f5eba41b10756d153bfe9cf61640c898f8d27f Mon Sep 17 00:00:00 2001 From: Francois Best Date: Sun, 9 Oct 2016 19:24:14 +0200 Subject: [PATCH 065/138] What if we don't specify lcov/gcov? --- .travis.yml | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index a748798..57203f3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -47,22 +47,18 @@ matrix: before_install: - sudo apt-get update -qq - - source <(curl -SLs https://raw.githubusercontent.com/fortyseveneffects/travis-ci-arduino/master/install.sh) + # - source <(curl -SLs https://raw.githubusercontent.com/fortyseveneffects/travis-ci-arduino/master/install.sh) install: # Install lcov from source - - wget http://ftp.fr.debian.org/debian/pool/main/l/lcov/lcov_1.12.orig.tar.gz - - tar xf lcov_1.12.orig.tar.gz - - sudo make -C lcov-1.12/ install - - sudo apt-get install ggcov + # - wget http://ftp.fr.debian.org/debian/pool/main/l/lcov/lcov_1.12.orig.tar.gz + # - tar xf lcov_1.12.orig.tar.gz + # - sudo make -C lcov-1.12/ install + # - sudo apt-get install ggcov - gem install coveralls-lcov - lcov --version - gcov --version -before_script: - # init coverage to 0 (optional) - - lcov --directory . --zerocounters - script: # Build examples with Arduino IDE on each available platform / board # - build_main_platforms @@ -75,7 +71,6 @@ script: after_success: # Generate code coverage information & send to Coveralls - - pwd - lcov --directory . --capture --output-file coverage.info - lcov --remove coverage.info 'test/*' '/usr/*' 'external/*' --output-file coverage.info - lcov --list coverage.info From f4d103ea36069889856f77986a340e0b24ffc185 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Sun, 9 Oct 2016 20:11:55 +0200 Subject: [PATCH 066/138] Reworking Travis script. --- .travis.yml | 99 ++++++++++++++++++++++++++--------------------------- 1 file changed, 48 insertions(+), 51 deletions(-) diff --git a/.travis.yml b/.travis.yml index 57203f3..5e13a37 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,63 +1,60 @@ # Kudos to these guys: # http://genbattle.bitbucket.org/blog/2016/01/17/c++-travis-ci/ # https://github.com/ticapix/arduino-toolbox/blob/master/.travis.yml +# https://github.com/Return-To-The-Roots/s25client/blob/master/.travis.yml -# Ubuntu 14.04 Trusty support -sudo: required -dist: trusty - +sudo: false language: cpp -matrix: - include: - - compiler: gcc - addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-4.9 - env: COMPILER=g++-4.9 - - compiler: gcc - addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-5 - env: COMPILER=g++-5 - - compiler: clang - addons: - apt: - sources: - - ubuntu-toolchain-r-test - - llvm-toolchain-precise-3.6 - packages: - - clang-3.6 - env: COMPILER=clang++-3.6 - - compiler: clang - addons: - apt: - sources: - - ubuntu-toolchain-r-test - - llvm-toolchain-precise-3.7 - packages: - - clang-3.7 - env: COMPILER=clang++-3.7 +os: + - linux + +compiler: + - clang + - g++ + +env: + - BUILD_TYPE=Debug + +addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.5 + packages: + - g++-4.8 + - clang-3.5 + - llvm-3.5 + - cmake before_install: - sudo apt-get update -qq # - source <(curl -SLs https://raw.githubusercontent.com/fortyseveneffects/travis-ci-arduino/master/install.sh) install: - # Install lcov from source - # - wget http://ftp.fr.debian.org/debian/pool/main/l/lcov/lcov_1.12.orig.tar.gz - # - tar xf lcov_1.12.orig.tar.gz - # - sudo make -C lcov-1.12/ install - # - sudo apt-get install ggcov - - gem install coveralls-lcov - - lcov --version - - gcov --version + # Enable coverage analysis only for clang + - | + if [ "$CXX" = "g++" ]; 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 + + else + export GCOV="gcov" # Just to have anything valid + fi + # Use clang 3.5 + - if [ "$CXX" = "clang++" ]; then export CXX="clang++-3.5"; export CC="clang-3.5"; fi script: # Build examples with Arduino IDE on each available platform / board @@ -65,14 +62,14 @@ script: # Build and run unit tests with regular C++ compiler - mkdir build && cd build - - cmake -DCMAKE_CXX_COMPILER=$COMPILER -DCMAKE_BUILD_TYPE=Debug .. + - cmake -DCMAKE_CXX_COMPILER=$COMPILER -DCMAKE_BUILD_TYPE=${BUILD_TYPE} --generator="Unix Makefiles" .. - make all - ctest --verbose after_success: # Generate code coverage information & send to Coveralls - - lcov --directory . --capture --output-file coverage.info - - lcov --remove coverage.info 'test/*' '/usr/*' 'external/*' --output-file coverage.info + - lcov --gcov-tool $GCOV --directory . --capture --output-file coverage.info + - lcov --gcov-tool $GCOV --remove coverage.info 'test/*' '/usr/*' 'external/*' --output-file coverage.info - lcov --list coverage.info - coveralls-lcov --repo-token ${COVERALLS_TOKEN} coverage.info From b21500e8e61993a8cc5321064ed4c8aed3d3e806 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Sun, 9 Oct 2016 20:13:26 +0200 Subject: [PATCH 067/138] Fix sudo. --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 5e13a37..c740b07 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,7 +28,6 @@ addons: - cmake before_install: - - sudo apt-get update -qq # - source <(curl -SLs https://raw.githubusercontent.com/fortyseveneffects/travis-ci-arduino/master/install.sh) install: From 80b46ec9034e1682d15a830b718fdf1d3d8ffcc9 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Sun, 9 Oct 2016 21:47:16 +0200 Subject: [PATCH 068/138] Coverage only for g++, reactivated examples. --- .travis.yml | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index c740b07..16627a6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,8 +10,8 @@ os: - linux compiler: - - clang - g++ + - clang env: - BUILD_TYPE=Debug @@ -28,10 +28,10 @@ addons: - cmake before_install: - # - source <(curl -SLs https://raw.githubusercontent.com/fortyseveneffects/travis-ci-arduino/master/install.sh) + - source <(curl -SLs https://raw.githubusercontent.com/fortyseveneffects/travis-ci-arduino/master/install.sh) install: - # Enable coverage analysis only for clang + # Enable coverage analysis only for GCC - | if [ "$CXX" = "g++" ]; then # GCov 4.6 cannot handle the file structure @@ -48,16 +48,18 @@ install: # Install coveralls tool gem install coveralls-lcov + export GENERATE_COVERAGE=1 else export GCOV="gcov" # Just to have anything valid + export GENERATE_COVERAGE=0 fi # Use clang 3.5 - if [ "$CXX" = "clang++" ]; then export CXX="clang++-3.5"; export CC="clang-3.5"; fi script: # Build examples with Arduino IDE on each available platform / board - # - build_main_platforms + - build_main_platforms # Build and run unit tests with regular C++ compiler - mkdir build && cd build @@ -66,11 +68,14 @@ script: - ctest --verbose after_success: - # 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 + - | + 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 From d6d3f9edb0dbeb095e05ed77ffe989d0937d2c27 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Mon, 10 Oct 2016 12:00:56 +0200 Subject: [PATCH 069/138] Enable profiling only in Travis. --- .travis.yml | 2 +- builder/CMakeLists.txt | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 16627a6..d061ec5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -63,7 +63,7 @@ script: # Build and run unit tests with regular C++ compiler - mkdir build && cd build - - cmake -DCMAKE_CXX_COMPILER=$COMPILER -DCMAKE_BUILD_TYPE=${BUILD_TYPE} --generator="Unix Makefiles" .. + - cmake -DCMAKE_CXX_COMPILER=$COMPILER -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DBUILDER_ENABLE_PROFILING=${GENERATE_COVERAGE} --generator="Unix Makefiles" .. - make all - ctest --verbose diff --git a/builder/CMakeLists.txt b/builder/CMakeLists.txt index 684103b..83c5831 100644 --- a/builder/CMakeLists.txt +++ b/builder/CMakeLists.txt @@ -1,3 +1,4 @@ +option(BUILDER_ENABLE_PROFILING OFF) macro(setup_builder) enable_testing() @@ -8,8 +9,10 @@ macro(setup_builder) include_directories(${ROOT_SOURCE_DIR}) set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall -W -Wshadow -Wunused-variable -Wunused-parameter -Wunused-function -Wunused -Wno-system-headers -Wno-deprecated -Woverloaded-virtual") - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -O0") - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} --coverage") + 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") + endif() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") endmacro() From 68444227b2877a74e599adff4eae3a02d7b6b3b2 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Mon, 10 Oct 2016 12:01:24 +0200 Subject: [PATCH 070/138] Added test for invalid send methods. --- test/unit-tests/tests/unit-tests_MidiOutput.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/unit-tests/tests/unit-tests_MidiOutput.cpp b/test/unit-tests/tests/unit-tests_MidiOutput.cpp index 47890ea..c6dd737 100644 --- a/test/unit-tests/tests/unit-tests_MidiOutput.cpp +++ b/test/unit-tests/tests/unit-tests_MidiOutput.cpp @@ -30,6 +30,22 @@ typedef std::vector Buffer; // -- +TEST(MidiOutput, sendInvalid) +{ + SerialMock serial; + MidiInterface midi(serial); + + midi.begin(); + midi.send(midi::NoteOn, 42, 42, 42); // Invalid channel > OFF + EXPECT_EQ(serial.mTxBuffer.getLength(), 0); + + midi.send(midi::InvalidType, 0, 0, 12); // Invalid type + EXPECT_EQ(serial.mTxBuffer.getLength(), 0); + + midi.send(midi::NoteOn, 12, 42, MIDI_CHANNEL_OMNI); // OMNI not allowed + EXPECT_EQ(serial.mTxBuffer.getLength(), 0); +} + TEST(MidiOutput, sendGenericSingle) { SerialMock serial; From ac1925a74f042791b789e367b4154843b141f8f0 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Mon, 10 Oct 2016 13:48:11 +0200 Subject: [PATCH 071/138] Testing send real-time shortcut & sendSysEx. --- .../tests/unit-tests_MidiOutput.cpp | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/test/unit-tests/tests/unit-tests_MidiOutput.cpp b/test/unit-tests/tests/unit-tests_MidiOutput.cpp index c6dd737..e340287 100644 --- a/test/unit-tests/tests/unit-tests_MidiOutput.cpp +++ b/test/unit-tests/tests/unit-tests_MidiOutput.cpp @@ -121,6 +121,27 @@ TEST(MidiOutput, sendGenericBreakingRunningStatus) EXPECT_THAT(buffer, ElementsAreArray({0x9b, 47, 42, 0x8b, 47, 42})); } +TEST(MidiOutput, sendGenericRealTimeShortcut) +{ + SerialMock serial; + MidiInterface midi(serial); + Buffer buffer; + buffer.resize(7); + + midi.begin(); + midi.send(midi::TuneRequest, 47, 42, 12); + midi.send(midi::Clock, 47, 42, 12); + midi.send(midi::Start, 47, 42, 12); + midi.send(midi::Continue, 47, 42, 12); + midi.send(midi::Stop, 47, 42, 12); + midi.send(midi::ActiveSensing, 47, 42, 12); + midi.send(midi::SystemReset, 47, 42, 12); + + EXPECT_EQ(serial.mTxBuffer.getLength(), 7); + serial.mTxBuffer.read(&buffer[0], 7); + EXPECT_THAT(buffer, ElementsAreArray({0xf6, 0xf8, 0xfa, 0xfb, 0xfc, 0xfe, 0xff})); +} + // -- TEST(MidiOutput, sendNoteOn) @@ -256,12 +277,85 @@ TEST(MidiOutput, sendPolyPressure) TEST(MidiOutput, sendAfterTouch) { + SerialMock serial; + MidiInterface midi(serial); + Buffer buffer; + buffer.resize(3); + midi.begin(); + midi.sendAfterTouch(42, 12); + midi.sendAfterTouch(47, 12); + EXPECT_EQ(serial.mTxBuffer.getLength(), 3); + serial.mTxBuffer.read(&buffer[0], 3); + EXPECT_THAT(buffer, ElementsAreArray({0xdb, 42, 47})); } TEST(MidiOutput, sendSysEx) { + typedef test_mocks::SerialMock<1024> SerialMock; + typedef midi::MidiInterface MidiInterface; + + SerialMock serial; + MidiInterface midi(serial); + Buffer buffer; + + // Small frame + { + static const char* frame = "Hello, World!"; + static const unsigned frameLength = strlen(frame); + static const byte expected[] = { + 0xf0, + 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', + 0xf7, + }; + + buffer.clear(); + buffer.resize(frameLength + 2); + + midi.begin(); + midi.sendSysEx(frameLength, reinterpret_cast(frame), false); + EXPECT_EQ(serial.mTxBuffer.getLength(), frameLength + 2); + serial.mTxBuffer.read(&buffer[0], frameLength + 2); + EXPECT_THAT(buffer, ElementsAreArray(expected)); + } + // Large frame + { + static const char* frame = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin maximus dui a massa maximus, a vestibulum mi venenatis. Cras sit amet ex id velit suscipit pharetra eget a turpis. Phasellus interdum metus ac sagittis cursus. Nam quis est at nisl ullamcorper egestas pulvinar eu erat. Duis a elit dignissim, vestibulum eros vel, tempus nisl. Aenean turpis nunc, cursus vel lacinia non, pharetra eget sapien. Duis condimentum, lacus at pulvinar tempor, leo libero volutpat nisl, eget porttitor lorem mi sed magna. Duis dictum, massa vel euismod interdum, lorem mi egestas elit, hendrerit tincidunt est arcu a libero. Interdum et malesuada fames ac ante ipsum primis in faucibus. Curabitur vehicula magna libero, at rhoncus sem ornare a. In elementum, elit et congue pulvinar, massa velit commodo velit, non elementum purus ligula eget lacus. Donec efficitur nisi eu ultrices efficitur. Donec neque dui, ullamcorper id molestie quis, consequat sit amet ligula."; + static const unsigned frameLength = strlen(frame); + static const byte expected[] = { + 0xf0, + 'L','o','r','e','m',' ','i','p','s','u','m',' ','d','o','l','o','r',' ','s','i','t',' ','a','m','e','t',',',' ', + 'c','o','n','s','e','c','t','e','t','u','r',' ','a','d','i','p','i','s','c','i','n','g',' ','e','l','i','t','.',' ','P','r','o','i','n',' ','m','a','x','i','m','u','s',' ','d','u','i',' ','a',' ','m','a','s','s','a',' ','m','a','x','i','m','u','s',',',' ', + 'a',' ','v','e','s','t','i','b','u','l','u','m',' ','m','i',' ','v','e','n','e','n','a','t','i','s','.',' ','C','r','a','s',' ','s','i','t',' ','a','m','e','t',' ','e','x',' ','i','d',' ','v','e','l','i','t',' ','s','u','s','c','i','p','i','t',' ','p','h','a','r','e','t','r','a',' ','e','g','e','t', ' ','a',' ','t','u','r','p','i','s','.',' ','P','h','a','s','e','l','l','u','s',' ','i','n','t','e','r','d','u','m',' ','m','e','t','u','s',' ','a','c',' ','s','a','g','i','t','t','i','s',' ','c','u','r','s','u','s','.',' ','N','a','m',' ','q','u','i','s',' ','e','s','t',' ','a','t',' ','n','i','s', 'l',' ','u','l','l','a','m','c','o','r','p','e','r',' ','e','g','e','s','t','a','s',' ','p','u','l','v','i','n','a','r',' ','e','u',' ','e','r','a','t','.',' ','D','u','i','s',' ','a',' ','e','l','i','t',' ','d','i','g','n','i','s','s','i','m',',',' ', + 'v','e','s','t','i','b','u','l','u','m',' ','e','r','o','s',' ','v','e','l',',',' ', + 't','e','m','p','u','s',' ','n','i','s','l','.',' ','A','e','n','e','a','n',' ','t','u','r','p','i','s',' ','n','u','n','c',',',' ', + 'c','u','r','s','u','s',' ','v','e','l',' ','l','a','c','i','n','i','a',' ','n','o','n',',',' ', + 'p','h','a','r','e','t','r','a',' ','e','g','e','t',' ','s','a','p','i','e','n','.',' ','D','u','i','s',' ','c','o','n','d','i','m','e','n','t','u','m',',',' ', + 'l','a','c','u','s',' ','a','t',' ','p','u','l','v','i','n','a','r',' ','t','e','m','p','o','r',',',' ', + 'l','e','o',' ','l','i','b','e','r','o',' ','v','o','l','u','t','p','a','t',' ','n','i','s','l',',',' ', + 'e','g','e','t',' ','p','o','r','t','t','i','t','o','r',' ','l','o','r','e','m',' ','m','i',' ','s','e','d',' ','m','a','g','n','a','.',' ','D','u','i','s',' ','d','i','c','t','u','m',',',' ', + 'm','a','s','s','a',' ','v','e','l',' ','e','u','i','s','m','o','d',' ','i','n','t','e','r','d','u','m',',',' ', + 'l','o','r','e','m',' ','m','i',' ','e','g','e','s','t','a','s',' ','e','l','i','t',',',' ', + 'h','e','n','d','r','e','r','i','t',' ','t','i','n','c','i','d','u','n','t',' ','e','s','t',' ','a','r','c','u',' ','a',' ','l','i','b','e','r','o','.',' ','I','n','t','e','r','d','u','m',' ','e','t',' ','m','a','l','e','s','u','a','d','a',' ','f','a','m','e','s',' ','a','c',' ','a','n','t','e',' ', 'i','p','s','u','m',' ','p','r','i','m','i','s',' ','i','n',' ','f','a','u','c','i','b','u','s','.',' ','C','u','r','a','b','i','t','u','r',' ','v','e','h','i','c','u','l','a',' ','m','a','g','n','a',' ','l','i','b','e','r','o',',',' ', + 'a','t',' ','r','h','o','n','c','u','s',' ','s','e','m',' ','o','r','n','a','r','e',' ','a','.',' ','I','n',' ','e','l','e','m','e','n','t','u','m',',',' ', + 'e','l','i','t',' ','e','t',' ','c','o','n','g','u','e',' ','p','u','l','v','i','n','a','r',',',' ', + 'm','a','s','s','a',' ','v','e','l','i','t',' ','c','o','m','m','o','d','o',' ','v','e','l','i','t',',',' ', + 'n','o','n',' ','e','l','e','m','e','n','t','u','m',' ','p','u','r','u','s',' ','l','i','g','u','l','a',' ','e','g','e','t',' ','l','a','c','u','s','.',' ','D','o','n','e','c',' ','e','f','f','i','c','i','t','u','r',' ','n','i','s','i',' ','e','u',' ','u','l','t','r','i','c','e','s',' ','e','f','f', 'i','c','i','t','u','r','.',' ','D','o','n','e','c',' ','n','e','q','u','e',' ','d','u','i',',',' ', + 'u','l','l','a','m','c','o','r','p','e','r',' ','i','d',' ','m','o','l','e','s','t','i','e',' ','q','u','i','s',',',' ', + 'c','o','n','s','e','q','u','a','t',' ','s','i','t',' ','a','m','e','t',' ','l','i','g','u','l','a','.', + 0xf7, + }; + + buffer.clear(); + buffer.resize(frameLength + 2); + + midi.begin(); + midi.sendSysEx(frameLength, reinterpret_cast(frame), false); + EXPECT_EQ(serial.mTxBuffer.getLength(), frameLength + 2); + serial.mTxBuffer.read(&buffer[0], frameLength + 2); + EXPECT_THAT(buffer, ElementsAreArray(expected)); + } } TEST(MidiOutput, sendTimeCodeQuarterFrame) From 300cb139e9009f1675300791cab32432d0ad35a7 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Mon, 10 Oct 2016 14:23:50 +0200 Subject: [PATCH 072/138] #54: Deprecated sending of TuneRequests with sendRealTime. --- src/MIDI.hpp | 22 +++++++++---------- .../tests/unit-tests_MidiOutput.cpp | 9 ++++---- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/MIDI.hpp b/src/MIDI.hpp index 570c759..7c59a72 100644 --- a/src/MIDI.hpp +++ b/src/MIDI.hpp @@ -176,7 +176,7 @@ void MidiInterface::send(MidiType inType, mSerial.write(inData2); } } - else if (inType >= TuneRequest && inType <= SystemReset) + else if (inType >= Clock && inType <= SystemReset) { sendRealTime(inType); // System Real-time and 1 byte. } @@ -344,7 +344,12 @@ void MidiInterface::sendSysEx(unsigned inLength, template void MidiInterface::sendTuneRequest() { - sendRealTime(TuneRequest); + mSerial.write(TuneRequest); + + if (Settings::UseRunningStatus) + { + mRunningStatus_TX = InvalidType; + } } /*! \brief Send a MIDI Time Code Quarter Frame. @@ -412,15 +417,16 @@ void MidiInterface::sendSongSelect(DataByte inSongNumber) \param inType The available Real Time types are: Start, Stop, Continue, Clock, ActiveSensing and SystemReset. - You can also send a Tune Request with this method. @see MidiType */ template void MidiInterface::sendRealTime(MidiType inType) { + // Do not invalidate Running Status for real-time messages + // as they can be interleaved within any message. + switch (inType) { - case TuneRequest: // Not really real-time, but one byte anyway. case Clock: case Start: case Stop: @@ -433,14 +439,6 @@ void MidiInterface::sendRealTime(MidiType inType) // Invalid Real Time marker break; } - - // Do not cancel Running Status for real-time messages as they can be - // interleaved within any message. Though, TuneRequest can be sent here, - // and as it is a System Common message, it must reset Running Status. - if (Settings::UseRunningStatus && inType == TuneRequest) - { - mRunningStatus_TX = InvalidType; - } } /*! \brief Start a Registered Parameter Number frame. diff --git a/test/unit-tests/tests/unit-tests_MidiOutput.cpp b/test/unit-tests/tests/unit-tests_MidiOutput.cpp index e340287..fc4a2ea 100644 --- a/test/unit-tests/tests/unit-tests_MidiOutput.cpp +++ b/test/unit-tests/tests/unit-tests_MidiOutput.cpp @@ -126,10 +126,9 @@ TEST(MidiOutput, sendGenericRealTimeShortcut) SerialMock serial; MidiInterface midi(serial); Buffer buffer; - buffer.resize(7); + buffer.resize(6); midi.begin(); - midi.send(midi::TuneRequest, 47, 42, 12); midi.send(midi::Clock, 47, 42, 12); midi.send(midi::Start, 47, 42, 12); midi.send(midi::Continue, 47, 42, 12); @@ -137,9 +136,9 @@ TEST(MidiOutput, sendGenericRealTimeShortcut) midi.send(midi::ActiveSensing, 47, 42, 12); midi.send(midi::SystemReset, 47, 42, 12); - EXPECT_EQ(serial.mTxBuffer.getLength(), 7); - serial.mTxBuffer.read(&buffer[0], 7); - EXPECT_THAT(buffer, ElementsAreArray({0xf6, 0xf8, 0xfa, 0xfb, 0xfc, 0xfe, 0xff})); + EXPECT_EQ(serial.mTxBuffer.getLength(), 6); + serial.mTxBuffer.read(&buffer[0], 6); + EXPECT_THAT(buffer, ElementsAreArray({0xf8, 0xfa, 0xfb, 0xfc, 0xfe, 0xff})); } // -- From 2b4b30b32a0f074a5ec4c3522aa1ef8a995968dc Mon Sep 17 00:00:00 2001 From: Francois Best Date: Mon, 10 Oct 2016 14:23:57 +0200 Subject: [PATCH 073/138] Moar tests. --- .../tests/unit-tests_MidiOutput.cpp | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) diff --git a/test/unit-tests/tests/unit-tests_MidiOutput.cpp b/test/unit-tests/tests/unit-tests_MidiOutput.cpp index fc4a2ea..6f781f7 100644 --- a/test/unit-tests/tests/unit-tests_MidiOutput.cpp +++ b/test/unit-tests/tests/unit-tests_MidiOutput.cpp @@ -355,31 +355,146 @@ TEST(MidiOutput, sendSysEx) serial.mTxBuffer.read(&buffer[0], frameLength + 2); EXPECT_THAT(buffer, ElementsAreArray(expected)); } + // With boundaries included + { + static const byte frame[] = { + 0xf0, 12, 17, 42, 47, 0xf7 + }; + + buffer.clear(); + buffer.resize(6); + + midi.begin(); + midi.sendSysEx(6, frame, true); + EXPECT_EQ(serial.mTxBuffer.getLength(), 6); + serial.mTxBuffer.read(&buffer[0], 6); + EXPECT_THAT(buffer, ElementsAreArray(frame)); + } } TEST(MidiOutput, sendTimeCodeQuarterFrame) { + SerialMock serial; + MidiInterface midi(serial); + Buffer buffer; + // Separate Nibbles + { + buffer.clear(); + buffer.resize(4); + + midi.begin(); + midi.sendTimeCodeQuarterFrame(0x05, 0x0a); + midi.sendTimeCodeQuarterFrame(0xff, 0xff); + EXPECT_EQ(serial.mTxBuffer.getLength(), 4); + serial.mTxBuffer.read(&buffer[0], 4); + EXPECT_THAT(buffer, ElementsAreArray({0xf1, 0x5a, + 0xf1, 0x7f})); + } + // Pre-encoded nibbles + { + buffer.clear(); + buffer.resize(4); + + midi.begin(); + midi.sendTimeCodeQuarterFrame(12); + midi.sendTimeCodeQuarterFrame(42); + EXPECT_EQ(serial.mTxBuffer.getLength(), 4); + serial.mTxBuffer.read(&buffer[0], 4); + EXPECT_THAT(buffer, ElementsAreArray({0xf1, 0x0c, + 0xf1, 0x2a})); + } } TEST(MidiOutput, sendSongPosition) { + SerialMock serial; + MidiInterface midi(serial); + Buffer buffer; + buffer.resize(6); + midi.begin(); + midi.sendSongPosition(1234); + midi.sendSongPosition(4321); + EXPECT_EQ(serial.mTxBuffer.getLength(), 6); + serial.mTxBuffer.read(&buffer[0], 6); + EXPECT_THAT(buffer, ElementsAreArray({0xf2, 0x52, 0x09, + 0xf2, 0x61, 0x21})); } TEST(MidiOutput, sendSongSelect) { + SerialMock serial; + MidiInterface midi(serial); + Buffer buffer; + buffer.resize(4); + midi.begin(); + midi.sendSongSelect(12); + midi.sendSongSelect(42); + EXPECT_EQ(serial.mTxBuffer.getLength(), 4); + serial.mTxBuffer.read(&buffer[0], 4); + EXPECT_THAT(buffer, ElementsAreArray({0xf3, 12, 0xf3, 42})); } TEST(MidiOutput, sendTuneRequest) { + SerialMock serial; + MidiInterface midi(serial); + Buffer buffer; + buffer.resize(1); + midi.begin(); + midi.sendTuneRequest(); + EXPECT_EQ(serial.mTxBuffer.getLength(), 1); + serial.mTxBuffer.read(&buffer[0], 1); + EXPECT_THAT(buffer, ElementsAreArray({0xf6})); } TEST(MidiOutput, sendRealTime) { + SerialMock serial; + MidiInterface midi(serial); + Buffer buffer; + // Test valid RealTime messages + { + buffer.clear(); + buffer.resize(6); + + midi.begin(); + midi.sendRealTime(midi::Clock); + midi.sendRealTime(midi::Start); + midi.sendRealTime(midi::Continue); + midi.sendRealTime(midi::Stop); + midi.sendRealTime(midi::ActiveSensing); + midi.sendRealTime(midi::SystemReset); + + EXPECT_EQ(serial.mTxBuffer.getLength(), 6); + serial.mTxBuffer.read(&buffer[0], 6); + EXPECT_THAT(buffer, ElementsAreArray({ + 0xf8, 0xfa, 0xfb, 0xfc, 0xfe, 0xff + })); + } + // Test invalid messages + { + midi.begin(); + midi.sendRealTime(midi::InvalidType); + midi.sendRealTime(midi::NoteOff); + midi.sendRealTime(midi::NoteOn); + midi.sendRealTime(midi::AfterTouchPoly); + midi.sendRealTime(midi::ControlChange); + midi.sendRealTime(midi::ProgramChange); + midi.sendRealTime(midi::AfterTouchChannel); + midi.sendRealTime(midi::PitchBend); + midi.sendRealTime(midi::SystemExclusive); + midi.sendRealTime(midi::TimeCodeQuarterFrame); + midi.sendRealTime(midi::SongPosition); + midi.sendRealTime(midi::SongSelect); + midi.sendRealTime(midi::TuneRequest); + + EXPECT_EQ(serial.mTxBuffer.getLength(), 0); + } } TEST(MidiOutput, RPN) From 606e73249031a9110ac7a754243ab6fb4ead9e05 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Mon, 10 Oct 2016 15:38:08 +0200 Subject: [PATCH 074/138] Moved examples & keywords.txt to follow 1.5 lib spec. --- examples/Basic_IO/Basic_IO.ino | 27 +++++++++++ .../Bench/Bench.ino | 0 .../Callbacks/Callbacks.ino | 0 .../DualMerger/DualMerger.ino | 0 .../Input/Input.ino | 0 .../RPN_NRPN/RPN_NRPN.ino | 0 .../RPN_NRPN}/utility.h | 0 .../SimpleSynth/SimpleSynth.ino | 0 .../SimpleSynth}/noteList.cpp | 0 .../SimpleSynth}/noteList.h | 0 .../SimpleSynth}/pitches.h | 0 res/keywords.txt => keywords.txt | 0 res/Examples/MIDI_Basic_IO/MIDI_Basic_IO.ino | 27 ----------- src/MIDI.h | 1 - src/midi_UsbTransport.h | 47 +++++++++++++++++++ 15 files changed, 74 insertions(+), 28 deletions(-) create mode 100644 examples/Basic_IO/Basic_IO.ino rename res/Examples/MIDI_Bench/MIDI_Bench.ino => examples/Bench/Bench.ino (100%) rename res/Examples/MIDI_Callbacks/MIDI_Callbacks.ino => examples/Callbacks/Callbacks.ino (100%) rename res/Examples/MIDI_DualMerger/MIDI_DualMerger.ino => examples/DualMerger/DualMerger.ino (100%) rename res/Examples/MIDI_Input/MIDI_Input.ino => examples/Input/Input.ino (100%) rename res/Examples/MIDI_RPN_NRPN/MIDI_RPN_NRPN.ino => examples/RPN_NRPN/RPN_NRPN.ino (100%) rename {res/Examples/MIDI_RPN_NRPN => examples/RPN_NRPN}/utility.h (100%) rename res/Examples/MIDI_SimpleSynth/MIDI_SimpleSynth.ino => examples/SimpleSynth/SimpleSynth.ino (100%) rename {res/Examples/MIDI_SimpleSynth => examples/SimpleSynth}/noteList.cpp (100%) rename {res/Examples/MIDI_SimpleSynth => examples/SimpleSynth}/noteList.h (100%) rename {res/Examples/MIDI_SimpleSynth => examples/SimpleSynth}/pitches.h (100%) rename res/keywords.txt => keywords.txt (100%) delete mode 100644 res/Examples/MIDI_Basic_IO/MIDI_Basic_IO.ino create mode 100644 src/midi_UsbTransport.h diff --git a/examples/Basic_IO/Basic_IO.ino b/examples/Basic_IO/Basic_IO.ino new file mode 100644 index 0000000..43a3fe3 --- /dev/null +++ b/examples/Basic_IO/Basic_IO.ino @@ -0,0 +1,27 @@ +#include + +// Simple tutorial on how to receive and send MIDI messages. +// Here, when receiving any message on channel 4, the Arduino +// will blink a led and play back a note for 1 second. + +MIDI_CREATE_DEFAULT_INSTANCE(); + +static const ledPin = 13; // LED pin on Arduino Uno + +void setup() +{ + pinMode(ledPin, OUTPUT); + MIDI.begin(4); // Launch MIDI and listen to channel 4 +} + +void loop() +{ + if (MIDI.read()) // If we have received a message + { + digitalWrite(ledPin, 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); + } +} diff --git a/res/Examples/MIDI_Bench/MIDI_Bench.ino b/examples/Bench/Bench.ino similarity index 100% rename from res/Examples/MIDI_Bench/MIDI_Bench.ino rename to examples/Bench/Bench.ino diff --git a/res/Examples/MIDI_Callbacks/MIDI_Callbacks.ino b/examples/Callbacks/Callbacks.ino similarity index 100% rename from res/Examples/MIDI_Callbacks/MIDI_Callbacks.ino rename to examples/Callbacks/Callbacks.ino diff --git a/res/Examples/MIDI_DualMerger/MIDI_DualMerger.ino b/examples/DualMerger/DualMerger.ino similarity index 100% rename from res/Examples/MIDI_DualMerger/MIDI_DualMerger.ino rename to examples/DualMerger/DualMerger.ino diff --git a/res/Examples/MIDI_Input/MIDI_Input.ino b/examples/Input/Input.ino similarity index 100% rename from res/Examples/MIDI_Input/MIDI_Input.ino rename to examples/Input/Input.ino diff --git a/res/Examples/MIDI_RPN_NRPN/MIDI_RPN_NRPN.ino b/examples/RPN_NRPN/RPN_NRPN.ino similarity index 100% rename from res/Examples/MIDI_RPN_NRPN/MIDI_RPN_NRPN.ino rename to examples/RPN_NRPN/RPN_NRPN.ino diff --git a/res/Examples/MIDI_RPN_NRPN/utility.h b/examples/RPN_NRPN/utility.h similarity index 100% rename from res/Examples/MIDI_RPN_NRPN/utility.h rename to examples/RPN_NRPN/utility.h diff --git a/res/Examples/MIDI_SimpleSynth/MIDI_SimpleSynth.ino b/examples/SimpleSynth/SimpleSynth.ino similarity index 100% rename from res/Examples/MIDI_SimpleSynth/MIDI_SimpleSynth.ino rename to examples/SimpleSynth/SimpleSynth.ino diff --git a/res/Examples/MIDI_SimpleSynth/noteList.cpp b/examples/SimpleSynth/noteList.cpp similarity index 100% rename from res/Examples/MIDI_SimpleSynth/noteList.cpp rename to examples/SimpleSynth/noteList.cpp diff --git a/res/Examples/MIDI_SimpleSynth/noteList.h b/examples/SimpleSynth/noteList.h similarity index 100% rename from res/Examples/MIDI_SimpleSynth/noteList.h rename to examples/SimpleSynth/noteList.h diff --git a/res/Examples/MIDI_SimpleSynth/pitches.h b/examples/SimpleSynth/pitches.h similarity index 100% rename from res/Examples/MIDI_SimpleSynth/pitches.h rename to examples/SimpleSynth/pitches.h diff --git a/res/keywords.txt b/keywords.txt similarity index 100% rename from res/keywords.txt rename to keywords.txt diff --git a/res/Examples/MIDI_Basic_IO/MIDI_Basic_IO.ino b/res/Examples/MIDI_Basic_IO/MIDI_Basic_IO.ino deleted file mode 100644 index f6efee2..0000000 --- a/res/Examples/MIDI_Basic_IO/MIDI_Basic_IO.ino +++ /dev/null @@ -1,27 +0,0 @@ -#include - -// Simple tutorial on how to receive and send MIDI messages. -// Here, when receiving any message on channel 4, the Arduino -// will blink a led and play back a note for 1 second. - -MIDI_CREATE_DEFAULT_INSTANCE(); - -#define LED 13 // LED pin on Arduino Uno - -void setup() -{ - pinMode(LED, OUTPUT); - MIDI.begin(4); // Launch MIDI and listen to channel 4 -} - -void loop() -{ - if (MIDI.read()) // If we have received a message - { - digitalWrite(LED,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,LOW); - } -} diff --git a/src/MIDI.h b/src/MIDI.h index 09961a2..11f0605 100644 --- a/src/MIDI.h +++ b/src/MIDI.h @@ -123,7 +123,6 @@ public: Channel inChannel); inline void endNrpn(Channel inChannel); - public: void send(MidiType inType, DataByte inData1, diff --git a/src/midi_UsbTransport.h b/src/midi_UsbTransport.h new file mode 100644 index 0000000..7d59480 --- /dev/null +++ b/src/midi_UsbTransport.h @@ -0,0 +1,47 @@ +/*! + * @file midi_UsbTransport.h + * Project Arduino MIDI Library + * @brief MIDI Library for the Arduino - Transport layer for USB MIDI + * @version 4.2 + * @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" + +BEGIN_MIDI_NAMESPACE + +class UsbTransport +{ +public: + inline UsbTransport(); + +public: // Serial / Stream API required for template compatibility + inline void begin(unsigned inBaudrate); + inline int available() const; + inline byte read(); + inline void write(byte); +}; + +END_MIDI_NAMESPACE From 47b206c279dce04d3e118eca50b972be9e3ba511 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Mon, 10 Oct 2016 16:57:15 +0200 Subject: [PATCH 075/138] Added MIDIUSB Arduino lib as a submodule. --- .gitmodules | 3 +++ external/midi-usb | 1 + 2 files changed, 4 insertions(+) create mode 160000 external/midi-usb diff --git a/.gitmodules b/.gitmodules index 53d7ecd..c1c2a77 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [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 diff --git a/external/midi-usb b/external/midi-usb new file mode 160000 index 0000000..0a1ef74 --- /dev/null +++ b/external/midi-usb @@ -0,0 +1 @@ +Subproject commit 0a1ef7498dad7904d2a54530616f418dcba9197c From 305c263afbbaf06e545b05afa31cc345d1209a63 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Mon, 10 Oct 2016 16:57:56 +0200 Subject: [PATCH 076/138] Added RingBuffer utility class for USB transport. --- src/midi_RingBuffer.h | 63 +++++++++++++++++++++++++++ src/midi_RingBuffer.hpp | 94 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 157 insertions(+) create mode 100644 src/midi_RingBuffer.h create mode 100644 src/midi_RingBuffer.hpp diff --git a/src/midi_RingBuffer.h b/src/midi_RingBuffer.h new file mode 100644 index 0000000..ea6884a --- /dev/null +++ b/src/midi_RingBuffer.h @@ -0,0 +1,63 @@ +/*! + * @file midi_RingBuffer.h + * Project Arduino MIDI Library + * @brief MIDI Library for Arduino - Ring Buffer + * @version 4.2 + * @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_Namespace.h" + +BEGIN_MIDI_NAMESPACE + +template +class RingBuffer +{ +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; +}; + +END_MIDI_NAMESPACE + +#include "midi_RingBuffer.hpp" diff --git a/src/midi_RingBuffer.hpp b/src/midi_RingBuffer.hpp new file mode 100644 index 0000000..b3e073e --- /dev/null +++ b/src/midi_RingBuffer.hpp @@ -0,0 +1,94 @@ +#pragma once + +BEGIN_MIDI_NAMESPACE + +template +RingBuffer::RingBuffer() + : mWriteHead(mData) + , mReadHead(mData) +{ + memset(mData, DataType(0), Size * sizeof(DataType)); +} + +template +RingBuffer::~RingBuffer() +{ +} + +// ----------------------------------------------------------------------------- + +template +int RingBuffer::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 +bool RingBuffer::isEmpty() const +{ + return mReadHead == mWriteHead; +} + +// ----------------------------------------------------------------------------- + +template +void RingBuffer::write(DataType inData) +{ + *mWriteHead++ = inData; + if (mWriteHead >= mData + Size) + { + mWriteHead = mData; + } +} + +template +void RingBuffer::write(const DataType* inData, int inSize) +{ + for (int i = 0; i < inSize; ++i) + { + write(inData[i]); + } +} + +template +void RingBuffer::clear() +{ + memset(mData, DataType(0), Size * sizeof(DataType)); + mReadHead = mData; + mWriteHead = mData; +} + +// ----------------------------------------------------------------------------- + +template +DataType RingBuffer::read() +{ + const DataType data = *mReadHead++; + if (mReadHead >= mData + Size) + { + mReadHead = mData; + } + return data; +} + +template +void RingBuffer::read(DataType* outData, int inSize) +{ + for (int i = 0; i < inSize; ++i) + { + outData[i] = read(); + } +} + +END_MIDI_NAMESPACE From 203a26ea3a66dede743259c8cee2e98db2f772c7 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Mon, 10 Oct 2016 16:59:03 +0200 Subject: [PATCH 077/138] Added USB transport for native MIDI through USB. #52 --- src/midi_UsbTransport.h | 30 +++++++- src/midi_UsbTransport.hpp | 153 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 181 insertions(+), 2 deletions(-) create mode 100644 src/midi_UsbTransport.hpp diff --git a/src/midi_UsbTransport.h b/src/midi_UsbTransport.h index 7d59480..8ea9044 100644 --- a/src/midi_UsbTransport.h +++ b/src/midi_UsbTransport.h @@ -29,19 +29,45 @@ #pragma once #include "midi_Defs.h" +#include "midi_RingBuffer.h" +#include BEGIN_MIDI_NAMESPACE +template class UsbTransport { public: inline UsbTransport(); + inline ~UsbTransport(); public: // Serial / Stream API required for template compatibility inline void begin(unsigned inBaudrate); - inline int available() const; + inline unsigned available(); inline byte read(); - inline void write(byte); + 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 Buffer; + Buffer mTxBuffer; + Buffer mRxBuffer; + + union TxPacket + { + byte mDataArray[4]; + midiEventPacket_t mPacket; + }; + TxPacket mCurrentTxPacket; + int mCurrentTxPacketByteIndex; }; END_MIDI_NAMESPACE + +#include "midi_UsbTransport.hpp" diff --git a/src/midi_UsbTransport.hpp b/src/midi_UsbTransport.hpp new file mode 100644 index 0000000..6849e59 --- /dev/null +++ b/src/midi_UsbTransport.hpp @@ -0,0 +1,153 @@ +#pragma once + +BEGIN_MIDI_NAMESPACE + +template +inline UsbTransport::UsbTransport() +{ + +} + +template +inline UsbTransport::~UsbTransport() +{ + +} + +// ----------------------------------------------------------------------------- + +template +inline void UsbTransport::begin(unsigned inBaudrate) +{ + mTxBuffer.clear(); + mRxBuffer.clear(); +} + +template +inline unsigned UsbTransport::available() +{ + pollUsbMidi(); + return mRxBuffer.getLength(); +} + +template +inline byte UsbTransport::read() +{ + return mRxBuffer.read(); +} + +template +inline void UsbTransport::write(byte inData) +{ + mTxBuffer.write(inData); + recomposeAndSendTxPackets(); +} + +// ----------------------------------------------------------------------------- + +template +inline bool UsbTransport::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 +inline void UsbTransport::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 +inline void UsbTransport::resetTx() +{ + mCurrentTxPacket.mPacket.header = 0; + mCurrentTxPacket.mPacket.byte1 = 0; + mCurrentTxPacket.mPacket.byte2 = 0; + mCurrentTxPacket.mPacket.byte3 = 0; + mCurrentTxPacketByteIndex = 0; +} + +template +inline byte UsbTransport::encodePacketHeader(StatusByte inStatusByte) +{ + // todo: fix me for other types than channel + return inStatusByte >> 4; +} + +template +inline int UsbTransport::getPacketLength(const midiEventPacket_t& inPacket) +{ + return 3; +} + +END_MIDI_NAMESPACE From ff6bf0111b3a00267ffc3ab7cc0654d99a1bdb19 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Mon, 10 Oct 2016 17:05:59 +0200 Subject: [PATCH 078/138] Added MidiUSB example (wip). --- examples/MidiUSB/MidiUSB.ino | 39 ++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 examples/MidiUSB/MidiUSB.ino diff --git a/examples/MidiUSB/MidiUSB.ino b/examples/MidiUSB/MidiUSB.ino new file mode 100644 index 0000000..d51eccd --- /dev/null +++ b/examples/MidiUSB/MidiUSB.ino @@ -0,0 +1,39 @@ +#include +#include + +static const unsigned sUsbTransportBufferSize = 16; +typedef midi::UsbTransport UsbTransport; + +UsbTransport sUsbTransport; + +MIDI_CREATE_INSTANCE(UsbTransport, sUsbTransport, MIDI); + +// -- + +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(); +} \ No newline at end of file From 73dfc798158b1ea63ad3826010d0e8902313f3b4 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Mon, 10 Oct 2016 17:16:04 +0200 Subject: [PATCH 079/138] Fix examples. --- .travis.yml | 1 + examples/Basic_IO/Basic_IO.ino | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d061ec5..599944e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -56,6 +56,7 @@ install: fi # Use clang 3.5 - if [ "$CXX" = "clang++" ]; then export CXX="clang++-3.5"; export CC="clang-3.5"; fi + - arduino --install-library "MIDIUSB" script: # Build examples with Arduino IDE on each available platform / board diff --git a/examples/Basic_IO/Basic_IO.ino b/examples/Basic_IO/Basic_IO.ino index 43a3fe3..434cf3f 100644 --- a/examples/Basic_IO/Basic_IO.ino +++ b/examples/Basic_IO/Basic_IO.ino @@ -6,7 +6,7 @@ MIDI_CREATE_DEFAULT_INSTANCE(); -static const ledPin = 13; // LED pin on Arduino Uno +static const unsigned ledPin = 13; // LED pin on Arduino Uno void setup() { From ebd10f034aedbe6e02d4911e7a32e8638b5a924a Mon Sep 17 00:00:00 2001 From: Francois Best Date: Mon, 10 Oct 2016 17:38:40 +0200 Subject: [PATCH 080/138] Listing new files. --- src/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7dc7b16..ef00cf1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,6 +5,10 @@ add_library(midi STATIC midi_Defs.h midi_Message.h midi_Settings.h + midi_RingBuffer.h + midi_RingBuffer.hpp + midi_UsbTransport.h + midi_UsbTransport.hpp MIDI.cpp MIDI.hpp MIDI.h From cf8761379c9231b9e0e27dbd44b94d18d0b40b02 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Tue, 11 Oct 2016 09:02:11 +0200 Subject: [PATCH 081/138] Skipping USB test for now. --- examples/MidiUSB/avr.test.skip | 0 examples/MidiUSB/sam.test.skip | 0 examples/MidiUSB/samd.test.skip | 0 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 examples/MidiUSB/avr.test.skip create mode 100644 examples/MidiUSB/sam.test.skip create mode 100644 examples/MidiUSB/samd.test.skip diff --git a/examples/MidiUSB/avr.test.skip b/examples/MidiUSB/avr.test.skip new file mode 100644 index 0000000..e69de29 diff --git a/examples/MidiUSB/sam.test.skip b/examples/MidiUSB/sam.test.skip new file mode 100644 index 0000000..e69de29 diff --git a/examples/MidiUSB/samd.test.skip b/examples/MidiUSB/samd.test.skip new file mode 100644 index 0000000..e69de29 From c17f2396cd963a1f9f3677f326ef19ed1354683e Mon Sep 17 00:00:00 2001 From: Francois Best Date: Wed, 12 Oct 2016 19:11:21 +0200 Subject: [PATCH 082/138] Fix syntax. --- src/midi_USB.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/midi_USB.h b/src/midi_USB.h index 7ff7875..14aaeed 100644 --- a/src/midi_USB.h +++ b/src/midi_USB.h @@ -99,7 +99,7 @@ struct UsbMidiEvent byte mCodeIndexNumber:4; byte mMidi[3]; }; - byte[4] mDataArray; + byte mDataArray[4]; }; }; From 63e8e515ad03dd5ad3f370326e8acffd7d4b9ce3 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Wed, 12 Oct 2016 19:16:27 +0200 Subject: [PATCH 083/138] Rename midi_USB.h to midi_UsbDefs.h --- src/{midi_USB.h => midi_UsbDefs.h} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{midi_USB.h => midi_UsbDefs.h} (100%) diff --git a/src/midi_USB.h b/src/midi_UsbDefs.h similarity index 100% rename from src/midi_USB.h rename to src/midi_UsbDefs.h From e84d12d9edc3ce3ddd56f4d251e8e253d7b7d64a Mon Sep 17 00:00:00 2001 From: Francois Best Date: Wed, 12 Oct 2016 19:18:29 +0200 Subject: [PATCH 084/138] Update license, renamed packet object. --- src/midi_UsbDefs.h | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/src/midi_UsbDefs.h b/src/midi_UsbDefs.h index 14aaeed..393ca35 100644 --- a/src/midi_UsbDefs.h +++ b/src/midi_UsbDefs.h @@ -1,24 +1,29 @@ /*! - * @file midi_USB.h + * @file midi_UsbDefs.h * Project Arduino MIDI Library - * @brief MIDI Library for the Arduino - USB - * @version 4.1 + * @brief MIDI Library for the Arduino - Definitions + * @version 4.2 * @author Francois Best * @date 24/02/11 - * @license GPL v3.0 - Copyright Forty Seven Effects 2014 + * @license MIT - Copyright (c) 2016 Francois Best * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * 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: * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * 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 @@ -88,7 +93,7 @@ struct CodeIndexNumbers // ----------------------------------------------------------------------------- -struct UsbMidiEvent +struct UsbMidiEventPacket { union { From 0252ce7ebe14594a2534760a89fc53f557997354 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Wed, 12 Oct 2016 19:22:36 +0200 Subject: [PATCH 085/138] Fixed noteOn/Off CINs, coding style & fixes. --- src/midi_UsbDefs.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/midi_UsbDefs.h b/src/midi_UsbDefs.h index 393ca35..514c1a0 100644 --- a/src/midi_UsbDefs.h +++ b/src/midi_UsbDefs.h @@ -51,9 +51,9 @@ struct CodeIndexNumbers sysExEnds2Bytes = 0x06, sysExEnds3Bytes = 0x07, - noteOn = 0x08, - noteOff = 0x09, - polyKeyPress = 0x0A, + noteOff = 0x08, + noteOn = 0x09, + polyPressure = 0x0A, controlChange = 0x0B, programChange = 0x0C, channelPressure = 0x0D, @@ -61,9 +61,9 @@ struct CodeIndexNumbers singleByte = 0x0F, }; - inline byte getSize(byte inCIN) + static inline byte getSize(byte inCodeIndexNumber) { - switch (inCIN) + switch (inCodeIndexNumber) { case noteOn: case noteOff: From 3da8bb013e86fb69440c917afb77c6c3481d681e Mon Sep 17 00:00:00 2001 From: Francois Best Date: Thu, 13 Oct 2016 17:29:58 +0200 Subject: [PATCH 086/138] Don't build examples for now. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 599944e..3b64ca2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -60,7 +60,7 @@ install: script: # Build examples with Arduino IDE on each available platform / board - - build_main_platforms + # - build_main_platforms # Build and run unit tests with regular C++ compiler - mkdir build && cd build From cf7885d79b777eec9aeb38fa95ec30f6e86d2875 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Thu, 13 Oct 2016 18:30:49 +0200 Subject: [PATCH 087/138] Fixed stuff, using struct & methods rather than union. --- src/midi_UsbDefs.h | 60 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 47 insertions(+), 13 deletions(-) diff --git a/src/midi_UsbDefs.h b/src/midi_UsbDefs.h index 514c1a0..5e607cf 100644 --- a/src/midi_UsbDefs.h +++ b/src/midi_UsbDefs.h @@ -28,7 +28,7 @@ #pragma once -#include "midi_Namespace.h" +#include "midi_Defs.h" BEGIN_MIDI_NAMESPACE @@ -69,9 +69,10 @@ struct CodeIndexNumbers case noteOff: case controlChange: case pitchBend: - case polyKeyPress: + case polyPressure: case systemCommon3Bytes: case sysExEnds3Bytes: + case sysExStart: return 3; case programChange: @@ -87,7 +88,7 @@ struct CodeIndexNumbers default: break; } - return 0; + return 0; // Can be any length (1, 2 or 3). } }; @@ -95,17 +96,50 @@ struct CodeIndexNumbers struct UsbMidiEventPacket { - union +public: + inline UsbMidiEventPacket() { - uint32_t mRawData; - struct - { - byte mCableNumber:4; - byte mCodeIndexNumber:4; - byte mMidi[3]; - }; - byte mDataArray[4]; - }; + 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 From 5a477fda4f30e1faecc2a6e96e444c9bb419f9df Mon Sep 17 00:00:00 2001 From: Francois Best Date: Thu, 13 Oct 2016 18:30:59 +0200 Subject: [PATCH 088/138] Added unit tests for USB stuff. --- test/unit-tests/CMakeLists.txt | 1 + test/unit-tests/tests/unit-tests_MidiUsb.cpp | 75 ++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 test/unit-tests/tests/unit-tests_MidiUsb.cpp diff --git a/test/unit-tests/CMakeLists.txt b/test/unit-tests/CMakeLists.txt index e784749..65162d8 100644 --- a/test/unit-tests/CMakeLists.txt +++ b/test/unit-tests/CMakeLists.txt @@ -21,6 +21,7 @@ add_executable(unit-tests tests/unit-tests_MidiInput.cpp tests/unit-tests_MidiOutput.cpp tests/unit-tests_MidiThru.cpp + tests/unit-tests_MidiUsb.cpp ) target_link_libraries(unit-tests diff --git a/test/unit-tests/tests/unit-tests_MidiUsb.cpp b/test/unit-tests/tests/unit-tests_MidiUsb.cpp new file mode 100644 index 0000000..1e87233 --- /dev/null +++ b/test/unit-tests/tests/unit-tests_MidiUsb.cpp @@ -0,0 +1,75 @@ +#include "unit-tests.h" +#include + +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 From e4bd7f1c180cc3b045693261b0c4c16ca447cf9d Mon Sep 17 00:00:00 2001 From: Francois Best Date: Thu, 13 Oct 2016 19:01:59 +0200 Subject: [PATCH 089/138] Fix initialization order warnings. --- src/MIDI.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/MIDI.h b/src/MIDI.h index 11f0605..ebedba4 100644 --- a/src/MIDI.h +++ b/src/MIDI.h @@ -230,9 +230,12 @@ private: typedef Message MidiMessage; private: + SerialPort& mSerial; + +private: + Channel mInputChannel; StatusByte mRunningStatus_RX; StatusByte mRunningStatus_TX; - Channel mInputChannel; byte mPendingMessage[3]; unsigned mPendingMessageExpectedLenght; unsigned mPendingMessageIndex; @@ -243,9 +246,6 @@ private: private: inline StatusByte getStatus(MidiType inType, Channel inChannel) const; - -private: - SerialPort& mSerial; }; // ----------------------------------------------------------------------------- From 7317243c36036102172787423dcbc857d7a86b37 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Thu, 13 Oct 2016 19:15:03 +0200 Subject: [PATCH 090/138] Fixed warnings. #55 --- test/unit-tests/tests/unit-tests_MidiInput.cpp | 2 +- test/unit-tests/tests/unit-tests_MidiMessage.cpp | 14 +++++++------- test/unit-tests/tests/unit-tests_MidiOutput.cpp | 4 ++-- test/unit-tests/tests/unit-tests_Settings.cpp | 2 +- test/unit-tests/tests/unit-tests_SysExCodec.cpp | 16 ++++++++-------- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/test/unit-tests/tests/unit-tests_MidiInput.cpp b/test/unit-tests/tests/unit-tests_MidiInput.cpp index 9ff755f..e418579 100644 --- a/test/unit-tests/tests/unit-tests_MidiInput.cpp +++ b/test/unit-tests/tests/unit-tests_MidiInput.cpp @@ -115,7 +115,7 @@ TEST(MidiInput, initMessage) EXPECT_EQ(midi.getChannel(), 0); EXPECT_EQ(midi.getData1(), 0); EXPECT_EQ(midi.getData2(), 0); - EXPECT_EQ(midi.getSysExArrayLength(), 0); + EXPECT_EQ(midi.getSysExArrayLength(), unsigned(0)); EXPECT_EQ(midi.check(), false); } diff --git a/test/unit-tests/tests/unit-tests_MidiMessage.cpp b/test/unit-tests/tests/unit-tests_MidiMessage.cpp index 1fb7272..d03b39d 100644 --- a/test/unit-tests/tests/unit-tests_MidiMessage.cpp +++ b/test/unit-tests/tests/unit-tests_MidiMessage.cpp @@ -24,7 +24,7 @@ TEST(MidiMessage, hasTheRightProperties) EXPECT_EQ(message.data1, 0); EXPECT_EQ(message.data2, 0); EXPECT_EQ(message.valid, false); - EXPECT_EQ(message.getSysExSize(), 0); + EXPECT_EQ(message.getSysExSize(), unsigned(0)); } template @@ -39,7 +39,7 @@ TEST(MidiMessage, getSysExSize) // Small message { typedef midi::Message<32> Message; - ASSERT_EQ(Message::sSysExMaxSize, 32); + ASSERT_EQ(Message::sSysExMaxSize, unsigned(32)); Message message = Message(); const unsigned sizeUnder = 20; @@ -48,12 +48,12 @@ TEST(MidiMessage, getSysExSize) const unsigned sizeOver = 64; setSysExSize(message, sizeOver); - ASSERT_EQ(message.getSysExSize(), 32); + ASSERT_EQ(message.getSysExSize(), unsigned(32)); } // Medium message { typedef midi::Message<256> Message; - ASSERT_EQ(Message::sSysExMaxSize, 256); + ASSERT_EQ(Message::sSysExMaxSize, unsigned(256)); Message message = Message(); const unsigned sizeUnder = 200; @@ -62,12 +62,12 @@ TEST(MidiMessage, getSysExSize) const unsigned sizeOver = 300; setSysExSize(message, sizeOver); - ASSERT_EQ(message.getSysExSize(), 256); + ASSERT_EQ(message.getSysExSize(), unsigned(256)); } // Large message { typedef midi::Message<1024> Message; - ASSERT_EQ(Message::sSysExMaxSize, 1024); + ASSERT_EQ(Message::sSysExMaxSize, unsigned(1024)); Message message = Message(); const unsigned sizeUnder = 1000; @@ -76,7 +76,7 @@ TEST(MidiMessage, getSysExSize) const unsigned sizeOver = 2000; setSysExSize(message, sizeOver); - ASSERT_EQ(message.getSysExSize(), 1024); + ASSERT_EQ(message.getSysExSize(), unsigned(1024)); } } diff --git a/test/unit-tests/tests/unit-tests_MidiOutput.cpp b/test/unit-tests/tests/unit-tests_MidiOutput.cpp index 6f781f7..c1bcd49 100644 --- a/test/unit-tests/tests/unit-tests_MidiOutput.cpp +++ b/test/unit-tests/tests/unit-tests_MidiOutput.cpp @@ -302,7 +302,7 @@ TEST(MidiOutput, sendSysEx) // Small frame { static const char* frame = "Hello, World!"; - static const unsigned frameLength = strlen(frame); + static const int frameLength = strlen(frame); static const byte expected[] = { 0xf0, 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', @@ -321,7 +321,7 @@ TEST(MidiOutput, sendSysEx) // Large frame { static const char* frame = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin maximus dui a massa maximus, a vestibulum mi venenatis. Cras sit amet ex id velit suscipit pharetra eget a turpis. Phasellus interdum metus ac sagittis cursus. Nam quis est at nisl ullamcorper egestas pulvinar eu erat. Duis a elit dignissim, vestibulum eros vel, tempus nisl. Aenean turpis nunc, cursus vel lacinia non, pharetra eget sapien. Duis condimentum, lacus at pulvinar tempor, leo libero volutpat nisl, eget porttitor lorem mi sed magna. Duis dictum, massa vel euismod interdum, lorem mi egestas elit, hendrerit tincidunt est arcu a libero. Interdum et malesuada fames ac ante ipsum primis in faucibus. Curabitur vehicula magna libero, at rhoncus sem ornare a. In elementum, elit et congue pulvinar, massa velit commodo velit, non elementum purus ligula eget lacus. Donec efficitur nisi eu ultrices efficitur. Donec neque dui, ullamcorper id molestie quis, consequat sit amet ligula."; - static const unsigned frameLength = strlen(frame); + static const int frameLength = strlen(frame); static const byte expected[] = { 0xf0, 'L','o','r','e','m',' ','i','p','s','u','m',' ','d','o','l','o','r',' ','s','i','t',' ','a','m','e','t',',',' ', diff --git a/test/unit-tests/tests/unit-tests_Settings.cpp b/test/unit-tests/tests/unit-tests_Settings.cpp index 49a3613..adedf1d 100644 --- a/test/unit-tests/tests/unit-tests_Settings.cpp +++ b/test/unit-tests/tests/unit-tests_Settings.cpp @@ -21,7 +21,7 @@ TEST(Settings, hasTheRightDefaultValues) EXPECT_EQ(midi::DefaultSettings::HandleNullVelocityNoteOnAsNoteOff, true); EXPECT_EQ(midi::DefaultSettings::Use1ByteParsing, true); EXPECT_EQ(midi::DefaultSettings::BaudRate, 31250); - EXPECT_EQ(midi::DefaultSettings::SysExMaxSize, 128); + EXPECT_EQ(midi::DefaultSettings::SysExMaxSize, unsigned(128)); } END_UNNAMED_NAMESPACE diff --git a/test/unit-tests/tests/unit-tests_SysExCodec.cpp b/test/unit-tests/tests/unit-tests_SysExCodec.cpp index ae0ab6d..e1b9428 100644 --- a/test/unit-tests/tests/unit-tests_SysExCodec.cpp +++ b/test/unit-tests/tests/unit-tests_SysExCodec.cpp @@ -19,7 +19,7 @@ TEST(SysExCodec, Encoder) byte buffer[16]; memset(buffer, 0, 16 * sizeof(byte)); const unsigned encodedSize = midi::encodeSysEx(input, buffer, 13); - EXPECT_EQ(encodedSize, 15); + EXPECT_EQ(encodedSize, unsigned(15)); const byte expected[16] = { 0, 'H', 'e', 'l', 'l', 'o', ',', ' ', 0, 'W', 'o', 'r', 'l', 'd', '!', 0, @@ -36,7 +36,7 @@ TEST(SysExCodec, Encoder) byte buffer[16]; memset(buffer, 0, 16 * sizeof(byte)); const unsigned encodedSize = midi::encodeSysEx(input, buffer, 12); - EXPECT_EQ(encodedSize, 14); + EXPECT_EQ(encodedSize, unsigned(14)); const byte expected[16] = { // MSB Data 120, 54, 108, 39, 49, 61, 91, 120, @@ -58,7 +58,7 @@ TEST(SysExCodec, Decoder) byte buffer[16]; memset(buffer, 0, 16 * sizeof(byte)); const unsigned decodedSize = midi::decodeSysEx(input, buffer, 15); - EXPECT_EQ(decodedSize, 13); + EXPECT_EQ(decodedSize, unsigned(13)); const byte expected[16] = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', 0, 0, 0, @@ -76,7 +76,7 @@ TEST(SysExCodec, Decoder) byte buffer[16]; memset(buffer, 0, 16 * sizeof(byte)); const unsigned encodedSize = midi::decodeSysEx(input, buffer, 14); - EXPECT_EQ(encodedSize, 12); + EXPECT_EQ(encodedSize, unsigned(12)); const byte expected[16] = { 182, 236, 167, 177, 61, 91, 120, 107, 94, 209, 87, 94, 0, 0, @@ -97,9 +97,9 @@ TEST(SysExCodec, Codec) memset(buffer1, 0, 16 * sizeof(byte)); memset(buffer2, 0, 16 * sizeof(byte)); const unsigned encodedSize = midi::encodeSysEx(input, buffer1, 13); - EXPECT_EQ(encodedSize, 15); + EXPECT_EQ(encodedSize, unsigned(15)); const unsigned decodedSize = midi::decodeSysEx(buffer1, buffer2, encodedSize); - EXPECT_EQ(decodedSize, 13); + EXPECT_EQ(decodedSize, unsigned(13)); EXPECT_STREQ(reinterpret_cast(buffer2), reinterpret_cast(input)); } @@ -115,9 +115,9 @@ TEST(SysExCodec, Codec) memset(buffer1, 0, 14 * sizeof(byte)); memset(buffer2, 0, 12 * sizeof(byte)); const unsigned encodedSize = midi::encodeSysEx(input, buffer1, 12); - EXPECT_EQ(encodedSize, 14); + EXPECT_EQ(encodedSize, unsigned(14)); const unsigned decodedSize = midi::decodeSysEx(buffer1, buffer2, encodedSize); - EXPECT_EQ(decodedSize, 12); + EXPECT_EQ(decodedSize, unsigned(12)); EXPECT_THAT(buffer2, ContainerEq(input)); } } From 338eea10ab1c21488db9175db07fa7489eba5db0 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Thu, 13 Oct 2016 19:35:01 +0200 Subject: [PATCH 091/138] Reworked packaging script. --- res/packaging.command | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/res/packaging.command b/res/packaging.command index 00fdfb8..c58731c 100755 --- a/res/packaging.command +++ b/res/packaging.command @@ -10,26 +10,26 @@ cd "`dirname "${0}"`" root="${PWD}/.." -build="$root/build/MIDI" +build="$root/build/dist/MIDI" echo "root: $root" echo "build: $build" -# Create a temporary destination folder -mkdir -p "$build" +# Create a destination directory structure mkdir -p "$build/examples" +mkdir -p "$build/src" # Copy sources -cd "$root/src/" -cp * "$build/" +cp -rf "$root/src" "$build" # Copy resources -cd "$root/res/" -cp keywords.txt "$build/" +cp -f "$root/keywords.txt" "$build/" +cp -f "$root/library.properties" "$build/" +cp -f "$root/library.json" "$build/" +cp -f "$root/LICENSE" "$build/" # Copy examples -cd "$root/res/examples/" -cp -r * "$build/examples" +cp -rf "$root/examples" "$build" # Generate package cd "$build/.." From 21a8cdea89165ec76cb6e8bfc297251b3591bf10 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Thu, 13 Oct 2016 19:35:19 +0200 Subject: [PATCH 092/138] Updated syntax highlighting file. --- keywords.txt | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 78 insertions(+), 3 deletions(-) diff --git a/keywords.txt b/keywords.txt index d415b4d..330c77c 100644 --- a/keywords.txt +++ b/keywords.txt @@ -29,6 +29,16 @@ sendSongPosition KEYWORD2 sendSongSelect KEYWORD2 sendTuneRequest KEYWORD2 sendRealTime KEYWORD2 +beginRpn KEYWORD2 +sendRpnValue KEYWORD2 +sendRpnIncrement KEYWORD2 +sendRpnDecrement KEYWORD2 +endRpn KEYWORD2 +beginNrpn KEYWORD2 +sendNrpnValue KEYWORD2 +sendNrpnIncrement KEYWORD2 +sendNrpnDecrement KEYWORD2 +endNrpn KEYWORD2 begin KEYWORD2 read KEYWORD2 getType KEYWORD2 @@ -36,14 +46,12 @@ getChannel KEYWORD2 getData1 KEYWORD2 getData2 KEYWORD2 getSysExArray KEYWORD2 +getSysExArrayLength KEYWORD2 getFilterMode KEYWORD2 getThruState KEYWORD2 getInputChannel KEYWORD2 check KEYWORD2 -delMsg KEYWORD2 -delSysEx KEYWORD2 setInputChannel KEYWORD2 -setStatus KEYWORD2 turnThruOn KEYWORD2 turnThruOff KEYWORD2 setThruFilterMode KEYWORD2 @@ -67,6 +75,8 @@ setHandleStop KEYWORD2 setHandleActiveSensing KEYWORD2 setHandleSystemReset KEYWORD2 getTypeFromStatusByte KEYWORD2 +getChannelFromStatusByte KEYWORD2 +isChannelMessage KEYWORD2 encodeSysEx KEYWORD2 decodeSysEx KEYWORD2 @@ -110,3 +120,68 @@ MIDI_CHANNEL_OFF LITERAL1 MIDI_CREATE_INSTANCE LITERAL1 MIDI_CREATE_DEFAULT_INSTANCE LITERAL1 MIDI_CREATE_CUSTOM_INSTANCE LITERAL1 +RPN LITERAL1 +BankSelect LITERAL1 +ModulationWheel LITERAL1 +BreathController LITERAL1 +FootController LITERAL1 +PortamentoTime LITERAL1 +DataEntryMSB LITERAL1 +ChannelVolume LITERAL1 +Balance LITERAL1 +Pan LITERAL1 +ExpressionController LITERAL1 +EffectControl1 LITERAL1 +EffectControl2 LITERAL1 +GeneralPurposeController1 LITERAL1 +GeneralPurposeController2 LITERAL1 +GeneralPurposeController3 LITERAL1 +GeneralPurposeController4 LITERAL1 +DataEntryLSB LITERAL1 +Sustain LITERAL1 +Portamento LITERAL1 +Sostenuto LITERAL1 +SoftPedal LITERAL1 +Legato LITERAL1 +Hold LITERAL1 +SoundController1 LITERAL1 +SoundController2 LITERAL1 +SoundController3 LITERAL1 +SoundController4 LITERAL1 +SoundController5 LITERAL1 +SoundController6 LITERAL1 +SoundController7 LITERAL1 +SoundController8 LITERAL1 +SoundController9 LITERAL1 +SoundController10 LITERAL1 +GeneralPurposeController5 LITERAL1 +GeneralPurposeController6 LITERAL1 +GeneralPurposeController7 LITERAL1 +GeneralPurposeController8 LITERAL1 +PortamentoControl LITERAL1 +Effects1 LITERAL1 +Effects2 LITERAL1 +Effects3 LITERAL1 +Effects4 LITERAL1 +Effects5 LITERAL1 +DataIncrement LITERAL1 +DataDecrement LITERAL1 +NRPNLSB LITERAL1 +NRPNMSB LITERAL1 +RPNLSB LITERAL1 +RPNMSB LITERAL1 +AllSoundOff LITERAL1 +ResetAllControllers LITERAL1 +LocalControl LITERAL1 +AllNotesOff LITERAL1 +OmniModeOff LITERAL1 +OmniModeOn LITERAL1 +MonoModeOn LITERAL1 +PolyModeOn LITERAL1 +PitchBendSensitivity LITERAL1 +ChannelFineTuning LITERAL1 +ChannelCoarseTuning LITERAL1 +SelectTuningProgram LITERAL1 +SelectTuningBank LITERAL1 +ModulationDepthRange LITERAL1 +NullFunction LITERAL1 From a2677c3a3386488a2eb590ac7be8df01d9021328 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Thu, 13 Oct 2016 20:02:52 +0200 Subject: [PATCH 093/138] Set badge cache TTL to 1 hour. --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0670245..f13050d 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # 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=2592000)](https://coveralls.io/github/FortySevenEffects/arduino_midi_library) -[![GitHub release](https://img.shields.io/github/release/FortySevenEffects/arduino_midi_library.svg?maxAge=2592000)](https://github.com/FortySevenEffects/arduino_midi_library/releases/latest) -[![License](https://img.shields.io/github/license/FortySevenEffects/arduino_midi_library.svg?maxAge=2592000)](LICENSE) +[![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) This library enables MIDI I/O communications on the Arduino serial ports. The purpose of this library is not to make a big synthesizer out of an Arduino board, the application remains yours. However, it will help you interfacing it with other MIDI devices. From 8badd2bbfaf012e443e41026f83c6aa186ece626 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Sat, 15 Oct 2016 10:53:55 +0200 Subject: [PATCH 094/138] Moved variable settings to separate file. --- test/unit-tests/CMakeLists.txt | 1 + test/unit-tests/tests/unit-tests_Settings.h | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 test/unit-tests/tests/unit-tests_Settings.h diff --git a/test/unit-tests/CMakeLists.txt b/test/unit-tests/CMakeLists.txt index 65162d8..e99276a 100644 --- a/test/unit-tests/CMakeLists.txt +++ b/test/unit-tests/CMakeLists.txt @@ -16,6 +16,7 @@ add_executable(unit-tests tests/unit-tests_MidiMessage.cpp 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 diff --git a/test/unit-tests/tests/unit-tests_Settings.h b/test/unit-tests/tests/unit-tests_Settings.h new file mode 100644 index 0000000..66a4bdc --- /dev/null +++ b/test/unit-tests/tests/unit-tests_Settings.h @@ -0,0 +1,20 @@ +#pragma once + +#include "unit-tests.h" +#include + +BEGIN_UNIT_TESTS_NAMESPACE + +template +struct VariableSettings : public midi::DefaultSettings +{ + static const bool UseRunningStatus = RunningStatus; + static const bool Use1ByteParsing = OneByteParsing; +}; + +template +const bool VariableSettings::UseRunningStatus; +template +const bool VariableSettings::Use1ByteParsing; + +END_UNIT_TESTS_NAMESPACE From 58e1ea2a65be009fddd2ef613c9ac581daa88cc0 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Sat, 15 Oct 2016 10:54:15 +0200 Subject: [PATCH 095/138] Added peek method for Ring Buffer. --- test/mocks/test-mocks_SerialMock.h | 1 + test/mocks/test-mocks_SerialMock.hpp | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/test/mocks/test-mocks_SerialMock.h b/test/mocks/test-mocks_SerialMock.h index a934d2f..028205d 100644 --- a/test/mocks/test-mocks_SerialMock.h +++ b/test/mocks/test-mocks_SerialMock.h @@ -22,6 +22,7 @@ public: void clear(); public: + DataType peek() const; DataType read(); void read(DataType* outData, int inSize); diff --git a/test/mocks/test-mocks_SerialMock.hpp b/test/mocks/test-mocks_SerialMock.hpp index 7855121..c0181b2 100644 --- a/test/mocks/test-mocks_SerialMock.hpp +++ b/test/mocks/test-mocks_SerialMock.hpp @@ -71,6 +71,12 @@ void RingBuffer::clear() // ----------------------------------------------------------------------------- +template +DataType RingBuffer::peek() const +{ + return *mReadHead; +} + template DataType RingBuffer::read() { From 4cebcbf915f52903df1fb1e214317207d7e2c155 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Sat, 15 Oct 2016 10:54:49 +0200 Subject: [PATCH 096/138] Added MIDI Input tests. --- .../unit-tests/tests/unit-tests_MidiInput.cpp | 272 ++++++++++++++++++ .../tests/unit-tests_MidiOutput.cpp | 19 +- test/unit-tests/tests/unit-tests_Settings.cpp | 3 +- 3 files changed, 278 insertions(+), 16 deletions(-) diff --git a/test/unit-tests/tests/unit-tests_MidiInput.cpp b/test/unit-tests/tests/unit-tests_MidiInput.cpp index e418579..18f07c8 100644 --- a/test/unit-tests/tests/unit-tests_MidiInput.cpp +++ b/test/unit-tests/tests/unit-tests_MidiInput.cpp @@ -1,4 +1,5 @@ #include "unit-tests.h" +#include "unit-tests_Settings.h" #include #include @@ -10,9 +11,17 @@ END_MIDI_NAMESPACE BEGIN_UNNAMED_NAMESPACE +using namespace testing; +USING_NAMESPACE_UNIT_TESTS typedef test_mocks::SerialMock<32> SerialMock; typedef midi::MidiInterface MidiInterface; +template +struct VariableSysExSettings : midi::DefaultSettings +{ + static const unsigned SysExMaxSize = Size; +}; + TEST(MidiInput, getTypeFromStatusByte) { // Channel Messages @@ -119,4 +128,267 @@ TEST(MidiInput, initMessage) EXPECT_EQ(midi.check(), false); } +TEST(MidiInput, channelFiltering) +{ + SerialMock serial; + MidiInterface midi(serial); + static const unsigned rxSize = 3; + static const byte rxData[rxSize] = { 0x9b, 12, 34 }; + midi.begin(4); // Mistmatching channel + serial.mRxBuffer.write(rxData, rxSize); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); +} + +TEST(MidiInput, noRxData) +{ + SerialMock serial; + MidiInterface midi(serial); + midi.begin(); + EXPECT_EQ(midi.read(), false); +} + +TEST(MidiInput, multiByteParsing) +{ + typedef VariableSettings Settings; + typedef midi::MidiInterface MidiInterface; + + SerialMock serial; + MidiInterface midi(serial); + static const unsigned rxSize = 3; + static const byte rxData[rxSize] = { 0x9b, 12, 34 }; + midi.begin(12); + serial.mRxBuffer.write(rxData, rxSize); + EXPECT_EQ(midi.read(), true); +} + +TEST(MidiInput, noteOn) +{ + SerialMock serial; + MidiInterface midi(serial); + static const unsigned rxSize = 10; + static const byte rxData[rxSize] = { + 0x9b, 12, 34, + 0x9b, 56, 78, + 12, 34, // Running status + 56, 0 // NoteOn with null velocity interpreted as NoteOff + }; + midi.begin(12); + serial.mRxBuffer.write(rxData, rxSize); + + // 1 byte parsing + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + + // First NoteOn + EXPECT_EQ(midi.getType(), midi::NoteOn); + EXPECT_EQ(midi.getChannel(), 12); + EXPECT_EQ(midi.getData1(), 12); + EXPECT_EQ(midi.getData2(), 34); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + + EXPECT_EQ(midi.getType(), midi::NoteOn); + EXPECT_EQ(midi.getChannel(), 12); + EXPECT_EQ(midi.getData1(), 56); + EXPECT_EQ(midi.getData2(), 78); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + + EXPECT_EQ(midi.getType(), midi::NoteOn); + EXPECT_EQ(midi.getChannel(), 12); + EXPECT_EQ(midi.getData1(), 12); + EXPECT_EQ(midi.getData2(), 34); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + + EXPECT_EQ(midi.getType(), midi::NoteOff); + EXPECT_EQ(midi.getChannel(), 12); + EXPECT_EQ(midi.getData1(), 56); + EXPECT_EQ(midi.getData2(), 0); +} + +TEST(MidiInput, noteOff) +{ + SerialMock serial; + MidiInterface midi(serial); + static const unsigned rxSize = 8; + static const byte rxData[rxSize] = { + 0x8b, 12, 34, + 0x8b, 56, 78, + 12, 34, // Running status + }; + midi.begin(12); + serial.mRxBuffer.write(rxData, rxSize); + + // 1 byte parsing + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + + // First NoteOn + EXPECT_EQ(midi.getType(), midi::NoteOff); + EXPECT_EQ(midi.getChannel(), 12); + EXPECT_EQ(midi.getData1(), 12); + EXPECT_EQ(midi.getData2(), 34); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + + EXPECT_EQ(midi.getType(), midi::NoteOff); + EXPECT_EQ(midi.getChannel(), 12); + EXPECT_EQ(midi.getData1(), 56); + EXPECT_EQ(midi.getData2(), 78); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + + EXPECT_EQ(midi.getType(), midi::NoteOff); + EXPECT_EQ(midi.getChannel(), 12); + EXPECT_EQ(midi.getData1(), 12); + EXPECT_EQ(midi.getData2(), 34); +} + +TEST(MidiInput, programChange) +{ + +} + +TEST(MidiInput, controlChange) +{ + +} + +TEST(MidiInput, pitchBend) +{ + +} + +TEST(MidiInput, polyPressure) +{ + +} + +TEST(MidiInput, afterTouch) +{ + +} + +TEST(MidiInput, sysExWithinBufferSize) +{ + typedef VariableSysExSettings<1024> Settings; + typedef test_mocks::SerialMock<2048> SerialMock; + typedef midi::MidiInterface MidiInterface; + + SerialMock serial; + MidiInterface midi(serial); + + // Short Frame < 256 + { + static const unsigned frameLength = 15; + static const byte frame[frameLength] = { + 0xf0, 'H','e','l','l','o',',',' ','W','o','r','l','d','!', 0xf7 + }; + + midi.begin(); + serial.mRxBuffer.write(frame, frameLength); + for (unsigned i = 0; i < frameLength - 1; ++i) + { + EXPECT_EQ(midi.read(), false); + } + EXPECT_EQ(midi.read(), true); // 0xf7 + + EXPECT_EQ(midi.getSysExArrayLength(), frameLength); + const std::vector sysExData(midi.getSysExArray(), + midi.getSysExArray() + frameLength); + EXPECT_THAT(sysExData, ElementsAreArray(frame)); + } + // Long Frame + { + static const unsigned frameLength = 957; + static const byte frame[frameLength] = { + 0xf0, + 'L','o','r','e','m',' ','i','p','s','u','m',' ','d','o','l','o','r',' ','s','i','t',' ','a','m','e','t',',',' ', + 'c','o','n','s','e','c','t','e','t','u','r',' ','a','d','i','p','i','s','c','i','n','g',' ','e','l','i','t','.',' ','P','r','o','i','n',' ','m','a','x','i','m','u','s',' ','d','u','i',' ','a',' ','m','a','s','s','a',' ','m','a','x','i','m','u','s',',',' ', + 'a',' ','v','e','s','t','i','b','u','l','u','m',' ','m','i',' ','v','e','n','e','n','a','t','i','s','.',' ','C','r','a','s',' ','s','i','t',' ','a','m','e','t',' ','e','x',' ','i','d',' ','v','e','l','i','t',' ','s','u','s','c','i','p','i','t',' ','p','h','a','r','e','t','r','a',' ','e','g','e','t', ' ','a',' ','t','u','r','p','i','s','.',' ','P','h','a','s','e','l','l','u','s',' ','i','n','t','e','r','d','u','m',' ','m','e','t','u','s',' ','a','c',' ','s','a','g','i','t','t','i','s',' ','c','u','r','s','u','s','.',' ','N','a','m',' ','q','u','i','s',' ','e','s','t',' ','a','t',' ','n','i','s', 'l',' ','u','l','l','a','m','c','o','r','p','e','r',' ','e','g','e','s','t','a','s',' ','p','u','l','v','i','n','a','r',' ','e','u',' ','e','r','a','t','.',' ','D','u','i','s',' ','a',' ','e','l','i','t',' ','d','i','g','n','i','s','s','i','m',',',' ', + 'v','e','s','t','i','b','u','l','u','m',' ','e','r','o','s',' ','v','e','l',',',' ', + 't','e','m','p','u','s',' ','n','i','s','l','.',' ','A','e','n','e','a','n',' ','t','u','r','p','i','s',' ','n','u','n','c',',',' ', + 'c','u','r','s','u','s',' ','v','e','l',' ','l','a','c','i','n','i','a',' ','n','o','n',',',' ', + 'p','h','a','r','e','t','r','a',' ','e','g','e','t',' ','s','a','p','i','e','n','.',' ','D','u','i','s',' ','c','o','n','d','i','m','e','n','t','u','m',',',' ', + 'l','a','c','u','s',' ','a','t',' ','p','u','l','v','i','n','a','r',' ','t','e','m','p','o','r',',',' ', + 'l','e','o',' ','l','i','b','e','r','o',' ','v','o','l','u','t','p','a','t',' ','n','i','s','l',',',' ', + 'e','g','e','t',' ','p','o','r','t','t','i','t','o','r',' ','l','o','r','e','m',' ','m','i',' ','s','e','d',' ','m','a','g','n','a','.',' ','D','u','i','s',' ','d','i','c','t','u','m',',',' ', + 'm','a','s','s','a',' ','v','e','l',' ','e','u','i','s','m','o','d',' ','i','n','t','e','r','d','u','m',',',' ', + 'l','o','r','e','m',' ','m','i',' ','e','g','e','s','t','a','s',' ','e','l','i','t',',',' ', + 'h','e','n','d','r','e','r','i','t',' ','t','i','n','c','i','d','u','n','t',' ','e','s','t',' ','a','r','c','u',' ','a',' ','l','i','b','e','r','o','.',' ','I','n','t','e','r','d','u','m',' ','e','t',' ','m','a','l','e','s','u','a','d','a',' ','f','a','m','e','s',' ','a','c',' ','a','n','t','e',' ', 'i','p','s','u','m',' ','p','r','i','m','i','s',' ','i','n',' ','f','a','u','c','i','b','u','s','.',' ','C','u','r','a','b','i','t','u','r',' ','v','e','h','i','c','u','l','a',' ','m','a','g','n','a',' ','l','i','b','e','r','o',',',' ', + 'a','t',' ','r','h','o','n','c','u','s',' ','s','e','m',' ','o','r','n','a','r','e',' ','a','.',' ','I','n',' ','e','l','e','m','e','n','t','u','m',',',' ', + 'e','l','i','t',' ','e','t',' ','c','o','n','g','u','e',' ','p','u','l','v','i','n','a','r',',',' ', + 'm','a','s','s','a',' ','v','e','l','i','t',' ','c','o','m','m','o','d','o',' ','v','e','l','i','t',',',' ', + 'n','o','n',' ','e','l','e','m','e','n','t','u','m',' ','p','u','r','u','s',' ','l','i','g','u','l','a',' ','e','g','e','t',' ','l','a','c','u','s','.',' ','D','o','n','e','c',' ','e','f','f','i','c','i','t','u','r',' ','n','i','s','i',' ','e','u',' ','u','l','t','r','i','c','e','s',' ','e','f','f', 'i','c','i','t','u','r','.',' ','D','o','n','e','c',' ','n','e','q','u','e',' ','d','u','i',',',' ', + 'u','l','l','a','m','c','o','r','p','e','r',' ','i','d',' ','m','o','l','e','s','t','i','e',' ','q','u','i','s',',',' ', + 'c','o','n','s','e','q','u','a','t',' ','s','i','t',' ','a','m','e','t',' ','l','i','g','u','l','a','.', + 0xf7, + }; + midi.begin(); + serial.mRxBuffer.write(frame, frameLength); + for (unsigned i = 0; i < frameLength - 1; ++i) + { + EXPECT_EQ(midi.read(), false); + } + EXPECT_EQ(serial.mRxBuffer.getLength(), 1); + EXPECT_EQ(serial.mRxBuffer.peek(), 0xf7); + EXPECT_EQ(midi.read(), true); + } +} + +TEST(MidiInput, sysExOverBufferSize) +{ + typedef VariableSysExSettings<8> Settings; + typedef midi::MidiInterface MidiInterface; + + SerialMock serial; + MidiInterface midi(serial); + + static const unsigned frameLength = 15; + static const byte frame[frameLength] = { + 0xf0, 'H','e','l','l','o',',',' ','W','o','r','l','d','!', 0xf7 + }; + + 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); +} + +TEST(MidiInput, mtcQuarterFrame) +{ + +} + +TEST(MidiInput, songPosition) +{ + +} + +TEST(MidiInput, songSelect) +{ + +} + +TEST(MidiInput, realTime) +{ + +} + END_UNNAMED_NAMESPACE diff --git a/test/unit-tests/tests/unit-tests_MidiOutput.cpp b/test/unit-tests/tests/unit-tests_MidiOutput.cpp index c1bcd49..e2ad984 100644 --- a/test/unit-tests/tests/unit-tests_MidiOutput.cpp +++ b/test/unit-tests/tests/unit-tests_MidiOutput.cpp @@ -1,4 +1,5 @@ #include "unit-tests.h" +#include "unit-tests_Settings.h" #include #include @@ -10,19 +11,9 @@ END_MIDI_NAMESPACE BEGIN_UNNAMED_NAMESPACE -template -struct VariableSettings : public midi::DefaultSettings -{ - static const bool UseRunningStatus = RunningStatus; - static const bool Use1ByteParsing = OneByteParsing; -}; - -template -const bool VariableSettings::UseRunningStatus; -template -const bool VariableSettings::Use1ByteParsing; - using namespace testing; +USING_NAMESPACE_UNIT_TESTS; + typedef test_mocks::SerialMock<32> SerialMock; typedef midi::MidiInterface MidiInterface; @@ -299,7 +290,7 @@ TEST(MidiOutput, sendSysEx) MidiInterface midi(serial); Buffer buffer; - // Small frame + // Short frame { static const char* frame = "Hello, World!"; static const int frameLength = strlen(frame); @@ -318,7 +309,7 @@ TEST(MidiOutput, sendSysEx) serial.mTxBuffer.read(&buffer[0], frameLength + 2); EXPECT_THAT(buffer, ElementsAreArray(expected)); } - // Large frame + // Long frame { static const char* frame = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin maximus dui a massa maximus, a vestibulum mi venenatis. Cras sit amet ex id velit suscipit pharetra eget a turpis. Phasellus interdum metus ac sagittis cursus. Nam quis est at nisl ullamcorper egestas pulvinar eu erat. Duis a elit dignissim, vestibulum eros vel, tempus nisl. Aenean turpis nunc, cursus vel lacinia non, pharetra eget sapien. Duis condimentum, lacus at pulvinar tempor, leo libero volutpat nisl, eget porttitor lorem mi sed magna. Duis dictum, massa vel euismod interdum, lorem mi egestas elit, hendrerit tincidunt est arcu a libero. Interdum et malesuada fames ac ante ipsum primis in faucibus. Curabitur vehicula magna libero, at rhoncus sem ornare a. In elementum, elit et congue pulvinar, massa velit commodo velit, non elementum purus ligula eget lacus. Donec efficitur nisi eu ultrices efficitur. Donec neque dui, ullamcorper id molestie quis, consequat sit amet ligula."; static const int frameLength = strlen(frame); diff --git a/test/unit-tests/tests/unit-tests_Settings.cpp b/test/unit-tests/tests/unit-tests_Settings.cpp index adedf1d..620a69c 100644 --- a/test/unit-tests/tests/unit-tests_Settings.cpp +++ b/test/unit-tests/tests/unit-tests_Settings.cpp @@ -1,5 +1,4 @@ -#include "unit-tests.h" -#include +#include "unit-tests_Settings.h" BEGIN_MIDI_NAMESPACE From 208a79e5f0c79c7d1ab7ad19c2e2b68ac27ad01f Mon Sep 17 00:00:00 2001 From: Francois Best Date: Sat, 15 Oct 2016 11:59:35 +0200 Subject: [PATCH 097/138] Moar tests. --- .../unit-tests/tests/unit-tests_MidiInput.cpp | 348 +++++++++++++++++- 1 file changed, 346 insertions(+), 2 deletions(-) diff --git a/test/unit-tests/tests/unit-tests_MidiInput.cpp b/test/unit-tests/tests/unit-tests_MidiInput.cpp index 18f07c8..172008f 100644 --- a/test/unit-tests/tests/unit-tests_MidiInput.cpp +++ b/test/unit-tests/tests/unit-tests_MidiInput.cpp @@ -149,6 +149,19 @@ TEST(MidiInput, noRxData) EXPECT_EQ(midi.read(), false); } +TEST(MidiInput, inputDisabled) +{ + SerialMock serial; + MidiInterface midi(serial); + static const unsigned rxSize = 3; + static const byte rxData[rxSize] = { 0x9b, 12, 34 }; + midi.begin(MIDI_CHANNEL_OFF); // Invalid channel + serial.mRxBuffer.write(rxData, rxSize); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); +} + TEST(MidiInput, multiByteParsing) { typedef VariableSettings Settings; @@ -258,27 +271,216 @@ TEST(MidiInput, noteOff) TEST(MidiInput, programChange) { + SerialMock serial; + MidiInterface midi(serial); + static const unsigned rxSize = 6; + static const byte rxData[rxSize] = { + 0xc3, 12, 34, + 0xc4, 56, 78 + }; + midi.begin(MIDI_CHANNEL_OMNI); + serial.mRxBuffer.write(rxData, rxSize); + // 1 byte parsing + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + + EXPECT_EQ(midi.getType(), midi::ProgramChange); + EXPECT_EQ(midi.getChannel(), 4); + EXPECT_EQ(midi.getData1(), 12); + EXPECT_EQ(midi.getData2(), 0); + + EXPECT_EQ(midi.read(), true); + + EXPECT_EQ(midi.getType(), midi::ProgramChange); + EXPECT_EQ(midi.getChannel(), 4); + EXPECT_EQ(midi.getData1(), 34); + EXPECT_EQ(midi.getData2(), 0); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + + EXPECT_EQ(midi.getType(), midi::ProgramChange); + EXPECT_EQ(midi.getChannel(), 5); + EXPECT_EQ(midi.getData1(), 56); + EXPECT_EQ(midi.getData2(), 0); + + EXPECT_EQ(midi.read(), true); + + EXPECT_EQ(midi.getType(), midi::ProgramChange); + EXPECT_EQ(midi.getChannel(), 5); + EXPECT_EQ(midi.getData1(), 78); + EXPECT_EQ(midi.getData2(), 0); } TEST(MidiInput, controlChange) { + SerialMock serial; + MidiInterface midi(serial); + static const unsigned rxSize = 8; + static const byte rxData[rxSize] = { + 0xbb, 12, 34, + 0xbb, 56, 78, + 12, 34 + }; + midi.begin(12); + serial.mRxBuffer.write(rxData, rxSize); + // 1 byte parsing + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + + // First NoteOn + EXPECT_EQ(midi.getType(), midi::ControlChange); + EXPECT_EQ(midi.getChannel(), 12); + EXPECT_EQ(midi.getData1(), 12); + EXPECT_EQ(midi.getData2(), 34); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + + EXPECT_EQ(midi.getType(), midi::ControlChange); + EXPECT_EQ(midi.getChannel(), 12); + EXPECT_EQ(midi.getData1(), 56); + EXPECT_EQ(midi.getData2(), 78); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + + EXPECT_EQ(midi.getType(), midi::ControlChange); + EXPECT_EQ(midi.getChannel(), 12); + EXPECT_EQ(midi.getData1(), 12); + EXPECT_EQ(midi.getData2(), 34); } TEST(MidiInput, pitchBend) { + SerialMock serial; + MidiInterface midi(serial); + static const unsigned rxSize = 8; + static const byte rxData[rxSize] = { + 0xeb, 12, 34, + 0xeb, 56, 78, + 12, 34 + }; + midi.begin(12); + serial.mRxBuffer.write(rxData, rxSize); + // 1 byte parsing + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + + // First NoteOn + EXPECT_EQ(midi.getType(), midi::PitchBend); + EXPECT_EQ(midi.getChannel(), 12); + EXPECT_EQ(midi.getData1(), 12); + EXPECT_EQ(midi.getData2(), 34); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + + EXPECT_EQ(midi.getType(), midi::PitchBend); + EXPECT_EQ(midi.getChannel(), 12); + EXPECT_EQ(midi.getData1(), 56); + EXPECT_EQ(midi.getData2(), 78); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + + EXPECT_EQ(midi.getType(), midi::PitchBend); + EXPECT_EQ(midi.getChannel(), 12); + EXPECT_EQ(midi.getData1(), 12); + EXPECT_EQ(midi.getData2(), 34); } -TEST(MidiInput, polyPressure) +TEST(MidiInput, afterTouchPoly) { + SerialMock serial; + MidiInterface midi(serial); + static const unsigned rxSize = 8; + static const byte rxData[rxSize] = { + 0xab, 12, 34, + 0xab, 56, 78, + 12, 34 + }; + midi.begin(12); + serial.mRxBuffer.write(rxData, rxSize); + // 1 byte parsing + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + + // First NoteOn + EXPECT_EQ(midi.getType(), midi::AfterTouchPoly); + EXPECT_EQ(midi.getChannel(), 12); + EXPECT_EQ(midi.getData1(), 12); + EXPECT_EQ(midi.getData2(), 34); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + + EXPECT_EQ(midi.getType(), midi::AfterTouchPoly); + EXPECT_EQ(midi.getChannel(), 12); + EXPECT_EQ(midi.getData1(), 56); + EXPECT_EQ(midi.getData2(), 78); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + + EXPECT_EQ(midi.getType(), midi::AfterTouchPoly); + EXPECT_EQ(midi.getChannel(), 12); + EXPECT_EQ(midi.getData1(), 12); + EXPECT_EQ(midi.getData2(), 34); } -TEST(MidiInput, afterTouch) +TEST(MidiInput, afterTouchChannel) { + SerialMock serial; + MidiInterface midi(serial); + static const unsigned rxSize = 6; + static const byte rxData[rxSize] = { + 0xd3, 12, 34, + 0xd4, 56, 78 + }; + midi.begin(MIDI_CHANNEL_OMNI); + serial.mRxBuffer.write(rxData, rxSize); + // 1 byte parsing + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + + EXPECT_EQ(midi.getType(), midi::AfterTouchChannel); + EXPECT_EQ(midi.getChannel(), 4); + EXPECT_EQ(midi.getData1(), 12); + EXPECT_EQ(midi.getData2(), 0); + + EXPECT_EQ(midi.read(), true); + + EXPECT_EQ(midi.getType(), midi::AfterTouchChannel); + EXPECT_EQ(midi.getChannel(), 4); + EXPECT_EQ(midi.getData1(), 34); + EXPECT_EQ(midi.getData2(), 0); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + + EXPECT_EQ(midi.getType(), midi::AfterTouchChannel); + EXPECT_EQ(midi.getChannel(), 5); + EXPECT_EQ(midi.getData1(), 56); + EXPECT_EQ(midi.getData2(), 0); + + EXPECT_EQ(midi.read(), true); + + EXPECT_EQ(midi.getType(), midi::AfterTouchChannel); + EXPECT_EQ(midi.getChannel(), 5); + EXPECT_EQ(midi.getData1(), 78); + EXPECT_EQ(midi.getData2(), 0); } TEST(MidiInput, sysExWithinBufferSize) @@ -373,22 +575,164 @@ TEST(MidiInput, sysExOverBufferSize) TEST(MidiInput, mtcQuarterFrame) { + SerialMock serial; + MidiInterface midi(serial); + static const unsigned rxSize = 4; + static const byte rxData[rxSize] = { + 0xf1, 12, + 0xf1, 42 + }; + midi.begin(12); + serial.mRxBuffer.write(rxData, rxSize); + // 1 byte parsing + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + + EXPECT_EQ(midi.getType(), midi::TimeCodeQuarterFrame); + EXPECT_EQ(midi.getChannel(), 0); + EXPECT_EQ(midi.getData1(), 12); + EXPECT_EQ(midi.getData2(), 0); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + + EXPECT_EQ(midi.getType(), midi::TimeCodeQuarterFrame); + EXPECT_EQ(midi.getChannel(), 0); + EXPECT_EQ(midi.getData1(), 42); + EXPECT_EQ(midi.getData2(), 0); } TEST(MidiInput, songPosition) { + SerialMock serial; + MidiInterface midi(serial); + static const unsigned rxSize = 6; + static const byte rxData[rxSize] = { + 0xf2, 12, 34, + 0xf2, 56, 78 + }; + midi.begin(12); + serial.mRxBuffer.write(rxData, rxSize); + // 1 byte parsing + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + + EXPECT_EQ(midi.getType(), midi::SongPosition); + EXPECT_EQ(midi.getChannel(), 0); + EXPECT_EQ(midi.getData1(), 12); + EXPECT_EQ(midi.getData2(), 34); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + + EXPECT_EQ(midi.getType(), midi::SongPosition); + EXPECT_EQ(midi.getChannel(), 0); + EXPECT_EQ(midi.getData1(), 56); + EXPECT_EQ(midi.getData2(), 78); } TEST(MidiInput, songSelect) { + SerialMock serial; + MidiInterface midi(serial); + static const unsigned rxSize = 4; + static const byte rxData[rxSize] = { + 0xf3, 12, + 0xf3, 42 + }; + midi.begin(12); + serial.mRxBuffer.write(rxData, rxSize); + // 1 byte parsing + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + + EXPECT_EQ(midi.getType(), midi::SongSelect); + EXPECT_EQ(midi.getChannel(), 0); + EXPECT_EQ(midi.getData1(), 12); + EXPECT_EQ(midi.getData2(), 0); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + + EXPECT_EQ(midi.getType(), midi::SongSelect); + EXPECT_EQ(midi.getChannel(), 0); + EXPECT_EQ(midi.getData1(), 42); + EXPECT_EQ(midi.getData2(), 0); +} + +TEST(MidiInput, tuneRequest) +{ + SerialMock serial; + MidiInterface midi(serial); + static const unsigned rxSize = 1; + static const byte rxData[rxSize] = { + 0xf6 + }; + midi.begin(12); + serial.mRxBuffer.write(rxData, rxSize); + + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(midi.getType(), midi::TuneRequest); + EXPECT_EQ(midi.getChannel(), 0); + EXPECT_EQ(midi.getData1(), 0); + EXPECT_EQ(midi.getData2(), 0); } TEST(MidiInput, realTime) { + SerialMock serial; + MidiInterface midi(serial); + static const unsigned rxSize = 8; + static const byte rxData[rxSize] = { + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff + }; + midi.begin(12); + serial.mRxBuffer.write(rxData, rxSize); + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(midi.getType(), midi::Clock); + EXPECT_EQ(midi.getChannel(), 0); + 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::Start); + 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::Continue); + 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::Stop); + EXPECT_EQ(midi.getChannel(), 0); + EXPECT_EQ(midi.getData1(), 0); + EXPECT_EQ(midi.getData2(), 0); + + EXPECT_EQ(midi.read(), false); // 0xfd = undefined + + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(midi.getType(), midi::ActiveSensing); + 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::SystemReset); + EXPECT_EQ(midi.getChannel(), 0); + EXPECT_EQ(midi.getData1(), 0); + EXPECT_EQ(midi.getData2(), 0); } END_UNNAMED_NAMESPACE From 5f7fa5d08351fc35a4f6bdd89340112c77cf30ab Mon Sep 17 00:00:00 2001 From: Francois Best Date: Sat, 15 Oct 2016 13:41:50 +0200 Subject: [PATCH 098/138] Fix #58. --- src/MIDI.hpp | 19 +- .../unit-tests/tests/unit-tests_MidiInput.cpp | 190 ++++++++++++++++++ 2 files changed, 203 insertions(+), 6 deletions(-) diff --git a/src/MIDI.hpp b/src/MIDI.hpp index 7c59a72..7e0b7db 100644 --- a/src/MIDI.hpp +++ b/src/MIDI.hpp @@ -677,6 +677,19 @@ bool MidiInterface::parse() const byte extracted = mSerial.read(); + // Ignore Undefined + if (extracted == 0xf9 || extracted == 0xfd) + { + if (Settings::Use1ByteParsing) + { + return false; + } + else + { + return parse(); + } + } + if (mPendingMessageIndex == 0) { // Start a new pending message @@ -717,10 +730,7 @@ bool MidiInterface::parse() mMessage.data2 = 0; mMessage.valid = true; - // \fix Running Status broken when receiving Clock messages. // Do not reset all input attributes, Running Status must remain unchanged. - //resetInput(); - // We still need to reset these mPendingMessageIndex = 0; mPendingMessageExpectedLenght = 0; @@ -828,8 +838,6 @@ bool MidiInterface::parse() mMessage.valid = true; return true; - break; - // End of Exclusive case 0xf7: if (mMessage.sysexArray[0] == SystemExclusive) @@ -854,7 +862,6 @@ bool MidiInterface::parse() return false; } - break; default: break; } diff --git a/test/unit-tests/tests/unit-tests_MidiInput.cpp b/test/unit-tests/tests/unit-tests_MidiInput.cpp index 172008f..725eae8 100644 --- a/test/unit-tests/tests/unit-tests_MidiInput.cpp +++ b/test/unit-tests/tests/unit-tests_MidiInput.cpp @@ -735,4 +735,194 @@ TEST(MidiInput, realTime) EXPECT_EQ(midi.getData2(), 0); } +// -- + +TEST(MidiInput, interleavedRealTime) +{ + SerialMock serial; + MidiInterface midi(serial); + + // Interleaved Clocks between NoteOn / Off messages (with running status) + { + static const unsigned rxSize = 13; + static const byte rxData[rxSize] = { + 0x9b, 12, 0xf8, 34, + 12, 0, + 42, 0xf8, 127, + 0xf8, + 42, 0xf8, 0 + }; + midi.begin(12); + serial.mRxBuffer.write(rxData, rxSize); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(midi.getType(), midi::Clock); + 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::NoteOn); + EXPECT_EQ(midi.getChannel(), 12); + EXPECT_EQ(midi.getData1(), 12); + EXPECT_EQ(midi.getData2(), 34); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(midi.getType(), midi::NoteOff); + EXPECT_EQ(midi.getChannel(), 12); + EXPECT_EQ(midi.getData1(), 12); + EXPECT_EQ(midi.getData2(), 0); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(midi.getType(), midi::Clock); + 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::NoteOn); + EXPECT_EQ(midi.getChannel(), 12); + EXPECT_EQ(midi.getData1(), 42); + EXPECT_EQ(midi.getData2(), 127); + + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(midi.getType(), midi::Clock); + EXPECT_EQ(midi.getChannel(), 0); + EXPECT_EQ(midi.getData1(), 0); + EXPECT_EQ(midi.getData2(), 0); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(midi.getType(), midi::Clock); + 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::NoteOff); + EXPECT_EQ(midi.getChannel(), 12); + EXPECT_EQ(midi.getData1(), 42); + EXPECT_EQ(midi.getData2(), 0); + } + // Interleaved ActiveSensing between SysEx + { + static const unsigned rxSize = 6; + static const byte rxData[rxSize] = { + 0xf0, 12, 34, 0xfe, 56, 0xf7 + }; + midi.begin(12); + serial.mRxBuffer.write(rxData, rxSize); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(midi.getType(), midi::ActiveSensing); + EXPECT_EQ(midi.getChannel(), 0); + EXPECT_EQ(midi.getData1(), 0); + EXPECT_EQ(midi.getData2(), 0); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(midi.getSysExArrayLength(), rxSize - 1); + const std::vector sysExData(midi.getSysExArray(), + midi.getSysExArray() + rxSize - 1); + EXPECT_THAT(sysExData, ElementsAreArray({ + 0xf0, 12, 34, 56, 0xf7 + })); + } +} + +TEST(MidiInput, strayEox) +{ + // A stray End of Exclusive will reset the parser, but should it ? + SerialMock serial; + MidiInterface midi(serial); + 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); + EXPECT_EQ(midi.read(), false); +} + +TEST(MidiInput, strayUndefinedOneByteParsing) +{ + SerialMock serial; + MidiInterface midi(serial); + + static const unsigned rxSize = 13; + static const byte rxData[rxSize] = { + 0xbb, 12, 0xf9, 34, + 12, 0, + 42, 0xfd, 127, + 0xf9, + 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 + + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(midi.getType(), midi::ControlChange); + EXPECT_EQ(midi.getChannel(), 12); + EXPECT_EQ(midi.getData1(), 12); + EXPECT_EQ(midi.getData2(), 34); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(midi.getType(), midi::ControlChange); + EXPECT_EQ(midi.getChannel(), 12); + EXPECT_EQ(midi.getData1(), 12); + EXPECT_EQ(midi.getData2(), 0); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(midi.getType(), midi::ControlChange); + EXPECT_EQ(midi.getChannel(), 12); + EXPECT_EQ(midi.getData1(), 42); + EXPECT_EQ(midi.getData2(), 127); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(midi.getType(), midi::ControlChange); + EXPECT_EQ(midi.getChannel(), 12); + EXPECT_EQ(midi.getData1(), 42); + EXPECT_EQ(midi.getData2(), 0); +} + +TEST(MidiInput, strayUndefinedMultiByteParsing) +{ + typedef VariableSettings Settings; + typedef midi::MidiInterface MidiInterface; + + SerialMock serial; + MidiInterface midi(serial); + + static const unsigned rxSize = 4; + static const byte rxData[rxSize] = { + 0xbb, 12, 0xf9, 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); + EXPECT_EQ(midi.getData1(), 12); + EXPECT_EQ(midi.getData2(), 34); +} + END_UNNAMED_NAMESPACE From ff94a77521a106959dd3d5705aaf7b03cb55a16e Mon Sep 17 00:00:00 2001 From: Francois Best Date: Mon, 17 Oct 2016 19:43:14 +0200 Subject: [PATCH 099/138] Disabled running status by default. Relates to #38, #39, #41, #49. --- src/midi_Settings.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/midi_Settings.h b/src/midi_Settings.h index 27e4be4..8e6ac5b 100644 --- a/src/midi_Settings.h +++ b/src/midi_Settings.h @@ -41,7 +41,7 @@ BEGIN_MIDI_NAMESPACE \code{.cpp} struct MySettings : public midi::DefaultSettings { - static const bool UseRunningStatus = false; // Messes with my old equipment! + static const unsigned SysExMaxSize = 1024; // Accept SysEx messages up to 1024 bytes long. }; MIDI_CREATE_CUSTOM_INSTANCE(HardwareSerial, Serial2, midi, MySettings); @@ -51,9 +51,9 @@ struct DefaultSettings { /*! Running status enables short messages when sending multiple values of the same type and channel.\n - Set to false if you have troubles controlling your hardware. + Warning: does not work with some hardware, enable with caution. */ - static const bool UseRunningStatus = true; + static const bool UseRunningStatus = false; /*! NoteOn with 0 velocity should be handled as NoteOf.\n Set to true to get NoteOff events when receiving null-velocity NoteOn messages.\n From 8eb881f39e925db656fe6e6849cd27ed34065f04 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Mon, 17 Oct 2016 20:32:39 +0200 Subject: [PATCH 100/138] Fixed unit tests regarding RunningStatus changes. --- .../tests/unit-tests_MidiOutput.cpp | 122 +++++++++--------- test/unit-tests/tests/unit-tests_Settings.cpp | 2 +- 2 files changed, 65 insertions(+), 59 deletions(-) diff --git a/test/unit-tests/tests/unit-tests_MidiOutput.cpp b/test/unit-tests/tests/unit-tests_MidiOutput.cpp index e2ad984..3c2b43c 100644 --- a/test/unit-tests/tests/unit-tests_MidiOutput.cpp +++ b/test/unit-tests/tests/unit-tests_MidiOutput.cpp @@ -53,6 +53,9 @@ TEST(MidiOutput, sendGenericSingle) TEST(MidiOutput, sendGenericWithRunningStatus) { + typedef VariableSettings Settings; + typedef midi::MidiInterface MidiInterface; + SerialMock serial; MidiInterface midi(serial); Buffer buffer; @@ -139,14 +142,14 @@ TEST(MidiOutput, sendNoteOn) SerialMock serial; MidiInterface midi(serial); Buffer buffer; - buffer.resize(5); + buffer.resize(6); midi.begin(); midi.sendNoteOn(10, 11, 12); - midi.sendNoteOn(12, 13, 12); - EXPECT_EQ(serial.mTxBuffer.getLength(), 5); - serial.mTxBuffer.read(&buffer[0], 5); - EXPECT_THAT(buffer, ElementsAreArray({0x9b, 10, 11, 12, 13})); + midi.sendNoteOn(12, 13, 4); + EXPECT_EQ(serial.mTxBuffer.getLength(), 6); + serial.mTxBuffer.read(&buffer[0], 6); + EXPECT_THAT(buffer, ElementsAreArray({0x9b, 10, 11, 0x93, 12, 13})); } TEST(MidiOutput, sendNoteOff) @@ -154,14 +157,14 @@ TEST(MidiOutput, sendNoteOff) SerialMock serial; MidiInterface midi(serial); Buffer buffer; - buffer.resize(5); + buffer.resize(6); midi.begin(); midi.sendNoteOff(10, 11, 12); - midi.sendNoteOff(12, 13, 12); - EXPECT_EQ(serial.mTxBuffer.getLength(), 5); - serial.mTxBuffer.read(&buffer[0], 5); - EXPECT_THAT(buffer, ElementsAreArray({0x8b, 10, 11, 12, 13})); + midi.sendNoteOff(12, 13, 4); + EXPECT_EQ(serial.mTxBuffer.getLength(), 6); + serial.mTxBuffer.read(&buffer[0], 6); + EXPECT_THAT(buffer, ElementsAreArray({0x8b, 10, 11, 0x83, 12, 13})); } TEST(MidiOutput, sendProgramChange) @@ -169,14 +172,14 @@ TEST(MidiOutput, sendProgramChange) SerialMock serial; MidiInterface midi(serial); Buffer buffer; - buffer.resize(3); + buffer.resize(4); midi.begin(); midi.sendProgramChange(42, 12); - midi.sendProgramChange(47, 12); - EXPECT_EQ(serial.mTxBuffer.getLength(), 3); - serial.mTxBuffer.read(&buffer[0], 3); - EXPECT_THAT(buffer, ElementsAreArray({0xcb, 42, 47})); + midi.sendProgramChange(47, 4); + EXPECT_EQ(serial.mTxBuffer.getLength(), 4); + serial.mTxBuffer.read(&buffer[0], 4); + EXPECT_THAT(buffer, ElementsAreArray({0xcb, 42, 0xc3, 47})); } TEST(MidiOutput, sendControlChange) @@ -184,14 +187,14 @@ TEST(MidiOutput, sendControlChange) SerialMock serial; MidiInterface midi(serial); Buffer buffer; - buffer.resize(5); + buffer.resize(6); midi.begin(); midi.sendControlChange(42, 12, 12); - midi.sendControlChange(47, 12, 12); - EXPECT_EQ(serial.mTxBuffer.getLength(), 5); - serial.mTxBuffer.read(&buffer[0], 5); - EXPECT_THAT(buffer, ElementsAreArray({0xbb, 42, 12, 47, 12})); + midi.sendControlChange(47, 12, 4); + EXPECT_EQ(serial.mTxBuffer.getLength(), 6); + serial.mTxBuffer.read(&buffer[0], 6); + EXPECT_THAT(buffer, ElementsAreArray({0xbb, 42, 12, 0xb3, 47, 12})); } TEST(MidiOutput, sendPitchBend) @@ -203,50 +206,47 @@ TEST(MidiOutput, sendPitchBend) // Int signature - arbitrary values { buffer.clear(); - buffer.resize(7); + buffer.resize(9); midi.begin(); - midi.sendPitchBend(0, 12); - midi.sendPitchBend(100, 12); - midi.sendPitchBend(-100, 12); - EXPECT_EQ(serial.mTxBuffer.getLength(), 7); - serial.mTxBuffer.read(&buffer[0], 7); - EXPECT_THAT(buffer, ElementsAreArray({0xeb, - 0x00, 0x40, - 0x64, 0x40, - 0x1c, 0x3f})); + midi.sendPitchBend(0, 12); + midi.sendPitchBend(100, 4); + midi.sendPitchBend(-100, 7); + EXPECT_EQ(serial.mTxBuffer.getLength(), 9); + serial.mTxBuffer.read(&buffer[0], 9); + EXPECT_THAT(buffer, ElementsAreArray({0xeb, 0x00, 0x40, + 0xe3, 0x64, 0x40, + 0xe6, 0x1c, 0x3f})); } // Int signature - min/max { buffer.clear(); - buffer.resize(7); + buffer.resize(9); midi.begin(); midi.sendPitchBend(0, 12); - midi.sendPitchBend(MIDI_PITCHBEND_MAX, 12); - midi.sendPitchBend(MIDI_PITCHBEND_MIN, 12); - EXPECT_EQ(serial.mTxBuffer.getLength(), 7); - serial.mTxBuffer.read(&buffer[0], 7); - EXPECT_THAT(buffer, ElementsAreArray({0xeb, - 0x00, 0x40, - 0x7f, 0x7f, - 0x00, 0x00})); + midi.sendPitchBend(MIDI_PITCHBEND_MAX, 4); + midi.sendPitchBend(MIDI_PITCHBEND_MIN, 7); + EXPECT_EQ(serial.mTxBuffer.getLength(), 9); + serial.mTxBuffer.read(&buffer[0], 9); + EXPECT_THAT(buffer, ElementsAreArray({0xeb, 0x00, 0x40, + 0xe3, 0x7f, 0x7f, + 0xe6, 0x00, 0x00})); } // Float signature { buffer.clear(); - buffer.resize(7); + buffer.resize(9); midi.begin(); midi.sendPitchBend(0.0, 12); - midi.sendPitchBend(1.0, 12); - midi.sendPitchBend(-1.0, 12); - EXPECT_EQ(serial.mTxBuffer.getLength(), 7); - serial.mTxBuffer.read(&buffer[0], 7); - EXPECT_THAT(buffer, ElementsAreArray({0xeb, - 0x00, 0x40, - 0x7f, 0x7f, - 0x00, 0x00})); + midi.sendPitchBend(1.0, 4); + midi.sendPitchBend(-1.0, 7); + EXPECT_EQ(serial.mTxBuffer.getLength(), 9); + serial.mTxBuffer.read(&buffer[0], 9); + EXPECT_THAT(buffer, ElementsAreArray({0xeb, 0x00, 0x40, + 0xe3, 0x7f, 0x7f, + 0xe6, 0x00, 0x00})); } } @@ -255,14 +255,14 @@ TEST(MidiOutput, sendPolyPressure) SerialMock serial; MidiInterface midi(serial); Buffer buffer; - buffer.resize(5); + buffer.resize(6); midi.begin(); midi.sendPolyPressure(42, 12, 12); - midi.sendPolyPressure(47, 12, 12); - EXPECT_EQ(serial.mTxBuffer.getLength(), 5); - serial.mTxBuffer.read(&buffer[0], 5); - EXPECT_THAT(buffer, ElementsAreArray({0xab, 42, 12, 47, 12})); + midi.sendPolyPressure(47, 12, 4); + EXPECT_EQ(serial.mTxBuffer.getLength(), 6); + serial.mTxBuffer.read(&buffer[0], 6); + EXPECT_THAT(buffer, ElementsAreArray({0xab, 42, 12, 0xa3, 47, 12})); } TEST(MidiOutput, sendAfterTouch) @@ -270,14 +270,14 @@ TEST(MidiOutput, sendAfterTouch) SerialMock serial; MidiInterface midi(serial); Buffer buffer; - buffer.resize(3); + buffer.resize(4); midi.begin(); midi.sendAfterTouch(42, 12); - midi.sendAfterTouch(47, 12); - EXPECT_EQ(serial.mTxBuffer.getLength(), 3); - serial.mTxBuffer.read(&buffer[0], 3); - EXPECT_THAT(buffer, ElementsAreArray({0xdb, 42, 47})); + midi.sendAfterTouch(47, 4); + EXPECT_EQ(serial.mTxBuffer.getLength(), 4); + serial.mTxBuffer.read(&buffer[0], 4); + EXPECT_THAT(buffer, ElementsAreArray({0xdb, 42, 0xd3, 47})); } TEST(MidiOutput, sendSysEx) @@ -490,6 +490,9 @@ TEST(MidiOutput, sendRealTime) TEST(MidiOutput, RPN) { + typedef VariableSettings Settings; + typedef midi::MidiInterface MidiInterface; + SerialMock serial; MidiInterface midi(serial); std::vector buffer; @@ -603,6 +606,9 @@ TEST(MidiOutput, RPN) TEST(MidiOutput, NRPN) { + typedef VariableSettings Settings; + typedef midi::MidiInterface MidiInterface; + SerialMock serial; MidiInterface midi(serial); std::vector buffer; diff --git a/test/unit-tests/tests/unit-tests_Settings.cpp b/test/unit-tests/tests/unit-tests_Settings.cpp index 620a69c..72f44a1 100644 --- a/test/unit-tests/tests/unit-tests_Settings.cpp +++ b/test/unit-tests/tests/unit-tests_Settings.cpp @@ -16,7 +16,7 @@ BEGIN_UNNAMED_NAMESPACE TEST(Settings, hasTheRightDefaultValues) { - EXPECT_EQ(midi::DefaultSettings::UseRunningStatus, true); + EXPECT_EQ(midi::DefaultSettings::UseRunningStatus, false); EXPECT_EQ(midi::DefaultSettings::HandleNullVelocityNoteOnAsNoteOff, true); EXPECT_EQ(midi::DefaultSettings::Use1ByteParsing, true); EXPECT_EQ(midi::DefaultSettings::BaudRate, 31250); From 8ebd4f916122a0d1e019597feb5d78f3b0c36117 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Thu, 20 Oct 2016 10:08:00 +0200 Subject: [PATCH 101/138] Cleanup & init'd thru. --- src/MIDI.h | 30 +++++++++++++----------------- src/MIDI.hpp | 7 +++++++ 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/MIDI.h b/src/MIDI.h index ebedba4..cb3fa83 100644 --- a/src/MIDI.h +++ b/src/MIDI.h @@ -152,8 +152,7 @@ public: public: static inline MidiType getTypeFromStatusByte(byte inStatus); static inline Channel getChannelFromStatusByte(byte inStatus); - static inline bool isChannelMessage(MidiType inType); - + static inline bool isChannelMessage(MidiType inType); // ------------------------------------------------------------------------- // Input Callbacks @@ -222,10 +221,6 @@ private: inline bool inputFilter(Channel inChannel); inline void resetInput(); -private: - bool mThruActivated : 1; - MidiFilterMode mThruFilterMode : 7; - private: typedef Message MidiMessage; @@ -233,15 +228,18 @@ private: SerialPort& mSerial; private: - Channel mInputChannel; - StatusByte mRunningStatus_RX; - StatusByte mRunningStatus_TX; - byte mPendingMessage[3]; - unsigned mPendingMessageExpectedLenght; - unsigned mPendingMessageIndex; - unsigned mCurrentRpnNumber; - unsigned mCurrentNrpnNumber; - MidiMessage mMessage; + Channel mInputChannel; + StatusByte mRunningStatus_RX; + StatusByte mRunningStatus_TX; + byte mPendingMessage[3]; + unsigned mPendingMessageExpectedLenght; + unsigned mPendingMessageIndex; + unsigned mCurrentRpnNumber; + unsigned mCurrentNrpnNumber; + bool mThruActivated : 1; + MidiFilterMode mThruFilterMode : 7; + MidiMessage mMessage; + private: inline StatusByte getStatus(MidiType inType, @@ -255,6 +253,4 @@ unsigned decodeSysEx(const byte* inSysEx, byte* outData, unsigned inLenght); END_MIDI_NAMESPACE -// ----------------------------------------------------------------------------- - #include "MIDI.hpp" diff --git a/src/MIDI.hpp b/src/MIDI.hpp index 7e0b7db..4fc2655 100644 --- a/src/MIDI.hpp +++ b/src/MIDI.hpp @@ -41,6 +41,8 @@ inline MidiInterface::MidiInterface(SerialPort& inSerial) , mPendingMessageIndex(0) , mCurrentRpnNumber(0xffff) , mCurrentNrpnNumber(0xffff) + , mThruActivated(true) + , mThruFilterMode(Full) { mNoteOffCallback = 0; mNoteOnCallback = 0; @@ -781,9 +783,14 @@ bool MidiInterface::parse() // Save data2 only if applicable if (mPendingMessageExpectedLenght == 3) + { + // todo: This code seems unreacheable, to clean up. mMessage.data2 = mPendingMessage[2]; + } else + { mMessage.data2 = 0; + } mPendingMessageIndex = 0; mPendingMessageExpectedLenght = 0; From 189288c03ffc8a8d02cc381a0af2f19bdab3d19c Mon Sep 17 00:00:00 2001 From: Francois Best Date: Thu, 20 Oct 2016 10:08:06 +0200 Subject: [PATCH 102/138] Testing. --- test/unit-tests/CMakeLists.txt | 1 + .../tests/unit-tests_MidiInputCallbacks.cpp | 65 +++++++++++++++ test/unit-tests/tests/unit-tests_MidiThru.cpp | 82 +++++++++++++++++++ 3 files changed, 148 insertions(+) create mode 100644 test/unit-tests/tests/unit-tests_MidiInputCallbacks.cpp diff --git a/test/unit-tests/CMakeLists.txt b/test/unit-tests/CMakeLists.txt index e99276a..39f4bb3 100644 --- a/test/unit-tests/CMakeLists.txt +++ b/test/unit-tests/CMakeLists.txt @@ -20,6 +20,7 @@ add_executable(unit-tests 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 diff --git a/test/unit-tests/tests/unit-tests_MidiInputCallbacks.cpp b/test/unit-tests/tests/unit-tests_MidiInputCallbacks.cpp new file mode 100644 index 0000000..4198016 --- /dev/null +++ b/test/unit-tests/tests/unit-tests_MidiInputCallbacks.cpp @@ -0,0 +1,65 @@ +#include "unit-tests.h" +#include "unit-tests_Settings.h" +#include +#include + +BEGIN_MIDI_NAMESPACE + +END_MIDI_NAMESPACE + +// ----------------------------------------------------------------------------- + +BEGIN_UNNAMED_NAMESPACE + +using namespace testing; +USING_NAMESPACE_UNIT_TESTS +typedef test_mocks::SerialMock<32> SerialMock; +typedef midi::MidiInterface MidiInterface; + +template +struct VariableSysExSettings : midi::DefaultSettings +{ + static const unsigned SysExMaxSize = Size; +}; + +MidiInterface* midi; + +// -- + +void handleNoteOn(byte inChannel, byte inPitch, byte inVelocity) +{ + EXPECT_NE(midi, nullptr); + midi->sendNoteOn(inPitch, inVelocity, inChannel); +} + +TEST(MidiInputCallbacks, noteOn) +{ + EXPECT_EQ(midi, nullptr); + SerialMock serial; + midi = new MidiInterface(serial); + + + midi->setHandleNoteOn(handleNoteOn); + midi->begin(MIDI_CHANNEL_OMNI); + midi->turnThruOff(); + + static const unsigned rxSize = 3; + static const byte rxData[rxSize] = { 0x9b, 12, 34 }; + serial.mRxBuffer.write(rxData, rxSize); + + EXPECT_EQ(midi->read(), false); + EXPECT_EQ(midi->read(), false); + EXPECT_EQ(midi->read(), true); + EXPECT_EQ(midi->getType(), midi::NoteOn); + EXPECT_EQ(midi->getChannel(), 12); + EXPECT_EQ(midi->getData1(), 12); + EXPECT_EQ(midi->getData2(), 34); + + EXPECT_EQ(serial.mTxBuffer.getLength(), 3); + + + delete midi; + midi = nullptr; +} + +END_UNNAMED_NAMESPACE diff --git a/test/unit-tests/tests/unit-tests_MidiThru.cpp b/test/unit-tests/tests/unit-tests_MidiThru.cpp index e69de29..a04ea03 100644 --- a/test/unit-tests/tests/unit-tests_MidiThru.cpp +++ b/test/unit-tests/tests/unit-tests_MidiThru.cpp @@ -0,0 +1,82 @@ +#include "unit-tests.h" +#include "unit-tests_Settings.h" +#include +#include + +BEGIN_MIDI_NAMESPACE + +END_MIDI_NAMESPACE + +// ----------------------------------------------------------------------------- + +BEGIN_UNNAMED_NAMESPACE + +using namespace testing; +USING_NAMESPACE_UNIT_TESTS +typedef test_mocks::SerialMock<32> SerialMock; +typedef midi::MidiInterface MidiInterface; + +template +struct VariableSysExSettings : midi::DefaultSettings +{ + static const unsigned SysExMaxSize = Size; +}; + +// ----------------------------------------------------------------------------- + +TEST(MidiThru, defaultValues) +{ + SerialMock serial; + MidiInterface midi(serial); + + EXPECT_EQ(midi.getThruState(), true); + EXPECT_EQ(midi.getFilterMode(), midi::Full); + midi.begin(); // Should not change the state + EXPECT_EQ(midi.getThruState(), true); + EXPECT_EQ(midi.getFilterMode(), midi::Full); +} + +TEST(MidiThru, beginEnablesThru) +{ + SerialMock serial; + MidiInterface midi(serial); + + midi.turnThruOff(); + EXPECT_EQ(midi.getThruState(), false); + EXPECT_EQ(midi.getFilterMode(), midi::Off); + midi.begin(); + EXPECT_EQ(midi.getThruState(), true); + EXPECT_EQ(midi.getFilterMode(), midi::Full); +} + +TEST(MidiThru, setGet) +{ + SerialMock serial; + MidiInterface midi(serial); + + midi.turnThruOff(); + EXPECT_EQ(midi.getThruState(), false); + EXPECT_EQ(midi.getFilterMode(), midi::Off); + + midi.turnThruOn(); + EXPECT_EQ(midi.getThruState(), true); + EXPECT_EQ(midi.getFilterMode(), midi::Full); + midi.turnThruOn(midi::SameChannel); + EXPECT_EQ(midi.getThruState(), true); + EXPECT_EQ(midi.getFilterMode(), midi::SameChannel); + midi.turnThruOn(midi::DifferentChannel); + EXPECT_EQ(midi.getThruState(), true); + EXPECT_EQ(midi.getFilterMode(), midi::DifferentChannel); + + midi.setThruFilterMode(midi::Full); + EXPECT_EQ(midi.getThruState(), true); + EXPECT_EQ(midi.getFilterMode(), midi::Full); + midi.setThruFilterMode(midi::SameChannel); + EXPECT_EQ(midi.getThruState(), true); + EXPECT_EQ(midi.getFilterMode(), midi::SameChannel); + midi.setThruFilterMode(midi::DifferentChannel); + EXPECT_EQ(midi.getThruState(), true); + EXPECT_EQ(midi.getFilterMode(), midi::DifferentChannel); +} + +END_UNNAMED_NAMESPACE From fdb68ab7850ce33caec399d369b2417656dcab73 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Thu, 20 Oct 2016 10:10:23 +0200 Subject: [PATCH 103/138] Faster builds until complete Travis process refactoring. --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3b64ca2..64c5b3c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,8 +27,8 @@ addons: - llvm-3.5 - cmake -before_install: - - source <(curl -SLs https://raw.githubusercontent.com/fortyseveneffects/travis-ci-arduino/master/install.sh) +#before_install: +# - source <(curl -SLs https://raw.githubusercontent.com/fortyseveneffects/travis-ci-arduino/master/install.sh) install: # Enable coverage analysis only for GCC @@ -56,7 +56,7 @@ install: fi # Use clang 3.5 - if [ "$CXX" = "clang++" ]; then export CXX="clang++-3.5"; export CC="clang-3.5"; fi - - arduino --install-library "MIDIUSB" + # - arduino --install-library "MIDIUSB" script: # Build examples with Arduino IDE on each available platform / board From e92c5fc6df02d05b9151166673105d5d4dca610a Mon Sep 17 00:00:00 2001 From: Francois Best Date: Fri, 21 Oct 2016 07:42:47 +0200 Subject: [PATCH 104/138] Test off case. --- test/unit-tests/tests/unit-tests_MidiThru.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/unit-tests/tests/unit-tests_MidiThru.cpp b/test/unit-tests/tests/unit-tests_MidiThru.cpp index a04ea03..31c9bd6 100644 --- a/test/unit-tests/tests/unit-tests_MidiThru.cpp +++ b/test/unit-tests/tests/unit-tests_MidiThru.cpp @@ -77,6 +77,9 @@ TEST(MidiThru, setGet) midi.setThruFilterMode(midi::DifferentChannel); EXPECT_EQ(midi.getThruState(), true); EXPECT_EQ(midi.getFilterMode(), midi::DifferentChannel); + midi.setThruFilterMode(midi::Off); + EXPECT_EQ(midi.getThruState(), false); + EXPECT_EQ(midi.getFilterMode(), midi::Off); } END_UNNAMED_NAMESPACE From 6fc3e3851297292df9fcac9dc1026d169d630fea Mon Sep 17 00:00:00 2001 From: Francois Best Date: Fri, 21 Oct 2016 07:43:46 +0200 Subject: [PATCH 105/138] Moved Thru defs to own scope to avoid pollution. --- src/midi_Defs.h | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/midi_Defs.h b/src/midi_Defs.h index 6ddb326..e1b053d 100644 --- a/src/midi_Defs.h +++ b/src/midi_Defs.h @@ -84,12 +84,26 @@ enum MidiType // ----------------------------------------------------------------------------- /*! Enumeration of Thru filter modes */ -enum MidiFilterMode +struct Thru { - Off = 0, ///< Thru disabled (nothing passes through). - Full = 1, ///< Fully enabled Thru (every incoming message is sent back). - SameChannel = 2, ///< Only the messages on the Input Channel will be sent back. - DifferentChannel = 3, ///< All the messages but the ones on the Input Channel will be sent back. + enum Mode + { + off = 0, ///< Thru disabled (nothing passes through). + full = 1, ///< Fully enabled Thru (every incoming message is sent back). + sameChannel = 2, ///< Only the messages on the Input Channel will be sent back. + differentChannel = 3, ///< All the messages but the ones on the Input Channel will be sent back. + }; +}; + +/*! Deprecated: use Thru::Mode instead. + Will be removed in v5.0. +*/ +enum __attribute__ ((deprecated)) MidiFilterMode +{ + Off __attribute__((deprecated)) = Thru::off, + Full __attribute__((deprecated)) = Thru::full, + SameChannel __attribute__((deprecated)) = Thru::sameChannel, + DifferentChannel __attribute__((deprecated)) = Thru::differentChannel, }; // ----------------------------------------------------------------------------- From 58880bb647d92fc9cedbdea90303ae0ddad6e322 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Fri, 21 Oct 2016 07:52:12 +0200 Subject: [PATCH 106/138] gcc does not like individual deprecated attributes. --- src/midi_Defs.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/midi_Defs.h b/src/midi_Defs.h index e1b053d..654eb8d 100644 --- a/src/midi_Defs.h +++ b/src/midi_Defs.h @@ -100,10 +100,10 @@ struct Thru */ enum __attribute__ ((deprecated)) MidiFilterMode { - Off __attribute__((deprecated)) = Thru::off, - Full __attribute__((deprecated)) = Thru::full, - SameChannel __attribute__((deprecated)) = Thru::sameChannel, - DifferentChannel __attribute__((deprecated)) = Thru::differentChannel, + Off = Thru::off, + Full = Thru::full, + SameChannel = Thru::sameChannel, + DifferentChannel = Thru::differentChannel, }; // ----------------------------------------------------------------------------- From 37e72bc7faf5c01f26f1cc718499c1fd798a4b9f Mon Sep 17 00:00:00 2001 From: Francois Best Date: Thu, 27 Oct 2016 08:02:34 +0200 Subject: [PATCH 107/138] Stay consistant in enums first letter case. --- src/midi_Defs.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/midi_Defs.h b/src/midi_Defs.h index 654eb8d..2da35e5 100644 --- a/src/midi_Defs.h +++ b/src/midi_Defs.h @@ -88,10 +88,10 @@ struct Thru { enum Mode { - off = 0, ///< Thru disabled (nothing passes through). - full = 1, ///< Fully enabled Thru (every incoming message is sent back). - sameChannel = 2, ///< Only the messages on the Input Channel will be sent back. - differentChannel = 3, ///< All the messages but the ones on the Input Channel will be sent back. + Off = 0, ///< Thru disabled (nothing passes through). + Full = 1, ///< Fully enabled Thru (every incoming message is sent back). + SameChannel = 2, ///< Only the messages on the Input Channel will be sent back. + DifferentChannel = 3, ///< All the messages but the ones on the Input Channel will be sent back. }; }; From 7117671b162fa718b2ff539923a29fb8247c50ea Mon Sep 17 00:00:00 2001 From: Francois Best Date: Thu, 27 Oct 2016 08:04:15 +0200 Subject: [PATCH 108/138] Fix. --- src/midi_Defs.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/midi_Defs.h b/src/midi_Defs.h index 2da35e5..6070128 100644 --- a/src/midi_Defs.h +++ b/src/midi_Defs.h @@ -100,10 +100,10 @@ struct Thru */ enum __attribute__ ((deprecated)) MidiFilterMode { - Off = Thru::off, - Full = Thru::full, - SameChannel = Thru::sameChannel, - DifferentChannel = Thru::differentChannel, + Off = Thru::Off, + Full = Thru::Full, + SameChannel = Thru::SameChannel, + DifferentChannel = Thru::DifferentChannel, }; // ----------------------------------------------------------------------------- From 6abbdd7963eb553585b3f8d785a8755c3e1f9284 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Thu, 27 Oct 2016 08:11:03 +0200 Subject: [PATCH 109/138] Set warnings for all build modes. --- builder/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builder/CMakeLists.txt b/builder/CMakeLists.txt index 83c5831..036c701 100644 --- a/builder/CMakeLists.txt +++ b/builder/CMakeLists.txt @@ -8,7 +8,7 @@ macro(setup_builder) include_directories(${ROOT_SOURCE_DIR}) - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -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") From f1f0ef41ce585a3b88007c85f3ca67c232ac503b Mon Sep 17 00:00:00 2001 From: Francois Best Date: Thu, 27 Oct 2016 08:11:29 +0200 Subject: [PATCH 110/138] Using new definitions for Thru. --- src/MIDI.h | 8 ++--- src/MIDI.hpp | 30 +++++++--------- test/unit-tests/tests/unit-tests_MidiThru.cpp | 36 +++++++++---------- 3 files changed, 34 insertions(+), 40 deletions(-) diff --git a/src/MIDI.h b/src/MIDI.h index cb3fa83..aa318cf 100644 --- a/src/MIDI.h +++ b/src/MIDI.h @@ -205,12 +205,12 @@ private: // MIDI Soft Thru public: - inline MidiFilterMode getFilterMode() const; + inline Thru::Mode getFilterMode() const; inline bool getThruState() const; - inline void turnThruOn(MidiFilterMode inThruFilterMode = Full); + inline void turnThruOn(Thru::Mode inThruFilterMode = Thru::Full); inline void turnThruOff(); - inline void setThruFilterMode(MidiFilterMode inThruFilterMode); + inline void setThruFilterMode(Thru::Mode inThruFilterMode); private: void thruFilter(byte inChannel); @@ -237,7 +237,7 @@ private: unsigned mCurrentRpnNumber; unsigned mCurrentNrpnNumber; bool mThruActivated : 1; - MidiFilterMode mThruFilterMode : 7; + Thru::Mode mThruFilterMode : 7; MidiMessage mMessage; diff --git a/src/MIDI.hpp b/src/MIDI.hpp index 4fc2655..57da760 100644 --- a/src/MIDI.hpp +++ b/src/MIDI.hpp @@ -42,7 +42,7 @@ inline MidiInterface::MidiInterface(SerialPort& inSerial) , mCurrentRpnNumber(0xffff) , mCurrentNrpnNumber(0xffff) , mThruActivated(true) - , mThruFilterMode(Full) + , mThruFilterMode(Thru::Full) { mNoteOffCallback = 0; mNoteOnCallback = 0; @@ -107,7 +107,7 @@ void MidiInterface::begin(Channel inChannel) mMessage.data1 = 0; mMessage.data2 = 0; - mThruFilterMode = Full; + mThruFilterMode = Thru::Full; mThruActivated = true; } @@ -1250,20 +1250,20 @@ void MidiInterface::launchCallback() /*! \brief Set the filter for thru mirroring \param inThruFilterMode a filter mode - @see MidiFilterMode + @see Thru::Mode */ template -void MidiInterface::setThruFilterMode(MidiFilterMode inThruFilterMode) +void MidiInterface::setThruFilterMode(Thru::Mode inThruFilterMode) { mThruFilterMode = inThruFilterMode; - if (mThruFilterMode != Off) + if (mThruFilterMode != Thru::Off) mThruActivated = true; else mThruActivated = false; } template -MidiFilterMode MidiInterface::getFilterMode() const +Thru::Mode MidiInterface::getFilterMode() const { return mThruFilterMode; } @@ -1275,7 +1275,7 @@ bool MidiInterface::getThruState() const } template -void MidiInterface::turnThruOn(MidiFilterMode inThruFilterMode) +void MidiInterface::turnThruOn(Thru::Mode inThruFilterMode) { mThruActivated = true; mThruFilterMode = inThruFilterMode; @@ -1285,7 +1285,7 @@ template void MidiInterface::turnThruOff() { mThruActivated = false; - mThruFilterMode = Off; + mThruFilterMode = Thru::Off; } /*! @} */ // End of doc group MIDI Thru @@ -1300,7 +1300,7 @@ template void MidiInterface::thruFilter(Channel inChannel) { // If the feature is disabled, don't do anything. - if (!mThruActivated || (mThruFilterMode == Off)) + if (!mThruActivated || (mThruFilterMode == Thru::Off)) return; // First, check if the received message is Channel @@ -1312,14 +1312,14 @@ void MidiInterface::thruFilter(Channel inChannel) // Now let's pass it to the output switch (mThruFilterMode) { - case Full: + case Thru::Full: send(mMessage.type, mMessage.data1, mMessage.data2, mMessage.channel); break; - case SameChannel: + case Thru::SameChannel: if (filter_condition) { send(mMessage.type, @@ -1329,7 +1329,7 @@ void MidiInterface::thruFilter(Channel inChannel) } break; - case DifferentChannel: + case Thru::DifferentChannel: if (!filter_condition) { send(mMessage.type, @@ -1339,12 +1339,6 @@ void MidiInterface::thruFilter(Channel inChannel) } break; - case Off: - // Do nothing. - // Technically it's impossible to get there because - // the case was already tested earlier. - break; - default: break; } diff --git a/test/unit-tests/tests/unit-tests_MidiThru.cpp b/test/unit-tests/tests/unit-tests_MidiThru.cpp index 31c9bd6..8f301dc 100644 --- a/test/unit-tests/tests/unit-tests_MidiThru.cpp +++ b/test/unit-tests/tests/unit-tests_MidiThru.cpp @@ -30,10 +30,10 @@ TEST(MidiThru, defaultValues) MidiInterface midi(serial); EXPECT_EQ(midi.getThruState(), true); - EXPECT_EQ(midi.getFilterMode(), midi::Full); + EXPECT_EQ(midi.getFilterMode(), midi::Thru::Full); midi.begin(); // Should not change the state EXPECT_EQ(midi.getThruState(), true); - EXPECT_EQ(midi.getFilterMode(), midi::Full); + EXPECT_EQ(midi.getFilterMode(), midi::Thru::Full); } TEST(MidiThru, beginEnablesThru) @@ -43,10 +43,10 @@ TEST(MidiThru, beginEnablesThru) midi.turnThruOff(); EXPECT_EQ(midi.getThruState(), false); - EXPECT_EQ(midi.getFilterMode(), midi::Off); + EXPECT_EQ(midi.getFilterMode(), midi::Thru::Off); midi.begin(); EXPECT_EQ(midi.getThruState(), true); - EXPECT_EQ(midi.getFilterMode(), midi::Full); + EXPECT_EQ(midi.getFilterMode(), midi::Thru::Full); } TEST(MidiThru, setGet) @@ -56,30 +56,30 @@ TEST(MidiThru, setGet) midi.turnThruOff(); EXPECT_EQ(midi.getThruState(), false); - EXPECT_EQ(midi.getFilterMode(), midi::Off); + EXPECT_EQ(midi.getFilterMode(), midi::Thru::Off); midi.turnThruOn(); EXPECT_EQ(midi.getThruState(), true); - EXPECT_EQ(midi.getFilterMode(), midi::Full); - midi.turnThruOn(midi::SameChannel); + EXPECT_EQ(midi.getFilterMode(), midi::Thru::Full); + midi.turnThruOn(midi::Thru::SameChannel); EXPECT_EQ(midi.getThruState(), true); - EXPECT_EQ(midi.getFilterMode(), midi::SameChannel); - midi.turnThruOn(midi::DifferentChannel); + EXPECT_EQ(midi.getFilterMode(), midi::Thru::SameChannel); + midi.turnThruOn(midi::Thru::DifferentChannel); EXPECT_EQ(midi.getThruState(), true); - EXPECT_EQ(midi.getFilterMode(), midi::DifferentChannel); + EXPECT_EQ(midi.getFilterMode(), midi::Thru::DifferentChannel); - midi.setThruFilterMode(midi::Full); + midi.setThruFilterMode(midi::Thru::Full); EXPECT_EQ(midi.getThruState(), true); - EXPECT_EQ(midi.getFilterMode(), midi::Full); - midi.setThruFilterMode(midi::SameChannel); + EXPECT_EQ(midi.getFilterMode(), midi::Thru::Full); + midi.setThruFilterMode(midi::Thru::SameChannel); EXPECT_EQ(midi.getThruState(), true); - EXPECT_EQ(midi.getFilterMode(), midi::SameChannel); - midi.setThruFilterMode(midi::DifferentChannel); + EXPECT_EQ(midi.getFilterMode(), midi::Thru::SameChannel); + midi.setThruFilterMode(midi::Thru::DifferentChannel); EXPECT_EQ(midi.getThruState(), true); - EXPECT_EQ(midi.getFilterMode(), midi::DifferentChannel); - midi.setThruFilterMode(midi::Off); + EXPECT_EQ(midi.getFilterMode(), midi::Thru::DifferentChannel); + midi.setThruFilterMode(midi::Thru::Off); EXPECT_EQ(midi.getThruState(), false); - EXPECT_EQ(midi.getFilterMode(), midi::Off); + EXPECT_EQ(midi.getFilterMode(), midi::Thru::Off); } END_UNNAMED_NAMESPACE From 5d3cbd1f9f9f319c0a8f5c77b53f783076c8af8e Mon Sep 17 00:00:00 2001 From: Francois Best Date: Fri, 28 Oct 2016 09:13:06 +0200 Subject: [PATCH 111/138] #54: added overload of sendAfterTouch for poly. Deprecates sendPolyPressure. --- src/MIDI.h | 5 ++++- src/MIDI.hpp | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/MIDI.h b/src/MIDI.h index aa318cf..15fe359 100644 --- a/src/MIDI.h +++ b/src/MIDI.h @@ -79,10 +79,13 @@ public: inline void sendPolyPressure(DataByte inNoteNumber, DataByte inPressure, - Channel inChannel); + Channel inChannel) __attribute__ ((deprecated)); inline void sendAfterTouch(DataByte inPressure, Channel inChannel); + inline void sendAfterTouch(DataByte inNoteNumber, + DataByte inPressure, + Channel inChannel); inline void sendSysEx(unsigned inLength, const byte* inArray, diff --git a/src/MIDI.hpp b/src/MIDI.hpp index 57da760..57bdd32 100644 --- a/src/MIDI.hpp +++ b/src/MIDI.hpp @@ -251,6 +251,8 @@ void MidiInterface::sendControlChange(DataByte inControlNu \param inNoteNumber The note to apply AfterTouch to (0 to 127). \param inPressure The amount of AfterTouch to apply (0 to 127). \param inChannel The channel on which the message will be sent (1 to 16). + Note: this method is deprecated and will be removed in a future revision of the + library, @see sendAfterTouch to send polyphonic and monophonic AfterTouch messages. */ template void MidiInterface::sendPolyPressure(DataByte inNoteNumber, @@ -271,6 +273,20 @@ void MidiInterface::sendAfterTouch(DataByte inPressure, send(AfterTouchChannel, inPressure, 0, inChannel); } +/*! \brief Send a Polyphonic AfterTouch message (applies to a specified note) + \param inNoteNumber The note to apply AfterTouch to (0 to 127). + \param inPressure The amount of AfterTouch to apply (0 to 127). + \param inChannel The channel on which the message will be sent (1 to 16). + @see Replaces sendPolyPressure (which is now deprecated). + */ +template +void MidiInterface::sendAfterTouch(DataByte inNoteNumber, + DataByte inPressure, + Channel inChannel) +{ + send(AfterTouchPoly, inNoteNumber, inPressure, inChannel); +} + /*! \brief Send a Pitch Bend message using a signed integer value. \param inPitchValue The amount of bend to send (in a signed integer format), between MIDI_PITCHBEND_MIN and MIDI_PITCHBEND_MAX, From 037b9fb9f2eb52195722be3accb5a33acfdaac35 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Fri, 28 Oct 2016 09:15:56 +0200 Subject: [PATCH 112/138] Added test for new sendAfterTouch signature. --- .../tests/unit-tests_MidiOutput.cpp | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/test/unit-tests/tests/unit-tests_MidiOutput.cpp b/test/unit-tests/tests/unit-tests_MidiOutput.cpp index 3c2b43c..59cd993 100644 --- a/test/unit-tests/tests/unit-tests_MidiOutput.cpp +++ b/test/unit-tests/tests/unit-tests_MidiOutput.cpp @@ -252,6 +252,10 @@ TEST(MidiOutput, sendPitchBend) TEST(MidiOutput, sendPolyPressure) { + // Note: sendPolyPressure is deprecated in favor of sendAfterTouch, which + // now supports both mono and poly AfterTouch messages. + // This test is kept for coverage until removal of sendPolyPressure. + SerialMock serial; MidiInterface midi(serial); Buffer buffer; @@ -265,7 +269,7 @@ TEST(MidiOutput, sendPolyPressure) EXPECT_THAT(buffer, ElementsAreArray({0xab, 42, 12, 0xa3, 47, 12})); } -TEST(MidiOutput, sendAfterTouch) +TEST(MidiOutput, sendAfterTouchMono) { SerialMock serial; MidiInterface midi(serial); @@ -280,6 +284,21 @@ TEST(MidiOutput, sendAfterTouch) EXPECT_THAT(buffer, ElementsAreArray({0xdb, 42, 0xd3, 47})); } +TEST(MidiOutput, sendAfterTouchPoly) +{ + SerialMock serial; + MidiInterface midi(serial); + Buffer buffer; + buffer.resize(6); + + midi.begin(); + midi.sendAfterTouch(42, 12, 12); + midi.sendAfterTouch(47, 12, 4); + EXPECT_EQ(serial.mTxBuffer.getLength(), 6); + serial.mTxBuffer.read(&buffer[0], 6); + EXPECT_THAT(buffer, ElementsAreArray({0xab, 42, 12, 0xa3, 47, 12})); +} + TEST(MidiOutput, sendSysEx) { typedef test_mocks::SerialMock<1024> SerialMock; From 7b36662a7fc64bd05d7ba79fe4a9a2ba92b8f263 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Fri, 28 Oct 2016 09:54:37 +0200 Subject: [PATCH 113/138] Added callback tests. --- .../tests/unit-tests_MidiInputCallbacks.cpp | 519 +++++++++++++++++- 1 file changed, 499 insertions(+), 20 deletions(-) diff --git a/test/unit-tests/tests/unit-tests_MidiInputCallbacks.cpp b/test/unit-tests/tests/unit-tests_MidiInputCallbacks.cpp index 4198016..f8642e2 100644 --- a/test/unit-tests/tests/unit-tests_MidiInputCallbacks.cpp +++ b/test/unit-tests/tests/unit-tests_MidiInputCallbacks.cpp @@ -24,6 +24,33 @@ struct VariableSysExSettings : midi::DefaultSettings MidiInterface* midi; +class MidiInputCallbacks : public Test +{ +public: + MidiInputCallbacks() + : mMidi(mSerial) + { + } + virtual ~MidiInputCallbacks() + { + } + +protected: + virtual void SetUp() + { + midi = &mMidi; + } + + virtual void TearDown() + { + midi = nullptr; + } + +protected: + SerialMock mSerial; + MidiInterface mMidi; +}; + // -- void handleNoteOn(byte inChannel, byte inPitch, byte inVelocity) @@ -32,34 +59,486 @@ void handleNoteOn(byte inChannel, byte inPitch, byte inVelocity) midi->sendNoteOn(inPitch, inVelocity, inChannel); } -TEST(MidiInputCallbacks, noteOn) +TEST_F(MidiInputCallbacks, noteOn) { - EXPECT_EQ(midi, nullptr); - SerialMock serial; - midi = new MidiInterface(serial); - - - midi->setHandleNoteOn(handleNoteOn); - midi->begin(MIDI_CHANNEL_OMNI); - midi->turnThruOff(); + mMidi.setHandleNoteOn(handleNoteOn); + mMidi.begin(MIDI_CHANNEL_OMNI); + mMidi.turnThruOff(); static const unsigned rxSize = 3; static const byte rxData[rxSize] = { 0x9b, 12, 34 }; - serial.mRxBuffer.write(rxData, rxSize); + mSerial.mRxBuffer.write(rxData, rxSize); - EXPECT_EQ(midi->read(), false); - EXPECT_EQ(midi->read(), false); - EXPECT_EQ(midi->read(), true); - EXPECT_EQ(midi->getType(), midi::NoteOn); - EXPECT_EQ(midi->getChannel(), 12); - EXPECT_EQ(midi->getData1(), 12); - EXPECT_EQ(midi->getData2(), 34); + EXPECT_EQ(mMidi.read(), false); + EXPECT_EQ(mMidi.read(), false); + EXPECT_EQ(mMidi.read(), true); + EXPECT_EQ(mMidi.getType(), midi::NoteOn); + EXPECT_EQ(mMidi.getChannel(), 12); + EXPECT_EQ(mMidi.getData1(), 12); + EXPECT_EQ(mMidi.getData2(), 34); - EXPECT_EQ(serial.mTxBuffer.getLength(), 3); + EXPECT_EQ(mSerial.mTxBuffer.getLength(), 3); + byte buffer[3] = { 0 }; + mSerial.mTxBuffer.read(buffer, 3); + EXPECT_THAT(buffer, ContainerEq(rxData)); + + // Test null velocity note on + EXPECT_EQ(MidiInterface::Settings::HandleNullVelocityNoteOnAsNoteOff, true); + mSerial.mRxBuffer.write(0x9b); + mSerial.mRxBuffer.write(12); + mSerial.mRxBuffer.write(0); + + EXPECT_EQ(mMidi.read(), false); + EXPECT_EQ(mMidi.read(), false); + EXPECT_EQ(mMidi.read(), true); + EXPECT_EQ(mMidi.getType(), midi::NoteOff); + EXPECT_EQ(mMidi.getChannel(), 12); + EXPECT_EQ(mMidi.getData1(), 12); + EXPECT_EQ(mMidi.getData2(), 0); + + EXPECT_EQ(mSerial.mTxBuffer.getLength(), 0); +} + +// -- + +void handleNoteOff(byte inChannel, byte inPitch, byte inVelocity) +{ + EXPECT_NE(midi, nullptr); + midi->sendNoteOff(inPitch, inVelocity, inChannel); +} + +TEST_F(MidiInputCallbacks, noteOff) +{ + mMidi.setHandleNoteOff(handleNoteOff); + mMidi.begin(MIDI_CHANNEL_OMNI); + mMidi.turnThruOff(); + + static const unsigned rxSize = 3; + static const byte rxData[rxSize] = { 0x8b, 12, 34 }; + mSerial.mRxBuffer.write(rxData, rxSize); + + EXPECT_EQ(mMidi.read(), false); + EXPECT_EQ(mMidi.read(), false); + EXPECT_EQ(mMidi.read(), true); + EXPECT_EQ(mMidi.getType(), midi::NoteOff); + EXPECT_EQ(mMidi.getChannel(), 12); + EXPECT_EQ(mMidi.getData1(), 12); + EXPECT_EQ(mMidi.getData2(), 34); + + EXPECT_EQ(mSerial.mTxBuffer.getLength(), 3); + byte buffer[3] = { 0 }; + mSerial.mTxBuffer.read(buffer, 3); + EXPECT_THAT(buffer, ContainerEq(rxData)); + + // Test null velocity note on + EXPECT_EQ(MidiInterface::Settings::HandleNullVelocityNoteOnAsNoteOff, true); + mSerial.mRxBuffer.write(0x9b); + mSerial.mRxBuffer.write(12); + mSerial.mRxBuffer.write(0); + + EXPECT_EQ(mMidi.read(), false); + EXPECT_EQ(mMidi.read(), false); + EXPECT_EQ(mMidi.read(), true); + EXPECT_EQ(mMidi.getType(), midi::NoteOff); + EXPECT_EQ(mMidi.getChannel(), 12); + EXPECT_EQ(mMidi.getData1(), 12); + EXPECT_EQ(mMidi.getData2(), 0); + + EXPECT_EQ(mSerial.mTxBuffer.getLength(), 3); + mSerial.mTxBuffer.read(buffer, 3); + EXPECT_THAT(buffer, ElementsAreArray({ + 0x8b, 12, 0 + })); +} + +// -- - delete midi; - midi = nullptr; + +void handleAfterTouchPoly(byte inChannel, byte inNote, byte inValue) +{ + EXPECT_NE(midi, nullptr); + midi->sendAfterTouch(inNote, inValue, inChannel); +} + +TEST_F(MidiInputCallbacks, afterTouchPoly) +{ + mMidi.setHandleAfterTouchPoly(handleAfterTouchPoly); + mMidi.begin(MIDI_CHANNEL_OMNI); + mMidi.turnThruOff(); + + static const unsigned rxSize = 3; + static const byte rxData[rxSize] = { 0xab, 12, 34 }; + mSerial.mRxBuffer.write(rxData, rxSize); + + EXPECT_EQ(mMidi.read(), false); + EXPECT_EQ(mMidi.read(), false); + EXPECT_EQ(mMidi.read(), true); + EXPECT_EQ(mMidi.getType(), midi::AfterTouchPoly); + EXPECT_EQ(mMidi.getChannel(), 12); + EXPECT_EQ(mMidi.getData1(), 12); + EXPECT_EQ(mMidi.getData2(), 34); + + EXPECT_EQ(mSerial.mTxBuffer.getLength(), 3); + byte buffer[3] = { 0 }; + mSerial.mTxBuffer.read(buffer, 3); + EXPECT_THAT(buffer, ContainerEq(rxData)); +} + +// -- + +void handleControlChange(byte inChannel, byte inNumber, byte inValue) +{ + EXPECT_NE(midi, nullptr); + midi->sendControlChange(inNumber, inValue, inChannel); +} + +TEST_F(MidiInputCallbacks, controlChange) +{ + mMidi.setHandleControlChange(handleControlChange); + mMidi.begin(MIDI_CHANNEL_OMNI); + mMidi.turnThruOff(); + + static const unsigned rxSize = 3; + static const byte rxData[rxSize] = { 0xbb, 12, 34 }; + mSerial.mRxBuffer.write(rxData, rxSize); + + EXPECT_EQ(mMidi.read(), false); + EXPECT_EQ(mMidi.read(), false); + EXPECT_EQ(mMidi.read(), true); + EXPECT_EQ(mMidi.getType(), midi::ControlChange); + EXPECT_EQ(mMidi.getChannel(), 12); + EXPECT_EQ(mMidi.getData1(), 12); + EXPECT_EQ(mMidi.getData2(), 34); + + EXPECT_EQ(mSerial.mTxBuffer.getLength(), 3); + byte buffer[3] = { 0 }; + mSerial.mTxBuffer.read(buffer, 3); + EXPECT_THAT(buffer, ContainerEq(rxData)); +} + +// -- + +void handleProgramChange(byte inChannel, byte inNumber) +{ + EXPECT_NE(midi, nullptr); + midi->sendProgramChange(inNumber, inChannel); +} + +TEST_F(MidiInputCallbacks, programChange) +{ + mMidi.setHandleProgramChange(handleProgramChange); + mMidi.begin(MIDI_CHANNEL_OMNI); + mMidi.turnThruOff(); + + static const unsigned rxSize = 2; + static const byte rxData[rxSize] = { 0xcb, 12 }; + mSerial.mRxBuffer.write(rxData, rxSize); + + EXPECT_EQ(mMidi.read(), false); + EXPECT_EQ(mMidi.read(), true); + EXPECT_EQ(mMidi.getType(), midi::ProgramChange); + EXPECT_EQ(mMidi.getChannel(), 12); + EXPECT_EQ(mMidi.getData1(), 12); + EXPECT_EQ(mMidi.getData2(), 0); + + EXPECT_EQ(mSerial.mTxBuffer.getLength(), 2); + byte buffer[2] = { 0 }; + mSerial.mTxBuffer.read(buffer, 2); + EXPECT_THAT(buffer, ContainerEq(rxData)); +} + +// -- + +void handleAfterTouchChannel(byte inChannel, byte inPressure) +{ + EXPECT_NE(midi, nullptr); + midi->sendAfterTouch(inPressure, inChannel); +} + + +TEST_F(MidiInputCallbacks, afterTouchChannel) +{ + mMidi.setHandleAfterTouchChannel(handleAfterTouchChannel); + mMidi.begin(MIDI_CHANNEL_OMNI); + mMidi.turnThruOff(); + + static const unsigned rxSize = 2; + static const byte rxData[rxSize] = { 0xdb, 12 }; + mSerial.mRxBuffer.write(rxData, rxSize); + + EXPECT_EQ(mMidi.read(), false); + EXPECT_EQ(mMidi.read(), true); + EXPECT_EQ(mMidi.getType(), midi::AfterTouchChannel); + EXPECT_EQ(mMidi.getChannel(), 12); + EXPECT_EQ(mMidi.getData1(), 12); + EXPECT_EQ(mMidi.getData2(), 0); + + EXPECT_EQ(mSerial.mTxBuffer.getLength(), 2); + byte buffer[2] = { 0 }; + mSerial.mTxBuffer.read(buffer, 2); + EXPECT_THAT(buffer, ContainerEq(rxData)); +} + +// -- + +void handlePitchBend(byte inChannel, int inValue) +{ + EXPECT_NE(midi, nullptr); + midi->sendPitchBend(inValue, inChannel); +} + +TEST_F(MidiInputCallbacks, pitchBend) +{ + mMidi.setHandlePitchBend(handlePitchBend); + mMidi.begin(MIDI_CHANNEL_OMNI); + mMidi.turnThruOff(); + + static const unsigned rxSize = 3; + static const byte rxData[rxSize] = { 0xeb, 12, 34 }; + mSerial.mRxBuffer.write(rxData, rxSize); + + EXPECT_EQ(mMidi.read(), false); + EXPECT_EQ(mMidi.read(), false); + EXPECT_EQ(mMidi.read(), true); + EXPECT_EQ(mMidi.getType(), midi::PitchBend); + EXPECT_EQ(mMidi.getChannel(), 12); + EXPECT_EQ(mMidi.getData1(), 12); + EXPECT_EQ(mMidi.getData2(), 34); + + EXPECT_EQ(mSerial.mTxBuffer.getLength(), 3); + byte buffer[3] = { 0 }; + mSerial.mTxBuffer.read(buffer, 3); + EXPECT_THAT(buffer, ContainerEq(rxData)); +} + +// -- + +void handleSysEx(byte* inData, unsigned inSize) +{ + EXPECT_NE(midi, nullptr); + midi->sendSysEx(inSize, inData, true); +} + +TEST_F(MidiInputCallbacks, sysEx) +{ + mMidi.setHandleSystemExclusive(handleSysEx); + mMidi.begin(MIDI_CHANNEL_OMNI); + mMidi.turnThruOff(); + + static const unsigned rxSize = 15; + static const byte rxData[rxSize] = { + 0xf0, 'H','e','l','l','o',',',' ','W','o','r','l','d','!', 0xf7 + }; + mSerial.mRxBuffer.write(rxData, rxSize); + + for (unsigned i = 0; i < rxSize - 1; ++i) + { + EXPECT_EQ(mMidi.read(), false); + } + EXPECT_EQ(mMidi.read(), true); + EXPECT_EQ(mMidi.getType(), midi::SystemExclusive); + EXPECT_EQ(mMidi.getChannel(), 0); + EXPECT_EQ(mMidi.getSysExArrayLength(), rxSize); + + EXPECT_EQ(unsigned(mSerial.mTxBuffer.getLength()), rxSize); + const std::vector sysExData(mMidi.getSysExArray(), + mMidi.getSysExArray() + rxSize); + EXPECT_THAT(sysExData, ElementsAreArray(rxData)); +} + +// -- + +void handleMtcQuarterFrame(byte inData) +{ + EXPECT_NE(midi, nullptr); + midi->sendTimeCodeQuarterFrame(inData); +} + +TEST_F(MidiInputCallbacks, mtcQuarterFrame) +{ + mMidi.setHandleTimeCodeQuarterFrame(handleMtcQuarterFrame); + mMidi.begin(MIDI_CHANNEL_OMNI); + mMidi.turnThruOff(); + + static const unsigned rxSize = 2; + static const byte rxData[rxSize] = { 0xf1, 12 }; + mSerial.mRxBuffer.write(rxData, rxSize); + + EXPECT_EQ(mMidi.read(), false); + EXPECT_EQ(mMidi.read(), true); + EXPECT_EQ(mMidi.getType(), midi::TimeCodeQuarterFrame); + EXPECT_EQ(mMidi.getChannel(), 0); + EXPECT_EQ(mMidi.getData1(), 12); + EXPECT_EQ(mMidi.getData2(), 0); + + EXPECT_EQ(mSerial.mTxBuffer.getLength(), 2); + byte buffer[2] = { 0 }; + mSerial.mTxBuffer.read(buffer, 2); + EXPECT_THAT(buffer, ContainerEq(rxData)); +} + +// -- + +void handleSongPosition(unsigned inBeats) +{ + EXPECT_NE(midi, nullptr); + midi->sendSongPosition(inBeats); +} + +TEST_F(MidiInputCallbacks, songPosition) +{ + mMidi.setHandleSongPosition(handleSongPosition); + mMidi.begin(MIDI_CHANNEL_OMNI); + mMidi.turnThruOff(); + + static const unsigned rxSize = 3; + static const byte rxData[rxSize] = { 0xf2, 12, 34 }; + mSerial.mRxBuffer.write(rxData, rxSize); + + EXPECT_EQ(mMidi.read(), false); + EXPECT_EQ(mMidi.read(), false); + EXPECT_EQ(mMidi.read(), true); + EXPECT_EQ(mMidi.getType(), midi::SongPosition); + EXPECT_EQ(mMidi.getChannel(), 0); + EXPECT_EQ(mMidi.getData1(), 12); + EXPECT_EQ(mMidi.getData2(), 34); + + EXPECT_EQ(mSerial.mTxBuffer.getLength(), 3); + byte buffer[3] = { 0 }; + mSerial.mTxBuffer.read(buffer, 3); + EXPECT_THAT(buffer, ContainerEq(rxData)); +} + +// -- + +void handleSongSelect(byte inSongNumber) +{ + EXPECT_NE(midi, nullptr); + midi->sendSongSelect(inSongNumber); +} + +TEST_F(MidiInputCallbacks, songSelect) +{ + mMidi.setHandleSongSelect(handleSongSelect); + mMidi.begin(MIDI_CHANNEL_OMNI); + mMidi.turnThruOff(); + + static const unsigned rxSize = 2; + static const byte rxData[rxSize] = { 0xf3, 12 }; + mSerial.mRxBuffer.write(rxData, rxSize); + + EXPECT_EQ(mMidi.read(), false); + EXPECT_EQ(mMidi.read(), true); + EXPECT_EQ(mMidi.getType(), midi::SongSelect); + EXPECT_EQ(mMidi.getChannel(), 0); + EXPECT_EQ(mMidi.getData1(), 12); + EXPECT_EQ(mMidi.getData2(), 0); + + EXPECT_EQ(mSerial.mTxBuffer.getLength(), 2); + byte buffer[2] = { 0 }; + mSerial.mTxBuffer.read(buffer, 2); + EXPECT_THAT(buffer, ContainerEq(rxData)); +} + +// -- + +void handleTuneRequest() +{ + EXPECT_NE(midi, nullptr); + midi->sendTuneRequest(); +} + +TEST_F(MidiInputCallbacks, tuneRequest) +{ + mMidi.setHandleTuneRequest(handleTuneRequest); + mMidi.begin(MIDI_CHANNEL_OMNI); + mMidi.turnThruOff(); + + mSerial.mRxBuffer.write(0xf6); + + EXPECT_EQ(mMidi.read(), true); + EXPECT_EQ(mMidi.getType(), midi::TuneRequest); + EXPECT_EQ(mMidi.getChannel(), 0); + EXPECT_EQ(mMidi.getData1(), 0); + EXPECT_EQ(mMidi.getData2(), 0); + + EXPECT_EQ(mSerial.mTxBuffer.getLength(), 1); + EXPECT_EQ(mSerial.mTxBuffer.read(), 0xf6); +} + +// -- + +void handleClock() +{ + EXPECT_NE(midi, nullptr); + midi->sendRealTime(midi::Clock); +} +void handleStart() +{ + EXPECT_NE(midi, nullptr); + midi->sendRealTime(midi::Start); +} +void handleContinue() +{ + EXPECT_NE(midi, nullptr); + midi->sendRealTime(midi::Continue); +} +void handleStop() +{ + EXPECT_NE(midi, nullptr); + midi->sendRealTime(midi::Stop); +} +void handleActiveSensing() +{ + EXPECT_NE(midi, nullptr); + midi->sendRealTime(midi::ActiveSensing); +} +void handleSystemReset() +{ + EXPECT_NE(midi, nullptr); + midi->sendRealTime(midi::SystemReset); +} + +TEST_F(MidiInputCallbacks, realTime) +{ + mMidi.setHandleClock(handleClock); + mMidi.setHandleStart(handleStart); + mMidi.setHandleContinue(handleContinue); + mMidi.setHandleStop(handleStop); + mMidi.setHandleActiveSensing(handleActiveSensing); + mMidi.setHandleSystemReset(handleSystemReset); + + mMidi.begin(MIDI_CHANNEL_OMNI); + mMidi.turnThruOff(); + + static const unsigned rxSize = 6; + static const byte rxData[rxSize] = { + 0xf8, 0xfa, 0xfb, 0xfc, 0xfe, 0xff + }; + mSerial.mRxBuffer.write(rxData, rxSize); + static const midi::MidiType types[rxSize] = { + midi::Clock, + midi::Start, + midi::Continue, + midi::Stop, + midi::ActiveSensing, + midi::SystemReset, + }; + + for (unsigned i = 0; i < rxSize; ++i) + { + EXPECT_EQ(mMidi.read(), true); + EXPECT_EQ(mMidi.getType(), types[i]); + EXPECT_EQ(mMidi.getChannel(), 0); + EXPECT_EQ(mMidi.getData1(), 0); + EXPECT_EQ(mMidi.getData2(), 0); + EXPECT_EQ(mSerial.mTxBuffer.getLength(), 1); + + const byte read = mSerial.mTxBuffer.read(); + EXPECT_EQ(read, rxData[i]); + EXPECT_EQ(read, types[i]); + } } END_UNNAMED_NAMESPACE From 597a75e6382cf3f0b4f8782e09c4720fed80a192 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Sat, 29 Oct 2016 09:42:47 +0200 Subject: [PATCH 114/138] Keep running status when not sending anything. Fixes #61 --- src/MIDI.hpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/MIDI.hpp b/src/MIDI.hpp index 57bdd32..6011fe5 100644 --- a/src/MIDI.hpp +++ b/src/MIDI.hpp @@ -141,10 +141,6 @@ void MidiInterface::send(MidiType inType, inChannel == MIDI_CHANNEL_OMNI || inType < 0x80) { - if (Settings::UseRunningStatus) - { - mRunningStatus_TX = InvalidType; - } return; // Don't send anything } From 2e816e3e39337a79862d659b4796ac271d7b1b39 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Sat, 29 Oct 2016 09:53:05 +0200 Subject: [PATCH 115/138] Added test for larger SysEx frames. #47 --- .../tests/unit-tests_MidiInputCallbacks.cpp | 50 ++++++++++++++++++- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/test/unit-tests/tests/unit-tests_MidiInputCallbacks.cpp b/test/unit-tests/tests/unit-tests_MidiInputCallbacks.cpp index f8642e2..803e738 100644 --- a/test/unit-tests/tests/unit-tests_MidiInputCallbacks.cpp +++ b/test/unit-tests/tests/unit-tests_MidiInputCallbacks.cpp @@ -13,8 +13,6 @@ BEGIN_UNNAMED_NAMESPACE using namespace testing; USING_NAMESPACE_UNIT_TESTS -typedef test_mocks::SerialMock<32> SerialMock; -typedef midi::MidiInterface MidiInterface; template struct VariableSysExSettings : midi::DefaultSettings @@ -22,6 +20,10 @@ struct VariableSysExSettings : midi::DefaultSettings static const unsigned SysExMaxSize = Size; }; +typedef test_mocks::SerialMock<256> SerialMock; +typedef VariableSysExSettings<256> Settings; +typedef midi::MidiInterface MidiInterface; + MidiInterface* midi; class MidiInputCallbacks : public Test @@ -347,6 +349,50 @@ TEST_F(MidiInputCallbacks, sysEx) EXPECT_THAT(sysExData, ElementsAreArray(rxData)); } +TEST_F(MidiInputCallbacks, sysExLong) +{ + mMidi.setHandleSystemExclusive(handleSysEx); + mMidi.begin(MIDI_CHANNEL_OMNI); + mMidi.turnThruOff(); + + static const unsigned rxSize = 210; + static const byte rxData[rxSize] = { + 0xf0, + 'H','e','l','l','o',',',' ','W','o','r','l','d','!', + 'H','e','l','l','o',',',' ','W','o','r','l','d','!', + 'H','e','l','l','o',',',' ','W','o','r','l','d','!', + 'H','e','l','l','o',',',' ','W','o','r','l','d','!', + 'H','e','l','l','o',',',' ','W','o','r','l','d','!', + 'H','e','l','l','o',',',' ','W','o','r','l','d','!', + 'H','e','l','l','o',',',' ','W','o','r','l','d','!', + 'H','e','l','l','o',',',' ','W','o','r','l','d','!', + 'H','e','l','l','o',',',' ','W','o','r','l','d','!', + 'H','e','l','l','o',',',' ','W','o','r','l','d','!', + 'H','e','l','l','o',',',' ','W','o','r','l','d','!', + 'H','e','l','l','o',',',' ','W','o','r','l','d','!', + 'H','e','l','l','o',',',' ','W','o','r','l','d','!', + 'H','e','l','l','o',',',' ','W','o','r','l','d','!', + 'H','e','l','l','o',',',' ','W','o','r','l','d','!', + 'H','e','l','l','o',',',' ','W','o','r','l','d','!', + 0xf7 + }; + mSerial.mRxBuffer.write(rxData, rxSize); + + for (unsigned i = 0; i < rxSize - 1; ++i) + { + EXPECT_EQ(mMidi.read(), false); + } + EXPECT_EQ(mMidi.read(), true); + EXPECT_EQ(mMidi.getType(), midi::SystemExclusive); + EXPECT_EQ(mMidi.getChannel(), 0); + EXPECT_EQ(mMidi.getSysExArrayLength(), rxSize); + + EXPECT_EQ(unsigned(mSerial.mTxBuffer.getLength()), rxSize); + const std::vector sysExData(mMidi.getSysExArray(), + mMidi.getSysExArray() + rxSize); + EXPECT_THAT(sysExData, ElementsAreArray(rxData)); +} + // -- void handleMtcQuarterFrame(byte inData) From f653d21ca11e431abf908063117e68e71c00d367 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Sat, 29 Oct 2016 12:20:54 +0200 Subject: [PATCH 116/138] Thru tests. #55 --- test/unit-tests/tests/unit-tests_MidiThru.cpp | 265 ++++++++++++++++++ 1 file changed, 265 insertions(+) diff --git a/test/unit-tests/tests/unit-tests_MidiThru.cpp b/test/unit-tests/tests/unit-tests_MidiThru.cpp index 8f301dc..62c3e38 100644 --- a/test/unit-tests/tests/unit-tests_MidiThru.cpp +++ b/test/unit-tests/tests/unit-tests_MidiThru.cpp @@ -15,6 +15,7 @@ using namespace testing; USING_NAMESPACE_UNIT_TESTS typedef test_mocks::SerialMock<32> SerialMock; typedef midi::MidiInterface MidiInterface; +typedef std::vector Buffer; template struct VariableSysExSettings : midi::DefaultSettings @@ -82,4 +83,268 @@ TEST(MidiThru, setGet) EXPECT_EQ(midi.getFilterMode(), midi::Thru::Off); } +TEST(MidiThru, off) +{ + SerialMock serial; + MidiInterface midi(serial); + + midi.begin(MIDI_CHANNEL_OMNI); + midi.turnThruOff(); + + static const unsigned rxSize = 5; + static const byte rxData[rxSize] = { 0x9b, 12, 34, 56, 78 }; + serial.mRxBuffer.write(rxData, rxSize); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + + EXPECT_EQ(serial.mTxBuffer.getLength(), 0); +} + +TEST(MidiThru, full) +{ + SerialMock serial; + MidiInterface midi(serial); + Buffer buffer; + + midi.begin(MIDI_CHANNEL_OMNI); + midi.setThruFilterMode(midi::Thru::Full); + + static const unsigned rxSize = 6; + static const byte rxData[rxSize] = { 0x9b, 12, 34, 0x9c, 56, 78 }; + serial.mRxBuffer.write(rxData, rxSize); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(serial.mTxBuffer.getLength(), 0); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(serial.mTxBuffer.getLength(), 0); + EXPECT_EQ(midi.read(), true); + + buffer.clear(); + buffer.resize(3); + EXPECT_EQ(serial.mTxBuffer.getLength(), 3); + serial.mTxBuffer.read(&buffer[0], 3); + EXPECT_THAT(buffer, ElementsAreArray({ + 0x9b, 12, 34 + })); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(serial.mTxBuffer.getLength(), 0); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(serial.mTxBuffer.getLength(), 0); + EXPECT_EQ(midi.read(), true); + + buffer.clear(); + buffer.resize(3); + EXPECT_EQ(serial.mTxBuffer.getLength(), 3); + serial.mTxBuffer.read(&buffer[0], 3); + EXPECT_THAT(buffer, ElementsAreArray({ + 0x9c, 56, 78 + })); +} + +TEST(MidiThru, sameChannel) +{ + SerialMock serial; + MidiInterface midi(serial); + Buffer buffer; + + midi.begin(12); + midi.setThruFilterMode(midi::Thru::SameChannel); + + static const unsigned rxSize = 6; + static const byte rxData[rxSize] = { 0x9b, 12, 34, 0x9c, 56, 78 }; + serial.mRxBuffer.write(rxData, rxSize); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + + buffer.clear(); + buffer.resize(3); + EXPECT_EQ(serial.mTxBuffer.getLength(), 3); + serial.mTxBuffer.read(&buffer[0], 3); + EXPECT_THAT(buffer, ElementsAreArray({ + 0x9b, 12, 34 + })); +} + +TEST(MidiThru, sameChannelOmni) // Acts like full +{ + SerialMock serial; + MidiInterface midi(serial); + Buffer buffer; + + midi.begin(MIDI_CHANNEL_OMNI); + midi.setThruFilterMode(midi::Thru::SameChannel); + + static const unsigned rxSize = 6; + static const byte rxData[rxSize] = { 0x9b, 12, 34, 0x9c, 56, 78 }; + serial.mRxBuffer.write(rxData, rxSize); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(serial.mTxBuffer.getLength(), 0); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(serial.mTxBuffer.getLength(), 0); + EXPECT_EQ(midi.read(), true); + + buffer.clear(); + buffer.resize(3); + EXPECT_EQ(serial.mTxBuffer.getLength(), 3); + serial.mTxBuffer.read(&buffer[0], 3); + EXPECT_THAT(buffer, ElementsAreArray({ + 0x9b, 12, 34 + })); + + buffer.clear(); + buffer.resize(3); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(serial.mTxBuffer.getLength(), 0); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(serial.mTxBuffer.getLength(), 0); + EXPECT_EQ(midi.read(), true); + + EXPECT_EQ(serial.mTxBuffer.getLength(), 3); // Not using TX running status + serial.mTxBuffer.read(&buffer[0], 3); + EXPECT_THAT(buffer, ElementsAreArray({ + 0x9c, 56, 78 + })); +} + +TEST(MidiThru, differentChannel) +{ + SerialMock serial; + MidiInterface midi(serial); + Buffer buffer; + + midi.begin(12); + midi.setThruFilterMode(midi::Thru::DifferentChannel); + + static const unsigned rxSize = 6; + static const byte rxData[rxSize] = { 0x9b, 12, 34, 0x9c, 56, 78 }; + serial.mRxBuffer.write(rxData, rxSize); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + + buffer.clear(); + buffer.resize(3); + EXPECT_EQ(serial.mTxBuffer.getLength(), 3); + serial.mTxBuffer.read(&buffer[0], 3); + EXPECT_THAT(buffer, ElementsAreArray({ + 0x9c, 56, 78 + })); +} + +TEST(MidiThru, differentChannelOmni) // Acts like off +{ + SerialMock serial; + MidiInterface midi(serial); + Buffer buffer; + + midi.begin(MIDI_CHANNEL_OMNI); + midi.setThruFilterMode(midi::Thru::DifferentChannel); + + static const unsigned rxSize = 6; + static const byte rxData[rxSize] = { 0x9b, 12, 34, 0x9c, 56, 78 }; + serial.mRxBuffer.write(rxData, rxSize); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(serial.mTxBuffer.getLength(), 0); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(serial.mTxBuffer.getLength(), 0); + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(serial.mTxBuffer.getLength(), 0); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(serial.mTxBuffer.getLength(), 0); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(serial.mTxBuffer.getLength(), 0); + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(serial.mTxBuffer.getLength(), 0); +} + +TEST(MidiThru, multiByteThru) +{ + typedef VariableSettings Settings; + typedef test_mocks::SerialMock<32> SerialMock; + typedef midi::MidiInterface MidiInterface; + + SerialMock serial; + MidiInterface midi(serial); + Buffer buffer; + + midi.begin(MIDI_CHANNEL_OMNI); + midi.setThruFilterMode(midi::Thru::Full); + + static const unsigned rxSize = 6; + static const byte rxData[rxSize] = { 0x9b, 12, 34, 56, 78 }; + serial.mRxBuffer.write(rxData, rxSize); + + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(serial.mTxBuffer.getLength(), 3); + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(serial.mTxBuffer.getLength(), 6); + + buffer.clear(); + buffer.resize(6); + serial.mTxBuffer.read(&buffer[0], 6); + EXPECT_THAT(buffer, ElementsAreArray({ + 0x9b, 12, 34, 0x9b, 56, 78 + })); +} + +TEST(MidiThru, withTxRunningStatus) +{ + typedef VariableSettings Settings; + typedef test_mocks::SerialMock<32> SerialMock; + typedef midi::MidiInterface MidiInterface; + + SerialMock serial; + MidiInterface midi(serial); + Buffer buffer; + + midi.begin(MIDI_CHANNEL_OMNI); + midi.setThruFilterMode(midi::Thru::Full); + + static const unsigned rxSize = 5; + static const byte rxData[rxSize] = { 0x9b, 12, 34, 56, 78 }; + serial.mRxBuffer.write(rxData, rxSize); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(serial.mTxBuffer.getLength(), 0); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(serial.mTxBuffer.getLength(), 0); + EXPECT_EQ(midi.read(), true); + + buffer.clear(); + buffer.resize(3); + EXPECT_EQ(serial.mTxBuffer.getLength(), 3); + serial.mTxBuffer.read(&buffer[0], 3); + EXPECT_THAT(buffer, ElementsAreArray({ + 0x9b, 12, 34 + })); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(serial.mTxBuffer.getLength(), 0); + EXPECT_EQ(midi.read(), true); + + buffer.clear(); + buffer.resize(2); + EXPECT_EQ(serial.mTxBuffer.getLength(), 2); + serial.mTxBuffer.read(&buffer[0], 2); + EXPECT_THAT(buffer, ElementsAreArray({ + 56, 78 + })); +} + END_UNNAMED_NAMESPACE From 53fdcc79b0ce61da4a1e3b864331bcd1a4ac53d5 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Sat, 29 Oct 2016 14:09:06 +0200 Subject: [PATCH 117/138] Testing invalid Thru mode. --- test/unit-tests/tests/unit-tests_MidiThru.cpp | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/test/unit-tests/tests/unit-tests_MidiThru.cpp b/test/unit-tests/tests/unit-tests_MidiThru.cpp index 62c3e38..8cca5f4 100644 --- a/test/unit-tests/tests/unit-tests_MidiThru.cpp +++ b/test/unit-tests/tests/unit-tests_MidiThru.cpp @@ -347,4 +347,25 @@ TEST(MidiThru, withTxRunningStatus) })); } +TEST(MidiThru, invalidMode) +{ + SerialMock serial; + MidiInterface midi(serial); + + midi.begin(MIDI_CHANNEL_OMNI); + midi.setThruFilterMode(midi::Thru::Mode(42)); + + static const unsigned rxSize = 6; + static const byte rxData[rxSize] = { 0x9b, 12, 34, 0x9c, 56, 78 }; + serial.mRxBuffer.write(rxData, rxSize); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + + EXPECT_EQ(serial.mTxBuffer.getLength(), 0); +} + END_UNNAMED_NAMESPACE From 2df247489ae8c856308e4648b1ac6352632e37c5 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Sat, 29 Oct 2016 15:45:53 +0200 Subject: [PATCH 118/138] Testing running status reset. --- .../tests/unit-tests_MidiOutput.cpp | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/test/unit-tests/tests/unit-tests_MidiOutput.cpp b/test/unit-tests/tests/unit-tests_MidiOutput.cpp index 59cd993..be8c228 100644 --- a/test/unit-tests/tests/unit-tests_MidiOutput.cpp +++ b/test/unit-tests/tests/unit-tests_MidiOutput.cpp @@ -739,4 +739,102 @@ TEST(MidiOutput, NRPN) } } +TEST(MidiOutput, runningStatusCancellation) +{ + typedef test_mocks::SerialMock<32> SerialMock; + typedef VariableSettings Settings; + typedef midi::MidiInterface MidiInterface; + + SerialMock serial; + MidiInterface midi(serial); + std::vector buffer; + + static const unsigned sysExLength = 13; + static const byte sysEx[sysExLength] = { + 'H','e','l','l','o',',',' ','W','o','r','l','d','!' + }; + + midi.begin(); + + midi.sendNoteOn(12, 34, 1); + midi.sendNoteOn(56, 78, 1); + EXPECT_EQ(serial.mTxBuffer.getLength(), 5); + + buffer.clear(); + buffer.resize(5); + serial.mTxBuffer.read(&buffer[0], 5); + EXPECT_THAT(buffer, ElementsAreArray({ + 0x90, 12, 34, 56, 78 + })); + + midi.sendRealTime(midi::Clock); // Should not reset running status. + midi.sendNoteOn(12, 34, 1); + EXPECT_EQ(serial.mTxBuffer.getLength(), 3); + buffer.clear(); + buffer.resize(3); + serial.mTxBuffer.read(&buffer[0], 3); + EXPECT_THAT(buffer, ElementsAreArray({ + 0xf8, 12, 34 + })); + + midi.sendSysEx(sysExLength, sysEx); // Should reset running status. + midi.sendNoteOn(12, 34, 1); + EXPECT_EQ(serial.mTxBuffer.getLength(), 18); + buffer.clear(); + buffer.resize(18); + serial.mTxBuffer.read(&buffer[0], 18); + { + static const byte expected[] = { + 0xf0, 'H','e','l','l','o',',',' ','W','o','r','l','d','!', 0xf7, + 0x90, 12, 34 + }; + EXPECT_THAT(buffer, ElementsAreArray(expected)); + } + + midi.sendTimeCodeQuarterFrame(42); // Should reset running status. + midi.sendNoteOn(12, 34, 1); + EXPECT_EQ(serial.mTxBuffer.getLength(), 5); + buffer.clear(); + buffer.resize(5); + serial.mTxBuffer.read(&buffer[0], 5); + EXPECT_THAT(buffer, ElementsAreArray({ + 0xf1, 42, + 0x90, 12, 34 + })); + + midi.sendSongPosition(42); // Should reset running status. + midi.sendNoteOn(12, 34, 1); + EXPECT_EQ(serial.mTxBuffer.getLength(), 6); + buffer.clear(); + buffer.resize(6); + serial.mTxBuffer.read(&buffer[0], 6); + EXPECT_THAT(buffer, ElementsAreArray({ + 0xf2, 42, 0, + 0x90, 12, 34 + })); + + midi.sendSongSelect(42); // Should reset running status. + midi.sendNoteOn(12, 34, 1); + EXPECT_EQ(serial.mTxBuffer.getLength(), 5); + buffer.clear(); + buffer.resize(5); + serial.mTxBuffer.read(&buffer[0], 5); + EXPECT_THAT(buffer, ElementsAreArray({ + 0xf3, 42, + 0x90, 12, 34 + })); + + midi.sendTuneRequest(); // Should reset running status. + midi.sendNoteOn(12, 34, 1); + EXPECT_EQ(serial.mTxBuffer.getLength(), 4); + buffer.clear(); + buffer.resize(4); + serial.mTxBuffer.read(&buffer[0], 4); + EXPECT_THAT(buffer, ElementsAreArray({ + 0xf6, + 0x90, 12, 34 + })); + +} + END_UNNAMED_NAMESPACE From 4ab8728c67228de07c5b3fb4ce2a2dbbdf630728 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Sat, 29 Oct 2016 16:09:04 +0200 Subject: [PATCH 119/138] Removed unreacheable code, inlined stuff. --- src/MIDI.hpp | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/MIDI.hpp b/src/MIDI.hpp index 6011fe5..06a96c2 100644 --- a/src/MIDI.hpp +++ b/src/MIDI.hpp @@ -882,7 +882,7 @@ bool MidiInterface::parse() } default: - break; + break; // LCOV_EXCL_LINE - Coverage blind spot } } @@ -983,9 +983,6 @@ inline bool MidiInterface::inputFilter(Channel inChannel) // This method handles recognition of channel // (to know if the message is destinated to the Arduino) - if (mMessage.type == InvalidType) - return false; - // First, check if the received message is Channel if (mMessage.type >= NoteOff && mMessage.type <= PitchBend) { @@ -1265,36 +1262,33 @@ void MidiInterface::launchCallback() @see Thru::Mode */ template -void MidiInterface::setThruFilterMode(Thru::Mode inThruFilterMode) +inline void MidiInterface::setThruFilterMode(Thru::Mode inThruFilterMode) { mThruFilterMode = inThruFilterMode; - if (mThruFilterMode != Thru::Off) - mThruActivated = true; - else - mThruActivated = false; + mThruActivated = mThruFilterMode != Thru::Off; } template -Thru::Mode MidiInterface::getFilterMode() const +inline Thru::Mode MidiInterface::getFilterMode() const { return mThruFilterMode; } template -bool MidiInterface::getThruState() const +inline bool MidiInterface::getThruState() const { return mThruActivated; } template -void MidiInterface::turnThruOn(Thru::Mode inThruFilterMode) +inline void MidiInterface::turnThruOn(Thru::Mode inThruFilterMode) { mThruActivated = true; mThruFilterMode = inThruFilterMode; } template -void MidiInterface::turnThruOff() +inline void MidiInterface::turnThruOff() { mThruActivated = false; mThruFilterMode = Thru::Off; @@ -1387,8 +1381,9 @@ void MidiInterface::thruFilter(Channel inChannel) case TimeCodeQuarterFrame: sendTimeCodeQuarterFrame(mMessage.data1,mMessage.data2); break; + default: - break; + break; // LCOV_EXCL_LINE - Unreacheable code, but prevents unhandled case warning. } } } From 4eee744b3586ed135fba4bdde86a572259fdc8e9 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Sat, 29 Oct 2016 16:21:06 +0200 Subject: [PATCH 120/138] More unreacheable code hunt. --- src/MIDI.hpp | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/src/MIDI.hpp b/src/MIDI.hpp index 06a96c2..3e66a98 100644 --- a/src/MIDI.hpp +++ b/src/MIDI.hpp @@ -792,17 +792,7 @@ bool MidiInterface::parse() mMessage.type = getTypeFromStatusByte(mPendingMessage[0]); mMessage.channel = getChannelFromStatusByte(mPendingMessage[0]); mMessage.data1 = mPendingMessage[1]; - - // Save data2 only if applicable - if (mPendingMessageExpectedLenght == 3) - { - // todo: This code seems unreacheable, to clean up. - mMessage.data2 = mPendingMessage[2]; - } - else - { - mMessage.data2 = 0; - } + mMessage.data2 = 0; // Completed new message has 1 data byte mPendingMessageIndex = 0; mPendingMessageExpectedLenght = 0; @@ -914,10 +904,7 @@ bool MidiInterface::parse() mMessage.data1 = mPendingMessage[1]; // Save data2 only if applicable - if (mPendingMessageExpectedLenght == 3) - mMessage.data2 = mPendingMessage[2]; - else - mMessage.data2 = 0; + mMessage.data2 = mPendingMessageExpectedLenght == 3 ? mPendingMessage[2] : 0; // Reset local variables mPendingMessageIndex = 0; @@ -1240,9 +1227,10 @@ void MidiInterface::launchCallback() case TuneRequest: if (mTuneRequestCallback != 0) mTuneRequestCallback(); break; case SystemReset: if (mSystemResetCallback != 0) mSystemResetCallback(); break; + case InvalidType: default: - break; + break; // LCOV_EXCL_LINE - Unreacheable code, but prevents unhandled case warning. } } From 0fabf63d49c5a568f68e76d6ebd98a4efdc3a00d Mon Sep 17 00:00:00 2001 From: Francois Best Date: Sun, 30 Oct 2016 09:09:06 +0100 Subject: [PATCH 121/138] Added reference to issue #60. --- examples/RPN_NRPN/RPN_NRPN.ino | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/RPN_NRPN/RPN_NRPN.ino b/examples/RPN_NRPN/RPN_NRPN.ino index 69e0569..fcd94ca 100644 --- a/examples/RPN_NRPN/RPN_NRPN.ino +++ b/examples/RPN_NRPN/RPN_NRPN.ino @@ -8,6 +8,9 @@ MIDI_CREATE_DEFAULT_INSTANCE(); The complexity of this example resides in the fact that keeping a state of all the 16384 * 2 RPN/NRPN values would not fit in memory. As we're only interested in a few of them, we use a separate state map. + +If you'd like to go further, have a look at this thread: +https://github.com/FortySevenEffects/arduino_midi_library/issues/60 */ template From 437d5ebce0e073e2fdaa0d336e3fa465c99dffdd Mon Sep 17 00:00:00 2001 From: Francois Best Date: Sun, 30 Oct 2016 09:50:01 +0100 Subject: [PATCH 122/138] Bump version in sources. --- src/MIDI.cpp | 2 +- src/MIDI.h | 2 +- src/MIDI.hpp | 2 +- src/midi_Defs.h | 2 +- src/midi_Message.h | 2 +- src/midi_Namespace.h | 2 +- src/midi_RingBuffer.h | 2 +- src/midi_RingBuffer.hpp | 28 ++++++++++++++++++++++++++++ src/midi_Settings.h | 2 +- src/midi_UsbDefs.h | 2 +- src/midi_UsbTransport.h | 2 +- src/midi_UsbTransport.hpp | 28 ++++++++++++++++++++++++++++ 12 files changed, 66 insertions(+), 10 deletions(-) diff --git a/src/MIDI.cpp b/src/MIDI.cpp index 9d53668..d85accc 100644 --- a/src/MIDI.cpp +++ b/src/MIDI.cpp @@ -2,7 +2,7 @@ * @file MIDI.cpp * Project Arduino MIDI Library * @brief MIDI Library for the Arduino - * @version 4.2 + * @version 4.3 * @author Francois Best * @date 24/02/11 * @license MIT - Copyright (c) 2015 Francois Best diff --git a/src/MIDI.h b/src/MIDI.h index 15fe359..22a84c5 100644 --- a/src/MIDI.h +++ b/src/MIDI.h @@ -2,7 +2,7 @@ * @file MIDI.h * Project Arduino MIDI Library * @brief MIDI Library for the Arduino - * @version 4.2 + * @version 4.3 * @author Francois Best * @date 24/02/11 * @license MIT - Copyright (c) 2015 Francois Best diff --git a/src/MIDI.hpp b/src/MIDI.hpp index 3e66a98..0df7be1 100644 --- a/src/MIDI.hpp +++ b/src/MIDI.hpp @@ -2,7 +2,7 @@ * @file MIDI.hpp * Project Arduino MIDI Library * @brief MIDI Library for the Arduino - Inline implementations - * @version 4.2 + * @version 4.3 * @author Francois Best * @date 24/02/11 * @license MIT - Copyright (c) 2015 Francois Best diff --git a/src/midi_Defs.h b/src/midi_Defs.h index 6070128..16ca1f2 100644 --- a/src/midi_Defs.h +++ b/src/midi_Defs.h @@ -2,7 +2,7 @@ * @file midi_Defs.h * Project Arduino MIDI Library * @brief MIDI Library for the Arduino - Definitions - * @version 4.2 + * @version 4.3 * @author Francois Best * @date 24/02/11 * @license MIT - Copyright (c) 2015 Francois Best diff --git a/src/midi_Message.h b/src/midi_Message.h index bbe345f..3dcd7da 100644 --- a/src/midi_Message.h +++ b/src/midi_Message.h @@ -2,7 +2,7 @@ * @file midi_Message.h * Project Arduino MIDI Library * @brief MIDI Library for the Arduino - Message struct definition - * @version 4.2 + * @version 4.3 * @author Francois Best * @date 11/06/14 * @license MIT - Copyright (c) 2015 Francois Best diff --git a/src/midi_Namespace.h b/src/midi_Namespace.h index efd2395..c241f95 100644 --- a/src/midi_Namespace.h +++ b/src/midi_Namespace.h @@ -2,7 +2,7 @@ * @file midi_Namespace.h * Project Arduino MIDI Library * @brief MIDI Library for the Arduino - Namespace declaration - * @version 4.2 + * @version 4.3 * @author Francois Best * @date 24/02/11 * @license MIT - Copyright (c) 2015 Francois Best diff --git a/src/midi_RingBuffer.h b/src/midi_RingBuffer.h index ea6884a..ef66b67 100644 --- a/src/midi_RingBuffer.h +++ b/src/midi_RingBuffer.h @@ -2,7 +2,7 @@ * @file midi_RingBuffer.h * Project Arduino MIDI Library * @brief MIDI Library for Arduino - Ring Buffer - * @version 4.2 + * @version 4.3 * @author Francois Best * @date 10/10/2016 * @license MIT - Copyright (c) 2016 Francois Best diff --git a/src/midi_RingBuffer.hpp b/src/midi_RingBuffer.hpp index b3e073e..3dc6750 100644 --- a/src/midi_RingBuffer.hpp +++ b/src/midi_RingBuffer.hpp @@ -1,3 +1,31 @@ +/*! + * @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 diff --git a/src/midi_Settings.h b/src/midi_Settings.h index 8e6ac5b..c25a707 100644 --- a/src/midi_Settings.h +++ b/src/midi_Settings.h @@ -2,7 +2,7 @@ * @file midi_Settings.h * Project Arduino MIDI Library * @brief MIDI Library for the Arduino - Settings - * @version 4.2 + * @version 4.3 * @author Francois Best * @date 24/02/11 * @license MIT - Copyright (c) 2015 Francois Best diff --git a/src/midi_UsbDefs.h b/src/midi_UsbDefs.h index 5e607cf..8a5ffd5 100644 --- a/src/midi_UsbDefs.h +++ b/src/midi_UsbDefs.h @@ -2,7 +2,7 @@ * @file midi_UsbDefs.h * Project Arduino MIDI Library * @brief MIDI Library for the Arduino - Definitions - * @version 4.2 + * @version 4.3 * @author Francois Best * @date 24/02/11 * @license MIT - Copyright (c) 2016 Francois Best diff --git a/src/midi_UsbTransport.h b/src/midi_UsbTransport.h index 8ea9044..cffe454 100644 --- a/src/midi_UsbTransport.h +++ b/src/midi_UsbTransport.h @@ -2,7 +2,7 @@ * @file midi_UsbTransport.h * Project Arduino MIDI Library * @brief MIDI Library for the Arduino - Transport layer for USB MIDI - * @version 4.2 + * @version 4.3 * @author Francois Best * @date 10/10/2016 * @license MIT - Copyright (c) 2016 Francois Best diff --git a/src/midi_UsbTransport.hpp b/src/midi_UsbTransport.hpp index 6849e59..ed53578 100644 --- a/src/midi_UsbTransport.hpp +++ b/src/midi_UsbTransport.hpp @@ -1,3 +1,31 @@ +/*! + * @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 From aa35573ca60f58e3105bb0c80496570107bc23ce Mon Sep 17 00:00:00 2001 From: Francois Best Date: Sun, 30 Oct 2016 09:55:30 +0100 Subject: [PATCH 123/138] Added version defines, might be useful later on. --- src/midi_Defs.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/midi_Defs.h b/src/midi_Defs.h index 16ca1f2..4c36b13 100644 --- a/src/midi_Defs.h +++ b/src/midi_Defs.h @@ -39,6 +39,11 @@ 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 From afbb2f296deaa800910419308e07b396eddf04a2 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Tue, 1 Nov 2016 23:47:33 +0100 Subject: [PATCH 124/138] Switched to platformio for examples building. --- .travis.yml | 121 ++++++++++++++++++++++++++++------------------------ 1 file changed, 65 insertions(+), 56 deletions(-) diff --git a/.travis.yml b/.travis.yml index 64c5b3c..45e5d8e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,82 +1,91 @@ # Kudos to these guys: -# http://genbattle.bitbucket.org/blog/2016/01/17/c++-travis-ci/ -# https://github.com/ticapix/arduino-toolbox/blob/master/.travis.yml # https://github.com/Return-To-The-Roots/s25client/blob/master/.travis.yml +# http://docs.platformio.org/en/stable/ci/travis.html sudo: false -language: cpp +language: python os: - - linux + - linux -compiler: - - g++ - - clang +python: + - "2.7" + +# Cache PlatformIO packages using Travis CI container-based infrastructure +cache: + directories: + - "~/.platformio" env: - - BUILD_TYPE=Debug + 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 + - PLATFORMIO_CI_SRC=examples/RPN_NRPN + - PLATFORMIO_CI_SRC=examples/SimpleSynth addons: - apt: - sources: - - ubuntu-toolchain-r-test - - llvm-toolchain-precise-3.5 - packages: - - g++-4.8 - - clang-3.5 - - llvm-3.5 - - cmake - -#before_install: -# - source <(curl -SLs https://raw.githubusercontent.com/fortyseveneffects/travis-ci-arduino/master/install.sh) + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-4.8 + - cmake install: - # Enable coverage analysis only for GCC - - | - if [ "$CXX" = "g++" ]; then - # GCov 4.6 cannot handle the file structure - export CXX="g++-4.8" - export GCOV="gcov-4.8" + - | + 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 + # 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 - export GCOV="gcov" # Just to have anything valid - export GENERATE_COVERAGE=0 + # Install PlatformIO + pip install -U platformio fi - # Use clang 3.5 - - if [ "$CXX" = "clang++" ]; then export CXX="clang++-3.5"; export CC="clang-3.5"; fi - # - arduino --install-library "MIDIUSB" script: - # Build examples with Arduino IDE on each available platform / board - # - build_main_platforms + # 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 and run unit tests with regular C++ compiler - - 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 + # Build current example + - | + if [ ! "${BUILD_UNIT_TESTS}" ]; then + platformio ci --lib="." --board=uno --board="due" --board="zero" --board="leonardo" + 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 + # 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 + email: false From 251cf54ba894ba769b31bcf70358ece314d53117 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Tue, 1 Nov 2016 23:53:28 +0100 Subject: [PATCH 125/138] Try and fix multiline commands. --- .travis.yml | 68 ++++++++++++++++++++++++++--------------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/.travis.yml b/.travis.yml index 45e5d8e..2d8f9e6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,52 +40,52 @@ addons: install: - | - if [ "$BUILD_UNIT_TESTS" ]; then - # GCov 4.6 cannot handle the file structure - export CXX="g++-4.8" - export GCOV="gcov-4.8" + 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 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 + # 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 + 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 - platformio ci --lib="." --board=uno --board="due" --board="zero" --board="leonardo" - fi + if [ ! "${BUILD_UNIT_TESTS}" ]; then + platformio ci --lib="." --board=uno --board="due" --board="zero" --board="leonardo" + 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 + 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 From 29c705fbfa28240bd91bff8477eb2489d970775a Mon Sep 17 00:00:00 2001 From: Francois Best Date: Wed, 2 Nov 2016 00:04:07 +0100 Subject: [PATCH 126/138] Cleanup. --- examples/MidiUSB/avr.test.skip | 0 examples/MidiUSB/sam.test.skip | 0 examples/MidiUSB/samd.test.skip | 0 3 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 examples/MidiUSB/avr.test.skip delete mode 100644 examples/MidiUSB/sam.test.skip delete mode 100644 examples/MidiUSB/samd.test.skip diff --git a/examples/MidiUSB/avr.test.skip b/examples/MidiUSB/avr.test.skip deleted file mode 100644 index e69de29..0000000 diff --git a/examples/MidiUSB/sam.test.skip b/examples/MidiUSB/sam.test.skip deleted file mode 100644 index e69de29..0000000 diff --git a/examples/MidiUSB/samd.test.skip b/examples/MidiUSB/samd.test.skip deleted file mode 100644 index e69de29..0000000 From 253e41acc6b68606689765c9b1d1431799027e02 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Wed, 2 Nov 2016 00:05:27 +0100 Subject: [PATCH 127/138] Add dep to MidiUSB for specific example & guards for non-usb boards. --- .travis.yml | 4 ++-- examples/MidiUSB/MidiUSB.ino | 8 +++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2d8f9e6..45b6ff1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,7 +26,7 @@ env: - PLATFORMIO_CI_SRC=examples/Callbacks - PLATFORMIO_CI_SRC=examples/DualMerger - PLATFORMIO_CI_SRC=examples/Input - - PLATFORMIO_CI_SRC=examples/MidiUSB + - PLATFORMIO_CI_SRC=examples/MidiUSB PLATFORMIO_CI_EXTRA_ARGS="--lib=external/midi-usb/src" - PLATFORMIO_CI_SRC=examples/RPN_NRPN - PLATFORMIO_CI_SRC=examples/SimpleSynth @@ -74,7 +74,7 @@ script: # Build current example - | if [ ! "${BUILD_UNIT_TESTS}" ]; then - platformio ci --lib="." --board=uno --board="due" --board="zero" --board="leonardo" + platformio ci --lib="." --board=uno --board="due" --board="zero" --board="leonardo" $PLATFORMIO_CI_EXTRA_ARGS fi after_success: diff --git a/examples/MidiUSB/MidiUSB.ino b/examples/MidiUSB/MidiUSB.ino index d51eccd..2f677aa 100644 --- a/examples/MidiUSB/MidiUSB.ino +++ b/examples/MidiUSB/MidiUSB.ino @@ -1,4 +1,6 @@ #include + +#if defined(USBCON) #include static const unsigned sUsbTransportBufferSize = 16; @@ -8,6 +10,10 @@ 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) @@ -36,4 +42,4 @@ void setup() { void loop() { MIDI.read(); -} \ No newline at end of file +} From b20a40ed9a104b431967f74ecb701f9561263340 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Wed, 2 Nov 2016 00:19:05 +0100 Subject: [PATCH 128/138] Fix USB requirements. --- .travis.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 45b6ff1..79b2fe6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,7 +26,7 @@ env: - PLATFORMIO_CI_SRC=examples/Callbacks - PLATFORMIO_CI_SRC=examples/DualMerger - PLATFORMIO_CI_SRC=examples/Input - - PLATFORMIO_CI_SRC=examples/MidiUSB PLATFORMIO_CI_EXTRA_ARGS="--lib=external/midi-usb/src" + - PLATFORMIO_CI_SRC=examples/MidiUSB REQUIRES_USB=1 - PLATFORMIO_CI_SRC=examples/RPN_NRPN - PLATFORMIO_CI_SRC=examples/SimpleSynth @@ -74,7 +74,11 @@ script: # Build current example - | if [ ! "${BUILD_UNIT_TESTS}" ]; then - platformio ci --lib="." --board=uno --board="due" --board="zero" --board="leonardo" $PLATFORMIO_CI_EXTRA_ARGS + if [ "${REQUIRES_USB}"]; then + platformio ci --lib="." --lib=external/midi-usb --board="due" --board="zero" --board="leonardo" + else + platformio ci --lib="." --board=uno --board="due" --board="zero" --board="leonardo" + fi fi after_success: From 7d6cd37ec3ce2ffd8e40c08792f855ef6692c1b4 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Wed, 2 Nov 2016 08:21:06 +0100 Subject: [PATCH 129/138] Fix space. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 79b2fe6..48d52e1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -74,7 +74,7 @@ script: # Build current example - | if [ ! "${BUILD_UNIT_TESTS}" ]; then - if [ "${REQUIRES_USB}"]; then + if [ "${REQUIRES_USB}" ]; then platformio ci --lib="." --lib=external/midi-usb --board="due" --board="zero" --board="leonardo" else platformio ci --lib="." --board=uno --board="due" --board="zero" --board="leonardo" From cfffdbea26f4552d107d5a726b571c3c3182a783 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Wed, 2 Nov 2016 09:02:00 +0100 Subject: [PATCH 130/138] Fix shadowing warnings. --- .../unit-tests/tests/unit-tests_MidiInput.cpp | 20 +++++----- .../tests/unit-tests_MidiOutput.cpp | 37 +++++++++---------- test/unit-tests/tests/unit-tests_MidiThru.cpp | 11 +++--- 3 files changed, 32 insertions(+), 36 deletions(-) diff --git a/test/unit-tests/tests/unit-tests_MidiInput.cpp b/test/unit-tests/tests/unit-tests_MidiInput.cpp index 725eae8..38d5c9f 100644 --- a/test/unit-tests/tests/unit-tests_MidiInput.cpp +++ b/test/unit-tests/tests/unit-tests_MidiInput.cpp @@ -165,10 +165,10 @@ TEST(MidiInput, inputDisabled) TEST(MidiInput, multiByteParsing) { typedef VariableSettings Settings; - typedef midi::MidiInterface MidiInterface; + typedef midi::MidiInterface MultiByteMidiInterface; SerialMock serial; - MidiInterface midi(serial); + MultiByteMidiInterface midi(serial); static const unsigned rxSize = 3; static const byte rxData[rxSize] = { 0x9b, 12, 34 }; midi.begin(12); @@ -486,11 +486,11 @@ TEST(MidiInput, afterTouchChannel) TEST(MidiInput, sysExWithinBufferSize) { typedef VariableSysExSettings<1024> Settings; - typedef test_mocks::SerialMock<2048> SerialMock; - typedef midi::MidiInterface MidiInterface; + typedef test_mocks::SerialMock<2048> LargerSerialMock; + typedef midi::MidiInterface LargerMidiInterface; - SerialMock serial; - MidiInterface midi(serial); + LargerSerialMock serial; + LargerMidiInterface midi(serial); // Short Frame < 256 { @@ -553,10 +553,10 @@ TEST(MidiInput, sysExWithinBufferSize) TEST(MidiInput, sysExOverBufferSize) { typedef VariableSysExSettings<8> Settings; - typedef midi::MidiInterface MidiInterface; + typedef midi::MidiInterface SmallMidiInterface; SerialMock serial; - MidiInterface midi(serial); + SmallMidiInterface midi(serial); static const unsigned frameLength = 15; static const byte frame[frameLength] = { @@ -907,10 +907,10 @@ TEST(MidiInput, strayUndefinedOneByteParsing) TEST(MidiInput, strayUndefinedMultiByteParsing) { typedef VariableSettings Settings; - typedef midi::MidiInterface MidiInterface; + typedef midi::MidiInterface MultiByteMidiInterface; SerialMock serial; - MidiInterface midi(serial); + MultiByteMidiInterface midi(serial); static const unsigned rxSize = 4; static const byte rxData[rxSize] = { diff --git a/test/unit-tests/tests/unit-tests_MidiOutput.cpp b/test/unit-tests/tests/unit-tests_MidiOutput.cpp index be8c228..a885984 100644 --- a/test/unit-tests/tests/unit-tests_MidiOutput.cpp +++ b/test/unit-tests/tests/unit-tests_MidiOutput.cpp @@ -54,10 +54,10 @@ TEST(MidiOutput, sendGenericSingle) TEST(MidiOutput, sendGenericWithRunningStatus) { typedef VariableSettings Settings; - typedef midi::MidiInterface MidiInterface; + typedef midi::MidiInterface RsMidiInterface; SerialMock serial; - MidiInterface midi(serial); + RsMidiInterface midi(serial); Buffer buffer; buffer.resize(5); @@ -74,10 +74,10 @@ TEST(MidiOutput, sendGenericWithRunningStatus) TEST(MidiOutput, sendGenericWithoutRunningStatus) { typedef VariableSettings Settings; // No running status - typedef midi::MidiInterface MidiInterface; + typedef midi::MidiInterface NoRsMidiInterface; SerialMock serial; - MidiInterface midi(serial); + NoRsMidiInterface midi(serial); Buffer buffer; buffer.resize(6); @@ -301,12 +301,11 @@ TEST(MidiOutput, sendAfterTouchPoly) TEST(MidiOutput, sendSysEx) { - typedef test_mocks::SerialMock<1024> SerialMock; - typedef midi::MidiInterface MidiInterface; + typedef test_mocks::SerialMock<1024> LargeSerialMock; + typedef midi::MidiInterface LargeMidiInterface; - - SerialMock serial; - MidiInterface midi(serial); + LargeSerialMock serial; + LargeMidiInterface midi(serial); Buffer buffer; // Short frame @@ -510,11 +509,11 @@ TEST(MidiOutput, sendRealTime) TEST(MidiOutput, RPN) { typedef VariableSettings Settings; - typedef midi::MidiInterface MidiInterface; + typedef midi::MidiInterface RsMidiInterface; SerialMock serial; - MidiInterface midi(serial); - std::vector buffer; + RsMidiInterface midi(serial); + Buffer buffer; // 14-bit Value Single Frame { @@ -626,11 +625,11 @@ TEST(MidiOutput, RPN) TEST(MidiOutput, NRPN) { typedef VariableSettings Settings; - typedef midi::MidiInterface MidiInterface; + typedef midi::MidiInterface RsMidiInterface; SerialMock serial; - MidiInterface midi(serial); - std::vector buffer; + RsMidiInterface midi(serial); + Buffer buffer; // 14-bit Value Single Frame { @@ -741,13 +740,12 @@ TEST(MidiOutput, NRPN) TEST(MidiOutput, runningStatusCancellation) { - typedef test_mocks::SerialMock<32> SerialMock; typedef VariableSettings Settings; - typedef midi::MidiInterface MidiInterface; + typedef midi::MidiInterface RsMidiInterface; SerialMock serial; - MidiInterface midi(serial); - std::vector buffer; + RsMidiInterface midi(serial); + Buffer buffer; static const unsigned sysExLength = 13; static const byte sysEx[sysExLength] = { @@ -834,7 +832,6 @@ TEST(MidiOutput, runningStatusCancellation) 0xf6, 0x90, 12, 34 })); - } END_UNNAMED_NAMESPACE diff --git a/test/unit-tests/tests/unit-tests_MidiThru.cpp b/test/unit-tests/tests/unit-tests_MidiThru.cpp index 8cca5f4..9681a52 100644 --- a/test/unit-tests/tests/unit-tests_MidiThru.cpp +++ b/test/unit-tests/tests/unit-tests_MidiThru.cpp @@ -275,12 +275,11 @@ TEST(MidiThru, differentChannelOmni) // Acts like off TEST(MidiThru, multiByteThru) { - typedef VariableSettings Settings; - typedef test_mocks::SerialMock<32> SerialMock; - typedef midi::MidiInterface MidiInterface; + typedef VariableSettings MultiByteParsing; + typedef midi::MidiInterface MultiByteMidiInterface; SerialMock serial; - MidiInterface midi(serial); + MultiByteMidiInterface midi(serial); Buffer buffer; midi.begin(MIDI_CHANNEL_OMNI); @@ -307,10 +306,10 @@ TEST(MidiThru, withTxRunningStatus) { typedef VariableSettings Settings; typedef test_mocks::SerialMock<32> SerialMock; - typedef midi::MidiInterface MidiInterface; + typedef midi::MidiInterface RsMidiInterface; SerialMock serial; - MidiInterface midi(serial); + RsMidiInterface midi(serial); Buffer buffer; midi.begin(MIDI_CHANNEL_OMNI); From a381c626674ee6f6c9039ac419dc0c11cbbe2aff Mon Sep 17 00:00:00 2001 From: Francois Best Date: Wed, 2 Nov 2016 09:07:58 +0100 Subject: [PATCH 131/138] Added many boards. --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 48d52e1..a8b51d3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -75,9 +75,9 @@ script: - | if [ ! "${BUILD_UNIT_TESTS}" ]; then if [ "${REQUIRES_USB}" ]; then - platformio ci --lib="." --lib=external/midi-usb --board="due" --board="zero" --board="leonardo" + platformio ci --lib="." --lib=external/midi-usb --board="due" --board="dueUSB" --board="zero" --board="seroUSB" --board="leonardo" --board="teensy20" --board="teensy20pp" --board="teensy30" --board="teensy31" else - platformio ci --lib="." --board=uno --board="due" --board="zero" --board="leonardo" + 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 From 7ee313ebb7c801d0772ba43cf4b06ba427270da3 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Wed, 2 Nov 2016 09:13:11 +0100 Subject: [PATCH 132/138] Fix tests. --- test/unit-tests/tests/unit-tests_MidiOutput.cpp | 2 +- test/unit-tests/tests/unit-tests_MidiThru.cpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/test/unit-tests/tests/unit-tests_MidiOutput.cpp b/test/unit-tests/tests/unit-tests_MidiOutput.cpp index a885984..4e7c8e4 100644 --- a/test/unit-tests/tests/unit-tests_MidiOutput.cpp +++ b/test/unit-tests/tests/unit-tests_MidiOutput.cpp @@ -62,7 +62,7 @@ TEST(MidiOutput, sendGenericWithRunningStatus) buffer.resize(5); midi.begin(); - EXPECT_EQ(MidiInterface::Settings::UseRunningStatus, true); + EXPECT_EQ(RsMidiInterface::Settings::UseRunningStatus, true); EXPECT_EQ(serial.mTxBuffer.isEmpty(), true); midi.send(midi::NoteOn, 47, 42, 12); midi.send(midi::NoteOn, 42, 47, 12); diff --git a/test/unit-tests/tests/unit-tests_MidiThru.cpp b/test/unit-tests/tests/unit-tests_MidiThru.cpp index 9681a52..59a873d 100644 --- a/test/unit-tests/tests/unit-tests_MidiThru.cpp +++ b/test/unit-tests/tests/unit-tests_MidiThru.cpp @@ -305,7 +305,6 @@ TEST(MidiThru, multiByteThru) TEST(MidiThru, withTxRunningStatus) { typedef VariableSettings Settings; - typedef test_mocks::SerialMock<32> SerialMock; typedef midi::MidiInterface RsMidiInterface; SerialMock serial; From 250e512ef701b0f07cc79d0cc32ff4bd795175b8 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Wed, 2 Nov 2016 09:14:06 +0100 Subject: [PATCH 133/138] Fix typo. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a8b51d3..4f2e68d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -75,7 +75,7 @@ script: - | if [ ! "${BUILD_UNIT_TESTS}" ]; then if [ "${REQUIRES_USB}" ]; then - platformio ci --lib="." --lib=external/midi-usb --board="due" --board="dueUSB" --board="zero" --board="seroUSB" --board="leonardo" --board="teensy20" --board="teensy20pp" --board="teensy30" --board="teensy31" + platformio ci --lib="." --lib=external/midi-usb --board="due" --board="dueUSB" --board="zero" --board="zeroUSB" --board="leonardo" --board="teensy20" --board="teensy20pp" --board="teensy30" --board="teensy31" 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 From 2b31380ba89c9992109f80d4c49b754b57408c0a Mon Sep 17 00:00:00 2001 From: Francois Best Date: Wed, 2 Nov 2016 09:17:39 +0100 Subject: [PATCH 134/138] Teensy does not handle Arduino's USB api. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4f2e68d..bf3e8bf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -75,7 +75,7 @@ script: - | 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" --board="teensy20" --board="teensy20pp" --board="teensy30" --board="teensy31" + 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 From 3d06d8fde5368508cb2dee4b6332511bff1084de Mon Sep 17 00:00:00 2001 From: Francois Best Date: Wed, 2 Nov 2016 10:01:33 +0100 Subject: [PATCH 135/138] Updated readme. [skip ci] --- README.md | 82 ++++++++++++++++--------------------------------- ReleaseNotes.md | 11 +++++++ 2 files changed, 38 insertions(+), 55 deletions(-) create mode 100644 ReleaseNotes.md diff --git a/README.md b/README.md index f13050d..4e0ed31 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,6 @@ [![License](https://img.shields.io/github/license/FortySevenEffects/arduino_midi_library.svg?maxAge=3600)](LICENSE) This library enables MIDI I/O communications on the Arduino serial ports. -The purpose of this library is not to make a big synthesizer out of an Arduino board, the application remains yours. However, it will help you interfacing it with other MIDI devices. - -Download the latest version [here](https://github.com/FortySevenEffects/arduino_midi_library/releases/latest). ### Features * Compatible with all Arduino boards (and clones with an AVR processor). @@ -17,73 +14,48 @@ Download the latest version [here](https://github.com/FortySevenEffects/arduino_ * 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](http://arduinomidilib.fortyseveneffects.com/a00013.html#details). +* 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. +### Getting Started -#### 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. +1. Use Arduino's Library Manager to install the library. +2. Start coding: + ```c++ + #include + // Created and binds the MIDI interface to the default hardware Serial port + MIDI_CREATE_DEFAULT_INSTANCE(); + void setup() + { + MIDI.begin(MIDI_CHANNEL_OMNI); // Listen to all incoming messages + } -**__Warning: this library requires Arduino 1.0 or more recent versions.__** + void loop() + { + // Send note 42 with velocity 127 on channel 1 + MIDI.sendNoteOn(42, 127, 1); + // Read incoming messages + MIDI.read(); + } + ``` -### What do I need to do? +3. Read the [documentation](#documentation) or watch the awesome video tutorials from [Notes & Volts](https://www.youtube.com/playlist?list=PL4_gPbvyebyH2xfPXePHtx8gK5zPBrVkg). -* Download the library ([link](https://github.com/FortySevenEffects/arduino_midi_library/releases/latest)). -* Follow the installation instructions - http://arduino.cc/en/Guide/Libraries. -* Include the library in your sketch using the menu in the IDE, or type `#include ` -* Create the MIDI instance using `MIDI_CREATE_DEFAULT_INSTANCE();` or take a look at the documentation for custom serial port, settings etc.. - -You are now ready to use the library. Look at the documentation to learn how to use it, or checkout the examples installed with the Library. -You can also watch the awesome video tutorials from [Notes & Volts](https://www.youtube.com/playlist?list=PL4_gPbvyebyH2xfPXePHtx8gK5zPBrVkg). - - -##Documentation - -See the extended documentation [here](http://arduinomidilib.fortyseveneffects.com) ([Mirror](http://fortyseveneffects.github.io/arduino_midi_library/)). - -### Using MIDI.begin - -In the `setup()` function of the Arduino, you must call the `MIDI.begin()` method. If you don't give any argument to this method, the input channel for MIDI in will be set to 1 (channels are going from 1 to 16, plus `MIDI_CHANNEL_OMNI to listen to all channels at the same time). - -This method will: -* Start the serial port at the MIDI baudrate (31250). -* Set the input channel at the argument given (if any, else 1). -* Enable Soft Thru, without filtering (everything at the input is sent back). - - - -### MIDI Thru - -The MIDI Thru allows you to redirect your incoming messages to the MIDI output. It replaces the need of a MIDI Thru connector, as it copies every valid incoming message from the input. For good performance, you might want to call read() in a fast loop, for low latency. - -Incoming unread bytes/messages are kept in the Arduino serial buffer, in order not to flood it, check regularily with MIDI.read. See the documentation for Thru explanations. - -Thru is enabled by default, you can turn it off using appropriate methods. - - -### Hardware - -Take a look at [the MIDI.org schematic](http://www.midi.org/techspecs/electrispec.php). +## 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). ## Contact -if you have any comment or support request to make, feel free to contact me: francois.best@fortyseveneffects.com + +To report a bug, contribute, discuss on usage, or simply request support, please [create an issue here](https://github.com/FortySevenEffects/arduino_midi_library/issues/new). You can also get informations about bug fixes and updates on my twitter account: [@fortysevenfx](http://twitter.com/fortysevenfx). ## License -MIT © 2015 [Francois Best](http://fortyseveneffects.com) +MIT © 2016 [Francois Best](http://fortyseveneffects.com) diff --git a/ReleaseNotes.md b/ReleaseNotes.md new file mode 100644 index 0000000..a7138c0 --- /dev/null +++ b/ReleaseNotes.md @@ -0,0 +1,11 @@ +#### 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. From 5aa283f9c53e64b04eb4f33d57de093c8a42a279 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Wed, 2 Nov 2016 20:08:26 +0100 Subject: [PATCH 136/138] Updated version to 4.3. --- doc/Doxyfile | 2 +- library.json | 16 ++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/doc/Doxyfile b/doc/Doxyfile index 79bba4c..5551e59 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -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.2" +PROJECT_NUMBER = "Version 4.3" # 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 diff --git a/library.json b/library.json index 15992bd..5962825 100644 --- a/library.json +++ b/library.json @@ -1,21 +1,25 @@ { "name": "MIDI Library", - "version": "4.2", + "version": "4.3", "keywords": "midi", - "description": "This library enables MIDI I/O communications on the Arduino serial ports", + "description": "Enables MIDI I/O communications on the Arduino serial ports", + "license": "MIT", "authors": { "name": "Francois Best", "email": "francois.best@fortyseveneffects.com", - "url": "http://fortyseveneffects.com" + "url": "https://github.com/Franky47", + "maintainer": true }, "repository": { "type": "git", - "url": "https://github.com/FortySevenEffects/arduino_midi_library.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": "res/Examples/*/*.ino", + "examples": "examples/*/*.ino", "frameworks": "arduino", - "platforms": "atmelavr" + "platforms": ["atmelavr", "atmelsam", "teensy"] } From e1e6e98ea93e583302682b333630e0af6a2882b7 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Wed, 2 Nov 2016 20:12:04 +0100 Subject: [PATCH 137/138] Added Thru definition. --- keywords.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/keywords.txt b/keywords.txt index 330c77c..470c923 100644 --- a/keywords.txt +++ b/keywords.txt @@ -111,6 +111,7 @@ Continue LITERAL1 ActiveSensing LITERAL1 SystemReset LITERAL1 InvalidType LITERAL1 +Thru LITERAL1 Off LITERAL1 Full LITERAL1 SameChannel LITERAL1 From 2a1e86dbafdba29fb1b144d57662ce9d8780ed5a Mon Sep 17 00:00:00 2001 From: Francois Best Date: Wed, 2 Nov 2016 20:22:23 +0100 Subject: [PATCH 138/138] Maintaining only one doc location. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4e0ed31..802ea86 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ This library enables MIDI I/O communications on the Arduino serial ports. ## Documentation -- [Doxygen Extended Documentation](http://arduinomidilib.fortyseveneffects.com) ([Mirror](http://fortyseveneffects.github.io/arduino_midi_library/)). +- [Doxygen Extended Documentation](http://fortyseveneffects.github.io/arduino_midi_library/). - [GitHub wiki](https://github.com/FortySevenEffects/arduino_midi_library/wiki). ## Contact