Merge branch 'master' into feature/usb
This commit is contained in:
commit
dd5b39a686
|
|
@ -1,2 +1,4 @@
|
|||
*.sublime-workspace
|
||||
*.pyc
|
||||
logs/
|
||||
build/
|
||||
|
|
|
|||
|
|
@ -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>`
|
||||
|
||||
|
|
|
|||
|
|
@ -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>@]
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
Binary file not shown.
|
|
@ -1,10 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <SoftwareSerial.h>
|
||||
#include <MIDI.h>
|
||||
|
||||
extern midi::MidiInterface<HardwareSerial> midiHW;
|
||||
extern midi::MidiInterface<SoftwareSerial> midiSW;
|
||||
|
||||
void setupMidi();
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
#pragma once
|
||||
#include <LiquidCrystal.h>
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
extern LiquidCrystal lcd;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void setupLCD();
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void setProgressBar(unsigned inProgress, unsigned inTotal);
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
#include <Arduino.h>
|
||||
#include "midi_ValidatorLEDs.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void setupLEDs()
|
||||
{
|
||||
pinMode(LED_PASS, OUTPUT);
|
||||
pinMode(LED_FAIL, OUTPUT);
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
void setupSerialDebug();
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
void setupTesters();
|
||||
bool launchTests();
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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()
|
||||
19
src/MIDI.cpp
19
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 <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)
|
||||
{
|
||||
|
|
|
|||
18
src/MIDI.h
18
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 <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:
|
||||
|
|
|
|||
87
src/MIDI.hpp
87
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 <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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Reference in New Issue