oddson
Well-known member
Teensy-based MIDI foot-controller system -- just add sustain and expression pedals.
Physical build consists of nothing but a Teensy 2, some 1/4" sockets, a USB cable and a polystyrene enclosure.
Here's a screenshot of the SysEx CC assign system (built with FlowStone [forum])
It sends a small (16 byte) sysex message to configure the box -- only nine bytes are program data, the rest is to make sure it's the intended message.
(I used the private-use (non-commercial) sysex ID '7D' with an added four bytes as a 'key'.)
The code also sends back three bytes as an acknowledge message.
Code - fragments and ideas stolen liberally from all over but especially Knobber
Physical build consists of nothing but a Teensy 2, some 1/4" sockets, a USB cable and a polystyrene enclosure.
Here's a screenshot of the SysEx CC assign system (built with FlowStone [forum])
It sends a small (16 byte) sysex message to configure the box -- only nine bytes are program data, the rest is to make sure it's the intended message.
(I used the private-use (non-commercial) sysex ID '7D' with an added four bytes as a 'key'.)
The code also sends back three bytes as an acknowledge message.
Code - fragments and ideas stolen liberally from all over but especially Knobber
Code:
#include <Bounce.h>
#include <EEPROM.h>
const int thrshld = 7; // threshold for when change in voltage updates CC on analog pins
const int delayL = 5; // > delay can reduce number of MIDI msgs - can be good or bad??
// higher delay likely advantage if using lower threshold to limit repeats at same CC
int chnl; // MIDI channel
int v0,v1;// analog values for volage from dividers
int v0L, v1L;// lagged voltage values - last time cc was recalc'd
int v0D = 10,v1D = 10; // delta values - current - lag; force cc to calc on init
int toggled[3] = {false,false,false}; // toggle indicates when toggle behavior in effect
int mem[14]={1,4,7,64,0,65,0,66,0};// an array of sysEx bytes, + defaults until EEPROM is loaded
Bounce button[3] = {Bounce(0, 5),Bounce(1, 5),Bounce(2, 5)}; // init 'bounce' for 3 buttons
void setup() {
Serial.begin(31250);
pinMode(0, INPUT_PULLUP); // set up three digital pins
pinMode(1, INPUT_PULLUP); // with PULLUPs
pinMode(2, INPUT_PULLUP); //
if (EEPROM.read(0)>0 && EEPROM.read(0)<17){ // EEPROM @ 0 is non-zer0 or not a viable MIDI channel
for (int i = 0; i <= 8; i++) { // read EEPROM for sysEx data
mem[i] = EEPROM.read(i);
delay(5); // give time for EEPROM read??
}
int chnl = mem[0];
}
}
// *************THE MAIN LOOP************
void loop() {
if(usbMIDI.read() && usbMIDI.getType() == 7) { //if MIDI is sysEx
doSysEx(); // look for CC change msg
}
getAnalogData(); // get/process analog pins
getDigitalData(); // get/process digital pins
delay(delayL);
}
//************ANALOG SECTION**************
void getAnalogData(){
v0 = analogRead(0);
v1 = analogRead(1);
if (v0D > thrshld) // if delta variable shows change past threshold - recalulate
{
usbMIDI.sendControlChange(mem[1], v0/8, chnl); // calculate CC for analog 1 and send
v0L = v0; // lag only on update
}
v0D = abs(v0L-v0);
if (v1D > thrshld)
{
usbMIDI.sendControlChange(mem[2], v1/8, chnl); // calculate CC for analog 2 and send
v1L = v1; // lag only on update
}
v1D = abs(v1L-v1);
}
//************DIGITAL SECTION**************
void getDigitalData(){
for (int i = 0; i < 3; i++){
button[i].update(); //update bounce object for each button
if (button[i].fallingEdge()) { // button press to ground
if (toggled[i] && mem[i * 2 + 4]==1){ // if toggled state and toggle behavoiour both true...
usbMIDI.sendControlChange(mem[i * 2 + 3], 0, chnl); // unlatch to OFF
toggled[i] = false ; // toggled to false for next time
}
else { // either latched and toggled==false or non-latched...
usbMIDI.sendControlChange(mem[i * 2 + 3],127, chnl); //...either way to to ON state
if(mem[i * 2 + 4]==1){
toggled[i] = true ; // but only change toggled state if in latched mode
}
}
}
if (button[i].risingEdge()) { // button release - pullup to HIGH
if (not(mem[i * 2 + 4]==1)){ // if non-latched
usbMIDI.sendControlChange(mem[i * 2 + 3], 0, chnl); // to to OFF
}
}
}
}
//************SYSEX SECTION**************
void doSysEx(){
byte *sysExBytes = usbMIDI.getSysExArray();
if (sysExBytes[0] == 0xf0
&& sysExBytes[15] == 0xf7
&& sysExBytes[1] == 0x7D // 7D is private use (non-commercial)
&& sysExBytes[2] == 0x4C // 4-byte 'key' - not really needed if via USB but why not!
&& sysExBytes[3] == 0x65
&& sysExBytes[4] == 0x69
&& sysExBytes[5] == 0x66){ // read and compare static bytes to ensure valid msg
for (int i = 0; i < 10; i++) {
EEPROM.write(i, sysExBytes[i+6]);
mem[i] = sysExBytes[i+6];
}
byte data[] = { 0xF0, 0x7D, 0xF7 }; // ACK msg - should be safe for any device even if listening for 7D
usbMIDI.sendSysEx(3, data); // SEND
for (int i = 0; i < 3; i++) {
toggled[i] = false; // for consistant behaviour, start in OFF position
}
}
}
Last edited: