Merge branch 'master' into feature/usb

This commit is contained in:
Francois Best 2014-04-16 09:06:39 +02:00
commit dd5b39a686
34 changed files with 556 additions and 836 deletions

2
.gitignore vendored
View File

@ -1,2 +1,4 @@
*.sublime-workspace
*.pyc
logs/
build/

View File

@ -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 <MIDI.h>`

View File

@ -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 <MIDI.h>@]

View File

@ -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"
}
]
}

View File

@ -1,17 +1,23 @@
#include <SoftwareSerial.h>
#define MIDI_AUTO_INSTANCIATE 0
#include <MIDI.h>
// 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.h>
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();
}

View File

@ -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.
}

View File

@ -1,4 +1,3 @@
#include <SoftwareSerial.h>
#include <MIDI.h>
// 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.h>
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.

View File

@ -1,39 +0,0 @@
#include <SoftwareSerial.h>
#include <MIDI.h>
#include <LiquidCrystal.h>
#include <Arduino.h>
#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);
}

View File

@ -1,10 +0,0 @@
#pragma once
#include <SoftwareSerial.h>
#include <MIDI.h>
extern midi::MidiInterface<HardwareSerial> midiHW;
extern midi::MidiInterface<SoftwareSerial> midiSW;
void setupMidi();

View File

@ -1,20 +0,0 @@
#include <Arduino.h>
#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();
}

View File

@ -1,14 +0,0 @@
#pragma once
#include <LiquidCrystal.h>
// -----------------------------------------------------------------------------
extern LiquidCrystal lcd;
// -----------------------------------------------------------------------------
void setupLCD();
// -----------------------------------------------------------------------------
void setProgressBar(unsigned inProgress, unsigned inTotal);

View File

@ -1,47 +0,0 @@
#include <Arduino.h>
#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);
}

View File

@ -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);
}
}
// -----------------------------------------------------------------------------

View File

@ -1,10 +0,0 @@
#include <Arduino.h>
#include "midi_ValidatorLEDs.h"
// -----------------------------------------------------------------------------
void setupLEDs()
{
pinMode(LED_PASS, OUTPUT);
pinMode(LED_FAIL, OUTPUT);
}

View File

@ -1,3 +0,0 @@
#pragma once
void setupSerialDebug();

View File

@ -1,12 +0,0 @@
#include <Arduino.h>
#include "midi_ValidatorSerialDebug.h"
void setupSerialDebug()
{
Serial.begin(9600);
while (!Serial)
{
; // wait for serial port to connect. Needed for Leonardo only
}
}

View File

@ -1,4 +0,0 @@
#pragma once
void setupTesters();
bool launchTests();

View File

@ -1,109 +0,0 @@
#include <Arduino.h>
#include "midi_ValidatorTester.h"
#include "midi_ValidatorInstances.h"
#include "midi_ValidatorTests.h"
// -----------------------------------------------------------------------------
template<class SerialClass>
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<HardwareSerial> testerHW(midiHW);
Tester<SoftwareSerial> 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;
}

View File

@ -1,62 +0,0 @@
#pragma once
// -----------------------------------------------------------------------------
#define NUM_TESTS 18
// -----------------------------------------------------------------------------
#define DECLARE_MIDI_TEST(Name) \
template<class SerialClass> \
bool Name(MIDI_CLASS(SerialClass)& inMidi)
#define IMPLEMENT_MIDI_TEST(Name, Instance) \
template<class SerialClass> \
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);

View File

@ -1,229 +0,0 @@
#include <Arduino.h>
#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;
}

View File

@ -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

View File

@ -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

View File

@ -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

36
res/packaging.command Executable file
View File

@ -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

114
res/validator/midi.py Normal file
View File

@ -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

24
res/validator/tester.py Normal file
View File

@ -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

167
res/validator/validate.py Normal file
View File

@ -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()

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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)
{

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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:

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#pragma once
@ -496,9 +509,7 @@ inline bool MidiInterface<SerialPort>::read(Channel inChannel)
template<class SerialPort>
bool MidiInterface<SerialPort>::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<SerialPort>::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<SerialPort>::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<SerialPort>::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<SerialPort>::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<SerialPort>::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<SerialPort>::getTypeFromStatusByte(byte inStatus)
return (MidiType)inStatus;
}
/*! \brief Returns channel in the range 1-16
*/
template<class SerialPort>
inline Channel MidiInterface<SerialPort>::getChannelFromStatusByte(byte inStatus)
{
return (inStatus & 0x0f) + 1;
}
template<class SerialPort>
bool MidiInterface<SerialPort>::isChannelMessage(MidiType inType)
{

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#pragma once

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#pragma once

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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.