diff --git a/.gitignore b/.gitignore index a5bd9cc..6681cf4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ *.sublime-workspace *.pyc +logs/ +build/ diff --git a/README.md b/README.md index 60b6311..d256d7a 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ -#Arduino MIDI Library v4.0 +#Arduino MIDI Library v4.1 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. -Download the latest version [here](https://github.com/FortySevenEffects/arduino_midi_library/releases/download/4.0/Arduino_MIDI_Library_v4.0.zip). +Download the latest version [here](https://github.com/FortySevenEffects/arduino_midi_library/releases/download/4.1/Arduino_MIDI_Library_v4.1.zip). ### Features * Compatible with all Arduino boards (and clones with an AVR processor) @@ -18,6 +18,7 @@ Download the latest version [here](https://github.com/FortySevenEffects/arduino_ #### 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 [here](http://sourceforge.net/news/?group_id=265194) * 06/05/2011 : Version 3.1 released. Added [callback](http://playground.arduino.cc/Main/MIDILibraryCallbacks) support. @@ -34,7 +35,7 @@ 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/download/4.0/Arduino_MIDI_Library_v4.0.zip)) +* Download the library ([link](https://github.com/FortySevenEffects/arduino_midi_library/releases/download/4.1/Arduino_MIDI_Library_v4.1.zip)) * 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 ` diff --git a/arduino-playground.md b/arduino-playground.md index 4f5228a..b68cd95 100644 --- a/arduino-playground.md +++ b/arduino-playground.md @@ -1,8 +1,8 @@ -!!MIDI Library v4.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.0/Arduino_MIDI_Library_v4.0.zip | here ]]. +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]]. @@ -20,6 +20,7 @@ You can now follow the developments on [[ http://github.com/FortySevenEffects/ar !!!!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. @@ -34,7 +35,7 @@ You can now follow the developments on [[ http://github.com/FortySevenEffects/ar !!!What do I need to do? -* Download the library ([[ https://github.com/FortySevenEffects/arduino_midi_library/releases/download/4.0/Arduino_MIDI_Library_v4.0.zip | link ]]) +* 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 @] diff --git a/arduino_midi_library.sublime-project b/arduino_midi_library.sublime-project index 24db303..2778d82 100644 --- a/arduino_midi_library.sublime-project +++ b/arduino_midi_library.sublime-project @@ -2,7 +2,17 @@ "folders": [ { - "path": "." + "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" + } + ] } diff --git a/res/Examples/MIDI_Bench/MIDI_Bench.ino b/res/Examples/MIDI_Bench/MIDI_Bench.ino index 0b3061b..a97eaaf 100644 --- a/res/Examples/MIDI_Bench/MIDI_Bench.ino +++ b/res/Examples/MIDI_Bench/MIDI_Bench.ino @@ -1,17 +1,23 @@ -#include -#define MIDI_AUTO_INSTANCIATE 0 #include -// This program demonstrates how to use two serial ports at a time, -// the hardware serial being used for sending messages to the computer, -// while MIDI is handled on a software serial port. -// This program measures the time spent to receive and parse a message. +// This program will measure the time needed to receive, parse and process a +// NoteOn message. +// For it to work, please connect RX and TX on the MIDI port: +// Due, Leonardo and other USB-native Arduinos: Serial1 +// All other Arduinos: Connect pins 2 and 3. +// The program will then wait for 100 loops and print the results. + +#if defined(ARDUINO_SAM_DUE) || defined(USBCON) + // Print through USB and bench with Hardware serial + MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, midiBench); +#else + #include + SoftwareSerial midiSerial(2,3); + MIDI_CREATE_INSTANCE(SoftwareSerial, midiSerial, midiBench); +#endif // ----------------------------------------------------------------------------- -SoftwareSerial midiSerial(2,3); -MIDI_CREATE_INSTANCE(SoftwareSerial, midiSerial, softMidi); - unsigned long gTime_start = 0; unsigned long gTime_stop = 0; unsigned gCounter = 0; @@ -24,39 +30,37 @@ unsigned long gTime_max = 0; void handleNoteOn(byte inChannel, byte inNote, byte inVelocity) { gTime_stop = micros(); - + const unsigned long diff = gTime_stop - gTime_start; gTime_sum += diff; - + if (diff > gTime_max) gTime_max = diff; if (diff < gTime_min) gTime_min = diff; - - gCounter++; - - if (gCounter >= 100) + + if (gCounter++ >= 1000) { const unsigned long average = gTime_sum / (float)gCounter; - + Serial.println("Time to receive NoteOn: "); - + Serial.print("Average: "); Serial.print(average); Serial.println(" microsecs"); - + Serial.print("Min: "); Serial.print(gTime_min); Serial.println(" microsecs"); - + Serial.print("Max: "); Serial.print(gTime_max); Serial.println(" microsecs"); - + gCounter = 0; gTime_sum = 0; gTime_max = 0; gTime_min = -1; - - softMidi.turnThruOff(); + + midiBench.turnThruOff(); } } @@ -64,18 +68,18 @@ void handleNoteOn(byte inChannel, byte inNote, byte inVelocity) void setup() { - softMidi.begin(); - - Serial.begin(38400); - Serial.print("Arduino Ready"); - - softMidi.sendNoteOn(69,127,1); -} + midiBench.setHandleNoteOn(handleNoteOn); + midiBench.begin(); + while(!Serial); + Serial.begin(115200); + Serial.println("Arduino Ready"); + + midiBench.sendNoteOn(69,127,1); +} void loop() { gTime_start = micros(); - softMidi.read(); + midiBench.read(); } - diff --git a/res/Examples/MIDI_Callbacks/MIDI_Callbacks.ino b/res/Examples/MIDI_Callbacks/MIDI_Callbacks.ino index 475c177..b8043e7 100644 --- a/res/Examples/MIDI_Callbacks/MIDI_Callbacks.ino +++ b/res/Examples/MIDI_Callbacks/MIDI_Callbacks.ino @@ -2,20 +2,22 @@ // This function will be automatically called when a NoteOn is received. // It must be a void-returning function with the correct parameters, -// see documentation here: -// http://arduinomidilib.sourceforge.net/class_m_i_d_i___class.html +// see documentation here: +// http://arduinomidilib.fortyseveneffects.com/a00022.html void HandleNoteOn(byte channel, byte pitch, byte velocity) { // Do whatever you want when you receive a Note On. - + if (velocity == 0) { - // This acts like a NoteOff. + // This acts like a NoteOff. You can ask the library to call the NoteOff + // callback when receiving null-velocity NoteOn messages. + // See MIDI_HANDLE_NULL_VELOCITY_NOTE_ON_AS_NOTE_OFF in midi_Settings.h } - - // Try to keep your callbacks short (no delays ect) - // otherwise it would slow down the loop() and have a bad impact + + // Try to keep your callbacks short (no delays ect) + // otherwise it would slow down the loop() and have a bad impact // on real-time performance. } @@ -23,22 +25,21 @@ void HandleNoteOn(byte channel, byte pitch, byte velocity) void setup() { - // Initiate MIDI communications, listen to all channels - MIDI.begin(MIDI_CHANNEL_OMNI); - - // Connect the HandleNoteOn function to the library, + // Connect the HandleNoteOn function to the library, // so it is called upon reception of a NoteOn. MIDI.setHandleNoteOn(HandleNoteOn); // Put only the name of the function -} + // Initiate MIDI communications, listen to all channels + MIDI.begin(MIDI_CHANNEL_OMNI); +} void loop() { // Call MIDI.read the fastest you can for real-time performance. MIDI.read(); - - // There is no need to check if there are messages incoming + + // There is no need to check if there are messages incoming // if they are bound to a Callback function. - // The attached method will be called automatically + // The attached method will be called automatically // when the corresponding message has been received. } diff --git a/res/Examples/MIDI_DualMerger/MIDI_DualMerger.ino b/res/Examples/MIDI_DualMerger/MIDI_DualMerger.ino index edff690..740fa5b 100644 --- a/res/Examples/MIDI_DualMerger/MIDI_DualMerger.ino +++ b/res/Examples/MIDI_DualMerger/MIDI_DualMerger.ino @@ -1,4 +1,3 @@ -#include #include // This example shows how to create two instances of the library to create a merger. @@ -7,10 +6,15 @@ // A out = A in + B in // B out = B in + A in -SoftwareSerial softSerial(2,3); - -MIDI_CREATE_INSTANCE(HardwareSerial, Serial, midiA); -MIDI_CREATE_INSTANCE(SoftwareSerial, softSerial, midiB); +#ifdef ARDUINO_SAM_DUE + MIDI_CREATE_INSTANCE(HardwareSerial, Serial, midiA); + MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, midiB); +#else + #include + SoftwareSerial softSerial(2,3); + MIDI_CREATE_INSTANCE(HardwareSerial, Serial, midiA); + MIDI_CREATE_INSTANCE(SoftwareSerial, softSerial, midiB); +#endif void setup() { @@ -30,7 +34,7 @@ void loop() midiA.getData2(), midiA.getChannel()); } - + if (midiB.read()) { // Thru on B has already pushed the input message to out B. diff --git a/res/Examples/MIDI_LibValidator/MIDI_LibValidator.ino b/res/Examples/MIDI_LibValidator/MIDI_LibValidator.ino deleted file mode 100644 index a1f63e6..0000000 --- a/res/Examples/MIDI_LibValidator/MIDI_LibValidator.ino +++ /dev/null @@ -1,39 +0,0 @@ - -#include -#include -#include - -#include -#include "midi_ValidatorSerialDebug.h" -#include "midi_ValidatorLCD.h" -#include "midi_ValidatorLEDs.h" -#include "midi_ValidatorInstances.h" -#include "midi_ValidatorTester.h" - -// ----------------------------------------------------------------------------- - -void setup() -{ - setupSerialDebug(); - setupLCD(); - setupLEDs(); - setupTesters(); - Serial.println("Tester ready"); -} - -// ----------------------------------------------------------------------------- - -void loop() -{ - if (launchTests() == true) - { - setLedsFinal(true); - Serial.println("All tests passed."); - } - else - { - setLedsFinal(false); - Serial.println("Some tests failed!"); - } - while (true); -} diff --git a/res/Examples/MIDI_LibValidator/fritzing/MIDI_LibValidator.fzz b/res/Examples/MIDI_LibValidator/fritzing/MIDI_LibValidator.fzz deleted file mode 100644 index d344b8e..0000000 Binary files a/res/Examples/MIDI_LibValidator/fritzing/MIDI_LibValidator.fzz and /dev/null differ diff --git a/res/Examples/MIDI_LibValidator/midi_ValidatorInstances.h b/res/Examples/MIDI_LibValidator/midi_ValidatorInstances.h deleted file mode 100644 index 8111f90..0000000 --- a/res/Examples/MIDI_LibValidator/midi_ValidatorInstances.h +++ /dev/null @@ -1,10 +0,0 @@ - -#pragma once - -#include -#include - -extern midi::MidiInterface midiHW; -extern midi::MidiInterface midiSW; - -void setupMidi(); diff --git a/res/Examples/MIDI_LibValidator/midi_ValidatorInstances.ino b/res/Examples/MIDI_LibValidator/midi_ValidatorInstances.ino deleted file mode 100644 index 31db157..0000000 --- a/res/Examples/MIDI_LibValidator/midi_ValidatorInstances.ino +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include "midi_ValidatorInstances.h" - -// ----------------------------------------------------------------------------- - -SoftwareSerial softSerial(10, 11); - -#if defined(__AVR_ATmega32U4__) // Leonardo uses Serial1 as hardware serial. - MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, midiHW); - MIDI_CREATE_INSTANCE(SoftwareSerial, softSerial, midiSW); -#else - MIDI_CREATE_INSTANCE(HardwareSerial, Serial, midiHW); - MIDI_CREATE_INSTANCE(SoftwareSerial, softSerial, midiSW); -#endif - -void setupMidi() -{ - while (!softSerial.isListening()) - softSerial.listen(); -} diff --git a/res/Examples/MIDI_LibValidator/midi_ValidatorLCD.h b/res/Examples/MIDI_LibValidator/midi_ValidatorLCD.h deleted file mode 100644 index a6319ce..0000000 --- a/res/Examples/MIDI_LibValidator/midi_ValidatorLCD.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once -#include - -// ----------------------------------------------------------------------------- - -extern LiquidCrystal lcd; - -// ----------------------------------------------------------------------------- - -void setupLCD(); - -// ----------------------------------------------------------------------------- - -void setProgressBar(unsigned inProgress, unsigned inTotal); diff --git a/res/Examples/MIDI_LibValidator/midi_ValidatorLCD.ino b/res/Examples/MIDI_LibValidator/midi_ValidatorLCD.ino deleted file mode 100644 index 85e8265..0000000 --- a/res/Examples/MIDI_LibValidator/midi_ValidatorLCD.ino +++ /dev/null @@ -1,47 +0,0 @@ -#include -#include "midi_ValidatorLCD.h" - -#define LCD_D4 8 -#define LCD_D5 9 -#define LCD_D6 10 -#define LCD_D7 11 -#define LCD_RS 12 -#define LCD_EN 13 - -// ----------------------------------------------------------------------------- - -byte progressChar[6][8] = -{ - { B00000, B00000, B00000, B00000, B00000, B00000, B00000, B00000 }, - { B10000, B10000, B10000, B10000, B10000, B10000, B10000, B10000 }, - { B11000, B11000, B11000, B11000, B11000, B11000, B11000, B11000 }, - { B11100, B11100, B11100, B11100, B11100, B11100, B11100, B11100 }, - { B11110, B11110, B11110, B11110, B11110, B11110, B11110, B11110 }, - { B11111, B11111, B11111, B11111, B11111, B11111, B11111, B11111 }, -}; - -// ----------------------------------------------------------------------------- - -LiquidCrystal lcd(LCD_RS, LCD_EN, LCD_D4, LCD_D5, LCD_D6, LCD_D7); - -void setupLCD() -{ - for (byte i = 0; i < 6; ++i) - lcd.createChar(i, progressChar[i]); - - lcd.begin(16,2); -} - -// ----------------------------------------------------------------------------- - -void setProgressBar(unsigned inProgress, unsigned inTotal) -{ - const byte numCols = 16; - const byte numPix = 5; - const unsigned progress = (inProgress * numCols* numPix) / inTotal; - const byte cursorX = progress / numPix; - const byte charIndex = progress % numPix; - - lcd.setCursor(cursorX, 1); - lcd.write(charIndex); -} diff --git a/res/Examples/MIDI_LibValidator/midi_ValidatorLEDs.h b/res/Examples/MIDI_LibValidator/midi_ValidatorLEDs.h deleted file mode 100644 index be7deaa..0000000 --- a/res/Examples/MIDI_LibValidator/midi_ValidatorLEDs.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#define LED_PASS 4 -#define LED_FAIL 5 - -// ----------------------------------------------------------------------------- - -void setupLEDs(); - -// ----------------------------------------------------------------------------- - -inline void blinkLed(byte inLedNum) -{ - digitalWrite(inLedNum, HIGH); - delay(100); - digitalWrite(inLedNum, LOW); -} - -inline void blinkPass() -{ - blinkLed(LED_PASS); -} - -inline void blinkFail() -{ - blinkLed(LED_FAIL); -} - -inline void setLedsFinal(bool inSuccess) -{ - if (inSuccess) - { - digitalWrite(LED_PASS, HIGH); - digitalWrite(LED_FAIL, LOW); - } - else - { - digitalWrite(LED_FAIL, HIGH); - digitalWrite(LED_PASS, LOW); - } -} - -// ----------------------------------------------------------------------------- - diff --git a/res/Examples/MIDI_LibValidator/midi_ValidatorLEDs.ino b/res/Examples/MIDI_LibValidator/midi_ValidatorLEDs.ino deleted file mode 100644 index 616d72c..0000000 --- a/res/Examples/MIDI_LibValidator/midi_ValidatorLEDs.ino +++ /dev/null @@ -1,10 +0,0 @@ -#include -#include "midi_ValidatorLEDs.h" - -// ----------------------------------------------------------------------------- - -void setupLEDs() -{ - pinMode(LED_PASS, OUTPUT); - pinMode(LED_FAIL, OUTPUT); -} diff --git a/res/Examples/MIDI_LibValidator/midi_ValidatorSerialDebug.h b/res/Examples/MIDI_LibValidator/midi_ValidatorSerialDebug.h deleted file mode 100644 index 1d8c3c0..0000000 --- a/res/Examples/MIDI_LibValidator/midi_ValidatorSerialDebug.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -void setupSerialDebug(); diff --git a/res/Examples/MIDI_LibValidator/midi_ValidatorSerialDebug.ino b/res/Examples/MIDI_LibValidator/midi_ValidatorSerialDebug.ino deleted file mode 100644 index 844fbe3..0000000 --- a/res/Examples/MIDI_LibValidator/midi_ValidatorSerialDebug.ino +++ /dev/null @@ -1,12 +0,0 @@ -#include -#include "midi_ValidatorSerialDebug.h" - -void setupSerialDebug() -{ - Serial.begin(9600); - while (!Serial) - { - ; // wait for serial port to connect. Needed for Leonardo only - } -} - diff --git a/res/Examples/MIDI_LibValidator/midi_ValidatorTester.h b/res/Examples/MIDI_LibValidator/midi_ValidatorTester.h deleted file mode 100644 index 9098ee7..0000000 --- a/res/Examples/MIDI_LibValidator/midi_ValidatorTester.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once - -void setupTesters(); -bool launchTests(); diff --git a/res/Examples/MIDI_LibValidator/midi_ValidatorTester.ino b/res/Examples/MIDI_LibValidator/midi_ValidatorTester.ino deleted file mode 100644 index cf06660..0000000 --- a/res/Examples/MIDI_LibValidator/midi_ValidatorTester.ino +++ /dev/null @@ -1,109 +0,0 @@ -#include -#include "midi_ValidatorTester.h" -#include "midi_ValidatorInstances.h" -#include "midi_ValidatorTests.h" - -// ----------------------------------------------------------------------------- - -template -class Tester -{ -public: - typedef bool (*Functor) (MIDI_CLASS(SerialClass)&); - -public: - explicit Tester(MIDI_CLASS(SerialClass)& inInstance) - : mMidiInstance(inInstance) - , mProgress(0) - { - } - - void setup() - { - mProgress = 0; - mMidiInstance.begin(MIDI_CHANNEL_OMNI); - mMidiInstance.turnThruOff(); - } - -public: - inline bool performTest(Functor inTestMethod) - { - if (inTestMethod != 0) - { - const bool result = expect((*inTestMethod)(mMidiInstance)); - setProgressBar(++mProgress, NUM_TESTS); - return result; - } - return false; - } - - inline bool expect(bool inCondition) const - { - Serial.print(testNames[mProgress]); - Serial.print(": "); - if (inCondition == false) - { - Serial.println("Failed /!\\"); - blinkFail(); - } - else - { - Serial.println("Passed"); - blinkPass(); - } - return inCondition; - } - - bool run() - { - bool result = true; - result &= performTest(testNoteOn); - result &= performTest(testNoteOff); - result &= performTest(testControlChange); - result &= performTest(testProgramChange); - result &= performTest(testAftertouchMono); - result &= performTest(testAftertouchPoly); - result &= performTest(testPitchBend); - result &= performTest(testSysEx); - result &= performTest(testClock); - result &= performTest(testStart); - result &= performTest(testStop); - result &= performTest(testContinue); - result &= performTest(testActiveSensing); - result &= performTest(testTimeCode); - result &= performTest(testSongSelect); - result &= performTest(testSongPosition); - result &= performTest(testTuneRequest); - result &= performTest(testSystemReset); - return result; - } - -private: - MIDI_CLASS(SerialClass)& mMidiInstance; - unsigned mProgress; -}; - -// ----------------------------------------------------------------------------- - -Tester testerHW(midiHW); -Tester testerSW(midiSW); - -// ----------------------------------------------------------------------------- - -void setupTesters() -{ - testerHW.setup(); - testerSW.setup(); - setupMidi(); -} - -bool launchTests() -{ - Serial.println("Testing HW:"); - if (testerHW.run() == false) - return false; - Serial.println("Testing SW:"); - if (testerSW.run() == false) - return false; - return true; -} diff --git a/res/Examples/MIDI_LibValidator/midi_ValidatorTests.h b/res/Examples/MIDI_LibValidator/midi_ValidatorTests.h deleted file mode 100644 index 6319cfe..0000000 --- a/res/Examples/MIDI_LibValidator/midi_ValidatorTests.h +++ /dev/null @@ -1,62 +0,0 @@ -#pragma once - -// ----------------------------------------------------------------------------- - -#define NUM_TESTS 18 - -// ----------------------------------------------------------------------------- - -#define DECLARE_MIDI_TEST(Name) \ - template \ - bool Name(MIDI_CLASS(SerialClass)& inMidi) - -#define IMPLEMENT_MIDI_TEST(Name, Instance) \ - template \ - bool Name(MIDI_CLASS(SerialClass)& Instance) - -// ----------------------------------------------------------------------------- - -static const char * testNames[] = -{ - // 0123456789ABCDEF - "NoteOn ", - "NoteOff ", - "ControlChange ", - "ProgramChange ", - "AftertouchMono ", - "AftertouchPoly ", - "PitchBend ", - "SysEx ", - "Clock ", - "Start ", - "Stop ", - "Continue ", - "ActiveSensing ", - "TimeCode ", - "SongSelect ", - "SongPosition ", - "TuneRequest ", - "SystemReset ", -}; - -// ----------------------------------------------------------------------------- - -DECLARE_MIDI_TEST(testNoteOn); -DECLARE_MIDI_TEST(testNoteOff); -DECLARE_MIDI_TEST(testControlChange); -DECLARE_MIDI_TEST(testProgramChange); -DECLARE_MIDI_TEST(testAftertouchMono); -DECLARE_MIDI_TEST(testAftertouchPoly); -DECLARE_MIDI_TEST(testPitchBend); -DECLARE_MIDI_TEST(testSysEx); -DECLARE_MIDI_TEST(testClock); -DECLARE_MIDI_TEST(testStart); -DECLARE_MIDI_TEST(testStop); -DECLARE_MIDI_TEST(testContinue); -DECLARE_MIDI_TEST(testActiveSensing); -DECLARE_MIDI_TEST(testTimeCode); -DECLARE_MIDI_TEST(testSongSelect); -DECLARE_MIDI_TEST(testSongPosition); -DECLARE_MIDI_TEST(testTuneRequest); -DECLARE_MIDI_TEST(testSystemReset); - diff --git a/res/Examples/MIDI_LibValidator/midi_ValidatorTests.ino b/res/Examples/MIDI_LibValidator/midi_ValidatorTests.ino deleted file mode 100644 index e15b325..0000000 --- a/res/Examples/MIDI_LibValidator/midi_ValidatorTests.ino +++ /dev/null @@ -1,229 +0,0 @@ -#include -#include "midi_ValidatorTests.h" - -// ----------------------------------------------------------------------------- - -IMPLEMENT_MIDI_TEST(testNoteOn, inMidi) -{ - inMidi.sendNoteOn(12, 42, 3); - while (inMidi.read() == false) { } - - bool result = inMidi.getType() == midi::NoteOn && - inMidi.getData1() == 12 && - inMidi.getData2() == 42 && - inMidi.getChannel() == 3; - return result; -} - -IMPLEMENT_MIDI_TEST(testNoteOff, inMidi) -{ - inMidi.sendNoteOff(12, 42, 3); - while (inMidi.read() == false) { } - - bool result = inMidi.getType() == midi::NoteOff && - inMidi.getData1() == 12 && - inMidi.getData2() == 42 && - inMidi.getChannel() == 3; - return result; -} - -IMPLEMENT_MIDI_TEST(testControlChange, inMidi) -{ - inMidi.sendControlChange(12, 42, 3); - while (inMidi.read() == false) { } - - bool result = inMidi.getType() == midi::ControlChange && - inMidi.getData1() == 12 && - inMidi.getData2() == 42 && - inMidi.getChannel() == 3; - return result; -} - -IMPLEMENT_MIDI_TEST(testProgramChange, inMidi) -{ - inMidi.sendProgramChange(12, 3); - while (inMidi.read() == false) { } - - bool result = inMidi.getType() == midi::ProgramChange && - inMidi.getData1() == 12 && - inMidi.getData2() == 0 && - inMidi.getChannel() == 3; - return result; -} - -IMPLEMENT_MIDI_TEST(testAftertouchMono, inMidi) -{ - inMidi.sendAfterTouch(12, 3); - while (inMidi.read() == false) { } - - bool result = inMidi.getType() == midi::AfterTouchChannel && - inMidi.getData1() == 12 && - inMidi.getData2() == 0 && - inMidi.getChannel() == 3; - return result; -} - -IMPLEMENT_MIDI_TEST(testAftertouchPoly, inMidi) -{ - inMidi.sendPolyPressure(12, 42, 3); - while (inMidi.read() == false) { } - - bool result = inMidi.getType() == midi::AfterTouchPoly && - inMidi.getData1() == 12 && - inMidi.getData2() == 42 && - inMidi.getChannel() == 3; - return result; -} - -// ----------------------------------------------------------------------------- - -volatile int pitchBendMemory = 0; - -void pitchBendCallback(byte inChannel, int inValue) -{ - pitchBendMemory = inValue; -} - -IMPLEMENT_MIDI_TEST(testPitchBend, inMidi) -{ - inMidi.setHandlePitchBend(pitchBendCallback); - pitchBendMemory = 0; - inMidi.sendPitchBend((int)1234, 3); - while (inMidi.read() == false) { } - - bool result = inMidi.getType() == midi::PitchBend && - pitchBendMemory == 1234 && - inMidi.getChannel() == 3; - return result; -} - -// ----------------------------------------------------------------------------- - -IMPLEMENT_MIDI_TEST(testSysEx, inMidi) -{ - static const byte testData[13] = - { - 'H', 'e', 'l', 'l', 'o', ',', ' ', - 'w', 'o', 'r', 'l', 'd', 0 - }; - - inMidi.sendSysEx(13, testData); - - while (inMidi.read() == false) { } - - bool result = inMidi.getSysExArrayLength() == 15 && // 13 + F0 + F7 - memcmp((const char*)inMidi.getSysExArray()+1, - (const char*)testData, - 13) == 0; - return result; -} - -IMPLEMENT_MIDI_TEST(testClock, inMidi) -{ - inMidi.sendRealTime(midi::Clock); - while (inMidi.read() == false) { } - return inMidi.getType() == midi::Clock; -} - -IMPLEMENT_MIDI_TEST(testStart, inMidi) -{ - inMidi.sendRealTime(midi::Start); - while (inMidi.read() == false) { } - return inMidi.getType() == midi::Start; -} - -IMPLEMENT_MIDI_TEST(testStop, inMidi) -{ - inMidi.sendRealTime(midi::Stop); - while (inMidi.read() == false) { } - return inMidi.getType() == midi::Stop; -} - -IMPLEMENT_MIDI_TEST(testContinue, inMidi) -{ - inMidi.sendRealTime(midi::Continue); - while (inMidi.read() == false) { } - return inMidi.getType() == midi::Continue; -} - -IMPLEMENT_MIDI_TEST(testActiveSensing, inMidi) -{ - inMidi.sendRealTime(midi::ActiveSensing); - while (inMidi.read() == false) { } - return inMidi.getType() == midi::ActiveSensing; -} - -// ----------------------------------------------------------------------------- - -// \todo Add callback to process parsed value - -volatile byte timeCodeMemory = 0; - -void timeCodeCallback(byte inData) -{ - timeCodeMemory = inData; -} - -IMPLEMENT_MIDI_TEST(testTimeCode, inMidi) -{ - timeCodeMemory = 0; - inMidi.setHandleTimeCodeQuarterFrame(timeCodeCallback); - inMidi.sendTimeCodeQuarterFrame(0x07, 0x0F); - while (inMidi.read() == false) { } - bool result = inMidi.getType() == midi::TimeCodeQuarterFrame && - timeCodeMemory == 0x7F && - inMidi.getChannel() == 0; - return result; -} - -// ----------------------------------------------------------------------------- - -IMPLEMENT_MIDI_TEST(testSongSelect, inMidi) -{ - inMidi.sendSongSelect(12); - while (inMidi.read() == false) { } - - bool result = inMidi.getType() == midi::SongSelect && - inMidi.getData1() == 12 && - inMidi.getData2() == 0 && - inMidi.getChannel() == 0; - return result; -} - -// ----------------------------------------------------------------------------- - -volatile int songPositionMemory = 0; - -void songPositionCallback(unsigned int inPosition) -{ - songPositionMemory = inPosition; -} - -IMPLEMENT_MIDI_TEST(testSongPosition, inMidi) -{ - songPositionMemory = 0; - inMidi.setHandleSongPosition(songPositionCallback); - inMidi.sendSongPosition(12345); - while (inMidi.read() == false) { } - - bool result = inMidi.getType() == midi::SongPosition && - songPositionMemory == 12345 && - inMidi.getChannel() == 0; - return result; -} - -// ----------------------------------------------------------------------------- - -IMPLEMENT_MIDI_TEST(testTuneRequest, inMidi) -{ - inMidi.sendTuneRequest(); - while (inMidi.read() == false) { } - return inMidi.getType() == midi::TuneRequest; -} - -IMPLEMENT_MIDI_TEST(testSystemReset, inMidi) -{ - inMidi.sendRealTime(midi::SystemReset); - while (inMidi.read() == false) { } - return inMidi.getType() == midi::SystemReset; -} diff --git a/res/install_local_mac b/res/install_local_mac deleted file mode 100755 index cf72e3a..0000000 --- a/res/install_local_mac +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash -# Use this script to install the library directy from the git clone. - - -if [[ -d /Applications/Arduino.app ]] -then - - # Define locations - - lib_path=/Applications/Arduino.app/Contents/Resources/Java/libraries/MIDI - - if [[ -d $lib_path ]] - then - # Remove old lib - rm -rf $lib_path - fi - - # Create folder - mkdir $lib_path - - # Copy sources - cp ../src/MIDI.cpp $lib_path - cp ../src/MIDI.h $lib_path - cp ../src/midi_* $lib_path - - # Copy resources - cp ../res/keywords.txt $lib_path - - # Copy examples - mkdir $lib_path/examples - - cp -r examples/* $lib_path/examples - - # Copy doc - mkdir $lib_path/doc - - cp -r ../doc/* $lib_path/doc - -else - echo "Arduino application not found." -fi diff --git a/res/install_mac b/res/install_mac deleted file mode 100755 index b94a610..0000000 --- a/res/install_mac +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash -# This script installs the Arduino MIDI Library into the Arduino application, -# so that every sketch can include it directly, without having to copy anything. -# -# To install the library, run this script by double-clicking it, -# it should be directly executable and seen as such by Mac OS X. -# If not, open a terminal, cd to the script location, and run ./install_mac -# -# Open the Arduino IDE, and you're ready to go! - -# The script assumes the Arduino application -# is installed in the default location. - -if [[ -d /Applications/Arduino.app ]] -then - - # Define locations - lib_path=/Applications/Arduino.app/Contents/Resources/Java/libraries/MIDI - - if [[ -d $lib_path ]] - then - # Remove old lib - rm -rf $lib_path - fi - - # Create folder - mkdir $lib_path - - # Install contents - cp -r * $lib_path - - # Cleanup - rm $lib_path/install_mac - -else - echo "Arduino application not found." -fi diff --git a/res/packaging b/res/packaging deleted file mode 100755 index 33ee9c3..0000000 --- a/res/packaging +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/bash -# -# Generate an archive with packaged content for easier delivery. -# The generated archive contains: -# - Source files (MIDI.cpp / MIDI.h) -# - Resources (keywords.txt) -# - Documentation (Doxygen) -# - Examples for Arduino IDE -# - Installation scripts - - -# Create a temporary destination folder -mkdir -p temp/doc -mkdir -p temp/examples - -# Copy sources -cp ../src/* temp - -# Copy resources -cp keywords.txt temp -cp install_* temp -rm temp/install_local_* - -# Copy examples -cp -r examples/* temp/examples - -# Generate & copy doc -cd ../doc -/Applications/Doxygen.app/Contents/Resources/doxygen Doxyfile -rm -rf latex -cd ../res - -cp -r ../doc/* temp/doc - -# Generate package -mv temp MIDI -zip -r MIDI.zip MIDI - - -# Remove temp folder -rm -rf MIDI - -# Archive generated packaged - -if [[ !( -d ../bin ) ]] -then - mkdir ../bin # Create archives location -fi - -mv MIDI.zip ../bin/Arduino_MIDI_Library.zip diff --git a/res/packaging.command b/res/packaging.command new file mode 100755 index 0000000..5f6a7e8 --- /dev/null +++ b/res/packaging.command @@ -0,0 +1,36 @@ +#!/bin/sh +# +# Generate an archive with packaged content for easier delivery. +# The generated archive contains: +# - Source files (MIDI.cpp / MIDI.h) +# - Resources (keywords.txt) +# - Examples for Arduino IDE +# - Installation scripts + +cd "`dirname "${0}"`" + +root="${PWD}/.." +build="$root/build/MIDI" + +echo root $root +echo build $build + +# Create a temporary destination folder +mkdir -p "$build" +mkdir -p "$build/examples" + +# Copy sources +cd "$root/src/" +cp * "$build/" + +# Copy resources +cd "$root/res/" +cp keywords.txt "$build/" + +# Copy examples +cd "$root/res/examples/" +cp -r * "$build/examples" + +# Generate package +cd "$build/.." +zip -r Arduino_MIDI_Library.zip MIDI diff --git a/res/validator/midi.py b/res/validator/midi.py new file mode 100644 index 0000000..200f167 --- /dev/null +++ b/res/validator/midi.py @@ -0,0 +1,114 @@ +# -*- coding: utf-8 -*- + +import rtmidi +import random + +# ------------------------------------------------------------------------------ + +class Midi: + InvalidType = 0x00 # For notifying errors + NoteOff = 0x80 # Note Off + NoteOn = 0x90 # Note On + AfterTouchPoly = 0xA0 # Polyphonic AfterTouch + ControlChange = 0xB0 # Control Change / Channel Mode + ProgramChange = 0xC0 # Program Change + AfterTouchChannel = 0xD0 # Channel (monophonic) AfterTouch + PitchBend = 0xE0 # Pitch Bend + SystemExclusive = 0xF0 # System Exclusive + TimeCodeQuarterFrame = 0xF1 # System Common - MIDI Time Code Quarter Frame + SongPosition = 0xF2 # System Common - Song Position Pointer + SongSelect = 0xF3 # System Common - Song Select + TuneRequest = 0xF6 # System Common - Tune Request + Clock = 0xF8 # System Real Time - Timing Clock + Start = 0xFA # System Real Time - Start + Continue = 0xFB # System Real Time - Continue + Stop = 0xFC # System Real Time - Stop + ActiveSensing = 0xFE # System Real Time - Active Sensing + SystemReset = 0xFF # System Real Time - System Reset + + @staticmethod + def getChannel(statusByte): + return statusByte & 0x0f; + + @staticmethod + def getType(statusByte): + if statusByte >= 0xf0: + # System messages + return statusByte + else: + # Channel messages + return statusByte & 0xf0; + + +# ------------------------------------------------------------------------------ + +class MidiInterface: + def __init__(self, listenerCallback = None): + self.input = rtmidi.MidiIn() + self.output = rtmidi.MidiOut() + self.listenerCallback = listenerCallback + self.ports = self.getAvailablePorts() + self.port = self.connect(self.choosePorts()) + + # -------------------------------------------------------------------------- + + def handleMidiInput(self, message, timestamp): + midiData = message[0] + if self.listenerCallback: + self.listenerCallback(midiData) + + def send(self, message): + print('Sending', message) + self.output.send_message(message) + + # -------------------------------------------------------------------------- + + def getAvailablePorts(self): + return { + 'input' : self.input.get_ports(), + 'output': self.output.get_ports(), + } + + def choosePorts(self): + return { + 'input' : self.choosePort(self.ports['input'], 'input'), + 'output': self.choosePort(self.ports['output'], 'output') + } + + def choosePort(self, ports, direction): + if not ports: + print('No MIDI ports available, bailing out.') + return None + + if len(ports) == 1: + return { + 'id': 0, + 'name': ports[0] + } + + else: + # Give a choice + print('Multiple %s ports available, please make a choice:' % direction) + choices = dict() + for port, i in zip(ports, range(0, len(ports))): + choices[i] = port + print(' [%d]' % i, port) + choiceIndex = int(input('-> ')) + return { + 'id': choiceIndex, + 'name': choices[choiceIndex] + } + + # -------------------------------------------------------------------------- + + def connect(self, ports): + if not ports: + return None + + print('Connecting input to %s' % ports['input']['name']) + print('Connecting output to %s' % ports['output']['name']) + + self.input.set_callback(self.handleMidiInput) + self.input.open_port(ports['input']['id']) + self.output.open_port(ports['output']['id']) + return ports diff --git a/res/validator/tester.py b/res/validator/tester.py new file mode 100644 index 0000000..f360b80 --- /dev/null +++ b/res/validator/tester.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- + + +# ------------------------------------------------------------------------------ + +class Tester: + def __init__(self, interface): + self.interface = interface + self.sent = None + self.expected = None + self.received = None + + def handleMidiInput(self, data): + print('Recived data:', data) + self.received = data + + def checkThru(self, message): + self.interface.send(message) + self.sent = message + self.expected = message + self.received = None + while not self.received: + pass + return self.expected == self.received diff --git a/res/validator/validate.py b/res/validator/validate.py new file mode 100644 index 0000000..72c97d8 --- /dev/null +++ b/res/validator/validate.py @@ -0,0 +1,167 @@ +# -*- coding: utf-8 -*- + +import sys +import os +import shutil +import subprocess +from pprint import pprint +from midi import * +from tester import * + +# ------------------------------------------------------------------------------ + +rootDir = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../..')) +logsDir = os.path.join(rootDir, 'logs') +resDir = os.path.join(rootDir, 'res') +srcDir = os.path.join(rootDir, 'src') + +# ------------------------------------------------------------------------------ + +class Dict(dict): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.__dict__ = self + +# ------------------------------------------------------------------------------ + +class Arduino: + if sys.platform == 'darwin': + binary = '/Applications/Arduino.app/Contents/MacOS/JavaApplicationStub' + home = os.path.expanduser('~/Documents/Arduino') + elif sys.platform == 'win32': + binary = 'arduino.exe' + home = os.path.expanduser('~/My Documents/Arduino') + elif sys.platform == 'linux': + binary = 'arduino' + home = os.path.expanduser('~/Arduino') + else: + print('Unsupported platform %s' % str(sys.platform)) + sys.exit(1) + + libraryDir = os.path.join(home, 'libraries') + + boards = [ + Dict({ + 'name': 'Uno', + 'id': 'arduino:avr:uno', + 'port': None, + }), + Dict({ + 'name': 'Leonardo', + 'id': 'arduino:avr:leonardo', + 'port': None, + }), + Dict({ + 'name': 'Mega', + 'id': 'arduino:avr:mega', + 'port': None, + }), + Dict({ + 'name': 'Due', + 'id': 'arduino:sam:due', + 'port': None, + }), + ] + + def checkReturnCode(code): + if code == 0: + return True + if code == 1: + print('Operation failed.') + if code == 2: + print('File not found') + if code == 3: + print('Invalid argument') + return False + + def verify(sketch, boardId): + return Arduino.checkReturnCode(subprocess.call([ + Arduino.binary, + '--verify', sketch, + '--board', boardId, + '--verbose-build', + ])) + #], stdout = open(os.devnull, 'wb'))) + +# ------------------------------------------------------------------------------ + +class ArduinoMidiLibrary: + def __init__(self): + self.path = os.path.join(Arduino.libraryDir, 'MIDI') + self.sources = self.getSources() + self.resources = self.getResources() + + def getSources(self): + sources = dict() + for root, dirs, files in os.walk(srcDir): + for name, ext in [os.path.splitext(f) for f in files]: + if ext in ('.cpp', '.hpp', '.h'): + source = os.path.join(root, name + ext) + dest = os.path.join(self.path, os.path.relpath(source, srcDir)) + sources[source] = dest + return sources + + def getResources(self): + return { + os.path.join(resDir, 'keywords.txt'): os.path.join(self.path, 'keywords.txt'), + os.path.join(resDir, 'examples/'): os.path.join(self.path, 'examples/'), + } + + def install(self): + payloads = dict(list(self.sources.items()) + list(self.resources.items())) + for s,d in payloads.items(): + if not os.path.exists(os.path.dirname(d)): + os.makedirs(os.path.dirname(d)) + if os.path.isfile(s): + shutil.copy2(s, d) + elif os.path.isdir(s): + if os.path.exists(d): + shutil.rmtree(d) + shutil.copytree(s, d) + + def getInstalledExamples(self): + exDir = os.path.join(self.path, 'examples') + return [os.path.join(exDir, x, x + '.ino') for x in next(os.walk(exDir))[1]] + + def validate(self): + for board in Arduino.boards: + # Validate examples + print('Validation for Arduino %s' % board.name) + for example in self.getInstalledExamples(): + if not Arduino.verify(example, board.id): + print('{0:40} {1}'.format(os.path.basename(example), 'FAILED')) + return False + else: + print('{0:40} {1}'.format(os.path.basename(example), 'PASSED')) + return True + +# ------------------------------------------------------------------------------ + +def main(): + midiInterface = MidiInterface() + tester = Tester(midiInterface) + midiInterface.listenerCallback = tester.handleMidiInput + + tester.checkThru([Midi.NoteOn, 64, 80]) + tester.checkThru([Midi.AfterTouchChannel, 1]) + tester.checkThru([2]) + tester.checkThru([3]) + tester.checkThru([Midi.NoteOn, 64, 0]) + tester.checkThru([65, 127]) + tester.checkThru([65, 0]) + tester.checkThru([66, 127]) + tester.checkThru([66, 0]) + + #lib = ArduinoMidiLibrary() + #lib.install() + #if lib.validate(): + # print('Validation passed') + #else: + # print('Validation failed') + + + +# ------------------------------------------------------------------------------ + +if __name__ == '__main__': + main() diff --git a/src/MIDI.cpp b/src/MIDI.cpp index a01beb4..b8f1c0c 100644 --- a/src/MIDI.cpp +++ b/src/MIDI.cpp @@ -2,10 +2,23 @@ * @file MIDI.cpp * Project Arduino MIDI Library * @brief MIDI Library for the Arduino - * @version 4.0 + * @version 4.1 * @author Francois Best * @date 24/02/11 - * license GPL Forty Seven Effects - 2011 + * @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 . */ #include "MIDI.h" @@ -44,6 +57,7 @@ BEGIN_MIDI_NAMESPACE \param inLength The lenght of the input buffer. \return The lenght of the encoded output buffer. @see decodeSysEx + Code inspired from Ruin & Wesen's SysEx encoder/decoder - http://ruinwesen.com */ unsigned encodeSysEx(const byte* inData, byte* outSysEx, unsigned inLength) { @@ -80,6 +94,7 @@ unsigned encodeSysEx(const byte* inData, byte* outSysEx, unsigned inLength) \param inLength The lenght of the input buffer. \return The lenght of the output buffer. @see encodeSysEx @see getSysExArrayLength + Code inspired from Ruin & Wesen's SysEx encoder/decoder - http://ruinwesen.com */ unsigned decodeSysEx(const byte* inSysEx, byte* outData, unsigned inLength) { diff --git a/src/MIDI.h b/src/MIDI.h index 2a92b80..5575e32 100644 --- a/src/MIDI.h +++ b/src/MIDI.h @@ -2,10 +2,23 @@ * @file MIDI.h * Project Arduino MIDI Library * @brief MIDI Library for the Arduino - * @version 4.0 + * @version 4.1 * @author Francois Best * @date 24/02/11 - * license GPL Forty Seven Effects - 2011 + * @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 @@ -117,6 +130,7 @@ public: public: static inline MidiType getTypeFromStatusByte(byte inStatus); + static inline Channel getChannelFromStatusByte(byte inStatus); static inline bool isChannelMessage(MidiType inType); private: diff --git a/src/MIDI.hpp b/src/MIDI.hpp index fd1f242..7a154c2 100644 --- a/src/MIDI.hpp +++ b/src/MIDI.hpp @@ -2,10 +2,23 @@ * @file midi_Inline.hpp * Project Arduino MIDI Library * @brief MIDI Library for the Arduino - Inline implementations - * @version 4.0 + * @version 4.1 * @author Francois Best * @date 24/02/11 - * license GPL Forty Seven Effects - 2011 + * @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 @@ -496,9 +509,7 @@ inline bool MidiInterface::read(Channel inChannel) template bool MidiInterface::parse() { - const byte bytes_available = mSerial.available(); - - if (bytes_available == 0) + if (mSerial.available() == 0) // No data available. return false; @@ -534,29 +545,11 @@ bool MidiInterface::parse() // Else: well, we received another status byte, // so the running status does not apply here. // It will be updated upon completion of this message. - - if (mPendingMessageIndex >= (mPendingMessageExpectedLenght - 1)) - { - mMessage.type = getTypeFromStatusByte(mPendingMessage[0]); - mMessage.channel = (mPendingMessage[0] & 0x0f) + 1; - mMessage.data1 = mPendingMessage[1]; - - // Save data2 only if applicable - if (mPendingMessageExpectedLenght == 3) - mMessage.data2 = mPendingMessage[2]; - else - mMessage.data2 = 0; - - mPendingMessageIndex = 0; - mPendingMessageExpectedLenght = 0; - mMessage.valid = true; - return true; - } } switch (getTypeFromStatusByte(mPendingMessage[0])) { - // 1 byte messages + // 1 byte messages case Start: case Continue: case Stop: @@ -616,17 +609,38 @@ bool MidiInterface::parse() break; } - // Then update the index of the pending message. - mPendingMessageIndex++; + if (mPendingMessageIndex >= (mPendingMessageExpectedLenght - 1)) + { + // Reception complete + mMessage.type = getTypeFromStatusByte(mPendingMessage[0]); + mMessage.channel = getChannelFromStatusByte(mPendingMessage[0]); + mMessage.data1 = mPendingMessage[1]; -#if USE_1BYTE_PARSING + // Save data2 only if applicable + if (mPendingMessageExpectedLenght == 3) + mMessage.data2 = mPendingMessage[2]; + else + mMessage.data2 = 0; + + mPendingMessageIndex = 0; + mPendingMessageExpectedLenght = 0; + mMessage.valid = true; + return true; + } + else + { + // Waiting for more data + mPendingMessageIndex++; + } + + #if USE_1BYTE_PARSING // Message is not complete. return false; -#else + #else // Call the parser recursively // to parse the rest of the message. return parse(); -#endif + #endif } else @@ -698,7 +712,7 @@ bool MidiInterface::parse() mPendingMessage[mPendingMessageIndex] = extracted; // Now we are going to check if we have reached the end of the message - if (mPendingMessageIndex >= (mPendingMessageExpectedLenght-1)) + if (mPendingMessageIndex >= (mPendingMessageExpectedLenght - 1)) { // "FML" case: fall down here with an overflown SysEx.. // This means we received the last possible data byte that can fit @@ -712,7 +726,7 @@ bool MidiInterface::parse() mMessage.type = getTypeFromStatusByte(mPendingMessage[0]); if (isChannelMessage(mMessage.type)) - mMessage.channel = (mPendingMessage[0] & 0x0f) + 1; + mMessage.channel = getChannelFromStatusByte(mPendingMessage[0]); else mMessage.channel = 0; @@ -766,9 +780,6 @@ bool MidiInterface::parse() #endif } } - - // What are our chances to fall here? - return false; } // Private method, see midi_Settings.h for documentation @@ -936,6 +947,14 @@ MidiType MidiInterface::getTypeFromStatusByte(byte inStatus) return (MidiType)inStatus; } +/*! \brief Returns channel in the range 1-16 + */ +template +inline Channel MidiInterface::getChannelFromStatusByte(byte inStatus) +{ + return (inStatus & 0x0f) + 1; +} + template bool MidiInterface::isChannelMessage(MidiType inType) { diff --git a/src/midi_Defs.h b/src/midi_Defs.h index 6739e1d..324f361 100644 --- a/src/midi_Defs.h +++ b/src/midi_Defs.h @@ -2,10 +2,23 @@ * @file midi_Defs.h * Project Arduino MIDI Library * @brief MIDI Library for the Arduino - Definitions - * @version 4.0 + * @version 4.1 * @author Francois Best * @date 24/02/11 - * license GPL Forty Seven Effects - 2011 + * @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 diff --git a/src/midi_Namespace.h b/src/midi_Namespace.h index c72e334..c99629e 100644 --- a/src/midi_Namespace.h +++ b/src/midi_Namespace.h @@ -2,10 +2,23 @@ * @file midi_Namespace.h * Project Arduino MIDI Library * @brief MIDI Library for the Arduino - Namespace declaration - * @version 4.0 + * @version 4.1 * @author Francois Best * @date 24/02/11 - * license GPL Forty Seven Effects - 2011 + * @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 diff --git a/src/midi_Settings.h b/src/midi_Settings.h index eae8555..cd2d021 100644 --- a/src/midi_Settings.h +++ b/src/midi_Settings.h @@ -2,10 +2,23 @@ * @file midi_Settings.h * Project Arduino MIDI Library * @brief MIDI Library for the Arduino - Settings - * @version 4.0 + * @version 4.1 * @author Francois Best * @date 24/02/11 - * license GPL Forty Seven Effects - 2011 + * @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 @@ -48,13 +61,13 @@ // Set the default port to use for MIDI. #if MIDI_AUTO_INSTANCIATE # ifdef ARDUINO +# include "Arduino.h" # ifdef USBCON # define MIDI_DEFAULT_SERIAL_PORT Serial1 // For Leonardo # else # define MIDI_DEFAULT_SERIAL_PORT Serial // For other Arduinos # endif # define MIDI_DEFAULT_SERIAL_CLASS HardwareSerial -# include "Arduino.h" # include "HardwareSerial.h" # else # error Auto-instanciation disabled. Use MIDI_CREATE_INSTANCE macro.