├── Schema.jpg ├── Libreries ├── wavTrigger │ ├── keywords.txt │ ├── wavTrigger.h │ ├── wavTrigger.cpp │ ├── examples │ │ └── WTriggerUno │ │ │ └── WTriggerUno.ino │ └── README.md ├── Metro │ ├── README.md │ ├── keywords.txt │ ├── examples │ │ ├── serialInterval │ │ │ └── serialInterval.ino │ │ ├── blinking │ │ │ └── blinking.ino │ │ ├── blinking_2_intervals │ │ │ └── blinking_2_intervals.ino │ │ └── blinking_2_instances │ │ │ └── blinking_2_instances.ino │ ├── Metro.cpp │ ├── LICENSE │ └── Metro.h ├── AltSoftSerial │ ├── keywords.txt │ ├── README.md │ ├── library.properties │ ├── library.json │ ├── examples │ │ ├── Echo │ │ │ └── Echo.ino │ │ ├── ReceiveTest │ │ │ └── ReceiveTest.ino │ │ └── ShowConfiguration │ │ │ └── ShowConfiguration.ino │ ├── AltSoftSerial.h │ ├── config │ │ ├── AltSoftSerial_Boards.h │ │ └── AltSoftSerial_Timers.h │ └── AltSoftSerial.cpp └── MIDI │ ├── examples │ ├── MIDI_Basic_IO │ │ └── MIDI_Basic_IO.ino │ ├── MIDI_SimpleSynth │ │ ├── noteList.cpp │ │ ├── MIDI_SimpleSynth.ino │ │ ├── pitches.h │ │ └── noteList.h │ ├── MIDI_DualMerger │ │ └── MIDI_DualMerger.ino │ ├── MIDI_Input │ │ └── MIDI_Input.ino │ ├── MIDI_Callbacks │ │ └── MIDI_Callbacks.ino │ └── MIDI_Bench │ │ └── MIDI_Bench.ino │ ├── midi_Namespace.h │ ├── midi_Message.h │ ├── midi_Settings.h │ ├── keywords.txt │ ├── MIDI.cpp │ ├── midi_Defs.h │ ├── MIDI.h │ └── MIDI.hpp ├── LICENSE ├── README.md └── Coda-88 └── Coda-88.ino /Schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandrolab/Coda-88/HEAD/Schema.jpg -------------------------------------------------------------------------------- /Libreries/wavTrigger/keywords.txt: -------------------------------------------------------------------------------- 1 | wavTrigger KEYWORD1 2 | active KEYWORD2 3 | overflow KEYWORD2 4 | library_version KEYWORD2 5 | -------------------------------------------------------------------------------- /Libreries/Metro/README.md: -------------------------------------------------------------------------------- 1 | Please visit https://github.com/thomasfredericks/Metro-Arduino-Wiring for latest code and documentation. -------------------------------------------------------------------------------- /Libreries/AltSoftSerial/keywords.txt: -------------------------------------------------------------------------------- 1 | AltSoftSerial KEYWORD1 2 | active KEYWORD2 3 | overflow KEYWORD2 4 | library_version KEYWORD2 5 | -------------------------------------------------------------------------------- /Libreries/AltSoftSerial/README.md: -------------------------------------------------------------------------------- 1 | #AltSoftSerial Library# 2 | 3 | Improved software emulated serial, using hardware timers for precise signal 4 | timing and availability of CPU time for other libraries to respond to interrupts 5 | during data AltSoftSerial data transmission and reception. 6 | 7 | http://www.pjrc.com/teensy/td_libs_AltSoftSerial.html 8 | 9 | ![AltSoftSerial on Teensy 2.0](http://www.pjrc.com/teensy/td_libs_AltSoftSerial_2.jpg) 10 | -------------------------------------------------------------------------------- /Libreries/AltSoftSerial/library.properties: -------------------------------------------------------------------------------- 1 | name=AltSoftSerial 2 | version=1.4 3 | author=Paul Stoffregen 4 | maintainer=Paul Stoffregen 5 | sentence=Software emulated serial using hardware timers for improved compatibility 6 | paragraph=Improved software emulated serial, using hardware timers for precise signal timing and improved compatibility with other interrupt-based libraries. 7 | category=Communication 8 | url=http://www.pjrc.com/teensy/td_libs_AltSoftSerial.html 9 | architectures=avr 10 | -------------------------------------------------------------------------------- /Libreries/AltSoftSerial/library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "AltSoftSerial", 3 | "frameworks": "Arduino", 4 | "keywords": "serial", 5 | "description": "Alternate Software Serial", 6 | "url": "http://www.pjrc.com/teensy/td_libs_AltSoftSerial.html", 7 | "authors": 8 | { 9 | "name": "Paul Stoffregen", 10 | "maintainer": true 11 | }, 12 | "repository": 13 | { 14 | "type": "git", 15 | "url": "https://github.com/PaulStoffregen/AltSoftSerial" 16 | }, 17 | "version": "1.4" 18 | } 19 | -------------------------------------------------------------------------------- /Libreries/Metro/keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For Test 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | Metro KEYWORD1 10 | 11 | ####################################### 12 | # Methods and Functions (KEYWORD2) 13 | ####################################### 14 | 15 | check KEYWORD2 16 | interval KEYWORD2 17 | 18 | ####################################### 19 | # Instances (KEYWORD2) 20 | ####################################### 21 | 22 | ####################################### 23 | # Constants (LITERAL1) 24 | ####################################### 25 | 26 | -------------------------------------------------------------------------------- /Libreries/Metro/examples/serialInterval/serialInterval.ino: -------------------------------------------------------------------------------- 1 | // This example sends a Serial message every 250 milliseconds 2 | 3 | #include // Include the Metro library 4 | 5 | Metro serialMetro = Metro(250); // Instantiate an instance 6 | 7 | void setup() { 8 | Serial.begin(115200); // Start the Serial communication 9 | } 10 | 11 | void loop() { 12 | 13 | if (serialMetro.check() == 1) { // check if the metro has passed it's interval . 14 | // Output all the analog readings seperated by a space character 15 | for (int i = 0; i < 6; i++ ) { 16 | Serial.print (analogRead( i) ); 17 | Serial.print(32,BYTE); 18 | } 19 | // Terminate message with a linefeed and a carriage return 20 | Serial.print(13,BYTE); 21 | Serial.print(10,BYTE); 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /Libreries/Metro/examples/blinking/blinking.ino: -------------------------------------------------------------------------------- 1 | /* 2 | This code will blink an LED attached to pin 13 on and off. 3 | It will stay on for 0.25 seconds. 4 | It will stay off for 1 second. 5 | */ 6 | #include //Include Metro library 7 | #define LED 13 // Define the led's pin 8 | 9 | //Create a variable to hold theled's current state 10 | int state = HIGH; 11 | 12 | // Instanciate a metro object and set the interval to 250 milliseconds (0.25 seconds). 13 | Metro ledMetro = Metro(250); 14 | 15 | void setup() 16 | { 17 | pinMode(LED,OUTPUT); 18 | digitalWrite(LED,state); 19 | } 20 | 21 | void loop() 22 | { 23 | 24 | if (ledMetro.check() == 1) { // check if the metro has passed its interval . 25 | if (state==HIGH) state=LOW; 26 | else state=HIGH; 27 | 28 | digitalWrite(LED,state); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Libreries/MIDI/examples/MIDI_Basic_IO/MIDI_Basic_IO.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // Simple tutorial on how to receive and send MIDI messages. 4 | // Here, when receiving any message on channel 4, the Arduino 5 | // will blink a led and play back a note for 1 second. 6 | 7 | MIDI_CREATE_DEFAULT_INSTANCE(); 8 | 9 | #define LED 13 // LED pin on Arduino Uno 10 | 11 | void setup() 12 | { 13 | pinMode(LED, OUTPUT); 14 | MIDI.begin(4); // Launch MIDI and listen to channel 4 15 | } 16 | 17 | void loop() 18 | { 19 | if (MIDI.read()) // If we have received a message 20 | { 21 | digitalWrite(LED,HIGH); 22 | MIDI.sendNoteOn(42,127,1); // Send a Note (pitch 42, velo 127 on channel 1) 23 | delay(1000); // Wait for a second 24 | MIDI.sendNoteOff(42,0,1); // Stop the note 25 | digitalWrite(LED,LOW); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Libreries/MIDI/examples/MIDI_SimpleSynth/noteList.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * \file synth-core_NoteList.h 3 | * \author Francois Best 4 | * \date 24/05/2013 5 | * \license GPL v3.0 - Copyright Forty Seven Effects 2013 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #include "noteList.h" 22 | -------------------------------------------------------------------------------- /Libreries/Metro/Metro.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #if defined(ARDUINO) && ARDUINO >= 100 4 | #include "Arduino.h" 5 | #else 6 | #include "WProgram.h" 7 | #endif 8 | #include "Metro.h" 9 | 10 | Metro::Metro() 11 | { 12 | 13 | this->interval_millis = 1000; 14 | 15 | } 16 | 17 | 18 | Metro::Metro(unsigned long interval_millis) 19 | { 20 | 21 | this->interval_millis = interval_millis; 22 | 23 | } 24 | 25 | 26 | void Metro::interval(unsigned long interval_millis) 27 | { 28 | this->interval_millis = interval_millis; 29 | } 30 | 31 | uint8_t Metro::check() 32 | { 33 | 34 | unsigned long now = millis(); 35 | 36 | if ( interval_millis == 0 ){ 37 | previous_millis = now; 38 | return 1; 39 | } 40 | 41 | if ( (now - previous_millis) >= interval_millis) { 42 | #ifdef NOCATCH-UP 43 | previous_millis = now ; 44 | #else 45 | previous_millis += interval_millis ; 46 | #endif 47 | return 1; 48 | } 49 | 50 | return 0; 51 | 52 | } 53 | 54 | void Metro::reset() 55 | { 56 | 57 | this->previous_millis = millis(); 58 | 59 | } 60 | 61 | 62 | -------------------------------------------------------------------------------- /Libreries/Metro/examples/blinking_2_intervals/blinking_2_intervals.ino: -------------------------------------------------------------------------------- 1 | /* 2 | This code will blink an LED attached to pin 13 on and off. 3 | It will stay on for 0.25 seconds. 4 | It will stay off for 1 second. 5 | */ 6 | #include //Include Metro library 7 | #define LED 13 // Define the led's pin 8 | 9 | //Create a variable to hold theled's current state 10 | int state = HIGH; 11 | 12 | // Instanciate a metro object and set the interval to 250 milliseconds (0.25 seconds). 13 | Metro ledMetro = Metro(250); 14 | 15 | void setup() 16 | { 17 | pinMode(LED,OUTPUT); 18 | digitalWrite(LED,state); 19 | } 20 | 21 | void loop() 22 | { 23 | 24 | if (ledMetro.check() == 1) { // check if the metro has passed its interval . 25 | if (state==HIGH) { 26 | state=LOW; 27 | ledMetro.interval(250); // if the pin is HIGH, set the interval to 0.25 seconds. 28 | } 29 | else { 30 | ledMetro.interval(1000); // if the pin is LOW, set the interval to 1 second. 31 | state=HIGH; 32 | } 33 | digitalWrite(LED,state); 34 | } 35 | } 36 | 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Sandro 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Libreries/AltSoftSerial/examples/Echo/Echo.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // AltSoftSerial always uses these pins: 4 | // 5 | // Board Transmit Receive PWM Unusable 6 | // ----- -------- ------- ------------ 7 | // Teensy 3.0 & 3.1 21 20 22 8 | // Teensy 2.0 9 10 (none) 9 | // Teensy++ 2.0 25 4 26, 27 10 | // Arduino Uno 9 8 10 11 | // Arduino Leonardo 5 13 (none) 12 | // Arduino Mega 46 48 44, 45 13 | // Wiring-S 5 6 4 14 | // Sanguino 13 14 12 15 | 16 | AltSoftSerial altSerial; 17 | 18 | void setup() { 19 | Serial.begin(9600); 20 | while (!Serial) ; // wait for Arduino Serial Monitor to open 21 | Serial.println("AltSoftSerial Test Begin"); 22 | altSerial.begin(9600); 23 | altSerial.println("Hello World"); 24 | } 25 | 26 | void loop() { 27 | char c; 28 | 29 | if (Serial.available()) { 30 | c = Serial.read(); 31 | altSerial.print(c); 32 | } 33 | if (altSerial.available()) { 34 | c = altSerial.read(); 35 | Serial.print(c); 36 | } 37 | } 38 | 39 | -------------------------------------------------------------------------------- /Libreries/Metro/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 thomasfredericks 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Libreries/Metro/examples/blinking_2_instances/blinking_2_instances.ino: -------------------------------------------------------------------------------- 1 | // This code will blink output 13 every 250 ms 2 | // abd will blink output 9 every 125 ms 3 | 4 | 5 | #include // Include Metro library 6 | #define LED0 13 // Define a LED pin 7 | #define LED1 9 // Define another LED pin 8 | 9 | // Create variables to hold the LED states 10 | int state0 = HIGH; 11 | int state1 = HIGH; 12 | 13 | // Instantiate a metro object and set the interval to 250 milliseconds (0.25 seconds). 14 | Metro metro0 = Metro(250); 15 | 16 | // Instantiate another metro object and set the interval to 125 milliseconds (0.125 seconds). 17 | Metro metro1 = Metro(125); 18 | 19 | void setup() 20 | { 21 | pinMode(LED0,OUTPUT); 22 | digitalWrite(LED0,state0); 23 | 24 | pinMode(LED1,OUTPUT); 25 | digitalWrite(LED1,state1); 26 | 27 | } 28 | 29 | void loop() 30 | { 31 | 32 | if (metro0.check() == 1) { // check if the metro has passed its interval . 33 | if (state0==HIGH) { 34 | state0=LOW; 35 | } else { 36 | state0=HIGH; 37 | } 38 | digitalWrite(LED0,state0); 39 | } 40 | 41 | if (metro1.check() == 1) { // check if the metro has passed its interval . 42 | if (state1==HIGH) { 43 | state1=LOW; 44 | } else { 45 | state1=HIGH; 46 | } 47 | digitalWrite(LED1,state1); 48 | } 49 | 50 | 51 | } 52 | -------------------------------------------------------------------------------- /Libreries/MIDI/midi_Namespace.h: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file midi_Namespace.h 3 | * Project Arduino MIDI Library 4 | * @brief MIDI Library for the Arduino - Namespace declaration 5 | * @version 4.2 6 | * @author Francois Best 7 | * @date 24/02/11 8 | * @license GPL v3.0 - Copyright Forty Seven Effects 2014 9 | * 10 | * This program is free software: you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation, either version 3 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program. If not, see . 22 | */ 23 | 24 | #pragma once 25 | 26 | #define MIDI_NAMESPACE midi 27 | #define BEGIN_MIDI_NAMESPACE namespace MIDI_NAMESPACE { 28 | #define END_MIDI_NAMESPACE } 29 | 30 | #define USING_NAMESPACE_MIDI using namespace MIDI_NAMESPACE; 31 | 32 | BEGIN_MIDI_NAMESPACE 33 | 34 | END_MIDI_NAMESPACE 35 | -------------------------------------------------------------------------------- /Libreries/Metro/Metro.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * This program is free software; you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation; either version 2 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 16 | * MA 02110-1301, USA. 17 | */ 18 | 19 | 20 | 21 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * 22 | Main code by Thomas O Fredericks (tof@t-o-f.info) 23 | Contributions by Paul Bouchier and Benjamin.soelberg 24 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 25 | 26 | #ifndef Metro_h 27 | #define Metro_h 28 | 29 | #include 30 | 31 | 32 | class Metro 33 | { 34 | 35 | public: 36 | Metro(); 37 | Metro(unsigned long interval_millis); 38 | void interval(unsigned long interval_millis); 39 | uint8_t check(); 40 | void reset(); 41 | 42 | private: 43 | unsigned long previous_millis, interval_millis; 44 | 45 | }; 46 | 47 | #endif 48 | 49 | 50 | -------------------------------------------------------------------------------- /Libreries/AltSoftSerial/examples/ReceiveTest/ReceiveTest.ino: -------------------------------------------------------------------------------- 1 | // AltSoftSerial Receive Test 2 | // 3 | // Transmit data with Serial1 and try to receive 4 | // it with AltSoftSerial. You must connect a wire 5 | // from Serial1 TX to AltSoftSerial RX. 6 | 7 | #include 8 | 9 | AltSoftSerial altser; 10 | const int mybaud = 9600; 11 | 12 | // Board Serial1 TX AltSoftSerial RX 13 | // ----- ---------- ---------------- 14 | // Teensy 3.x 1 20 15 | // Teensy 2.0 8 (D3) 10 (C7) 16 | // Teensy++ 2.0 3 (D3) 4 (D4) 17 | // Arduino Leonardo 1 13 18 | // Arduino Mega 18 48 19 | 20 | // Serial1 on AVR @ 16 MHz minimum baud is 245 21 | // Serial1 on Teensy 3.2 @ 96 MHz minimum baud is 733 22 | 23 | byte sentbyte; 24 | unsigned long prevmillis; 25 | byte testbyte=0xF0; 26 | 27 | void setup() { 28 | delay(200); 29 | Serial.begin(9600); 30 | while (!Serial) ; // wait for Arduino Serial Monitor 31 | Serial1.begin(mybaud); // connect a wire from TX1 32 | altser.begin(mybaud); // to AltSoftSerial RX 33 | Serial.println("AltSoftSerial Receive Test"); 34 | prevmillis = millis(); 35 | } 36 | 37 | void loop() { 38 | // transmit a test byte on Serial 1 39 | if (millis() - prevmillis > 250) { 40 | sentbyte = testbyte++; 41 | Serial1.write(sentbyte); 42 | prevmillis = millis(); 43 | } 44 | // attempt to receive it by AltSoftSerial 45 | if (altser.available() > 0) { 46 | byte b = altser.read(); 47 | Serial.println(b); 48 | if (b != sentbyte) Serial.println("***** ERROR *****"); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Libreries/MIDI/examples/MIDI_DualMerger/MIDI_DualMerger.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // This example shows how to create two instances of the library to create a merger. 4 | // There are two MIDI couples of IO, A and B, each using thru and merging with the 5 | // input from the other node. The result is the following: 6 | // A out = A in + B in 7 | // B out = B in + A in 8 | 9 | #ifdef ARDUINO_SAM_DUE 10 | MIDI_CREATE_INSTANCE(HardwareSerial, Serial, midiA); 11 | MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, midiB); 12 | #else 13 | #include 14 | SoftwareSerial softSerial(2,3); 15 | MIDI_CREATE_INSTANCE(HardwareSerial, Serial, midiA); 16 | MIDI_CREATE_INSTANCE(SoftwareSerial, softSerial, midiB); 17 | #endif 18 | 19 | void setup() 20 | { 21 | // Initiate MIDI communications, listen to all channels 22 | midiA.begin(MIDI_CHANNEL_OMNI); 23 | midiB.begin(MIDI_CHANNEL_OMNI); 24 | } 25 | 26 | void loop() 27 | { 28 | if (midiA.read()) 29 | { 30 | // Thru on A has already pushed the input message to out A. 31 | // Forward the message to out B as well. 32 | midiB.send(midiA.getType(), 33 | midiA.getData1(), 34 | midiA.getData2(), 35 | midiA.getChannel()); 36 | } 37 | 38 | if (midiB.read()) 39 | { 40 | // Thru on B has already pushed the input message to out B. 41 | // Forward the message to out A as well. 42 | midiA.send(midiB.getType(), 43 | midiB.getData1(), 44 | midiB.getData2(), 45 | midiB.getChannel()); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Libreries/MIDI/examples/MIDI_Input/MIDI_Input.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | MIDI_CREATE_DEFAULT_INSTANCE(); 4 | 5 | // ----------------------------------------------------------------------------- 6 | 7 | // This example shows the old way of checking for input messages. 8 | // It's simpler to use the callbacks now, check out the dedicated example. 9 | 10 | #define LED 13 // LED pin on Arduino Uno 11 | 12 | // ----------------------------------------------------------------------------- 13 | 14 | void BlinkLed(byte num) // Basic blink function 15 | { 16 | for (byte i=0;i 2 | 3 | MIDI_CREATE_DEFAULT_INSTANCE(); 4 | 5 | // ----------------------------------------------------------------------------- 6 | 7 | // This function will be automatically called when a NoteOn is received. 8 | // It must be a void-returning function with the correct parameters, 9 | // see documentation here: 10 | // http://arduinomidilib.fortyseveneffects.com/a00022.html 11 | 12 | void handleNoteOn(byte channel, byte pitch, byte velocity) 13 | { 14 | // Do whatever you want when a note is pressed. 15 | 16 | // Try to keep your callbacks short (no delays ect) 17 | // otherwise it would slow down the loop() and have a bad impact 18 | // on real-time performance. 19 | } 20 | 21 | void handleNoteOff(byte channel, byte pitch, byte velocity) 22 | { 23 | // Do something when the note is released. 24 | // Note that NoteOn messages with 0 velocity are interpreted as NoteOffs. 25 | } 26 | 27 | // ----------------------------------------------------------------------------- 28 | 29 | void setup() 30 | { 31 | // Connect the handleNoteOn function to the library, 32 | // so it is called upon reception of a NoteOn. 33 | MIDI.setHandleNoteOn(handleNoteOn); // Put only the name of the function 34 | 35 | // Do the same for NoteOffs 36 | MIDI.setHandleNoteOff(handleNoteOff); 37 | 38 | // Initiate MIDI communications, listen to all channels 39 | MIDI.begin(MIDI_CHANNEL_OMNI); 40 | } 41 | 42 | void loop() 43 | { 44 | // Call MIDI.read the fastest you can for real-time performance. 45 | MIDI.read(); 46 | 47 | // There is no need to check if there are messages incoming 48 | // if they are bound to a Callback function. 49 | // The attached method will be called automatically 50 | // when the corresponding message has been received. 51 | } 52 | -------------------------------------------------------------------------------- /Libreries/MIDI/examples/MIDI_Bench/MIDI_Bench.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // This program will measure the time needed to receive, parse and process a 4 | // NoteOn message. 5 | // For it to work, please connect RX and TX on the MIDI port: 6 | // Due, Leonardo and other USB-native Arduinos: Serial1 7 | // All other Arduinos: Connect pins 2 and 3. 8 | // The program will then wait for 100 loops and print the results. 9 | 10 | #if defined(ARDUINO_SAM_DUE) || defined(USBCON) 11 | // Print through USB and bench with Hardware serial 12 | MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, midiBench); 13 | #else 14 | #include 15 | SoftwareSerial midiSerial(2,3); 16 | MIDI_CREATE_INSTANCE(SoftwareSerial, midiSerial, midiBench); 17 | #endif 18 | 19 | // ----------------------------------------------------------------------------- 20 | 21 | unsigned long gTime_start = 0; 22 | unsigned long gTime_stop = 0; 23 | unsigned gCounter = 0; 24 | unsigned long gTime_sum = 0; 25 | unsigned long gTime_min = -1; 26 | unsigned long gTime_max = 0; 27 | 28 | // ----------------------------------------------------------------------------- 29 | 30 | void handleNoteOn(byte inChannel, byte inNote, byte inVelocity) 31 | { 32 | gTime_stop = micros(); 33 | 34 | const unsigned long diff = gTime_stop - gTime_start; 35 | gTime_sum += diff; 36 | 37 | if (diff > gTime_max) gTime_max = diff; 38 | if (diff < gTime_min) gTime_min = diff; 39 | 40 | if (gCounter++ >= 1000) 41 | { 42 | const unsigned long average = gTime_sum / (float)gCounter; 43 | 44 | Serial.println("Time to receive NoteOn: "); 45 | 46 | Serial.print("Average: "); 47 | Serial.print(average); 48 | Serial.println(" microsecs"); 49 | 50 | Serial.print("Min: "); 51 | Serial.print(gTime_min); 52 | Serial.println(" microsecs"); 53 | 54 | Serial.print("Max: "); 55 | Serial.print(gTime_max); 56 | Serial.println(" microsecs"); 57 | 58 | gCounter = 0; 59 | gTime_sum = 0; 60 | gTime_max = 0; 61 | gTime_min = -1; 62 | 63 | midiBench.turnThruOff(); 64 | } 65 | } 66 | 67 | // ----------------------------------------------------------------------------- 68 | 69 | void setup() 70 | { 71 | midiBench.setHandleNoteOn(handleNoteOn); 72 | midiBench.begin(); 73 | 74 | while(!Serial); 75 | Serial.begin(115200); 76 | Serial.println("Arduino Ready"); 77 | 78 | midiBench.sendNoteOn(69,127,1); 79 | } 80 | 81 | void loop() 82 | { 83 | gTime_start = micros(); 84 | midiBench.read(); 85 | } 86 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Coda-88 2 | 3 | Minimal piano sound module/expander with dynamics based on Arduino and WAV Trigger 4 | 5 | ![](https://www.sandrolabbate.com/wp-content/uploads/2023/11/2018_coda_close.jpg) 6 |
7 | *© 2018 [Sandro L'Abbate](https://www.sandrolabbate.com "Sandro L'Abbate")* 8 | 9 | ## Features 10 | - 88-key keyboard compatible 11 | - MIDI connection 12 | - Zero boot time 13 | - Low latency 14 | - Polyphony (14-stereo) 15 | - Realistic dynamics (3 sampling layers) 16 | - Dumper and release-key effects 17 | 18 | ## Parts 19 | - Arduino UNO 20 | - WAV Trigger 21 | - 6N138 22 | - Diode 1N914 23 | - Resistor 220 Ohm (x2) 24 | - Resistor 4.7K 25 | - Switch (optional - you need to disconnect RX before upload) 26 | 27 | ## Schema 28 | ![Coda-88_Schema](https://github.com/sandrolab/Coda-88/blob/1e316c8b399025062a1382ba375b062ecdef1a1b/Schema.jpg "Coda-88_Schema")
29 | *WAV Trigger SVG from [sjpiper145](https://github.com/sjpiper145/Sparkfun_wavTrigger_SVG "sjpiper145")* 30 | 31 | ## Arduino 32 | 33 | ### 1) Libraries 34 | - AltSoftSerial 35 | - Metro 36 | - MIDI 37 | - wavTrigger 38 | 39 | ### 2) Dumper pedal and release-key sounds 40 | Set `true` these two variables (leave `false` for a better performance): 41 | ```cpp 42 | bool RELSOUND = true; 43 | bool PEDALSOUND = true; 44 | ``` 45 | ### 3) Upload 46 | Disconnect (or use switch button) RX connection from MIDI to Arduino before upload 47 | 48 | ### 4) Boot/reset 49 | Press reset button on the Arduino after every boot (or strange behavior) 50 | 51 | ## WAV Trigger 52 | 53 | ### Samples numeration (ex. 032.wav) 54 | | Samples | Start | End | 55 | | ------------ | ------------ | ------------ | 56 | | Init sound | `020` | | 57 | | Piano | `021 ` | `108` | 58 | | Medio | `109` | `196` | 59 | | Forte | `197` | `284` | 60 | | Release keys | `285` | `372` | 61 | | Pedal down | `373` | | 62 | | Pedal up | `374` | | 63 | 64 | ### Piano Samples 65 | [Download](https://bit.ly/Coda88_PianoSamples "Download") this folder and copy its content into the WAV Trigger microSD. 66 | 67 | These sample kit comes from [Iowa Piano](https://theremin.music.uiowa.edu/MISpiano.html "Iowa Piano") (main piano) and [Salamander Piano](https://freepats.zenvoid.org/Piano/acoustic-grand-piano.html "Salamander Piano") (only for dumper and release sounds). 68 | Both libraries are free licensed. 69 | 70 | See [here](https://robertsonics.com/microsd-cards-for-audio/ "here") for the best microSD cards for audio. 71 | 72 | ### Official Library 73 | https://github.com/robertsonics/WAV-Trigger-Arduino-Serial-Library 74 | 75 | ------------ 76 | 77 | ### [Video demonstration](https://youtu.be/3IshDsRlHGw "Video demonstration") 78 | -------------------------------------------------------------------------------- /Libreries/MIDI/midi_Message.h: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file midi_Message.h 3 | * Project Arduino MIDI Library 4 | * @brief MIDI Library for the Arduino - Message struct definition 5 | * @version 4.2 6 | * @author Francois Best 7 | * @date 11/06/14 8 | * @license GPL v3.0 - Copyright Forty Seven Effects 2014 9 | * 10 | * This program is free software: you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation, either version 3 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program. If not, see . 22 | */ 23 | 24 | #pragma once 25 | 26 | #include "midi_Namespace.h" 27 | #include "midi_Defs.h" 28 | 29 | BEGIN_MIDI_NAMESPACE 30 | 31 | /*! The Message structure contains decoded data of a MIDI message 32 | read from the serial port with read() 33 | */ 34 | template 35 | struct Message 36 | { 37 | /*! The maximum size for the System Exclusive array. 38 | */ 39 | static const unsigned sSysExMaxSize = SysExMaxSize; 40 | 41 | /*! The MIDI channel on which the message was recieved. 42 | \n Value goes from 1 to 16. 43 | */ 44 | Channel channel; 45 | 46 | /*! The type of the message 47 | (see the MidiType enum for types reference) 48 | */ 49 | MidiType type; 50 | 51 | /*! The first data byte. 52 | \n Value goes from 0 to 127. 53 | */ 54 | DataByte data1; 55 | 56 | /*! The second data byte. 57 | If the message is only 2 bytes long, this one is null. 58 | \n Value goes from 0 to 127. 59 | */ 60 | DataByte data2; 61 | 62 | /*! System Exclusive dedicated byte array. 63 | \n Array length is stocked on 16 bits, 64 | in data1 (LSB) and data2 (MSB) 65 | */ 66 | DataByte sysexArray[sSysExMaxSize]; 67 | 68 | /*! This boolean indicates if the message is valid or not. 69 | There is no channel consideration here, 70 | validity means the message respects the MIDI norm. 71 | */ 72 | bool valid; 73 | 74 | inline unsigned getSysExSize() const 75 | { 76 | const unsigned size = unsigned(data2) << 8 | data1; 77 | return size > sSysExMaxSize ? sSysExMaxSize : size; 78 | } 79 | }; 80 | 81 | END_MIDI_NAMESPACE 82 | -------------------------------------------------------------------------------- /Libreries/AltSoftSerial/examples/ShowConfiguration/ShowConfiguration.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // AltSoftSerial show configuration example 4 | // Will print library configuration to default serial port 5 | // Open your serial monitor to see config for your board 6 | // Printout would repeat every 10sec (just in case you missed it somehow) 7 | 8 | // Print Configuration 9 | // ----------------------- 10 | 11 | // Direct include AltSoftSerial internals to obtaion PIN setup (you do not need this in regular code) 12 | #include 13 | 14 | void printAltSoftSerialSetup(Stream &port) 15 | { 16 | #define PRINT_PFX "AltSoftSerial:" 17 | #define PRINT_PIN_NAME(pin,name) { char buffer[128+1]; sprintf(buffer, PRINT_PFX "PIN:%2d %s", (int)pin, (const char*)name); port.println(buffer); } 18 | 19 | port.println(PRINT_PFX "Setup info: begin"); 20 | 21 | #if defined(ALTSS_USE_FTM0) 22 | port.println(PRINT_PFX "USE FTM0"); 23 | #endif 24 | 25 | #if defined(ALTSS_USE_TIMER1) 26 | port.println(PRINT_PFX "USE TIMER1"); 27 | #endif 28 | 29 | #if defined(ALTSS_USE_TIMER2) 30 | port.println(PRINT_PFX "USE TIMER2"); 31 | #endif 32 | 33 | #if defined(ALTSS_USE_TIMER3) 34 | port.println(PRINT_PFX "USE TIMER3"); 35 | #endif 36 | 37 | #if defined(ALTSS_USE_TIMER4) 38 | port.println(PRINT_PFX "USE TIMER4"); 39 | #endif 40 | 41 | #if defined(ALTSS_USE_TIMER5) 42 | port.println(PRINT_PFX "USE TIMER5"); 43 | #endif 44 | 45 | #if defined(INPUT_CAPTURE_PIN) 46 | PRINT_PIN_NAME(INPUT_CAPTURE_PIN,"RX"); 47 | #endif 48 | 49 | #if defined(OUTPUT_COMPARE_A_PIN) 50 | PRINT_PIN_NAME(OUTPUT_COMPARE_A_PIN,"TX"); 51 | #endif 52 | 53 | #if defined(OUTPUT_COMPARE_B_PIN) 54 | PRINT_PIN_NAME(OUTPUT_COMPARE_B_PIN,"(unused PWM)"); 55 | #endif 56 | 57 | #if defined(OUTPUT_COMPARE_C_PIN) 58 | PRINT_PIN_NAME(OUTPUT_COMPARE_C_PIN,"(unused PWM)"); 59 | #endif 60 | 61 | #if defined(OUTPUT_COMPARE_D_PIN) 62 | PRINT_PIN_NAME(OUTPUT_COMPARE_D_PIN,"(unused PWM)"); 63 | #endif 64 | 65 | #if defined(OUTPUT_COMPARE_E_PIN) 66 | PRINT_PIN_NAME(OUTPUT_COMPARE_E_PIN,"(unused PWM)"); 67 | #endif 68 | 69 | #if defined(OUTPUT_COMPARE_F_PIN) 70 | PRINT_PIN_NAME(OUTPUT_COMPARE_F_PIN,"(unused PWM)"); 71 | #endif 72 | 73 | port.println(PRINT_PFX "Setup info: end"); 74 | 75 | #undef PRINT_PIN_NAME 76 | #undef PRINT_PFX 77 | } 78 | 79 | void setup() 80 | { 81 | // Open default serial to dump config to 82 | Serial.begin(9600); 83 | while (!Serial) ; // wait for serial monitor 84 | printAltSoftSerialSetup(Serial); 85 | } 86 | 87 | void loop() 88 | { 89 | // Repeat every 10 sec (just in case) 90 | delay(10000); 91 | Serial.println(""); 92 | printAltSoftSerialSetup(Serial); 93 | } 94 | 95 | -------------------------------------------------------------------------------- /Libreries/MIDI/examples/MIDI_SimpleSynth/MIDI_SimpleSynth.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include "noteList.h" 3 | #include "pitches.h" 4 | 5 | MIDI_CREATE_DEFAULT_INSTANCE(); 6 | 7 | #ifdef ARDUINO_SAM_DUE // Due has no tone function (yet), overriden to prevent build errors. 8 | #define tone(...) 9 | #define noTone(...) 10 | #endif 11 | 12 | // This example shows how to make a simple synth out of an Arduino, using the 13 | // tone() function. It also outputs a gate signal for controlling external 14 | // analog synth components (like envelopes). 15 | 16 | static const unsigned sGatePin = 13; 17 | static const unsigned sAudioOutPin = 10; 18 | static const unsigned sMaxNumNotes = 16; 19 | MidiNoteList midiNotes; 20 | 21 | // ----------------------------------------------------------------------------- 22 | 23 | inline void handleGateChanged(bool inGateActive) 24 | { 25 | digitalWrite(sGatePin, inGateActive ? HIGH : LOW); 26 | } 27 | 28 | inline void pulseGate() 29 | { 30 | handleGateChanged(false); 31 | delay(1); 32 | handleGateChanged(true); 33 | } 34 | 35 | // ----------------------------------------------------------------------------- 36 | 37 | void handleNotesChanged(bool isFirstNote = false) 38 | { 39 | if (midiNotes.empty()) 40 | { 41 | handleGateChanged(false); 42 | noTone(sAudioOutPin); 43 | } 44 | else 45 | { 46 | // Possible playing modes: 47 | // Mono Low: use midiNotes.getLow 48 | // Mono High: use midiNotes.getHigh 49 | // Mono Last: use midiNotes.getLast 50 | 51 | byte currentNote = 0; 52 | if (midiNotes.getLast(currentNote)) 53 | { 54 | tone(sAudioOutPin, sNotePitches[currentNote]); 55 | 56 | if (isFirstNote) 57 | { 58 | handleGateChanged(true); 59 | } 60 | else 61 | { 62 | pulseGate(); // Retrigger envelopes. Remove for legato effect. 63 | } 64 | } 65 | } 66 | } 67 | 68 | // ----------------------------------------------------------------------------- 69 | 70 | void handleNoteOn(byte inChannel, byte inNote, byte inVelocity) 71 | { 72 | const bool firstNote = midiNotes.empty(); 73 | midiNotes.add(MidiNote(inNote, inVelocity)); 74 | handleNotesChanged(firstNote); 75 | } 76 | 77 | void handleNoteOff(byte inChannel, byte inNote, byte inVelocity) 78 | { 79 | midiNotes.remove(inNote); 80 | handleNotesChanged(); 81 | } 82 | 83 | // ----------------------------------------------------------------------------- 84 | 85 | void setup() 86 | { 87 | pinMode(sGatePin, OUTPUT); 88 | pinMode(sAudioOutPin, OUTPUT); 89 | MIDI.setHandleNoteOn(handleNoteOn); 90 | MIDI.setHandleNoteOff(handleNoteOff); 91 | MIDI.begin(); 92 | } 93 | 94 | void loop() 95 | { 96 | MIDI.read(); 97 | } 98 | -------------------------------------------------------------------------------- /Libreries/AltSoftSerial/AltSoftSerial.h: -------------------------------------------------------------------------------- 1 | /* An Alternative Software Serial Library 2 | * http://www.pjrc.com/teensy/td_libs_AltSoftSerial.html 3 | * Copyright (c) 2014 PJRC.COM, LLC, Paul Stoffregen, paul@pjrc.com 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | 24 | #ifndef AltSoftSerial_h 25 | #define AltSoftSerial_h 26 | 27 | #include 28 | 29 | #if ARDUINO >= 100 30 | #include "Arduino.h" 31 | #else 32 | #include "WProgram.h" 33 | #include "pins_arduino.h" 34 | #endif 35 | 36 | #if defined(__arm__) && defined(CORE_TEENSY) 37 | #define ALTSS_BASE_FREQ F_BUS 38 | #else 39 | #define ALTSS_BASE_FREQ F_CPU 40 | #endif 41 | 42 | class AltSoftSerial : public Stream 43 | { 44 | public: 45 | AltSoftSerial() { } 46 | ~AltSoftSerial() { end(); } 47 | static void begin(uint32_t baud) { init((ALTSS_BASE_FREQ + baud / 2) / baud); } 48 | static void end(); 49 | int peek(); 50 | int read(); 51 | int available(); 52 | #if ARDUINO >= 100 53 | size_t write(uint8_t byte) { writeByte(byte); return 1; } 54 | void flush() { flushOutput(); } 55 | #else 56 | void write(uint8_t byte) { writeByte(byte); } 57 | void flush() { flushInput(); } 58 | #endif 59 | using Print::write; 60 | static void flushInput(); 61 | static void flushOutput(); 62 | // for drop-in compatibility with NewSoftSerial, rxPin & txPin ignored 63 | AltSoftSerial(uint8_t rxPin, uint8_t txPin, bool inverse = false) { } 64 | bool listen() { return false; } 65 | bool isListening() { return true; } 66 | bool overflow() { bool r = timing_error; timing_error = false; return r; } 67 | static int library_version() { return 1; } 68 | static void enable_timer0(bool enable) { } 69 | static bool timing_error; 70 | private: 71 | static void init(uint32_t cycles_per_bit); 72 | static void writeByte(uint8_t byte); 73 | }; 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /Libreries/MIDI/midi_Settings.h: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file midi_Settings.h 3 | * Project Arduino MIDI Library 4 | * @brief MIDI Library for the Arduino - Settings 5 | * @version 4.2 6 | * @author Francois Best 7 | * @date 24/02/11 8 | * @license GPL v3.0 - Copyright Forty Seven Effects 2014 9 | * 10 | * This program is free software: you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation, either version 3 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program. If not, see . 22 | */ 23 | 24 | #pragma once 25 | 26 | #include "midi_Defs.h" 27 | 28 | BEGIN_MIDI_NAMESPACE 29 | 30 | /*! \brief Default Settings for the MIDI Library. 31 | 32 | To change the default settings, don't edit them there, create a subclass and 33 | override the values in that subclass, then use the MIDI_CREATE_CUSTOM_INSTANCE 34 | macro to create your instance. The settings you don't override will keep their 35 | default value. Eg: 36 | \code{.cpp} 37 | struct MySettings : public midi::DefaultSettings 38 | { 39 | static const bool UseRunningStatus = false; // Messes with my old equipment! 40 | }; 41 | 42 | MIDI_CREATE_CUSTOM_INSTANCE(HardwareSerial, Serial2, midi, MySettings); 43 | \endcode 44 | */ 45 | struct DefaultSettings 46 | { 47 | /*! Running status enables short messages when sending multiple values 48 | of the same type and channel.\n 49 | Set to 0 if you have troubles controlling your hardware. 50 | */ 51 | static const bool UseRunningStatus = true; 52 | 53 | /* NoteOn with 0 velocity should be handled as NoteOf.\n 54 | Set to 1 to get NoteOff events when receiving null-velocity NoteOn messages.\n 55 | Set to 0 to get NoteOn events when receiving null-velocity NoteOn messages. 56 | */ 57 | static const bool HandleNullVelocityNoteOnAsNoteOff = true; 58 | 59 | // Setting this to 1 will make MIDI.read parse only one byte of data for each 60 | // call when data is available. This can speed up your application if receiving 61 | // a lot of traffic, but might induce MIDI Thru and treatment latency. 62 | static const bool Use1ByteParsing = true; 63 | 64 | /*! Override the default MIDI baudrate to transmit over USB serial, to 65 | a decoding program such as Hairless MIDI (set baudrate to 115200)\n 66 | http://projectgus.github.io/hairless-midiserial/ 67 | */ 68 | static const long BaudRate = 31250; 69 | 70 | /*! Maximum size of SysEx receivable. Decrease to save RAM if you don't expect 71 | to receive SysEx, or adjust accordingly. 72 | */ 73 | static const unsigned SysExMaxSize = 128; 74 | }; 75 | 76 | END_MIDI_NAMESPACE 77 | -------------------------------------------------------------------------------- /Libreries/MIDI/keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For Test 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | MIDI KEYWORD1 10 | MIDI.h KEYWORD1 11 | MidiInterface KEYWORD1 12 | DefaultSettings KEYWORD1 13 | 14 | ####################################### 15 | # Methods and Functions (KEYWORD2) 16 | ####################################### 17 | 18 | send KEYWORD2 19 | sendNoteOn KEYWORD2 20 | sendNoteOff KEYWORD2 21 | sendProgramChange KEYWORD2 22 | sendControlChange KEYWORD2 23 | sendPitchBend KEYWORD2 24 | sendPolyPressure KEYWORD2 25 | sendAfterTouch KEYWORD2 26 | sendSysEx KEYWORD2 27 | sendTimeCodeQuarterFrame KEYWORD2 28 | sendSongPosition KEYWORD2 29 | sendSongSelect KEYWORD2 30 | sendTuneRequest KEYWORD2 31 | sendRealTime KEYWORD2 32 | begin KEYWORD2 33 | read KEYWORD2 34 | getType KEYWORD2 35 | getChannel KEYWORD2 36 | getData1 KEYWORD2 37 | getData2 KEYWORD2 38 | getSysExArray KEYWORD2 39 | getFilterMode KEYWORD2 40 | getThruState KEYWORD2 41 | getInputChannel KEYWORD2 42 | check KEYWORD2 43 | delMsg KEYWORD2 44 | delSysEx KEYWORD2 45 | setInputChannel KEYWORD2 46 | setStatus KEYWORD2 47 | turnThruOn KEYWORD2 48 | turnThruOff KEYWORD2 49 | setThruFilterMode KEYWORD2 50 | disconnectCallbackFromType KEYWORD2 51 | setHandleNoteOff KEYWORD2 52 | setHandleNoteOn KEYWORD2 53 | setHandleAfterTouchPoly KEYWORD2 54 | setHandleControlChange KEYWORD2 55 | setHandleProgramChange KEYWORD2 56 | setHandleAfterTouchChannel KEYWORD2 57 | setHandlePitchBend KEYWORD2 58 | setHandleSystemExclusive KEYWORD2 59 | setHandleTimeCodeQuarterFrame KEYWORD2 60 | setHandleSongPosition KEYWORD2 61 | setHandleSongSelect KEYWORD2 62 | setHandleTuneRequest KEYWORD2 63 | setHandleClock KEYWORD2 64 | setHandleStart KEYWORD2 65 | setHandleContinue KEYWORD2 66 | setHandleStop KEYWORD2 67 | setHandleActiveSensing KEYWORD2 68 | setHandleSystemReset KEYWORD2 69 | getTypeFromStatusByte KEYWORD2 70 | encodeSysEx KEYWORD2 71 | decodeSysEx KEYWORD2 72 | 73 | 74 | ####################################### 75 | # Instances (KEYWORD2) 76 | ####################################### 77 | 78 | ####################################### 79 | # Constants (LITERAL1) 80 | ####################################### 81 | 82 | # Namespace, considering it as a literal 83 | midi LITERAL1 84 | 85 | NoteOff LITERAL1 86 | NoteOn LITERAL1 87 | AfterTouchPoly LITERAL1 88 | ControlChange LITERAL1 89 | ProgramChange LITERAL1 90 | AfterTouchChannel LITERAL1 91 | PitchBend LITERAL1 92 | SystemExclusive LITERAL1 93 | TimeCodeQuarterFrame LITERAL1 94 | SongPosition LITERAL1 95 | SongSelect LITERAL1 96 | TuneRequest LITERAL1 97 | Clock LITERAL1 98 | Start LITERAL1 99 | Stop LITERAL1 100 | Continue LITERAL1 101 | ActiveSensing LITERAL1 102 | SystemReset LITERAL1 103 | InvalidType LITERAL1 104 | Off LITERAL1 105 | Full LITERAL1 106 | SameChannel LITERAL1 107 | DifferentChannel LITERAL1 108 | MIDI_CHANNEL_OMNI LITERAL1 109 | MIDI_CHANNEL_OFF LITERAL1 110 | MIDI_CREATE_INSTANCE LITERAL1 111 | MIDI_CREATE_DEFAULT_INSTANCE LITERAL1 112 | MIDI_CREATE_CUSTOM_INSTANCE LITERAL1 113 | -------------------------------------------------------------------------------- /Libreries/wavTrigger/wavTrigger.h: -------------------------------------------------------------------------------- 1 | // ************************************************************** 2 | // Filename: wavTrigger.h 3 | // Date Created: 2/23/2014 4 | // 5 | // Comments: Robertsonics WAV Trigger serial control library 6 | // 7 | // Programmers: Jamie Robertson, jamie@robertsonics.com 8 | // 9 | // ************************************************************** 10 | // 11 | // Revision History 12 | // 13 | // Date Description 14 | // -------- ----------- 15 | // 16 | // 02/22/14 First version created. 17 | // LIMITATIONS: Hard-coded for AltSoftwareSerial Library. 18 | // Also only supports commands TO the WAV Trigger. Will 19 | // fix these things. 20 | // 21 | // 05/10/14 Tested with UNO. Added new functions for fades, cross- 22 | // fades and starting multiple tracks in sample sync. 23 | // 24 | // 04/26/15 Added support for sample-rate / pitch bend control, 25 | // and compile macro switches for hardware serial ports. 26 | // 27 | 28 | #ifndef WAVTRIGGER_H 29 | #define WAVTRIGGER_H 30 | 31 | // ================================================================== 32 | // The following defines are used to control which serial class is 33 | // used. Uncomment only the one you wish to use. If all of them are 34 | // commented out, the library will use Hardware Serial 35 | #define __WT_USE_ALTSOFTSERIAL__ 36 | //#define __WT_USE_SERIAL1__ 37 | //#define __WT_USE_SERIAL2__ 38 | //#define __WT_USE_SERIAL3__ 39 | // ================================================================== 40 | 41 | #define CMD_TRACK_CONTROL 3 42 | #define CMD_STOP_ALL 4 43 | #define CMD_MASTER_VOLUME 5 44 | #define CMD_TRACK_VOLUME 8 45 | #define CMD_TRACK_FADE 10 46 | #define CMD_RESUME_ALL_SYNC 11 47 | #define CMD_SAMPLERATE_OFFSET 12 48 | 49 | #define TRK_PLAY_SOLO 0 50 | #define TRK_PLAY_POLY 1 51 | #define TRK_PAUSE 2 52 | #define TRK_RESUME 3 53 | #define TRK_STOP 4 54 | #define TRK_LOOP_ON 5 55 | #define TRK_LOOP_OFF 6 56 | #define TRK_LOAD 7 57 | 58 | #ifdef __WT_USE_ALTSOFTSERIAL__ 59 | #include "../AltSoftSerial/AltSoftSerial.h" 60 | #else 61 | #include 62 | #ifdef __WT_USE_SERIAL1__ 63 | #define WTSerial Serial1 64 | #define __WT_SERIAL_ASSIGNED__ 65 | #endif 66 | #ifdef __WT_USE_SERIAL2__ 67 | #define WTSerial Serial2 68 | #define __WT_SERIAL_ASSIGNED__ 69 | #endif 70 | #ifdef __WT_USE_SERIAL3__ 71 | #define WTSerial Serial3 72 | #define __WT_SERIAL_ASSIGNED__ 73 | #endif 74 | #ifndef __WT_SERIAL_ASSIGNED__ 75 | #define WTSerial Serial 76 | #endif 77 | #endif 78 | 79 | class wavTrigger 80 | { 81 | public: 82 | wavTrigger() {;} 83 | ~wavTrigger() {;} 84 | void start(void); 85 | void masterGain(int gain); 86 | void stopAllTracks(void); 87 | void resumeAllInSync(void); 88 | void trackPlaySolo(int trk); 89 | void trackPlayPoly(int trk); 90 | void trackLoad(int trk); 91 | void trackStop(int trk); 92 | void trackPause(int trk); 93 | void trackResume(int trk); 94 | void trackLoop(int trk, bool enable); 95 | void trackGain(int trk, int gain); 96 | void trackFade(int trk, int gain, int time, bool stopFlag); 97 | void trackCrossFade(int trkFrom, int trkTo, int gain, int time); 98 | void samplerateOffset(int offset); 99 | private: 100 | void trackControl(int trk, int code); 101 | 102 | #ifdef __WT_USE_ALTSOFTSERIAL__ 103 | AltSoftSerial WTSerial; 104 | #endif 105 | 106 | }; 107 | 108 | #endif 109 | -------------------------------------------------------------------------------- /Libreries/MIDI/examples/MIDI_SimpleSynth/pitches.h: -------------------------------------------------------------------------------- 1 | /************************************************* 2 | * Public Constants 3 | *************************************************/ 4 | #include 5 | 6 | #define NOTE_B0 31 7 | #define NOTE_C1 33 8 | #define NOTE_CS1 35 9 | #define NOTE_D1 37 10 | #define NOTE_DS1 39 11 | #define NOTE_E1 41 12 | #define NOTE_F1 44 13 | #define NOTE_FS1 46 14 | #define NOTE_G1 49 15 | #define NOTE_GS1 52 16 | #define NOTE_A1 55 17 | #define NOTE_AS1 58 18 | #define NOTE_B1 62 19 | #define NOTE_C2 65 20 | #define NOTE_CS2 69 21 | #define NOTE_D2 73 22 | #define NOTE_DS2 78 23 | #define NOTE_E2 82 24 | #define NOTE_F2 87 25 | #define NOTE_FS2 93 26 | #define NOTE_G2 98 27 | #define NOTE_GS2 104 28 | #define NOTE_A2 110 29 | #define NOTE_AS2 117 30 | #define NOTE_B2 123 31 | #define NOTE_C3 131 32 | #define NOTE_CS3 139 33 | #define NOTE_D3 147 34 | #define NOTE_DS3 156 35 | #define NOTE_E3 165 36 | #define NOTE_F3 175 37 | #define NOTE_FS3 185 38 | #define NOTE_G3 196 39 | #define NOTE_GS3 208 40 | #define NOTE_A3 220 41 | #define NOTE_AS3 233 42 | #define NOTE_B3 247 43 | #define NOTE_C4 262 44 | #define NOTE_CS4 277 45 | #define NOTE_D4 294 46 | #define NOTE_DS4 311 47 | #define NOTE_E4 330 48 | #define NOTE_F4 349 49 | #define NOTE_FS4 370 50 | #define NOTE_G4 392 51 | #define NOTE_GS4 415 52 | #define NOTE_A4 440 53 | #define NOTE_AS4 466 54 | #define NOTE_B4 494 55 | #define NOTE_C5 523 56 | #define NOTE_CS5 554 57 | #define NOTE_D5 587 58 | #define NOTE_DS5 622 59 | #define NOTE_E5 659 60 | #define NOTE_F5 698 61 | #define NOTE_FS5 740 62 | #define NOTE_G5 784 63 | #define NOTE_GS5 831 64 | #define NOTE_A5 880 65 | #define NOTE_AS5 932 66 | #define NOTE_B5 988 67 | #define NOTE_C6 1047 68 | #define NOTE_CS6 1109 69 | #define NOTE_D6 1175 70 | #define NOTE_DS6 1245 71 | #define NOTE_E6 1319 72 | #define NOTE_F6 1397 73 | #define NOTE_FS6 1480 74 | #define NOTE_G6 1568 75 | #define NOTE_GS6 1661 76 | #define NOTE_A6 1760 77 | #define NOTE_AS6 1865 78 | #define NOTE_B6 1976 79 | #define NOTE_C7 2093 80 | #define NOTE_CS7 2217 81 | #define NOTE_D7 2349 82 | #define NOTE_DS7 2489 83 | #define NOTE_E7 2637 84 | #define NOTE_F7 2794 85 | #define NOTE_FS7 2960 86 | #define NOTE_G7 3136 87 | #define NOTE_GS7 3322 88 | #define NOTE_A7 3520 89 | #define NOTE_AS7 3729 90 | #define NOTE_B7 3951 91 | #define NOTE_C8 4186 92 | #define NOTE_CS8 4435 93 | #define NOTE_D8 4699 94 | #define NOTE_DS8 4978 95 | 96 | static const uint16_t sNotePitches[] = { 97 | NOTE_B0, NOTE_C1, NOTE_CS1, NOTE_D1, NOTE_DS1, NOTE_E1, NOTE_F1, NOTE_FS1, 98 | NOTE_G1, NOTE_GS1, NOTE_A1, NOTE_AS1, NOTE_B1, NOTE_C2, NOTE_CS2, NOTE_D2, 99 | NOTE_DS2, NOTE_E2, NOTE_F2, NOTE_FS2, NOTE_G2, NOTE_GS2, NOTE_A2, NOTE_AS2, 100 | NOTE_B2, NOTE_C3, NOTE_CS3, NOTE_D3, NOTE_DS3, NOTE_E3, NOTE_F3, NOTE_FS3, 101 | NOTE_G3, NOTE_GS3, NOTE_A3, NOTE_AS3, NOTE_B3, NOTE_C4, NOTE_CS4, NOTE_D4, 102 | NOTE_DS4, NOTE_E4, NOTE_F4, NOTE_FS4, NOTE_G4, NOTE_GS4, NOTE_A4, NOTE_AS4, 103 | NOTE_B4, NOTE_C5, NOTE_CS5, NOTE_D5, NOTE_DS5, NOTE_E5, NOTE_F5, NOTE_FS5, 104 | NOTE_G5, NOTE_GS5, NOTE_A5, NOTE_AS5, NOTE_B5, NOTE_C6, NOTE_CS6, NOTE_D6, 105 | NOTE_DS6, NOTE_E6, NOTE_F6, NOTE_FS6, NOTE_G6, NOTE_GS6, NOTE_A6, NOTE_AS6, 106 | NOTE_B6, NOTE_C7, NOTE_CS7, NOTE_D7, NOTE_DS7, NOTE_E7, NOTE_F7, NOTE_FS7, 107 | NOTE_G7, NOTE_GS7, NOTE_A7, NOTE_AS7, NOTE_B7, NOTE_C8, NOTE_CS8, NOTE_D8, NOTE_DS8, 108 | }; 109 | -------------------------------------------------------------------------------- /Libreries/MIDI/MIDI.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file MIDI.cpp 3 | * Project Arduino MIDI Library 4 | * @brief MIDI Library for the Arduino 5 | * @version 4.2 6 | * @author Francois Best 7 | * @date 24/02/11 8 | * @license GPL v3.0 - Copyright Forty Seven Effects 2014 9 | * 10 | * This program is free software: you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation, either version 3 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program. If not, see . 22 | */ 23 | 24 | #include "MIDI.h" 25 | 26 | // ----------------------------------------------------------------------------- 27 | 28 | BEGIN_MIDI_NAMESPACE 29 | 30 | /*! \brief Encode System Exclusive messages. 31 | SysEx messages are encoded to guarantee transmission of data bytes higher than 32 | 127 without breaking the MIDI protocol. Use this static method to convert the 33 | data you want to send. 34 | \param inData The data to encode. 35 | \param outSysEx The output buffer where to store the encoded message. 36 | \param inLength The lenght of the input buffer. 37 | \return The lenght of the encoded output buffer. 38 | @see decodeSysEx 39 | Code inspired from Ruin & Wesen's SysEx encoder/decoder - http://ruinwesen.com 40 | */ 41 | unsigned encodeSysEx(const byte* inData, byte* outSysEx, unsigned inLength) 42 | { 43 | unsigned outLength = 0; // Num bytes in output array. 44 | byte count = 0; // Num 7bytes in a block. 45 | outSysEx[0] = 0; 46 | 47 | for (unsigned i = 0; i < inLength; ++i) 48 | { 49 | const byte data = inData[i]; 50 | const byte msb = data >> 7; 51 | const byte body = data & 0x7f; 52 | 53 | outSysEx[0] |= (msb << count); 54 | outSysEx[1 + count] = body; 55 | 56 | if (count++ == 6) 57 | { 58 | outSysEx += 8; 59 | outLength += 8; 60 | outSysEx[0] = 0; 61 | count = 0; 62 | } 63 | } 64 | return outLength + count + (count != 0 ? 1 : 0); 65 | } 66 | 67 | /*! \brief Decode System Exclusive messages. 68 | SysEx messages are encoded to guarantee transmission of data bytes higher than 69 | 127 without breaking the MIDI protocol. Use this static method to reassemble 70 | your received message. 71 | \param inSysEx The SysEx data received from MIDI in. 72 | \param outData The output buffer where to store the decrypted message. 73 | \param inLength The lenght of the input buffer. 74 | \return The lenght of the output buffer. 75 | @see encodeSysEx @see getSysExArrayLength 76 | Code inspired from Ruin & Wesen's SysEx encoder/decoder - http://ruinwesen.com 77 | */ 78 | unsigned decodeSysEx(const byte* inSysEx, byte* outData, unsigned inLength) 79 | { 80 | unsigned count = 0; 81 | byte msbStorage = 0; 82 | 83 | for (unsigned i = 0; i < inLength; ++i) 84 | { 85 | if ((i % 8) == 0) 86 | { 87 | msbStorage = inSysEx[i]; 88 | } 89 | else 90 | { 91 | outData[count++] = inSysEx[i] | ((msbStorage & 1) << 7); 92 | msbStorage >>= 1; 93 | } 94 | } 95 | return count; 96 | } 97 | 98 | END_MIDI_NAMESPACE 99 | -------------------------------------------------------------------------------- /Libreries/AltSoftSerial/config/AltSoftSerial_Boards.h: -------------------------------------------------------------------------------- 1 | /* An Alternative Software Serial Library 2 | * http://www.pjrc.com/teensy/td_libs_AltSoftSerial.html 3 | * Copyright (c) 2014 PJRC.COM, LLC, Paul Stoffregen, paul@pjrc.com 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | 24 | 25 | // Teensy 2.0 26 | // 27 | #if defined(__AVR_ATmega32U4__) && defined(CORE_TEENSY) 28 | 29 | //#define ALTSS_USE_TIMER1 30 | //#define INPUT_CAPTURE_PIN 22 // receive 31 | //#define OUTPUT_COMPARE_A_PIN 14 // transmit 32 | //#define OUTPUT_COMPARE_B_PIN 15 // unusable PWM 33 | //#define OUTPUT_COMPARE_C_PIN 4 // unusable PWM 34 | 35 | #define ALTSS_USE_TIMER3 36 | #define INPUT_CAPTURE_PIN 10 // receive 37 | #define OUTPUT_COMPARE_A_PIN 9 // transmit 38 | 39 | 40 | 41 | // Teensy++ 2.0 42 | // 43 | #elif defined(__AVR_AT90USB1286__) && defined(CORE_TEENSY) 44 | 45 | #define ALTSS_USE_TIMER1 46 | #define INPUT_CAPTURE_PIN 4 // receive 47 | #define OUTPUT_COMPARE_A_PIN 25 // transmit 48 | #define OUTPUT_COMPARE_B_PIN 26 // unusable PWM 49 | #define OUTPUT_COMPARE_C_PIN 27 // unusable PWM 50 | 51 | //#define ALTSS_USE_TIMER3 52 | //#define INPUT_CAPTURE_PIN 17 // receive 53 | //#define OUTPUT_COMPARE_A_PIN 16 // transmit 54 | //#define OUTPUT_COMPARE_B_PIN 15 // unusable PWM 55 | //#define OUTPUT_COMPARE_C_PIN 14 // unusable PWM 56 | 57 | 58 | // Teensy 3.x 59 | // 60 | #elif defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) 61 | #define ALTSS_USE_FTM0 62 | #define INPUT_CAPTURE_PIN 20 // receive (FTM0_CH5) 63 | #define OUTPUT_COMPARE_A_PIN 21 // transmit (FTM0_CH6) 64 | #define OUTPUT_COMPARE_B_PIN 22 // unusable PWM (FTM0_CH0) 65 | #define OUTPUT_COMPARE_C_PIN 23 // PWM usable fixed freq 66 | #define OUTPUT_COMPARE_D_PIN 5 // PWM usable fixed freq 67 | #define OUTPUT_COMPARE_E_PIN 6 // PWM usable fixed freq 68 | #define OUTPUT_COMPARE_F_PIN 9 // PWM usable fixed freq 69 | #define OUTPUT_COMPARE_G_PIN 10 // PWM usable fixed freq 70 | 71 | 72 | // Wiring-S 73 | // 74 | #elif defined(__AVR_ATmega644P__) && defined(WIRING) 75 | 76 | #define ALTSS_USE_TIMER1 77 | #define INPUT_CAPTURE_PIN 6 // receive 78 | #define OUTPUT_COMPARE_A_PIN 5 // transmit 79 | #define OUTPUT_COMPARE_B_PIN 4 // unusable PWM 80 | 81 | 82 | 83 | // Arduino Uno, Duemilanove, LilyPad, etc 84 | // 85 | #elif defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) 86 | 87 | #define ALTSS_USE_TIMER1 88 | #define INPUT_CAPTURE_PIN 8 // receive 89 | #define OUTPUT_COMPARE_A_PIN 9 // transmit 90 | #define OUTPUT_COMPARE_B_PIN 10 // unusable PWM 91 | 92 | 93 | // Arduino Leonardo & Yun (from Cristian Maglie) 94 | // 95 | #elif defined(ARDUINO_AVR_YUN) || defined(ARDUINO_AVR_LEONARDO) || defined(__AVR_ATmega32U4__) 96 | 97 | //#define ALTSS_USE_TIMER1 98 | //#define INPUT_CAPTURE_PIN 4 // receive 99 | //#define OUTPUT_COMPARE_A_PIN 9 // transmit 100 | //#define OUTPUT_COMPARE_B_PIN 10 // unusable PWM 101 | //#define OUTPUT_COMPARE_C_PIN 11 // unusable PWM 102 | 103 | #define ALTSS_USE_TIMER3 104 | #define INPUT_CAPTURE_PIN 13 // receive 105 | #define OUTPUT_COMPARE_A_PIN 5 // transmit 106 | 107 | 108 | // Arduino Mega 109 | // 110 | #elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) 111 | 112 | //#define ALTSS_USE_TIMER4 113 | //#define INPUT_CAPTURE_PIN 49 // receive 114 | //#define OUTPUT_COMPARE_A_PIN 6 // transmit 115 | //#define OUTPUT_COMPARE_B_PIN 7 // unusable PWM 116 | //#define OUTPUT_COMPARE_C_PIN 8 // unusable PWM 117 | 118 | #define ALTSS_USE_TIMER5 119 | #define INPUT_CAPTURE_PIN 48 // receive 120 | #define OUTPUT_COMPARE_A_PIN 46 // transmit 121 | #define OUTPUT_COMPARE_B_PIN 45 // unusable PWM 122 | #define OUTPUT_COMPARE_C_PIN 44 // unusable PWM 123 | 124 | 125 | 126 | // Sanguino 127 | #elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) 128 | #define ALTSS_USE_TIMER1 129 | #define INPUT_CAPTURE_PIN 14 // receive 130 | #define OUTPUT_COMPARE_A_PIN 13 // transmit 131 | #define OUTPUT_COMPARE_B_PIN 12 // unusable PWM 132 | 133 | 134 | // Unknown board 135 | #else 136 | #error "Please define your board timer and pins" 137 | #endif 138 | 139 | -------------------------------------------------------------------------------- /Coda-88/Coda-88.ino: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Coda 88 is a MIDI sound module with three layer 4 | of dynamics for full 88 keys master keyboards 5 | 6 | https://github.com/sandrolab/coda-88 7 | 8 | Author: 9 | Sandro L'Abbate 10 | https://sandrolabbate.com 11 | 12 | Coding support: 13 | Alfredo Ardia 14 | https://alfredoardia.com 15 | 16 | WAV Trigger: 17 | https://robertsonics.com/wav-trigger/ 18 | 19 | WIRING: 20 | 21 | MIDI Uno 22 | ==== === 23 | GND <------> GND 24 | 5V <------> 5V 25 | RX <------> RX 26 | 27 | Uno WAV Trigger 28 | === =========== 29 | GND <------> GND 30 | Pin9 <------> RX 31 | 32 | If you want to power the WAV Trigger from the Uno, then close the 5V 33 | solder jumper on the WAV Trigger and connect a 3rd wire: 34 | 35 | 5V <------> 5V 36 | 37 | SAMPLES NUMERATION (ex. 032.wav): 38 | 020 Start sound 39 | 021 -> 108 Piano 40 | 109 -> 196 Medio (+88) 41 | 197 -> 284 Forte (+176) 42 | 285 -> 372 Release (+264) 43 | 373 Damper Down 44 | 374 Damper Up 45 | 46 | IMPORTANT: 47 | 1) Disconnect RX (MIDI <---> Uno) before upload 48 | 2) Press reset button on the Arduino after every boot or strange beahavior 49 | 50 | 51 | */ 52 | 53 | #include 54 | #include 55 | #include 56 | #include 57 | 58 | // SAMPLES POSITION 59 | #define layerMedio 88 60 | #define layerForte 176 61 | #define layerRelease 264 62 | #define firstRel 285 63 | #define lastRel 372 64 | #define pedalDown 373 65 | #define pedalUp 374 66 | // Dampers range (90 = G6) 67 | #define dampEnd 90 68 | 69 | // VELOCITY 70 | #define velMinPiano 0 71 | #define velMaxPiano 75 72 | #define velMinMedio 75 73 | #define velMaxMedio 110 74 | #define velMinForte 110 75 | #define velMaxForte 127 76 | 77 | // GAIN 78 | // -70 to +4 79 | #define gainMaster 4 80 | // -70 to +10 81 | #define gainMinPiano -50 82 | #define gainMaxPiano -20 83 | #define gainMinMedio -20 84 | #define gainMaxMedio -5 85 | #define gainMinForte -5 86 | #define gainMaxForte 0 87 | #define gainStartSound -20 88 | #define gainRelease -55 89 | #define gainDamperUp -30 90 | #define gainDamperDown -20 91 | 92 | #define AfterPedalLength 16 93 | 94 | // Ser 'true' for dumper pedal or release-key sounds 95 | bool RELSOUND = false; 96 | bool PEDALSOUND = false; 97 | 98 | byte DamperState; 99 | int AfterPedal[AfterPedalLength]; 100 | int KeyCount = 0; 101 | 102 | MIDI_CREATE_DEFAULT_INSTANCE(); 103 | wavTrigger wTrig; // Our WAV Trigger object 104 | 105 | void setup() { 106 | 107 | MIDI.begin(MIDI_CHANNEL_OMNI); 108 | MIDI.setHandleNoteOn(KeyOn); 109 | MIDI.setHandleNoteOff(KeyOff); 110 | MIDI.setHandleControlChange(Sustain); 111 | 112 | wTrig.start(); // WAV Trigger startup at 57600 113 | wTrig.masterGain(gainMaster); 114 | wTrig.trackGain(pedalDown, gainDamperDown); 115 | wTrig.trackGain(pedalUp, gainDamperUp); 116 | wTrig.trackGain(20, gainStartSound); 117 | 118 | for (int i = firstRel; i <= lastRel; i++) { 119 | wTrig.trackGain(i, gainRelease); 120 | } 121 | 122 | delay(500); 123 | wTrig.trackPlaySolo(20); // Ready 124 | 125 | } 126 | 127 | void KeyOn (byte ch, byte note, byte vel) { 128 | 129 | int gain; 130 | 131 | // Piano 132 | if (vel < velMaxPiano) { 133 | gain = map(vel, velMinPiano, velMaxPiano, gainMinPiano, gainMaxPiano); 134 | wTrig.trackGain(note, gain); 135 | wTrig.trackPlayPoly(note); 136 | } 137 | 138 | // Medio 139 | else if (vel >= velMinMedio && vel < velMaxMedio) { 140 | gain = map(vel, velMinMedio, velMaxMedio, gainMinMedio, gainMaxMedio); 141 | wTrig.trackGain((note + layerMedio), gain); 142 | wTrig.trackPlayPoly(note + layerMedio); 143 | } 144 | 145 | // Forte 146 | else { 147 | gain = map(vel, velMinForte, velMaxForte, gainMinForte, gainMaxForte); 148 | wTrig.trackGain((note + layerForte), gain); 149 | wTrig.trackPlayPoly(note + layerForte); 150 | } 151 | 152 | // Tenuto 153 | for (int i = 0; i < AfterPedalLength; i++) { 154 | if (AfterPedal[i] == note) AfterPedal[i] = 0; 155 | } 156 | 157 | } 158 | 159 | void KeyOff (byte ch, byte noteoff, byte vel) { 160 | 161 | if (RELSOUND) wTrig.trackPlayPoly(noteoff + layerRelease); 162 | 163 | if (noteoff <= dampEnd) { 164 | switch (DamperState) { 165 | case 0: 166 | wTrig.trackStop(noteoff); 167 | wTrig.trackStop(noteoff + layerMedio); 168 | wTrig.trackStop(noteoff + layerForte); 169 | break; 170 | case 127: 171 | AfterPedal[KeyCount++] = noteoff; 172 | if (KeyCount == (AfterPedalLength - 1)) KeyCount = 0; 173 | break; 174 | } 175 | } 176 | 177 | } 178 | 179 | void Sustain (byte ch, byte num, byte val) { 180 | 181 | DamperState = val; 182 | 183 | if (PEDALSOUND) { 184 | wTrig.trackPlayPoly(pedalUp); 185 | wTrig.trackStop(pedalDown); 186 | } 187 | 188 | for (int i = 0; i < AfterPedalLength; i++) { 189 | wTrig.trackStop(AfterPedal[i]); 190 | wTrig.trackStop(AfterPedal[i] + layerMedio); 191 | wTrig.trackStop(AfterPedal[i] + layerForte); 192 | } 193 | 194 | if (DamperState == 127) { 195 | if (PEDALSOUND) wTrig.trackPlayPoly(pedalDown); 196 | KeyCount = 0; 197 | for (int i = 0; i < AfterPedalLength; i++) { 198 | AfterPedal[i] = 0; 199 | } 200 | } 201 | 202 | } 203 | 204 | void loop() { 205 | 206 | MIDI.read(); 207 | 208 | } 209 | -------------------------------------------------------------------------------- /Libreries/wavTrigger/wavTrigger.cpp: -------------------------------------------------------------------------------- 1 | // ************************************************************** 2 | // Filename: wavTrigger.cpp 3 | // Date Created: 2/23/2014 4 | // 5 | // Comments: Robertsonics WAV Trigger serial control library 6 | // 7 | // Programmers: Jamie Robertson, jamie@robertsonics.com 8 | // 9 | // ************************************************************** 10 | 11 | #include "wavTrigger.h" 12 | 13 | 14 | // ************************************************************** 15 | void wavTrigger::start(void) { 16 | 17 | WTSerial.begin(57600); 18 | } 19 | 20 | // ************************************************************** 21 | void wavTrigger::masterGain(int gain) { 22 | 23 | uint8_t txbuf[8]; 24 | unsigned short vol; 25 | 26 | txbuf[0] = 0xf0; 27 | txbuf[1] = 0xaa; 28 | txbuf[2] = 0x07; 29 | txbuf[3] = CMD_MASTER_VOLUME; 30 | vol = (unsigned short)gain; 31 | txbuf[4] = (uint8_t)vol; 32 | txbuf[5] = (uint8_t)(vol >> 8); 33 | txbuf[6] = 0x55; 34 | WTSerial.write(txbuf, 7); 35 | } 36 | 37 | // ************************************************************** 38 | void wavTrigger::trackPlaySolo(int trk) { 39 | 40 | trackControl(trk, TRK_PLAY_SOLO); 41 | } 42 | 43 | // ************************************************************** 44 | void wavTrigger::trackPlayPoly(int trk) { 45 | 46 | trackControl(trk, TRK_PLAY_POLY); 47 | } 48 | 49 | // ************************************************************** 50 | void wavTrigger::trackLoad(int trk) { 51 | 52 | trackControl(trk, TRK_LOAD); 53 | } 54 | 55 | // ************************************************************** 56 | void wavTrigger::trackStop(int trk) { 57 | 58 | trackControl(trk, TRK_STOP); 59 | } 60 | 61 | // ************************************************************** 62 | void wavTrigger::trackPause(int trk) { 63 | 64 | trackControl(trk, TRK_PAUSE); 65 | } 66 | 67 | // ************************************************************** 68 | void wavTrigger::trackResume(int trk) { 69 | 70 | trackControl(trk, TRK_RESUME); 71 | } 72 | 73 | // ************************************************************** 74 | void wavTrigger::trackLoop(int trk, bool enable) { 75 | 76 | if (enable) 77 | trackControl(trk, TRK_LOOP_ON); 78 | else 79 | trackControl(trk, TRK_LOOP_OFF); 80 | } 81 | 82 | // ************************************************************** 83 | void wavTrigger::trackControl(int trk, int code) { 84 | 85 | uint8_t txbuf[8]; 86 | 87 | txbuf[0] = 0xf0; 88 | txbuf[1] = 0xaa; 89 | txbuf[2] = 0x08; 90 | txbuf[3] = CMD_TRACK_CONTROL; 91 | txbuf[4] = (uint8_t)code; 92 | txbuf[5] = (uint8_t)trk; 93 | txbuf[6] = (uint8_t)(trk >> 8); 94 | txbuf[7] = 0x55; 95 | WTSerial.write(txbuf, 8); 96 | } 97 | 98 | // ************************************************************** 99 | void wavTrigger::stopAllTracks(void) { 100 | 101 | uint8_t txbuf[5]; 102 | 103 | txbuf[0] = 0xf0; 104 | txbuf[1] = 0xaa; 105 | txbuf[2] = 0x05; 106 | txbuf[3] = CMD_STOP_ALL; 107 | txbuf[4] = 0x55; 108 | WTSerial.write(txbuf, 5); 109 | } 110 | 111 | // ************************************************************** 112 | void wavTrigger::resumeAllInSync(void) { 113 | 114 | uint8_t txbuf[5]; 115 | 116 | txbuf[0] = 0xf0; 117 | txbuf[1] = 0xaa; 118 | txbuf[2] = 0x05; 119 | txbuf[3] = CMD_RESUME_ALL_SYNC; 120 | txbuf[4] = 0x55; 121 | WTSerial.write(txbuf, 5); 122 | } 123 | 124 | // ************************************************************** 125 | void wavTrigger::trackGain(int trk, int gain) { 126 | 127 | uint8_t txbuf[9]; 128 | unsigned short vol; 129 | 130 | txbuf[0] = 0xf0; 131 | txbuf[1] = 0xaa; 132 | txbuf[2] = 0x09; 133 | txbuf[3] = CMD_TRACK_VOLUME; 134 | txbuf[4] = (uint8_t)trk; 135 | txbuf[5] = (uint8_t)(trk >> 8); 136 | vol = (unsigned short)gain; 137 | txbuf[6] = (uint8_t)vol; 138 | txbuf[7] = (uint8_t)(vol >> 8); 139 | txbuf[8] = 0x55; 140 | WTSerial.write(txbuf, 9); 141 | } 142 | 143 | // ************************************************************** 144 | void wavTrigger::trackFade(int trk, int gain, int time, bool stopFlag) { 145 | 146 | uint8_t txbuf[12]; 147 | unsigned short vol; 148 | 149 | txbuf[0] = 0xf0; 150 | txbuf[1] = 0xaa; 151 | txbuf[2] = 0x0c; 152 | txbuf[3] = CMD_TRACK_FADE; 153 | txbuf[4] = (uint8_t)trk; 154 | txbuf[5] = (uint8_t)(trk >> 8); 155 | vol = (unsigned short)gain; 156 | txbuf[6] = (uint8_t)vol; 157 | txbuf[7] = (uint8_t)(vol >> 8); 158 | txbuf[8] = (uint8_t)time; 159 | txbuf[9] = (uint8_t)(time >> 8); 160 | txbuf[10] = stopFlag; 161 | txbuf[11] = 0x55; 162 | WTSerial.write(txbuf, 12); 163 | } 164 | 165 | // ************************************************************** 166 | void wavTrigger::trackCrossFade(int trkFrom, int trkTo, int gain, int time) { 167 | 168 | uint8_t txbuf[12]; 169 | unsigned short vol; 170 | 171 | // Start the To track with -40 dB gain 172 | trackGain(trkTo, -40); 173 | trackPlayPoly(trkTo); 174 | 175 | // Start a fade-in to the target volume 176 | txbuf[0] = 0xf0; 177 | txbuf[1] = 0xaa; 178 | txbuf[2] = 0x0c; 179 | txbuf[3] = CMD_TRACK_FADE; 180 | txbuf[4] = (uint8_t)trkTo; 181 | txbuf[5] = (uint8_t)(trkTo >> 8); 182 | vol = (unsigned short)gain; 183 | txbuf[6] = (uint8_t)vol; 184 | txbuf[7] = (uint8_t)(vol >> 8); 185 | txbuf[8] = (uint8_t)time; 186 | txbuf[9] = (uint8_t)(time >> 8); 187 | txbuf[10] = 0x00; 188 | txbuf[11] = 0x55; 189 | WTSerial.write(txbuf, 12); 190 | 191 | // Start a fade-out on the From track 192 | txbuf[0] = 0xf0; 193 | txbuf[1] = 0xaa; 194 | txbuf[2] = 0x0c; 195 | txbuf[3] = CMD_TRACK_FADE; 196 | txbuf[4] = (uint8_t)trkFrom; 197 | txbuf[5] = (uint8_t)(trkFrom >> 8); 198 | vol = (unsigned short)-40; 199 | txbuf[6] = (uint8_t)vol; 200 | txbuf[7] = (uint8_t)(vol >> 8); 201 | txbuf[8] = (uint8_t)time; 202 | txbuf[9] = (uint8_t)(time >> 8); 203 | txbuf[10] = 0x01; 204 | txbuf[11] = 0x55; 205 | WTSerial.write(txbuf, 12); 206 | } 207 | 208 | // ************************************************************** 209 | void wavTrigger::samplerateOffset(int offset) { 210 | 211 | uint8_t txbuf[8]; 212 | unsigned short off; 213 | 214 | txbuf[0] = 0xf0; 215 | txbuf[1] = 0xaa; 216 | txbuf[2] = 0x07; 217 | txbuf[3] = CMD_SAMPLERATE_OFFSET; 218 | off = (unsigned short)offset; 219 | txbuf[4] = (uint8_t)off; 220 | txbuf[5] = (uint8_t)(off >> 8); 221 | txbuf[6] = 0x55; 222 | WTSerial.write(txbuf, 7); 223 | } 224 | 225 | 226 | 227 | 228 | 229 | -------------------------------------------------------------------------------- /Libreries/wavTrigger/examples/WTriggerUno/WTriggerUno.ino: -------------------------------------------------------------------------------- 1 | // **************************************************************************** 2 | // Sketch: WTriggerUno 3 | // Date Created: 4/22/2015 4 | // 5 | // Comments: Demonstrates basic serial control of the WAV Trigger from an 6 | // Arduino UNO. 7 | // 8 | // Programmers: Jamie Robertson, jamie@robertsonics.com 9 | // 10 | // **************************************************************************** 11 | // 12 | // To use this sketch, you'll need to: 13 | // 14 | // 1) Download and install the AltSoftSerial library. 15 | // 2) Download and install the Metro library. 16 | // 3) Connect 2 wires from the UNO to the WAV Trigger's serial connector: 17 | // 18 | // Uno WAV Trigger 19 | // === =========== 20 | // GND <------> GND 21 | // Pin9 <------> RX 22 | // 23 | // If you want to power the WAV Trigger from the Uno, then close the 5V 24 | // solder jumper on the WAV Trigger and connect a 3rd wire: 25 | // 26 | // 5V <------> 5V 27 | // 28 | // 4) Download and install the demo wav files onto the WAV Trigger's microSD 29 | // card. You can find them here: 30 | // 31 | // 32 | // You can certainly use your own tracks instead, although the demo may 33 | // not make as much sense. If you do, make sure your tracks are at least 10 34 | // to 20 seconds long and have no silence at the start of the file. 35 | 36 | #include 37 | #include // Arduino build environment requires this 38 | #include 39 | 40 | #define LED 13 // our LED 41 | 42 | wavTrigger wTrig; // Our WAV Trigger object 43 | 44 | Metro gLedMetro(500); // LED blink interval timer 45 | Metro gWTrigMetro(6000); // WAV Trigger state machine interval timer 46 | 47 | byte gLedState = 0; // LED State 48 | int gWTrigState = 0; // WAV Trigger state 49 | int gRateOffset = 0; // WAV Trigger sample-rate offset 50 | 51 | 52 | // **************************************************************************** 53 | void setup() { 54 | 55 | // Serial monitor 56 | Serial.begin(9600); 57 | 58 | // Initialize the LED pin 59 | pinMode(LED,OUTPUT); 60 | digitalWrite(LED,gLedState); 61 | 62 | // WAV Trigger startup at 57600 63 | wTrig.start(); 64 | 65 | // If the Uno is powering the WAV Trigger, we should wait for the WAV Trigger 66 | // to finish reset before trying to send commands. 67 | delay(1000); 68 | 69 | // If we're not powering the WAV Trigger, send a stop-all command in case it 70 | // was already playing tracks. If we are powering the WAV Trigger, it doesn't 71 | // hurt to do this. 72 | wTrig.stopAllTracks(); 73 | 74 | } 75 | 76 | 77 | // **************************************************************************** 78 | // This program uses a Metro timer to create a state machine that steps 79 | // through states at 6 second intervals - you can change this rate above. 80 | // Each state will execute a new wavTrigger command. 81 | 82 | void loop() { 83 | 84 | int i; 85 | 86 | // If time to do so, perform the next WAV Trigger task and then increment 87 | // the state machine variable 88 | if (gWTrigMetro.check() == 1) { 89 | 90 | switch (gWTrigState) { 91 | 92 | // Demonstrates how to fade in a music track 93 | case 0: 94 | wTrig.masterGain(0); // Reset the master gain to 0dB 95 | wTrig.trackGain(2, -40); // Preset Track 2 gain to -40dB 96 | wTrig.trackPlayPoly(2); // Start Track 2 97 | wTrig.trackFade(2, 0, 2000, 0); // Fade Track 2 to 0dB 98 | break; 99 | 100 | // Demonstrates how to cross-fade music tracks 101 | case 1: 102 | wTrig.trackCrossFade(2, 1, 0, 3000); // Cross-fade Track 2 to Track 1 103 | break; 104 | 105 | // Fade down music and start looping dialog 106 | case 2: 107 | wTrig.trackFade(1, -6, 500, 0); 108 | wTrig.trackPlayPoly(4); // Start Track 4 poly 109 | wTrig.trackLoop(4, 1); // Enable Track 4 looping 110 | break; 111 | 112 | // Honk the horn 2 times 113 | case 3: 114 | wTrig.trackPlayPoly(5); // Start Track 5 poly 115 | delay(500); 116 | wTrig.trackStop(5); // Stop Track 5 117 | delay(250); 118 | wTrig.trackPlayPoly(5); // Start Track 5 poly 119 | delay(500); 120 | wTrig.trackStop(5); // Stop Track 5 121 | break; 122 | 123 | // Fade out and stop dialog 124 | case 4: 125 | wTrig.trackLoop(4, 0); // Disable Track 4 looping 126 | wTrig.trackFade(4, -50, 5000, 1); // Fade Track 4 to -50dB and stop 127 | break; 128 | 129 | // This demonstrates playing musical instrument samples, with decay on 130 | // release 131 | case 5: 132 | wTrig.masterGain(-8); // Lower main volume 133 | wTrig.trackPlayPoly(6); // Play first note 134 | delay(1000); 135 | wTrig.trackPlayPoly(7); // Play second note 136 | delay(1000); 137 | wTrig.trackPlayPoly(8); // Play third note 138 | delay(1000); 139 | wTrig.trackFade(6, -50, 5000, 1); // Fade Track 6 to -50dB and stop 140 | wTrig.trackFade(7, -50, 5000, 1); // Fade Track 7 to -50dB and stop 141 | wTrig.trackFade(8, -50, 5000, 1); // Fade Track 8 to -50dB and stop 142 | break; 143 | 144 | // Demonstrates preloading tracks and starting them in sample-sync, and 145 | // real-time samplerate control (pitch bending); 146 | case 6: 147 | wTrig.trackLoad(6); // Load and pause Track 6 148 | wTrig.trackLoad(7); // Load and pause Track 7 149 | wTrig.trackLoad(8); // Load and pause Track 8 150 | wTrig.resumeAllInSync(); // Start all in sample sync 151 | for (i = 0; i < 100; i++) { 152 | gRateOffset -= 200; 153 | wTrig.samplerateOffset(gRateOffset); 154 | delay(10); 155 | } 156 | for (i = 0; i < 100; i++) { 157 | gRateOffset += 200; 158 | wTrig.samplerateOffset(gRateOffset); 159 | delay(10); 160 | } 161 | delay(500); 162 | wTrig.stopAllTracks(); // Stop all 163 | break; 164 | 165 | 166 | } // switch 167 | 168 | // Increment our state 169 | gWTrigState++; 170 | if (gWTrigState > 6) 171 | gWTrigState = 0; 172 | 173 | } // if (gWTrigState.check() == 1) 174 | 175 | // If time to do so, toggle the LED 176 | if (gLedMetro.check() == 1) { 177 | if (gLedState == 0) gLedState = 1; 178 | else gLedState = 0; 179 | digitalWrite(LED, gLedState); 180 | } // if (gLedMetro.check() == 1) 181 | 182 | // Delay 30 msecs 183 | delay(30); 184 | } 185 | 186 | -------------------------------------------------------------------------------- /Libreries/wavTrigger/README.md: -------------------------------------------------------------------------------- 1 | WAV-Trigger-Arduino-Serial-Library 2 | ================================== 3 | 4 | WAV Trigger Serial Control Arduino Library 5 | 6 | This version of the library uses the AltSoftwareSerial library from PJRC by 7 | default, so you'll need to download and install that library as well. Be sure 8 | to include both library headers at the top of your sketch. 9 | 10 | ``` 11 | #include 12 | #include 13 | ``` 14 | 15 | If you want to use a hardware serial port instead, you'll need to make one small 16 | change to the library's **wavTrigger.h file**. Near the top of the file, look for: 17 | 18 | ``` 19 | // ================================================================== 20 | // The following defines are used to control which serial class is 21 | // used. Uncomment only the one you wish to use. If all of them are 22 | // commented out, the library will use Hardware Serial 23 | #define __WT_USE_ALTSOFTSERIAL__ 24 | //#define __WT_USE_SERIAL1__ 25 | //#define __WT_USE_SERIAL2__ 26 | //#define __WT_USE_SERIAL3__ 27 | // ================================================================== 28 | ``` 29 | 30 | Comment out the `__WT_USER_ALTSOFTSERIAL__` line and uncomment the line correspond- 31 | ing to the hardware port you want to use. If all the lines are commented out, the 32 | library will use Serial (the only hardware serial port on an Uno.) 33 | 34 | This version currently only sends commands TO the WAV Trigger. I've not yet 35 | implemented any functions to receive info FROM the WAV Trigger. 36 | 37 | I make no attempt to throttle the amount of messages that are sent. If you send 38 | continuous volume or sample-rate commands at full speed, you risk overflowing the 39 | WAV Trigger's serial input buffer and/or causing clicks in the WAV Triggers audio 40 | output due to excessive serial interrupt processing stealing cycles from audio 41 | playback. If you are connecting a continuous controller that can change rapidly 42 | for volume or sample-rate control, you should use a timer to send changes only 43 | every 10 or more msecs. You can, of course, experiment with this. If you're only 44 | ever playing 1 or 2 tracks at a time, you'll likely be able to get away with send- 45 | ing volume changes more frequently than if you are playing 8 tracks at a time. 46 | 47 | Beginning with WAV Trigger firmware v0.80 and higher, track fade and crossfade 48 | functions are supported, allowing you to achieve smooth volume ramps (up or down) 49 | and crossfades with a single serial command. Also beginning with v.080 and higher 50 | it is possible to pre-load multiple tracks and issue a single resume message that 51 | allows them start and play in sample locked synchronization. 52 | 53 | The library now includes an example sketch for the Arduino Uno that demonstrates 54 | many of the library commands with a set of demo tracks which you can download from 55 | www.robertsonics.com. 56 | 57 | 58 | Usage: 59 | ====== 60 | 61 | In all cases below, the range for t (track number) is 1 through 999; 62 | 63 | wavTrigger wTtrig; 64 | 65 | **wTrig.start()** - you must call this method first to initialize the serial 66 | communications. 67 | 68 | **wTrig.masterGain(int gain)** - this function immediately sets the gain of the 69 | final output stage to the specified value. The range for gain is -70 to +4. If 70 | audio is playing, you will hear the result immediately. If audio is not playing, 71 | the new gain will be used the next time a track is started. 72 | 73 | **wTrig.samplerateOffset(int offset)** - this function immediately sets sample- 74 | rate offset, or playback speed / pitch, of the main output mix. The range for 75 | for the offset is -32767 to +32676, giving a speed range of 1/2x to 2x, or a 76 | pitch range of down one octave to up one octave. If audio is playing, you will 77 | hear the result immediately. If audio is not playing, the new sample-rate offset 78 | will be used the next time a track is started. 79 | 80 | **wTrig.trackPlaySolo(int t)** - this function stops any and all tracks that are 81 | currently playing and starts track number **t** from the beginning. 82 | 83 | **wTrig.trackPlayPoly(int t)** - this function starts track number **t** from the 84 | beginning, blending it with any other tracks that are currently playing, 85 | including potentially another copy of the same track. 86 | 87 | **wTrig.trackLoad(int t)** - this function loads track number **t** and pauses it 88 | at the beginning of the track. Loading muiltiple tracks and then un-pausing them 89 | all with resumeAllInSync() function below allows for starting multiple tracks in 90 | sample sync. 91 | 92 | **wTrig.trackStop(int t)** - this function stops track number **t** if it's currently 93 | playing. If track t is not playing, this function does nothing. No other 94 | tracks are affected. 95 | 96 | **wTrig.trackPause(int t)** - this function pauses track number **t** if it's currently 97 | playing. If track t is not playing, this function does nothing. Keep in mind 98 | that a paused track is still using one of the 8 voice slots. A voice allocated 99 | to playing a track becomes free only when that sound is stopped or the track 100 | reaches the end of the file (and is not looping). 101 | 102 | **wTrig.trackResume(int t)** - this function resumes track number **t** if it's currently 103 | paused. If track number **t** is not paused, this function does nothing. 104 | 105 | **wTrig.trackLoop(int t, bool enable)** - this function enables (true) or disables 106 | (false) the loop flag for track **t**. This command does not actually start a track, 107 | only determines how it behaves once it is playing and reaches the end. If the 108 | loop flag is set, that track will loop continuously until it's stopped, in which 109 | case it will stop immediately but the loop flag will remain set, or until the loop 110 | flag is cleared, in which case it will stop when it reaches the end of the track. 111 | This command may be used either before a track is started or while it's playing. 112 | 113 | **wTrig.trackGain(int t, int gain)** - this function immediately sets the gain of 114 | track **t** to the specified value. The range for gain is -70 to +10. A value of 115 | 0 (no gain) plays the track at the nominal value in the wav file. This is the 116 | default gain for every track until changed. A value of -70 is completely 117 | muted. If the track is playing, you will hear the result immediately. If the 118 | track is not playing, the gain will be used the next time the track is started. 119 | Every track can have its own gain. 120 | 121 | Because the effect is immediate, large changes can produce ubrupt results. If 122 | you want to fade in or fade out a track, send small changes spaced out at regular 123 | intervals. Increment or decrementing by 1 every 20 to 50 msecs produces nice 124 | smooth fades. Better yet, use the new trackFade() and trackCrossFade() commands 125 | below. 126 | 127 | **wTrig.stopAllTracks()** - this commands stops any and all tracks that are currently 128 | playing. 129 | 130 | **wTrig.resumeAllInSync()** - this command resumes all paused tracks within the same 131 | audio buffer. Any tracks that were loaded using the trackLoad() function will start 132 | and remain sample locked (in sample sync) with one another. 133 | 134 | **wTrig.trackFade(int t, int gain, int time, bool stopFlag)** - this command initiates 135 | a hardware volume fade on track number **t** if it is currently playing. The track 136 | volume will transition smoothly from the current value to the target gain in the 137 | specified number of milliseconds. If the stopFlag is non-zero, the track will be 138 | stopped at the completion of the fade (for fade-outs.) 139 | 140 | **wTrig.trackCrossFade(int tFrom, int tTo, int gain, int time)** - this command 141 | initiates a hardware crossfade from one track to another in a specified number of 142 | milliseconds. The **From** track will be faded out and stopped, and the **To** track 143 | will be started and faded in to the specified volume. 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /Libreries/MIDI/midi_Defs.h: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file midi_Defs.h 3 | * Project Arduino MIDI Library 4 | * @brief MIDI Library for the Arduino - Definitions 5 | * @version 4.2 6 | * @author Francois Best 7 | * @date 24/02/11 8 | * @license GPL v3.0 - Copyright Forty Seven Effects 2014 9 | * 10 | * This program is free software: you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation, either version 3 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program. If not, see . 22 | */ 23 | 24 | #pragma once 25 | 26 | #include "midi_Namespace.h" 27 | 28 | #if ARDUINO 29 | #include 30 | #else 31 | #include 32 | typedef uint8_t byte; 33 | #endif 34 | 35 | BEGIN_MIDI_NAMESPACE 36 | 37 | // ----------------------------------------------------------------------------- 38 | 39 | #define MIDI_CHANNEL_OMNI 0 40 | #define MIDI_CHANNEL_OFF 17 // and over 41 | 42 | #define MIDI_PITCHBEND_MIN -8192 43 | #define MIDI_PITCHBEND_MAX 8191 44 | 45 | // ----------------------------------------------------------------------------- 46 | // Type definitions 47 | 48 | typedef byte StatusByte; 49 | typedef byte DataByte; 50 | typedef byte Channel; 51 | typedef byte FilterMode; 52 | 53 | // ----------------------------------------------------------------------------- 54 | 55 | /*! Enumeration of MIDI types */ 56 | enum MidiType 57 | { 58 | InvalidType = 0x00, ///< For notifying errors 59 | NoteOff = 0x80, ///< Note Off 60 | NoteOn = 0x90, ///< Note On 61 | AfterTouchPoly = 0xA0, ///< Polyphonic AfterTouch 62 | ControlChange = 0xB0, ///< Control Change / Channel Mode 63 | ProgramChange = 0xC0, ///< Program Change 64 | AfterTouchChannel = 0xD0, ///< Channel (monophonic) AfterTouch 65 | PitchBend = 0xE0, ///< Pitch Bend 66 | SystemExclusive = 0xF0, ///< System Exclusive 67 | TimeCodeQuarterFrame = 0xF1, ///< System Common - MIDI Time Code Quarter Frame 68 | SongPosition = 0xF2, ///< System Common - Song Position Pointer 69 | SongSelect = 0xF3, ///< System Common - Song Select 70 | TuneRequest = 0xF6, ///< System Common - Tune Request 71 | Clock = 0xF8, ///< System Real Time - Timing Clock 72 | Start = 0xFA, ///< System Real Time - Start 73 | Continue = 0xFB, ///< System Real Time - Continue 74 | Stop = 0xFC, ///< System Real Time - Stop 75 | ActiveSensing = 0xFE, ///< System Real Time - Active Sensing 76 | SystemReset = 0xFF, ///< System Real Time - System Reset 77 | }; 78 | 79 | // ----------------------------------------------------------------------------- 80 | 81 | /*! Enumeration of Thru filter modes */ 82 | enum MidiFilterMode 83 | { 84 | Off = 0, ///< Thru disabled (nothing passes through). 85 | Full = 1, ///< Fully enabled Thru (every incoming message is sent back). 86 | SameChannel = 2, ///< Only the messages on the Input Channel will be sent back. 87 | DifferentChannel = 3, ///< All the messages but the ones on the Input Channel will be sent back. 88 | }; 89 | 90 | // ----------------------------------------------------------------------------- 91 | 92 | /*! \brief Enumeration of Control Change command numbers. 93 | See the detailed controllers numbers & description here: 94 | http://www.somascape.org/midi/tech/spec.html#ctrlnums 95 | */ 96 | enum MidiControlChangeNumber 97 | { 98 | // High resolution Continuous Controllers MSB (+32 for LSB) ---------------- 99 | BankSelect = 0, 100 | ModulationWheel = 1, 101 | BreathController = 2, 102 | // CC3 undefined 103 | FootController = 4, 104 | PortamentoTime = 5, 105 | DataEntry = 6, 106 | ChannelVolume = 7, 107 | Balance = 8, 108 | // CC9 undefined 109 | Pan = 10, 110 | ExpressionController = 11, 111 | EffectControl1 = 12, 112 | EffectControl2 = 13, 113 | // CC14 undefined 114 | // CC15 undefined 115 | GeneralPurposeController1 = 16, 116 | GeneralPurposeController2 = 17, 117 | GeneralPurposeController3 = 18, 118 | GeneralPurposeController4 = 19, 119 | 120 | // Switches ---------------------------------------------------------------- 121 | Sustain = 64, 122 | Portamento = 65, 123 | Sostenuto = 66, 124 | SoftPedal = 67, 125 | Legato = 68, 126 | Hold = 69, 127 | 128 | // Low resolution continuous controllers ----------------------------------- 129 | SoundController1 = 70, ///< Synth: Sound Variation FX: Exciter On/Off 130 | SoundController2 = 71, ///< Synth: Harmonic Content FX: Compressor On/Off 131 | SoundController3 = 72, ///< Synth: Release Time FX: Distortion On/Off 132 | SoundController4 = 73, ///< Synth: Attack Time FX: EQ On/Off 133 | SoundController5 = 74, ///< Synth: Brightness FX: Expander On/Off 134 | SoundController6 = 75, ///< Synth: Decay Time FX: Reverb On/Off 135 | SoundController7 = 76, ///< Synth: Vibrato Rate FX: Delay On/Off 136 | SoundController8 = 77, ///< Synth: Vibrato Depth FX: Pitch Transpose On/Off 137 | SoundController9 = 78, ///< Synth: Vibrato Delay FX: Flange/Chorus On/Off 138 | SoundController10 = 79, ///< Synth: Undefined FX: Special Effects On/Off 139 | GeneralPurposeController5 = 80, 140 | GeneralPurposeController6 = 81, 141 | GeneralPurposeController7 = 82, 142 | GeneralPurposeController8 = 83, 143 | PortamentoControl = 84, 144 | // CC85 to CC90 undefined 145 | Effects1 = 91, ///< Reverb send level 146 | Effects2 = 92, ///< Tremolo depth 147 | Effects3 = 93, ///< Chorus send level 148 | Effects4 = 94, ///< Celeste depth 149 | Effects5 = 95, ///< Phaser depth 150 | 151 | // Channel Mode messages --------------------------------------------------- 152 | AllSoundOff = 120, 153 | ResetAllControllers = 121, 154 | LocalControl = 122, 155 | AllNotesOff = 123, 156 | OmniModeOff = 124, 157 | OmniModeOn = 125, 158 | MonoModeOn = 126, 159 | PolyModeOn = 127 160 | }; 161 | 162 | // ----------------------------------------------------------------------------- 163 | 164 | /*! \brief Create an instance of the library attached to a serial port. 165 | You can use HardwareSerial or SoftwareSerial for the serial port. 166 | Example: MIDI_CREATE_INSTANCE(HardwareSerial, Serial2, midi2); 167 | Then call midi2.begin(), midi2.read() etc.. 168 | */ 169 | #define MIDI_CREATE_INSTANCE(Type, SerialPort, Name) \ 170 | midi::MidiInterface Name((Type&)SerialPort); 171 | 172 | #if defined(ARDUINO_SAM_DUE) || defined(USBCON) 173 | // Leonardo, Due and other USB boards use Serial1 by default. 174 | #define MIDI_CREATE_DEFAULT_INSTANCE() \ 175 | MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI); 176 | #else 177 | /*! \brief Create an instance of the library with default name, serial port 178 | and settings, for compatibility with sketches written with pre-v4.2 MIDI Lib, 179 | or if you don't bother using custom names, serial port or settings. 180 | */ 181 | #define MIDI_CREATE_DEFAULT_INSTANCE() \ 182 | MIDI_CREATE_INSTANCE(HardwareSerial, Serial, MIDI); 183 | #endif 184 | 185 | /*! \brief Create an instance of the library attached to a serial port with 186 | custom settings. 187 | @see DefaultSettings 188 | @see MIDI_CREATE_INSTANCE 189 | */ 190 | #define MIDI_CREATE_CUSTOM_INSTANCE(Type, SerialPort, Name, Settings) \ 191 | midi::MidiInterface Name((Type&)SerialPort); 192 | 193 | END_MIDI_NAMESPACE 194 | -------------------------------------------------------------------------------- /Libreries/MIDI/MIDI.h: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file MIDI.h 3 | * Project Arduino MIDI Library 4 | * @brief MIDI Library for the Arduino 5 | * @version 4.2 6 | * @author Francois Best 7 | * @date 24/02/11 8 | * @license GPL v3.0 - Copyright Forty Seven Effects 2014 9 | * 10 | * This program is free software: you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation, either version 3 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program. If not, see . 22 | */ 23 | 24 | #pragma once 25 | 26 | #include "midi_Defs.h" 27 | #include "midi_Settings.h" 28 | #include "midi_Message.h" 29 | 30 | // ----------------------------------------------------------------------------- 31 | 32 | BEGIN_MIDI_NAMESPACE 33 | 34 | /*! \brief The main class for MIDI handling. 35 | It is templated over the type of serial port to provide abstraction from 36 | the hardware interface, meaning you can use HardwareSerial, SoftwareSerial 37 | or ak47's Uart classes. The only requirement is that the class implements 38 | the begin, read, write and available methods. 39 | */ 40 | template 41 | class MidiInterface 42 | { 43 | public: 44 | inline MidiInterface(SerialPort& inSerial); 45 | inline ~MidiInterface(); 46 | 47 | public: 48 | void begin(Channel inChannel = 1); 49 | 50 | // ------------------------------------------------------------------------- 51 | // MIDI Output 52 | 53 | public: 54 | inline void sendNoteOn(DataByte inNoteNumber, 55 | DataByte inVelocity, 56 | Channel inChannel); 57 | 58 | inline void sendNoteOff(DataByte inNoteNumber, 59 | DataByte inVelocity, 60 | Channel inChannel); 61 | 62 | inline void sendProgramChange(DataByte inProgramNumber, 63 | Channel inChannel); 64 | 65 | inline void sendControlChange(DataByte inControlNumber, 66 | DataByte inControlValue, 67 | Channel inChannel); 68 | 69 | inline void sendPitchBend(int inPitchValue, Channel inChannel); 70 | inline void sendPitchBend(double inPitchValue, Channel inChannel); 71 | 72 | inline void sendPolyPressure(DataByte inNoteNumber, 73 | DataByte inPressure, 74 | Channel inChannel); 75 | 76 | inline void sendAfterTouch(DataByte inPressure, 77 | Channel inChannel); 78 | 79 | inline void sendSysEx(unsigned inLength, 80 | const byte* inArray, 81 | bool inArrayContainsBoundaries = false); 82 | 83 | inline void sendTimeCodeQuarterFrame(DataByte inTypeNibble, 84 | DataByte inValuesNibble); 85 | inline void sendTimeCodeQuarterFrame(DataByte inData); 86 | 87 | inline void sendSongPosition(unsigned inBeats); 88 | inline void sendSongSelect(DataByte inSongNumber); 89 | inline void sendTuneRequest(); 90 | inline void sendRealTime(MidiType inType); 91 | 92 | public: 93 | void send(MidiType inType, 94 | DataByte inData1, 95 | DataByte inData2, 96 | Channel inChannel); 97 | 98 | // ------------------------------------------------------------------------- 99 | // MIDI Input 100 | 101 | public: 102 | inline bool read(); 103 | inline bool read(Channel inChannel); 104 | 105 | public: 106 | inline MidiType getType() const; 107 | inline Channel getChannel() const; 108 | inline DataByte getData1() const; 109 | inline DataByte getData2() const; 110 | inline const byte* getSysExArray() const; 111 | inline unsigned getSysExArrayLength() const; 112 | inline bool check() const; 113 | 114 | public: 115 | inline Channel getInputChannel() const; 116 | inline void setInputChannel(Channel inChannel); 117 | 118 | public: 119 | static inline MidiType getTypeFromStatusByte(byte inStatus); 120 | static inline Channel getChannelFromStatusByte(byte inStatus); 121 | static inline bool isChannelMessage(MidiType inType); 122 | 123 | 124 | // ------------------------------------------------------------------------- 125 | // Input Callbacks 126 | 127 | public: 128 | inline void setHandleNoteOff(void (*fptr)(byte channel, byte note, byte velocity)); 129 | inline void setHandleNoteOn(void (*fptr)(byte channel, byte note, byte velocity)); 130 | inline void setHandleAfterTouchPoly(void (*fptr)(byte channel, byte note, byte pressure)); 131 | inline void setHandleControlChange(void (*fptr)(byte channel, byte number, byte value)); 132 | inline void setHandleProgramChange(void (*fptr)(byte channel, byte number)); 133 | inline void setHandleAfterTouchChannel(void (*fptr)(byte channel, byte pressure)); 134 | inline void setHandlePitchBend(void (*fptr)(byte channel, int bend)); 135 | inline void setHandleSystemExclusive(void (*fptr)(byte * array, unsigned size)); 136 | inline void setHandleTimeCodeQuarterFrame(void (*fptr)(byte data)); 137 | inline void setHandleSongPosition(void (*fptr)(unsigned beats)); 138 | inline void setHandleSongSelect(void (*fptr)(byte songnumber)); 139 | inline void setHandleTuneRequest(void (*fptr)(void)); 140 | inline void setHandleClock(void (*fptr)(void)); 141 | inline void setHandleStart(void (*fptr)(void)); 142 | inline void setHandleContinue(void (*fptr)(void)); 143 | inline void setHandleStop(void (*fptr)(void)); 144 | inline void setHandleActiveSensing(void (*fptr)(void)); 145 | inline void setHandleSystemReset(void (*fptr)(void)); 146 | 147 | inline void disconnectCallbackFromType(MidiType inType); 148 | 149 | private: 150 | void launchCallback(); 151 | 152 | void (*mNoteOffCallback)(byte channel, byte note, byte velocity); 153 | void (*mNoteOnCallback)(byte channel, byte note, byte velocity); 154 | void (*mAfterTouchPolyCallback)(byte channel, byte note, byte velocity); 155 | void (*mControlChangeCallback)(byte channel, byte, byte); 156 | void (*mProgramChangeCallback)(byte channel, byte); 157 | void (*mAfterTouchChannelCallback)(byte channel, byte); 158 | void (*mPitchBendCallback)(byte channel, int); 159 | void (*mSystemExclusiveCallback)(byte * array, unsigned size); 160 | void (*mTimeCodeQuarterFrameCallback)(byte data); 161 | void (*mSongPositionCallback)(unsigned beats); 162 | void (*mSongSelectCallback)(byte songnumber); 163 | void (*mTuneRequestCallback)(void); 164 | void (*mClockCallback)(void); 165 | void (*mStartCallback)(void); 166 | void (*mContinueCallback)(void); 167 | void (*mStopCallback)(void); 168 | void (*mActiveSensingCallback)(void); 169 | void (*mSystemResetCallback)(void); 170 | 171 | // ------------------------------------------------------------------------- 172 | // MIDI Soft Thru 173 | 174 | public: 175 | inline MidiFilterMode getFilterMode() const; 176 | inline bool getThruState() const; 177 | 178 | inline void turnThruOn(MidiFilterMode inThruFilterMode = Full); 179 | inline void turnThruOff(); 180 | inline void setThruFilterMode(MidiFilterMode inThruFilterMode); 181 | 182 | private: 183 | void thruFilter(byte inChannel); 184 | 185 | private: 186 | bool parse(); 187 | inline void handleNullVelocityNoteOnAsNoteOff(); 188 | inline bool inputFilter(Channel inChannel); 189 | inline void resetInput(); 190 | 191 | private: 192 | bool mThruActivated : 1; 193 | MidiFilterMode mThruFilterMode : 7; 194 | 195 | private: 196 | typedef Message MidiMessage; 197 | 198 | private: 199 | StatusByte mRunningStatus_RX; 200 | StatusByte mRunningStatus_TX; 201 | Channel mInputChannel; 202 | byte mPendingMessage[3]; 203 | unsigned mPendingMessageExpectedLenght; 204 | unsigned mPendingMessageIndex; 205 | MidiMessage mMessage; 206 | 207 | private: 208 | inline StatusByte getStatus(MidiType inType, 209 | Channel inChannel) const; 210 | 211 | private: 212 | SerialPort& mSerial; 213 | }; 214 | 215 | // ----------------------------------------------------------------------------- 216 | 217 | unsigned encodeSysEx(const byte* inData, byte* outSysEx, unsigned inLenght); 218 | unsigned decodeSysEx(const byte* inSysEx, byte* outData, unsigned inLenght); 219 | 220 | END_MIDI_NAMESPACE 221 | 222 | // ----------------------------------------------------------------------------- 223 | 224 | #include "MIDI.hpp" 225 | -------------------------------------------------------------------------------- /Libreries/AltSoftSerial/AltSoftSerial.cpp: -------------------------------------------------------------------------------- 1 | /* An Alternative Software Serial Library 2 | * http://www.pjrc.com/teensy/td_libs_AltSoftSerial.html 3 | * Copyright (c) 2014 PJRC.COM, LLC, Paul Stoffregen, paul@pjrc.com 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | 24 | // Revisions are now tracked on GitHub 25 | // https://github.com/PaulStoffregen/AltSoftSerial 26 | // 27 | // Version 1.2: Support Teensy 3.x 28 | // 29 | // Version 1.1: Improve performance in receiver code 30 | // 31 | // Version 1.0: Initial Release 32 | 33 | 34 | #include "AltSoftSerial.h" 35 | #include "config/AltSoftSerial_Boards.h" 36 | #include "config/AltSoftSerial_Timers.h" 37 | 38 | /****************************************/ 39 | /** Initialization **/ 40 | /****************************************/ 41 | 42 | static uint16_t ticks_per_bit=0; 43 | bool AltSoftSerial::timing_error=false; 44 | 45 | static uint8_t rx_state; 46 | static uint8_t rx_byte; 47 | static uint8_t rx_bit = 0; 48 | static uint16_t rx_target; 49 | static uint16_t rx_stop_ticks=0; 50 | static volatile uint8_t rx_buffer_head; 51 | static volatile uint8_t rx_buffer_tail; 52 | #define RX_BUFFER_SIZE 80 53 | static volatile uint8_t rx_buffer[RX_BUFFER_SIZE]; 54 | 55 | static volatile uint8_t tx_state=0; 56 | static uint8_t tx_byte; 57 | static uint8_t tx_bit; 58 | static volatile uint8_t tx_buffer_head; 59 | static volatile uint8_t tx_buffer_tail; 60 | #define TX_BUFFER_SIZE 68 61 | static volatile uint8_t tx_buffer[TX_BUFFER_SIZE]; 62 | 63 | 64 | #ifndef INPUT_PULLUP 65 | #define INPUT_PULLUP INPUT 66 | #endif 67 | 68 | #define MAX_COUNTS_PER_BIT 6241 // 65536 / 10.5 69 | 70 | void AltSoftSerial::init(uint32_t cycles_per_bit) 71 | { 72 | //Serial.printf("cycles_per_bit = %d\n", cycles_per_bit); 73 | if (cycles_per_bit < MAX_COUNTS_PER_BIT) { 74 | CONFIG_TIMER_NOPRESCALE(); 75 | } else { 76 | cycles_per_bit /= 8; 77 | //Serial.printf("cycles_per_bit/8 = %d\n", cycles_per_bit); 78 | if (cycles_per_bit < MAX_COUNTS_PER_BIT) { 79 | CONFIG_TIMER_PRESCALE_8(); 80 | } else { 81 | #if defined(CONFIG_TIMER_PRESCALE_256) 82 | cycles_per_bit /= 32; 83 | //Serial.printf("cycles_per_bit/256 = %d\n", cycles_per_bit); 84 | if (cycles_per_bit < MAX_COUNTS_PER_BIT) { 85 | CONFIG_TIMER_PRESCALE_256(); 86 | } else { 87 | return; // baud rate too low for AltSoftSerial 88 | } 89 | #elif defined(CONFIG_TIMER_PRESCALE_128) 90 | cycles_per_bit /= 16; 91 | //Serial.printf("cycles_per_bit/128 = %d\n", cycles_per_bit); 92 | if (cycles_per_bit < MAX_COUNTS_PER_BIT) { 93 | CONFIG_TIMER_PRESCALE_128(); 94 | } else { 95 | return; // baud rate too low for AltSoftSerial 96 | } 97 | #else 98 | return; // baud rate too low for AltSoftSerial 99 | #endif 100 | } 101 | } 102 | ticks_per_bit = cycles_per_bit; 103 | rx_stop_ticks = cycles_per_bit * 37 / 4; 104 | pinMode(INPUT_CAPTURE_PIN, INPUT_PULLUP); 105 | digitalWrite(OUTPUT_COMPARE_A_PIN, HIGH); 106 | pinMode(OUTPUT_COMPARE_A_PIN, OUTPUT); 107 | rx_state = 0; 108 | rx_buffer_head = 0; 109 | rx_buffer_tail = 0; 110 | tx_state = 0; 111 | tx_buffer_head = 0; 112 | tx_buffer_tail = 0; 113 | ENABLE_INT_INPUT_CAPTURE(); 114 | } 115 | 116 | void AltSoftSerial::end(void) 117 | { 118 | DISABLE_INT_COMPARE_B(); 119 | DISABLE_INT_INPUT_CAPTURE(); 120 | flushInput(); 121 | flushOutput(); 122 | DISABLE_INT_COMPARE_A(); 123 | // TODO: restore timer to original settings? 124 | } 125 | 126 | 127 | /****************************************/ 128 | /** Transmission **/ 129 | /****************************************/ 130 | 131 | void AltSoftSerial::writeByte(uint8_t b) 132 | { 133 | uint8_t intr_state, head; 134 | 135 | head = tx_buffer_head + 1; 136 | if (head >= TX_BUFFER_SIZE) head = 0; 137 | while (tx_buffer_tail == head) ; // wait until space in buffer 138 | intr_state = SREG; 139 | cli(); 140 | if (tx_state) { 141 | tx_buffer[head] = b; 142 | tx_buffer_head = head; 143 | } else { 144 | tx_state = 1; 145 | tx_byte = b; 146 | tx_bit = 0; 147 | ENABLE_INT_COMPARE_A(); 148 | CONFIG_MATCH_CLEAR(); 149 | SET_COMPARE_A(GET_TIMER_COUNT() + 16); 150 | } 151 | SREG = intr_state; 152 | } 153 | 154 | 155 | ISR(COMPARE_A_INTERRUPT) 156 | { 157 | uint8_t state, byte, bit, head, tail; 158 | uint16_t target; 159 | 160 | state = tx_state; 161 | byte = tx_byte; 162 | target = GET_COMPARE_A(); 163 | while (state < 10) { 164 | target += ticks_per_bit; 165 | if (state < 9) 166 | bit = byte & 1; 167 | else 168 | bit = 1; // stopbit 169 | byte >>= 1; 170 | state++; 171 | if (bit != tx_bit) { 172 | if (bit) { 173 | CONFIG_MATCH_SET(); 174 | } else { 175 | CONFIG_MATCH_CLEAR(); 176 | } 177 | SET_COMPARE_A(target); 178 | tx_bit = bit; 179 | tx_byte = byte; 180 | tx_state = state; 181 | // TODO: how to detect timing_error? 182 | return; 183 | } 184 | } 185 | head = tx_buffer_head; 186 | tail = tx_buffer_tail; 187 | if (head == tail) { 188 | if (state == 10) { 189 | // Wait for final stop bit to finish 190 | tx_state = 11; 191 | SET_COMPARE_A(target + ticks_per_bit); 192 | } else { 193 | tx_state = 0; 194 | CONFIG_MATCH_NORMAL(); 195 | DISABLE_INT_COMPARE_A(); 196 | } 197 | } else { 198 | if (++tail >= TX_BUFFER_SIZE) tail = 0; 199 | tx_buffer_tail = tail; 200 | tx_byte = tx_buffer[tail]; 201 | tx_bit = 0; 202 | CONFIG_MATCH_CLEAR(); 203 | if (state == 10) 204 | SET_COMPARE_A(target + ticks_per_bit); 205 | else 206 | SET_COMPARE_A(GET_TIMER_COUNT() + 16); 207 | tx_state = 1; 208 | // TODO: how to detect timing_error? 209 | } 210 | } 211 | 212 | void AltSoftSerial::flushOutput(void) 213 | { 214 | while (tx_state) /* wait */ ; 215 | } 216 | 217 | 218 | /****************************************/ 219 | /** Reception **/ 220 | /****************************************/ 221 | 222 | ISR(CAPTURE_INTERRUPT) 223 | { 224 | uint8_t state, bit, head; 225 | uint16_t capture, target; 226 | uint16_t offset, offset_overflow; 227 | 228 | capture = GET_INPUT_CAPTURE(); 229 | bit = rx_bit; 230 | if (bit) { 231 | CONFIG_CAPTURE_FALLING_EDGE(); 232 | rx_bit = 0; 233 | } else { 234 | CONFIG_CAPTURE_RISING_EDGE(); 235 | rx_bit = 0x80; 236 | } 237 | state = rx_state; 238 | if (state == 0) { 239 | if (!bit) { 240 | uint16_t end = capture + rx_stop_ticks; 241 | SET_COMPARE_B(end); 242 | ENABLE_INT_COMPARE_B(); 243 | rx_target = capture + ticks_per_bit + ticks_per_bit/2; 244 | rx_state = 1; 245 | } 246 | } else { 247 | target = rx_target; 248 | offset_overflow = 65535 - ticks_per_bit; 249 | while (1) { 250 | offset = capture - target; 251 | if (offset > offset_overflow) break; 252 | rx_byte = (rx_byte >> 1) | rx_bit; 253 | target += ticks_per_bit; 254 | state++; 255 | if (state >= 9) { 256 | DISABLE_INT_COMPARE_B(); 257 | head = rx_buffer_head + 1; 258 | if (head >= RX_BUFFER_SIZE) head = 0; 259 | if (head != rx_buffer_tail) { 260 | rx_buffer[head] = rx_byte; 261 | rx_buffer_head = head; 262 | } 263 | CONFIG_CAPTURE_FALLING_EDGE(); 264 | rx_bit = 0; 265 | rx_state = 0; 266 | return; 267 | } 268 | } 269 | rx_target = target; 270 | rx_state = state; 271 | } 272 | //if (GET_TIMER_COUNT() - capture > ticks_per_bit) AltSoftSerial::timing_error = true; 273 | } 274 | 275 | ISR(COMPARE_B_INTERRUPT) 276 | { 277 | uint8_t head, state, bit; 278 | 279 | DISABLE_INT_COMPARE_B(); 280 | CONFIG_CAPTURE_FALLING_EDGE(); 281 | state = rx_state; 282 | bit = rx_bit ^ 0x80; 283 | while (state < 9) { 284 | rx_byte = (rx_byte >> 1) | bit; 285 | state++; 286 | } 287 | head = rx_buffer_head + 1; 288 | if (head >= RX_BUFFER_SIZE) head = 0; 289 | if (head != rx_buffer_tail) { 290 | rx_buffer[head] = rx_byte; 291 | rx_buffer_head = head; 292 | } 293 | rx_state = 0; 294 | CONFIG_CAPTURE_FALLING_EDGE(); 295 | rx_bit = 0; 296 | } 297 | 298 | 299 | 300 | int AltSoftSerial::read(void) 301 | { 302 | uint8_t head, tail, out; 303 | 304 | head = rx_buffer_head; 305 | tail = rx_buffer_tail; 306 | if (head == tail) return -1; 307 | if (++tail >= RX_BUFFER_SIZE) tail = 0; 308 | out = rx_buffer[tail]; 309 | rx_buffer_tail = tail; 310 | return out; 311 | } 312 | 313 | int AltSoftSerial::peek(void) 314 | { 315 | uint8_t head, tail; 316 | 317 | head = rx_buffer_head; 318 | tail = rx_buffer_tail; 319 | if (head == tail) return -1; 320 | if (++tail >= RX_BUFFER_SIZE) tail = 0; 321 | return rx_buffer[tail]; 322 | } 323 | 324 | int AltSoftSerial::available(void) 325 | { 326 | uint8_t head, tail; 327 | 328 | head = rx_buffer_head; 329 | tail = rx_buffer_tail; 330 | if (head >= tail) return head - tail; 331 | return RX_BUFFER_SIZE + head - tail; 332 | } 333 | 334 | void AltSoftSerial::flushInput(void) 335 | { 336 | rx_buffer_head = rx_buffer_tail; 337 | } 338 | 339 | 340 | #ifdef ALTSS_USE_FTM0 341 | void ftm0_isr(void) 342 | { 343 | uint32_t flags = FTM0_STATUS; 344 | FTM0_STATUS = 0; 345 | if (flags & (1<<0) && (FTM0_C0SC & 0x40)) altss_compare_b_interrupt(); 346 | if (flags & (1<<5)) altss_capture_interrupt(); 347 | if (flags & (1<<6) && (FTM0_C6SC & 0x40)) altss_compare_a_interrupt(); 348 | } 349 | #endif 350 | 351 | -------------------------------------------------------------------------------- /Libreries/MIDI/examples/MIDI_SimpleSynth/noteList.h: -------------------------------------------------------------------------------- 1 | /*! 2 | * \file noteList.h 3 | * \author Francois Best 4 | * \date 24/05/2013 5 | * \brief Linked list of notes, for Low, Last & High playing modes. 6 | * \license GPL v3.0 - Copyright Forty Seven Effects 2013 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | #pragma once 23 | 24 | #include 25 | 26 | typedef uint8_t byte; 27 | 28 | // ----------------------------------------------------------------------------- 29 | 30 | struct MidiNote 31 | { 32 | inline MidiNote(); 33 | inline MidiNote(byte inPitch, byte inVelocity); 34 | inline MidiNote(const MidiNote& inOther); 35 | inline MidiNote& operator= (const MidiNote& inOther); 36 | 37 | byte pitch; 38 | byte velocity; 39 | }; 40 | 41 | // ----------------------------------------------------------------------------- 42 | 43 | template 44 | class MidiNoteList 45 | { 46 | private: 47 | struct Cell 48 | { 49 | inline Cell(); 50 | inline Cell(const Cell& inOther); 51 | inline Cell& operator= (const Cell& inOther); 52 | 53 | MidiNote note; 54 | bool active; 55 | Cell* next; 56 | Cell* prev; 57 | }; 58 | 59 | public: 60 | inline MidiNoteList(); 61 | inline ~MidiNoteList(); 62 | 63 | public: 64 | inline void add(const MidiNote& inNote); 65 | inline void remove(byte inPitch); 66 | 67 | public: 68 | inline bool get(byte inIndex, byte& outPitch) const; 69 | inline bool getLast(byte& outPitch) const; 70 | inline bool getHigh(byte& outPitch) const; 71 | inline bool getLow(byte& outPitch) const; 72 | 73 | public: 74 | inline bool empty() const; 75 | inline byte size() const; 76 | 77 | private: 78 | inline Cell* getFirstEmptyCell(); 79 | inline void print() const; 80 | 81 | private: 82 | Cell mArray[Size]; 83 | Cell* mHead; 84 | Cell* mTail; 85 | byte mSize; 86 | }; 87 | 88 | // ########################################################################## // 89 | // Inline implementation 90 | 91 | inline MidiNote::MidiNote() 92 | : pitch(0) 93 | , velocity(0) 94 | { 95 | } 96 | 97 | inline MidiNote::MidiNote(byte inPitch, byte inVelocity) 98 | : pitch(inPitch) 99 | , velocity(inVelocity) 100 | { 101 | } 102 | 103 | inline MidiNote::MidiNote(const MidiNote& inOther) 104 | : pitch(inOther.pitch) 105 | , velocity(inOther.velocity) 106 | { 107 | } 108 | 109 | inline MidiNote& MidiNote::operator= (const MidiNote& inOther) 110 | { 111 | pitch = inOther.pitch; 112 | velocity = inOther.velocity; 113 | return *this; 114 | } 115 | 116 | // ########################################################################## // 117 | 118 | template 119 | inline MidiNoteList::Cell::Cell() 120 | : note() 121 | , active(false) 122 | , next(0) 123 | , prev(0) 124 | { 125 | } 126 | 127 | template 128 | inline MidiNoteList::Cell::Cell(const Cell& inOther) 129 | : note(inOther.note) 130 | , active(inOther.active) 131 | , next(inOther.next) 132 | , prev(inOther.prev) 133 | { 134 | } 135 | 136 | template 137 | inline typename MidiNoteList::Cell& MidiNoteList::Cell::operator= (const Cell& inOther) 138 | { 139 | note = inOther.note; 140 | active = inOther.active; 141 | next = inOther.next; 142 | prev = inOther.prev; 143 | return *this; 144 | } 145 | 146 | // ########################################################################## // 147 | 148 | template 149 | inline MidiNoteList::MidiNoteList() 150 | { 151 | } 152 | 153 | template 154 | inline MidiNoteList::~MidiNoteList() 155 | { 156 | } 157 | 158 | // ----------------------------------------------------------------------------- 159 | 160 | /*! \brief Add a note, sorting it by time. 161 | Call this when receiving a NoteOn event. This will add the new note as the tail 162 | of the list. 163 | */ 164 | template 165 | inline void MidiNoteList::add(const MidiNote& inNote) 166 | { 167 | if (mHead == 0) 168 | { 169 | mArray[0].note = inNote; 170 | mArray[0].active = true; 171 | mArray[0].next = 0; 172 | mArray[0].prev = 0; 173 | mHead = mArray; 174 | mTail = mArray; 175 | } 176 | else 177 | { 178 | // Find the first inactive cell, and use it as tail. 179 | Cell* const oldTail = mTail; 180 | Cell* const newTail = getFirstEmptyCell(); 181 | 182 | newTail->active = true; 183 | newTail->note = inNote; 184 | 185 | oldTail->next = newTail; 186 | newTail->prev = oldTail; 187 | newTail->next = 0; 188 | mTail = newTail; 189 | } 190 | mSize++; 191 | print(); 192 | } 193 | 194 | /*! \brief Remove a note 195 | Call this when receiving a NoteOff event. 196 | */ 197 | template 198 | inline void MidiNoteList::remove(byte inPitch) 199 | { 200 | if (mTail != 0) 201 | { 202 | for (Cell* it = mTail; it != 0; it = it->prev) 203 | { 204 | if (it->note.pitch == inPitch) 205 | { 206 | Cell* const prev = it->prev; 207 | Cell* const next = it->next; 208 | 209 | it->active = false; 210 | it->next = 0; 211 | it->prev = 0; 212 | 213 | // Reconnect both ends 214 | if (it == mHead) 215 | { 216 | //AVR_ASSERT(prev == 0); 217 | mHead = next; 218 | } 219 | else 220 | { 221 | //AVR_ASSERT(prev != 0); 222 | prev->next = next; 223 | } 224 | 225 | if (it == mTail) 226 | { 227 | //AVR_ASSERT(next == 0); 228 | mTail = prev; 229 | } 230 | else 231 | { 232 | //AVR_ASSERT(next != 0); 233 | next->prev = prev; 234 | } 235 | 236 | mSize--; 237 | break; 238 | } 239 | } 240 | } 241 | print(); 242 | } 243 | 244 | // ----------------------------------------------------------------------------- 245 | 246 | /*! \brief Get a note at an arbitrary position 247 | This can be interesting for duo/multi/polyphony operations. 248 | */ 249 | template 250 | inline bool MidiNoteList::get(byte inIndex, byte& outPitch) const 251 | { 252 | if (mTail) 253 | { 254 | const Cell* it = mTail; 255 | for (byte i = 0; i < inIndex; ++i) 256 | { 257 | if (it->prev) 258 | { 259 | it = it->prev; 260 | } 261 | } 262 | 263 | print(); 264 | //AVR_LOG("Index " << inIndex << ": " << it->note.pitch); 265 | 266 | outPitch = it->note.pitch; 267 | return true; 268 | } 269 | return false; 270 | } 271 | 272 | /*! \brief Get the last active note played 273 | This implements the Mono Last playing mode. 274 | */ 275 | template 276 | inline bool MidiNoteList::getLast(byte& outPitch) const 277 | { 278 | if (!mTail) 279 | { 280 | return false; 281 | } 282 | 283 | outPitch = mTail->note.pitch; 284 | return true; 285 | } 286 | 287 | /*! \brief Get the highest pitched active note 288 | This implements the Mono High playing mode. 289 | */ 290 | template 291 | inline bool MidiNoteList::getHigh(byte& outPitch) const 292 | { 293 | if (!mTail) 294 | { 295 | return false; 296 | } 297 | 298 | outPitch = 0; 299 | const Cell* it = mTail; 300 | for (byte i = 0; i < mSize; ++i) 301 | { 302 | if (it->note.pitch > outPitch) 303 | { 304 | outPitch = it->note.pitch; 305 | } 306 | 307 | if (it->prev) 308 | { 309 | it = it->prev; 310 | } 311 | } 312 | return true; 313 | } 314 | 315 | /*! \brief Get the lowest pitched active note 316 | This implements the Mono Low playing mode. 317 | */ 318 | template 319 | inline bool MidiNoteList::getLow(byte& outPitch) const 320 | { 321 | if (!mTail) 322 | { 323 | return false; 324 | } 325 | 326 | outPitch = 0xff; 327 | const Cell* it = mTail; 328 | for (byte i = 0; i < mSize; ++i) 329 | { 330 | if (it->note.pitch < outPitch) 331 | { 332 | outPitch = it->note.pitch; 333 | } 334 | 335 | if (it->prev) 336 | { 337 | it = it->prev; 338 | } 339 | } 340 | return true; 341 | } 342 | 343 | // ----------------------------------------------------------------------------- 344 | 345 | template 346 | inline bool MidiNoteList::empty() const 347 | { 348 | return mSize == 0; 349 | } 350 | 351 | /*! \brief Get the number of active notes. 352 | */ 353 | template 354 | inline byte MidiNoteList::size() const 355 | { 356 | return mSize; 357 | } 358 | 359 | // ----------------------------------------------------------------------------- 360 | // Private implementations, for internal use only. 361 | 362 | template 363 | inline typename MidiNoteList::Cell* MidiNoteList::getFirstEmptyCell() 364 | { 365 | for (byte i = 0; i < Size; ++i) 366 | { 367 | if (mArray[i].active == false) 368 | { 369 | return mArray + i; 370 | } 371 | } 372 | return 0; 373 | } 374 | 375 | template 376 | inline void MidiNoteList::print() const 377 | { 378 | //#ifndef NDEBUG 379 | // AVR_DBG("Note List: [ "); 380 | // if (mHead) 381 | // { 382 | // for (const Cell* it = mHead; it != 0; it = it->next) 383 | // { 384 | // AVR_DBG(it->note.pitch); 385 | // if (it->next) 386 | // AVR_DBG(" -> "); 387 | // } 388 | // } 389 | // AVR_LOG(" ]"); 390 | //#endif 391 | } 392 | -------------------------------------------------------------------------------- /Libreries/AltSoftSerial/config/AltSoftSerial_Timers.h: -------------------------------------------------------------------------------- 1 | /* An Alternative Software Serial Library 2 | * http://www.pjrc.com/teensy/td_libs_AltSoftSerial.html 3 | * Copyright (c) 2014 PJRC.COM, LLC, Paul Stoffregen, paul@pjrc.com 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | 24 | #if defined(ALTSS_USE_TIMER1) 25 | #define CONFIG_TIMER_NOPRESCALE() (TIMSK1 = 0, TCCR1A = 0, TCCR1B = (1<. 22 | */ 23 | 24 | #pragma once 25 | 26 | BEGIN_MIDI_NAMESPACE 27 | 28 | /// \brief Constructor for MidiInterface. 29 | template 30 | inline MidiInterface::MidiInterface(SerialPort& inSerial) 31 | : mSerial(inSerial) 32 | { 33 | mNoteOffCallback = 0; 34 | mNoteOnCallback = 0; 35 | mAfterTouchPolyCallback = 0; 36 | mControlChangeCallback = 0; 37 | mProgramChangeCallback = 0; 38 | mAfterTouchChannelCallback = 0; 39 | mPitchBendCallback = 0; 40 | mSystemExclusiveCallback = 0; 41 | mTimeCodeQuarterFrameCallback = 0; 42 | mSongPositionCallback = 0; 43 | mSongSelectCallback = 0; 44 | mTuneRequestCallback = 0; 45 | mClockCallback = 0; 46 | mStartCallback = 0; 47 | mContinueCallback = 0; 48 | mStopCallback = 0; 49 | mActiveSensingCallback = 0; 50 | mSystemResetCallback = 0; 51 | } 52 | 53 | /*! \brief Destructor for MidiInterface. 54 | 55 | This is not really useful for the Arduino, as it is never called... 56 | */ 57 | template 58 | inline MidiInterface::~MidiInterface() 59 | { 60 | } 61 | 62 | // ----------------------------------------------------------------------------- 63 | 64 | /*! \brief Call the begin method in the setup() function of the Arduino. 65 | 66 | All parameters are set to their default values: 67 | - Input channel set to 1 if no value is specified 68 | - Full thru mirroring 69 | */ 70 | template 71 | void MidiInterface::begin(Channel inChannel) 72 | { 73 | // Initialise the Serial port 74 | #if defined(FSE_AVR) 75 | mSerial. template open(); 76 | #else 77 | mSerial.begin(Settings::BaudRate); 78 | #endif 79 | 80 | mInputChannel = inChannel; 81 | mRunningStatus_TX = InvalidType; 82 | mRunningStatus_RX = InvalidType; 83 | 84 | mPendingMessageIndex = 0; 85 | mPendingMessageExpectedLenght = 0; 86 | 87 | mMessage.valid = false; 88 | mMessage.type = InvalidType; 89 | mMessage.channel = 0; 90 | mMessage.data1 = 0; 91 | mMessage.data2 = 0; 92 | 93 | mThruFilterMode = Full; 94 | mThruActivated = true; 95 | } 96 | 97 | // ----------------------------------------------------------------------------- 98 | // Output 99 | // ----------------------------------------------------------------------------- 100 | 101 | /*! \addtogroup output 102 | @{ 103 | */ 104 | 105 | /*! \brief Generate and send a MIDI message from the values given. 106 | \param inType The message type (see type defines for reference) 107 | \param inData1 The first data byte. 108 | \param inData2 The second data byte (if the message contains only 1 data byte, 109 | set this one to 0). 110 | \param inChannel The output channel on which the message will be sent 111 | (values from 1 to 16). Note: you cannot send to OMNI. 112 | 113 | This is an internal method, use it only if you need to send raw data 114 | from your code, at your own risks. 115 | */ 116 | template 117 | void MidiInterface::send(MidiType inType, 118 | DataByte inData1, 119 | DataByte inData2, 120 | Channel inChannel) 121 | { 122 | // Then test if channel is valid 123 | if (inChannel >= MIDI_CHANNEL_OFF || 124 | inChannel == MIDI_CHANNEL_OMNI || 125 | inType < 0x80) 126 | { 127 | if (Settings::UseRunningStatus) 128 | { 129 | mRunningStatus_TX = InvalidType; 130 | } 131 | return; // Don't send anything 132 | } 133 | 134 | if (inType <= PitchBend) // Channel messages 135 | { 136 | // Protection: remove MSBs on data 137 | inData1 &= 0x7f; 138 | inData2 &= 0x7f; 139 | 140 | const StatusByte status = getStatus(inType, inChannel); 141 | 142 | if (Settings::UseRunningStatus) 143 | { 144 | if (mRunningStatus_TX != status) 145 | { 146 | // New message, memorise and send header 147 | mRunningStatus_TX = status; 148 | mSerial.write(mRunningStatus_TX); 149 | } 150 | } 151 | else 152 | { 153 | // Don't care about running status, send the status byte. 154 | mSerial.write(status); 155 | } 156 | 157 | // Then send data 158 | mSerial.write(inData1); 159 | if (inType != ProgramChange && inType != AfterTouchChannel) 160 | { 161 | mSerial.write(inData2); 162 | } 163 | } 164 | else if (inType >= TuneRequest && inType <= SystemReset) 165 | { 166 | sendRealTime(inType); // System Real-time and 1 byte. 167 | } 168 | } 169 | 170 | // ----------------------------------------------------------------------------- 171 | 172 | /*! \brief Send a Note On message 173 | \param inNoteNumber Pitch value in the MIDI format (0 to 127). 174 | \param inVelocity Note attack velocity (0 to 127). A NoteOn with 0 velocity 175 | is considered as a NoteOff. 176 | \param inChannel The channel on which the message will be sent (1 to 16). 177 | 178 | Take a look at the values, names and frequencies of notes here: 179 | http://www.phys.unsw.edu.au/jw/notes.html 180 | */ 181 | template 182 | void MidiInterface::sendNoteOn(DataByte inNoteNumber, 183 | DataByte inVelocity, 184 | Channel inChannel) 185 | { 186 | send(NoteOn, inNoteNumber, inVelocity, inChannel); 187 | } 188 | 189 | /*! \brief Send a Note Off message 190 | \param inNoteNumber Pitch value in the MIDI format (0 to 127). 191 | \param inVelocity Release velocity (0 to 127). 192 | \param inChannel The channel on which the message will be sent (1 to 16). 193 | 194 | Note: you can send NoteOn with zero velocity to make a NoteOff, this is based 195 | on the Running Status principle, to avoid sending status messages and thus 196 | sending only NoteOn data. sendNoteOff will always send a real NoteOff message. 197 | Take a look at the values, names and frequencies of notes here: 198 | http://www.phys.unsw.edu.au/jw/notes.html 199 | */ 200 | template 201 | void MidiInterface::sendNoteOff(DataByte inNoteNumber, 202 | DataByte inVelocity, 203 | Channel inChannel) 204 | { 205 | send(NoteOff, inNoteNumber, inVelocity, inChannel); 206 | } 207 | 208 | /*! \brief Send a Program Change message 209 | \param inProgramNumber The Program to select (0 to 127). 210 | \param inChannel The channel on which the message will be sent (1 to 16). 211 | */ 212 | template 213 | void MidiInterface::sendProgramChange(DataByte inProgramNumber, 214 | Channel inChannel) 215 | { 216 | send(ProgramChange, inProgramNumber, 0, inChannel); 217 | } 218 | 219 | /*! \brief Send a Control Change message 220 | \param inControlNumber The controller number (0 to 127). 221 | \param inControlValue The value for the specified controller (0 to 127). 222 | \param inChannel The channel on which the message will be sent (1 to 16). 223 | @see MidiControlChangeNumber 224 | */ 225 | template 226 | void MidiInterface::sendControlChange(DataByte inControlNumber, 227 | DataByte inControlValue, 228 | Channel inChannel) 229 | { 230 | send(ControlChange, inControlNumber, inControlValue, inChannel); 231 | } 232 | 233 | /*! \brief Send a Polyphonic AfterTouch message (applies to a specified note) 234 | \param inNoteNumber The note to apply AfterTouch to (0 to 127). 235 | \param inPressure The amount of AfterTouch to apply (0 to 127). 236 | \param inChannel The channel on which the message will be sent (1 to 16). 237 | */ 238 | template 239 | void MidiInterface::sendPolyPressure(DataByte inNoteNumber, 240 | DataByte inPressure, 241 | Channel inChannel) 242 | { 243 | send(AfterTouchPoly, inNoteNumber, inPressure, inChannel); 244 | } 245 | 246 | /*! \brief Send a MonoPhonic AfterTouch message (applies to all notes) 247 | \param inPressure The amount of AfterTouch to apply to all notes. 248 | \param inChannel The channel on which the message will be sent (1 to 16). 249 | */ 250 | template 251 | void MidiInterface::sendAfterTouch(DataByte inPressure, 252 | Channel inChannel) 253 | { 254 | send(AfterTouchChannel, inPressure, 0, inChannel); 255 | } 256 | 257 | /*! \brief Send a Pitch Bend message using a signed integer value. 258 | \param inPitchValue The amount of bend to send (in a signed integer format), 259 | between MIDI_PITCHBEND_MIN and MIDI_PITCHBEND_MAX, 260 | center value is 0. 261 | \param inChannel The channel on which the message will be sent (1 to 16). 262 | */ 263 | template 264 | void MidiInterface::sendPitchBend(int inPitchValue, 265 | Channel inChannel) 266 | { 267 | const unsigned bend = inPitchValue - MIDI_PITCHBEND_MIN; 268 | send(PitchBend, (bend & 0x7f), (bend >> 7) & 0x7f, inChannel); 269 | } 270 | 271 | 272 | /*! \brief Send a Pitch Bend message using a floating point value. 273 | \param inPitchValue The amount of bend to send (in a floating point format), 274 | between -1.0f (maximum downwards bend) 275 | and +1.0f (max upwards bend), center value is 0.0f. 276 | \param inChannel The channel on which the message will be sent (1 to 16). 277 | */ 278 | template 279 | void MidiInterface::sendPitchBend(double inPitchValue, 280 | Channel inChannel) 281 | { 282 | const int value = inPitchValue * MIDI_PITCHBEND_MAX * Settings::Toto; 283 | sendPitchBend(value, inChannel); 284 | } 285 | 286 | /*! \brief Generate and send a System Exclusive frame. 287 | \param inLength The size of the array to send 288 | \param inArray The byte array containing the data to send 289 | \param inArrayContainsBoundaries When set to 'true', 0xf0 & 0xf7 bytes 290 | (start & stop SysEx) will NOT be sent 291 | (and therefore must be included in the array). 292 | default value for ArrayContainsBoundaries is set to 'false' for compatibility 293 | with previous versions of the library. 294 | */ 295 | template 296 | void MidiInterface::sendSysEx(unsigned inLength, 297 | const byte* inArray, 298 | bool inArrayContainsBoundaries) 299 | { 300 | const bool writeBeginEndBytes = !inArrayContainsBoundaries; 301 | 302 | if (writeBeginEndBytes) 303 | { 304 | mSerial.write(0xf0); 305 | } 306 | 307 | for (unsigned i = 0; i < inLength; ++i) 308 | { 309 | mSerial.write(inArray[i]); 310 | } 311 | 312 | if (writeBeginEndBytes) 313 | { 314 | mSerial.write(0xf7); 315 | } 316 | 317 | if (Settings::UseRunningStatus) 318 | { 319 | mRunningStatus_TX = InvalidType; 320 | } 321 | } 322 | 323 | /*! \brief Send a Tune Request message. 324 | 325 | When a MIDI unit receives this message, 326 | it should tune its oscillators (if equipped with any). 327 | */ 328 | template 329 | void MidiInterface::sendTuneRequest() 330 | { 331 | sendRealTime(TuneRequest); 332 | } 333 | 334 | /*! \brief Send a MIDI Time Code Quarter Frame. 335 | 336 | \param inTypeNibble MTC type 337 | \param inValuesNibble MTC data 338 | See MIDI Specification for more information. 339 | */ 340 | template 341 | void MidiInterface::sendTimeCodeQuarterFrame(DataByte inTypeNibble, 342 | DataByte inValuesNibble) 343 | { 344 | const byte data = (((inTypeNibble & 0x07) << 4) | (inValuesNibble & 0x0f)); 345 | sendTimeCodeQuarterFrame(data); 346 | } 347 | 348 | /*! \brief Send a MIDI Time Code Quarter Frame. 349 | 350 | See MIDI Specification for more information. 351 | \param inData if you want to encode directly the nibbles in your program, 352 | you can send the byte here. 353 | */ 354 | template 355 | void MidiInterface::sendTimeCodeQuarterFrame(DataByte inData) 356 | { 357 | mSerial.write((byte)TimeCodeQuarterFrame); 358 | mSerial.write(inData); 359 | 360 | if (Settings::UseRunningStatus) 361 | { 362 | mRunningStatus_TX = InvalidType; 363 | } 364 | } 365 | 366 | /*! \brief Send a Song Position Pointer message. 367 | \param inBeats The number of beats since the start of the song. 368 | */ 369 | template 370 | void MidiInterface::sendSongPosition(unsigned inBeats) 371 | { 372 | mSerial.write((byte)SongPosition); 373 | mSerial.write(inBeats & 0x7f); 374 | mSerial.write((inBeats >> 7) & 0x7f); 375 | 376 | if (Settings::UseRunningStatus) 377 | { 378 | mRunningStatus_TX = InvalidType; 379 | } 380 | } 381 | 382 | /*! \brief Send a Song Select message */ 383 | template 384 | void MidiInterface::sendSongSelect(DataByte inSongNumber) 385 | { 386 | mSerial.write((byte)SongSelect); 387 | mSerial.write(inSongNumber & 0x7f); 388 | 389 | if (Settings::UseRunningStatus) 390 | { 391 | mRunningStatus_TX = InvalidType; 392 | } 393 | } 394 | 395 | /*! \brief Send a Real Time (one byte) message. 396 | 397 | \param inType The available Real Time types are: 398 | Start, Stop, Continue, Clock, ActiveSensing and SystemReset. 399 | You can also send a Tune Request with this method. 400 | @see MidiType 401 | */ 402 | template 403 | void MidiInterface::sendRealTime(MidiType inType) 404 | { 405 | switch (inType) 406 | { 407 | case TuneRequest: // Not really real-time, but one byte anyway. 408 | case Clock: 409 | case Start: 410 | case Stop: 411 | case Continue: 412 | case ActiveSensing: 413 | case SystemReset: 414 | mSerial.write((byte)inType); 415 | break; 416 | default: 417 | // Invalid Real Time marker 418 | break; 419 | } 420 | 421 | // Do not cancel Running Status for real-time messages as they can be 422 | // interleaved within any message. Though, TuneRequest can be sent here, 423 | // and as it is a System Common message, it must reset Running Status. 424 | if (Settings::UseRunningStatus && inType == TuneRequest) 425 | { 426 | mRunningStatus_TX = InvalidType; 427 | } 428 | } 429 | 430 | /*! @} */ // End of doc group MIDI Output 431 | 432 | // ----------------------------------------------------------------------------- 433 | 434 | template 435 | StatusByte MidiInterface::getStatus(MidiType inType, 436 | Channel inChannel) const 437 | { 438 | return ((byte)inType | ((inChannel - 1) & 0x0f)); 439 | } 440 | 441 | // ----------------------------------------------------------------------------- 442 | // Input 443 | // ----------------------------------------------------------------------------- 444 | 445 | /*! \addtogroup input 446 | @{ 447 | */ 448 | 449 | /*! \brief Read messages from the serial port using the main input channel. 450 | 451 | \return True if a valid message has been stored in the structure, false if not. 452 | A valid message is a message that matches the input channel. \n\n 453 | If the Thru is enabled and the message matches the filter, 454 | it is sent back on the MIDI output. 455 | @see see setInputChannel() 456 | */ 457 | template 458 | inline bool MidiInterface::read() 459 | { 460 | return read(mInputChannel); 461 | } 462 | 463 | /*! \brief Read messages on a specified channel. 464 | */ 465 | template 466 | inline bool MidiInterface::read(Channel inChannel) 467 | { 468 | if (inChannel >= MIDI_CHANNEL_OFF) 469 | return false; // MIDI Input disabled. 470 | 471 | if (!parse()) 472 | return false; 473 | 474 | handleNullVelocityNoteOnAsNoteOff(); 475 | const bool channelMatch = inputFilter(inChannel); 476 | 477 | if (channelMatch) 478 | { 479 | launchCallback(); 480 | } 481 | 482 | thruFilter(inChannel); 483 | 484 | return channelMatch; 485 | } 486 | 487 | // ----------------------------------------------------------------------------- 488 | 489 | // Private method: MIDI parser 490 | template 491 | bool MidiInterface::parse() 492 | { 493 | if (mSerial.available() == 0) 494 | // No data available. 495 | return false; 496 | 497 | // Parsing algorithm: 498 | // Get a byte from the serial buffer. 499 | // If there is no pending message to be recomposed, start a new one. 500 | // - Find type and channel (if pertinent) 501 | // - Look for other bytes in buffer, call parser recursively, 502 | // until the message is assembled or the buffer is empty. 503 | // Else, add the extracted byte to the pending message, and check validity. 504 | // When the message is done, store it. 505 | 506 | const byte extracted = mSerial.read(); 507 | 508 | if (mPendingMessageIndex == 0) 509 | { 510 | // Start a new pending message 511 | mPendingMessage[0] = extracted; 512 | 513 | // Check for running status first 514 | if (isChannelMessage(getTypeFromStatusByte(mRunningStatus_RX))) 515 | { 516 | // Only these types allow Running Status 517 | 518 | // If the status byte is not received, prepend it 519 | // to the pending message 520 | if (extracted < 0x80) 521 | { 522 | mPendingMessage[0] = mRunningStatus_RX; 523 | mPendingMessage[1] = extracted; 524 | mPendingMessageIndex = 1; 525 | } 526 | // Else: well, we received another status byte, 527 | // so the running status does not apply here. 528 | // It will be updated upon completion of this message. 529 | } 530 | 531 | switch (getTypeFromStatusByte(mPendingMessage[0])) 532 | { 533 | // 1 byte messages 534 | case Start: 535 | case Continue: 536 | case Stop: 537 | case Clock: 538 | case ActiveSensing: 539 | case SystemReset: 540 | case TuneRequest: 541 | // Handle the message type directly here. 542 | mMessage.type = getTypeFromStatusByte(mPendingMessage[0]); 543 | mMessage.channel = 0; 544 | mMessage.data1 = 0; 545 | mMessage.data2 = 0; 546 | mMessage.valid = true; 547 | 548 | // \fix Running Status broken when receiving Clock messages. 549 | // Do not reset all input attributes, Running Status must remain unchanged. 550 | //resetInput(); 551 | 552 | // We still need to reset these 553 | mPendingMessageIndex = 0; 554 | mPendingMessageExpectedLenght = 0; 555 | 556 | return true; 557 | break; 558 | 559 | // 2 bytes messages 560 | case ProgramChange: 561 | case AfterTouchChannel: 562 | case TimeCodeQuarterFrame: 563 | case SongSelect: 564 | mPendingMessageExpectedLenght = 2; 565 | break; 566 | 567 | // 3 bytes messages 568 | case NoteOn: 569 | case NoteOff: 570 | case ControlChange: 571 | case PitchBend: 572 | case AfterTouchPoly: 573 | case SongPosition: 574 | mPendingMessageExpectedLenght = 3; 575 | break; 576 | 577 | case SystemExclusive: 578 | // The message can be any lenght 579 | // between 3 and MidiMessage::sSysExMaxSize bytes 580 | mPendingMessageExpectedLenght = MidiMessage::sSysExMaxSize; 581 | mRunningStatus_RX = InvalidType; 582 | mMessage.sysexArray[0] = SystemExclusive; 583 | break; 584 | 585 | case InvalidType: 586 | default: 587 | // This is obviously wrong. Let's get the hell out'a here. 588 | resetInput(); 589 | return false; 590 | break; 591 | } 592 | 593 | if (mPendingMessageIndex >= (mPendingMessageExpectedLenght - 1)) 594 | { 595 | // Reception complete 596 | mMessage.type = getTypeFromStatusByte(mPendingMessage[0]); 597 | mMessage.channel = getChannelFromStatusByte(mPendingMessage[0]); 598 | mMessage.data1 = mPendingMessage[1]; 599 | 600 | // Save data2 only if applicable 601 | if (mPendingMessageExpectedLenght == 3) 602 | mMessage.data2 = mPendingMessage[2]; 603 | else 604 | mMessage.data2 = 0; 605 | 606 | mPendingMessageIndex = 0; 607 | mPendingMessageExpectedLenght = 0; 608 | mMessage.valid = true; 609 | return true; 610 | } 611 | else 612 | { 613 | // Waiting for more data 614 | mPendingMessageIndex++; 615 | } 616 | 617 | if (Settings::Use1ByteParsing) 618 | { 619 | // Message is not complete. 620 | return false; 621 | } 622 | else 623 | { 624 | // Call the parser recursively 625 | // to parse the rest of the message. 626 | return parse(); 627 | } 628 | } 629 | else 630 | { 631 | // First, test if this is a status byte 632 | if (extracted >= 0x80) 633 | { 634 | // Reception of status bytes in the middle of an uncompleted message 635 | // are allowed only for interleaved Real Time message or EOX 636 | switch (extracted) 637 | { 638 | case Clock: 639 | case Start: 640 | case Continue: 641 | case Stop: 642 | case ActiveSensing: 643 | case SystemReset: 644 | 645 | // Here we will have to extract the one-byte message, 646 | // pass it to the structure for being read outside 647 | // the MIDI class, and recompose the message it was 648 | // interleaved into. Oh, and without killing the running status.. 649 | // This is done by leaving the pending message as is, 650 | // it will be completed on next calls. 651 | 652 | mMessage.type = (MidiType)extracted; 653 | mMessage.data1 = 0; 654 | mMessage.data2 = 0; 655 | mMessage.channel = 0; 656 | mMessage.valid = true; 657 | return true; 658 | 659 | break; 660 | 661 | // End of Exclusive 662 | case 0xf7: 663 | if (mMessage.sysexArray[0] == SystemExclusive) 664 | { 665 | // Store the last byte (EOX) 666 | mMessage.sysexArray[mPendingMessageIndex++] = 0xf7; 667 | mMessage.type = SystemExclusive; 668 | 669 | // Get length 670 | mMessage.data1 = mPendingMessageIndex & 0xff; // LSB 671 | mMessage.data2 = mPendingMessageIndex >> 8; // MSB 672 | mMessage.channel = 0; 673 | mMessage.valid = true; 674 | 675 | resetInput(); 676 | return true; 677 | } 678 | else 679 | { 680 | // Well well well.. error. 681 | resetInput(); 682 | return false; 683 | } 684 | 685 | break; 686 | default: 687 | break; 688 | } 689 | } 690 | 691 | // Add extracted data byte to pending message 692 | if (mPendingMessage[0] == SystemExclusive) 693 | mMessage.sysexArray[mPendingMessageIndex] = extracted; 694 | else 695 | mPendingMessage[mPendingMessageIndex] = extracted; 696 | 697 | // Now we are going to check if we have reached the end of the message 698 | if (mPendingMessageIndex >= (mPendingMessageExpectedLenght - 1)) 699 | { 700 | // "FML" case: fall down here with an overflown SysEx.. 701 | // This means we received the last possible data byte that can fit 702 | // the buffer. If this happens, try increasing MidiMessage::sSysExMaxSize. 703 | if (mPendingMessage[0] == SystemExclusive) 704 | { 705 | resetInput(); 706 | return false; 707 | } 708 | 709 | mMessage.type = getTypeFromStatusByte(mPendingMessage[0]); 710 | 711 | if (isChannelMessage(mMessage.type)) 712 | mMessage.channel = getChannelFromStatusByte(mPendingMessage[0]); 713 | else 714 | mMessage.channel = 0; 715 | 716 | mMessage.data1 = mPendingMessage[1]; 717 | 718 | // Save data2 only if applicable 719 | if (mPendingMessageExpectedLenght == 3) 720 | mMessage.data2 = mPendingMessage[2]; 721 | else 722 | mMessage.data2 = 0; 723 | 724 | // Reset local variables 725 | mPendingMessageIndex = 0; 726 | mPendingMessageExpectedLenght = 0; 727 | 728 | mMessage.valid = true; 729 | 730 | // Activate running status (if enabled for the received type) 731 | switch (mMessage.type) 732 | { 733 | case NoteOff: 734 | case NoteOn: 735 | case AfterTouchPoly: 736 | case ControlChange: 737 | case ProgramChange: 738 | case AfterTouchChannel: 739 | case PitchBend: 740 | // Running status enabled: store it from received message 741 | mRunningStatus_RX = mPendingMessage[0]; 742 | break; 743 | 744 | default: 745 | // No running status 746 | mRunningStatus_RX = InvalidType; 747 | break; 748 | } 749 | return true; 750 | } 751 | else 752 | { 753 | // Then update the index of the pending message. 754 | mPendingMessageIndex++; 755 | 756 | if (Settings::Use1ByteParsing) 757 | { 758 | // Message is not complete. 759 | return false; 760 | } 761 | else 762 | { 763 | // Call the parser recursively to parse the rest of the message. 764 | return parse(); 765 | } 766 | } 767 | } 768 | } 769 | 770 | // Private method, see midi_Settings.h for documentation 771 | template 772 | inline void MidiInterface::handleNullVelocityNoteOnAsNoteOff() 773 | { 774 | if (Settings::HandleNullVelocityNoteOnAsNoteOff && 775 | getType() == NoteOn && getData2() == 0) 776 | { 777 | mMessage.type = NoteOff; 778 | } 779 | } 780 | 781 | // Private method: check if the received message is on the listened channel 782 | template 783 | inline bool MidiInterface::inputFilter(Channel inChannel) 784 | { 785 | // This method handles recognition of channel 786 | // (to know if the message is destinated to the Arduino) 787 | 788 | if (mMessage.type == InvalidType) 789 | return false; 790 | 791 | // First, check if the received message is Channel 792 | if (mMessage.type >= NoteOff && mMessage.type <= PitchBend) 793 | { 794 | // Then we need to know if we listen to it 795 | if ((mMessage.channel == mInputChannel) || 796 | (mInputChannel == MIDI_CHANNEL_OMNI)) 797 | { 798 | return true; 799 | } 800 | else 801 | { 802 | // We don't listen to this channel 803 | return false; 804 | } 805 | } 806 | else 807 | { 808 | // System messages are always received 809 | return true; 810 | } 811 | } 812 | 813 | // Private method: reset input attributes 814 | template 815 | inline void MidiInterface::resetInput() 816 | { 817 | mPendingMessageIndex = 0; 818 | mPendingMessageExpectedLenght = 0; 819 | mRunningStatus_RX = InvalidType; 820 | } 821 | 822 | // ----------------------------------------------------------------------------- 823 | 824 | /*! \brief Get the last received message's type 825 | 826 | Returns an enumerated type. @see MidiType 827 | */ 828 | template 829 | inline MidiType MidiInterface::getType() const 830 | { 831 | return mMessage.type; 832 | } 833 | 834 | /*! \brief Get the channel of the message stored in the structure. 835 | 836 | \return Channel range is 1 to 16. 837 | For non-channel messages, this will return 0. 838 | */ 839 | template 840 | inline Channel MidiInterface::getChannel() const 841 | { 842 | return mMessage.channel; 843 | } 844 | 845 | /*! \brief Get the first data byte of the last received message. */ 846 | template 847 | inline DataByte MidiInterface::getData1() const 848 | { 849 | return mMessage.data1; 850 | } 851 | 852 | /*! \brief Get the second data byte of the last received message. */ 853 | template 854 | inline DataByte MidiInterface::getData2() const 855 | { 856 | return mMessage.data2; 857 | } 858 | 859 | /*! \brief Get the System Exclusive byte array. 860 | 861 | @see getSysExArrayLength to get the array's length in bytes. 862 | */ 863 | template 864 | inline const byte* MidiInterface::getSysExArray() const 865 | { 866 | return mMessage.sysexArray; 867 | } 868 | 869 | /*! \brief Get the lenght of the System Exclusive array. 870 | 871 | It is coded using data1 as LSB and data2 as MSB. 872 | \return The array's length, in bytes. 873 | */ 874 | template 875 | inline unsigned MidiInterface::getSysExArrayLength() const 876 | { 877 | return mMessage.getSysExSize(); 878 | } 879 | 880 | /*! \brief Check if a valid message is stored in the structure. */ 881 | template 882 | inline bool MidiInterface::check() const 883 | { 884 | return mMessage.valid; 885 | } 886 | 887 | // ----------------------------------------------------------------------------- 888 | 889 | template 890 | inline Channel MidiInterface::getInputChannel() const 891 | { 892 | return mInputChannel; 893 | } 894 | 895 | /*! \brief Set the value for the input MIDI channel 896 | \param inChannel the channel value. Valid values are 1 to 16, MIDI_CHANNEL_OMNI 897 | if you want to listen to all channels, and MIDI_CHANNEL_OFF to disable input. 898 | */ 899 | template 900 | inline void MidiInterface::setInputChannel(Channel inChannel) 901 | { 902 | mInputChannel = inChannel; 903 | } 904 | 905 | // ----------------------------------------------------------------------------- 906 | 907 | /*! \brief Extract an enumerated MIDI type from a status byte. 908 | 909 | This is a utility static method, used internally, 910 | made public so you can handle MidiTypes more easily. 911 | */ 912 | template 913 | MidiType MidiInterface::getTypeFromStatusByte(byte inStatus) 914 | { 915 | if ((inStatus < 0x80) || 916 | (inStatus == 0xf4) || 917 | (inStatus == 0xf5) || 918 | (inStatus == 0xf9) || 919 | (inStatus == 0xfD)) 920 | { 921 | // Data bytes and undefined. 922 | return InvalidType; 923 | } 924 | if (inStatus < 0xf0) 925 | { 926 | // Channel message, remove channel nibble. 927 | return MidiType(inStatus & 0xf0); 928 | } 929 | 930 | return MidiType(inStatus); 931 | } 932 | 933 | /*! \brief Returns channel in the range 1-16 934 | */ 935 | template 936 | inline Channel MidiInterface::getChannelFromStatusByte(byte inStatus) 937 | { 938 | return (inStatus & 0x0f) + 1; 939 | } 940 | 941 | template 942 | bool MidiInterface::isChannelMessage(MidiType inType) 943 | { 944 | return (inType == NoteOff || 945 | inType == NoteOn || 946 | inType == ControlChange || 947 | inType == AfterTouchPoly || 948 | inType == AfterTouchChannel || 949 | inType == PitchBend || 950 | inType == ProgramChange); 951 | } 952 | 953 | // ----------------------------------------------------------------------------- 954 | 955 | /*! \addtogroup callbacks 956 | @{ 957 | */ 958 | 959 | template void MidiInterface::setHandleNoteOff(void (*fptr)(byte channel, byte note, byte velocity)) { mNoteOffCallback = fptr; } 960 | template void MidiInterface::setHandleNoteOn(void (*fptr)(byte channel, byte note, byte velocity)) { mNoteOnCallback = fptr; } 961 | template void MidiInterface::setHandleAfterTouchPoly(void (*fptr)(byte channel, byte note, byte pressure)) { mAfterTouchPolyCallback = fptr; } 962 | template void MidiInterface::setHandleControlChange(void (*fptr)(byte channel, byte number, byte value)) { mControlChangeCallback = fptr; } 963 | template void MidiInterface::setHandleProgramChange(void (*fptr)(byte channel, byte number)) { mProgramChangeCallback = fptr; } 964 | template void MidiInterface::setHandleAfterTouchChannel(void (*fptr)(byte channel, byte pressure)) { mAfterTouchChannelCallback = fptr; } 965 | template void MidiInterface::setHandlePitchBend(void (*fptr)(byte channel, int bend)) { mPitchBendCallback = fptr; } 966 | template void MidiInterface::setHandleSystemExclusive(void (*fptr)(byte* array, unsigned size)) { mSystemExclusiveCallback = fptr; } 967 | template void MidiInterface::setHandleTimeCodeQuarterFrame(void (*fptr)(byte data)) { mTimeCodeQuarterFrameCallback = fptr; } 968 | template void MidiInterface::setHandleSongPosition(void (*fptr)(unsigned beats)) { mSongPositionCallback = fptr; } 969 | template void MidiInterface::setHandleSongSelect(void (*fptr)(byte songnumber)) { mSongSelectCallback = fptr; } 970 | template void MidiInterface::setHandleTuneRequest(void (*fptr)(void)) { mTuneRequestCallback = fptr; } 971 | template void MidiInterface::setHandleClock(void (*fptr)(void)) { mClockCallback = fptr; } 972 | template void MidiInterface::setHandleStart(void (*fptr)(void)) { mStartCallback = fptr; } 973 | template void MidiInterface::setHandleContinue(void (*fptr)(void)) { mContinueCallback = fptr; } 974 | template void MidiInterface::setHandleStop(void (*fptr)(void)) { mStopCallback = fptr; } 975 | template void MidiInterface::setHandleActiveSensing(void (*fptr)(void)) { mActiveSensingCallback = fptr; } 976 | template void MidiInterface::setHandleSystemReset(void (*fptr)(void)) { mSystemResetCallback = fptr; } 977 | 978 | /*! \brief Detach an external function from the given type. 979 | 980 | Use this method to cancel the effects of setHandle********. 981 | \param inType The type of message to unbind. 982 | When a message of this type is received, no function will be called. 983 | */ 984 | template 985 | void MidiInterface::disconnectCallbackFromType(MidiType inType) 986 | { 987 | switch (inType) 988 | { 989 | case NoteOff: mNoteOffCallback = 0; break; 990 | case NoteOn: mNoteOnCallback = 0; break; 991 | case AfterTouchPoly: mAfterTouchPolyCallback = 0; break; 992 | case ControlChange: mControlChangeCallback = 0; break; 993 | case ProgramChange: mProgramChangeCallback = 0; break; 994 | case AfterTouchChannel: mAfterTouchChannelCallback = 0; break; 995 | case PitchBend: mPitchBendCallback = 0; break; 996 | case SystemExclusive: mSystemExclusiveCallback = 0; break; 997 | case TimeCodeQuarterFrame: mTimeCodeQuarterFrameCallback = 0; break; 998 | case SongPosition: mSongPositionCallback = 0; break; 999 | case SongSelect: mSongSelectCallback = 0; break; 1000 | case TuneRequest: mTuneRequestCallback = 0; break; 1001 | case Clock: mClockCallback = 0; break; 1002 | case Start: mStartCallback = 0; break; 1003 | case Continue: mContinueCallback = 0; break; 1004 | case Stop: mStopCallback = 0; break; 1005 | case ActiveSensing: mActiveSensingCallback = 0; break; 1006 | case SystemReset: mSystemResetCallback = 0; break; 1007 | default: 1008 | break; 1009 | } 1010 | } 1011 | 1012 | /*! @} */ // End of doc group MIDI Callbacks 1013 | 1014 | // Private - launch callback function based on received type. 1015 | template 1016 | void MidiInterface::launchCallback() 1017 | { 1018 | // The order is mixed to allow frequent messages to trigger their callback faster. 1019 | switch (mMessage.type) 1020 | { 1021 | // Notes 1022 | case NoteOff: if (mNoteOffCallback != 0) mNoteOffCallback(mMessage.channel, mMessage.data1, mMessage.data2); break; 1023 | case NoteOn: if (mNoteOnCallback != 0) mNoteOnCallback(mMessage.channel, mMessage.data1, mMessage.data2); break; 1024 | 1025 | // Real-time messages 1026 | case Clock: if (mClockCallback != 0) mClockCallback(); break; 1027 | case Start: if (mStartCallback != 0) mStartCallback(); break; 1028 | case Continue: if (mContinueCallback != 0) mContinueCallback(); break; 1029 | case Stop: if (mStopCallback != 0) mStopCallback(); break; 1030 | case ActiveSensing: if (mActiveSensingCallback != 0) mActiveSensingCallback(); break; 1031 | 1032 | // Continuous controllers 1033 | case ControlChange: if (mControlChangeCallback != 0) mControlChangeCallback(mMessage.channel, mMessage.data1, mMessage.data2); break; 1034 | case PitchBend: if (mPitchBendCallback != 0) mPitchBendCallback(mMessage.channel, (int)((mMessage.data1 & 0x7f) | ((mMessage.data2 & 0x7f) << 7)) + MIDI_PITCHBEND_MIN); break; // TODO: check this 1035 | case AfterTouchPoly: if (mAfterTouchPolyCallback != 0) mAfterTouchPolyCallback(mMessage.channel, mMessage.data1, mMessage.data2); break; 1036 | case AfterTouchChannel: if (mAfterTouchChannelCallback != 0) mAfterTouchChannelCallback(mMessage.channel, mMessage.data1); break; 1037 | 1038 | case ProgramChange: if (mProgramChangeCallback != 0) mProgramChangeCallback(mMessage.channel, mMessage.data1); break; 1039 | case SystemExclusive: if (mSystemExclusiveCallback != 0) mSystemExclusiveCallback(mMessage.sysexArray, mMessage.getSysExSize()); break; 1040 | 1041 | // Occasional messages 1042 | case TimeCodeQuarterFrame: if (mTimeCodeQuarterFrameCallback != 0) mTimeCodeQuarterFrameCallback(mMessage.data1); break; 1043 | case SongPosition: if (mSongPositionCallback != 0) mSongPositionCallback((mMessage.data1 & 0x7f) | ((mMessage.data2 & 0x7f) << 7)); break; 1044 | case SongSelect: if (mSongSelectCallback != 0) mSongSelectCallback(mMessage.data1); break; 1045 | case TuneRequest: if (mTuneRequestCallback != 0) mTuneRequestCallback(); break; 1046 | 1047 | case SystemReset: if (mSystemResetCallback != 0) mSystemResetCallback(); break; 1048 | case InvalidType: 1049 | default: 1050 | break; 1051 | } 1052 | } 1053 | 1054 | /*! @} */ // End of doc group MIDI Input 1055 | 1056 | // ----------------------------------------------------------------------------- 1057 | // Thru 1058 | // ----------------------------------------------------------------------------- 1059 | 1060 | /*! \addtogroup thru 1061 | @{ 1062 | */ 1063 | 1064 | /*! \brief Set the filter for thru mirroring 1065 | \param inThruFilterMode a filter mode 1066 | 1067 | @see MidiFilterMode 1068 | */ 1069 | template 1070 | void MidiInterface::setThruFilterMode(MidiFilterMode inThruFilterMode) 1071 | { 1072 | mThruFilterMode = inThruFilterMode; 1073 | if (mThruFilterMode != Off) 1074 | mThruActivated = true; 1075 | else 1076 | mThruActivated = false; 1077 | } 1078 | 1079 | template 1080 | MidiFilterMode MidiInterface::getFilterMode() const 1081 | { 1082 | return mThruFilterMode; 1083 | } 1084 | 1085 | template 1086 | bool MidiInterface::getThruState() const 1087 | { 1088 | return mThruActivated; 1089 | } 1090 | 1091 | template 1092 | void MidiInterface::turnThruOn(MidiFilterMode inThruFilterMode) 1093 | { 1094 | mThruActivated = true; 1095 | mThruFilterMode = inThruFilterMode; 1096 | } 1097 | 1098 | template 1099 | void MidiInterface::turnThruOff() 1100 | { 1101 | mThruActivated = false; 1102 | mThruFilterMode = Off; 1103 | } 1104 | 1105 | /*! @} */ // End of doc group MIDI Thru 1106 | 1107 | // This method is called upon reception of a message 1108 | // and takes care of Thru filtering and sending. 1109 | // - All system messages (System Exclusive, Common and Real Time) are passed 1110 | // to output unless filter is set to Off. 1111 | // - Channel messages are passed to the output whether their channel 1112 | // is matching the input channel and the filter setting 1113 | template 1114 | void MidiInterface::thruFilter(Channel inChannel) 1115 | { 1116 | // If the feature is disabled, don't do anything. 1117 | if (!mThruActivated || (mThruFilterMode == Off)) 1118 | return; 1119 | 1120 | // First, check if the received message is Channel 1121 | if (mMessage.type >= NoteOff && mMessage.type <= PitchBend) 1122 | { 1123 | const bool filter_condition = ((mMessage.channel == mInputChannel) || 1124 | (mInputChannel == MIDI_CHANNEL_OMNI)); 1125 | 1126 | // Now let's pass it to the output 1127 | switch (mThruFilterMode) 1128 | { 1129 | case Full: 1130 | send(mMessage.type, 1131 | mMessage.data1, 1132 | mMessage.data2, 1133 | mMessage.channel); 1134 | break; 1135 | 1136 | case SameChannel: 1137 | if (filter_condition) 1138 | { 1139 | send(mMessage.type, 1140 | mMessage.data1, 1141 | mMessage.data2, 1142 | mMessage.channel); 1143 | } 1144 | break; 1145 | 1146 | case DifferentChannel: 1147 | if (!filter_condition) 1148 | { 1149 | send(mMessage.type, 1150 | mMessage.data1, 1151 | mMessage.data2, 1152 | mMessage.channel); 1153 | } 1154 | break; 1155 | 1156 | case Off: 1157 | // Do nothing. 1158 | // Technically it's impossible to get there because 1159 | // the case was already tested earlier. 1160 | break; 1161 | 1162 | default: 1163 | break; 1164 | } 1165 | } 1166 | else 1167 | { 1168 | // Send the message to the output 1169 | switch (mMessage.type) 1170 | { 1171 | // Real Time and 1 byte 1172 | case Clock: 1173 | case Start: 1174 | case Stop: 1175 | case Continue: 1176 | case ActiveSensing: 1177 | case SystemReset: 1178 | case TuneRequest: 1179 | sendRealTime(mMessage.type); 1180 | break; 1181 | 1182 | case SystemExclusive: 1183 | // Send SysEx (0xf0 and 0xf7 are included in the buffer) 1184 | sendSysEx(getSysExArrayLength(), getSysExArray(), true); 1185 | break; 1186 | 1187 | case SongSelect: 1188 | sendSongSelect(mMessage.data1); 1189 | break; 1190 | 1191 | case SongPosition: 1192 | sendSongPosition(mMessage.data1 | ((unsigned)mMessage.data2 << 7)); 1193 | break; 1194 | 1195 | case TimeCodeQuarterFrame: 1196 | sendTimeCodeQuarterFrame(mMessage.data1,mMessage.data2); 1197 | break; 1198 | default: 1199 | break; 1200 | } 1201 | } 1202 | } 1203 | 1204 | END_MIDI_NAMESPACE 1205 | --------------------------------------------------------------------------------