MIDI Foot Controller

Status
Not open for further replies.
I'm working on a project using a Teensy 3.2. The purpose of the project is to allow a guitar player to control Ableton Live. To make it fit with the guitar players existing pedal board, we want to have 6 button and the teensy in one enclosure and 12 buttons in a second enclosure. In order to not have to find a way to connect 13 wires between enclosure 1 and 2, the plan was to use a pair of the Sparkfun 74HC4051 breakout boards, which, in my understanding, should allow me to use something like a pair of standard RJ45 jacks and a cat5e cable (3 write pins, V+, GND and 1 signal from each of the 75HC4051's, 7 total wires), There has also been discussion of adding a latching switch to enclosure 2 and have those buttons be able to send either notes or CC Messages (unless there is a way to shift the notes being sent to 12 different notes) but we haven't got to tackling that issue yet. Where I am getting hung up is on how to read the MUX. I currently have 1 hooked up with 2 buttons on it. Currently it is hooked up as Pin 21=SO, Pin 22=S1, Pin 23=S2 and the signal is routed to pin 20. The code I have I originally configured for 24 buttons, and I've been reworking it to the latest idea we've had. What I don't know is how tell teensy what MIDI note I want to send from the multiplexed buttons.
Code:
#include <Bounce.h>
const int channel = 1;
Bounce button0 = Bounce(0, 95);
Bounce button1 = Bounce(1, 95);
Bounce button2 = Bounce(2, 95);
Bounce button3 = Bounce(3, 95);
Bounce button4 = Bounce(4, 95);
Bounce button5 = Bounce(5, 95);
Bounce button6 = Bounce(6, 95);
Bounce button7 = Bounce(7, 95);
Bounce button8 = Bounce(8, 95);
Bounce button9 = Bounce(9, 95);
Bounce button10 = Bounce(10, 95);
Bounce button11 = Bounce(11, 95);
Bounce button12 = Bounce(12, 95);
Bounce button13 = Bounce(13, 95);
Bounce button14 = Bounce(14, 95);
Bounce button15 = Bounce(15, 95);
Bounce button16 = Bounce(16, 95);
Bounce button17 = Bounce(17, 95);
Bounce button18 = Bounce(18, 95);
Bounce button19 = Bounce(19, 95);
Bounce button20 = Bounce(20, 95);

void setup() {
pinMode(0, INPUT_PULLUP);
pinMode(1, INPUT_PULLUP);
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
pinMode(4, INPUT_PULLUP);
pinMode(5, INPUT_PULLUP);
pinMode(6, INPUT_PULLUP); 
pinMode(7, INPUT_PULLUP);
pinMode(8, INPUT_PULLUP);
pinMode(9, INPUT_PULLUP);
pinMode(10, INPUT_PULLUP);
pinMode(11, INPUT_PULLUP);
pinMode(12, INPUT_PULLUP);
pinMode(13, INPUT_PULLUP);
pinMode(14, INPUT_PULLUP);
pinMode(15, INPUT_PULLUP);
pinMode(16, INPUT_PULLUP);
pinMode(17, INPUT_PULLUP);
pinMode(18, INPUT_PULLUP);
pinMode(19, INPUT_PULLUP);
pinMode(20,INPUT);
pinMode(21,OUTPUT);
pinMode(22, OUTPUT);
pinMode(23,OUTPUT);}



void loop() {
button0.update();
button1.update();
button3.update();
button4.update();
button5.update();
button6.update();
button7.update();
button8.update();
button9.update();
button10.update();
button11.update();
button12.update();
button13.update();
button14.update();
button15.update();
button16.update();
button17.update();
button18.update();
button19.update();
digitalWrite(21,LOW);
digitalWrite(22,LOW);
digitalWrite(23,LOW);
delayMicroseconds(50);
button20channel0.update();
digitalWrite(21,HIGH);
digitalWrite(22,LOW);
digitalWrite(23,LOW);
delayMicroseconds(50); 
button2channel1.update();


if (button0.fallingEdge()) {usbMIDI.sendNoteOn(60, 99, channel);}
if (button0.risingEdge())  {usbMIDI.sendNoteOff(60, 0, channel);}
if (button1.fallingEdge()) {usbMIDI.sendNoteOn(61, 99, channel);}
if (button1.risingEdge())  {usbMIDI.sendNoteOff(61, 0, channel);}
if (button2.fallingEdge()) {usbMIDI.sendNoteOn(62, 99, channel);}
if (button2.risingEdge())  {usbMIDI.sendNoteOff(62, 0, channel);}
if (button3.fallingEdge()) {usbMIDI.sendNoteOn(63, 99, channel);}
if (button3.risingEdge())  {usbMIDI.sendNoteOff(63, 0, channel);}     
if (button4.fallingEdge()) {usbMIDI.sendNoteOn(64, 99, channel);}
if (button4.risingEdge())  {usbMIDI.sendNoteOff(64, 0, channel);}
if (button5.fallingEdge()) {usbMIDI.sendNoteOn(65, 99, channel);}
if (button5.risingEdge())  {usbMIDI.sendNoteOff(65, 0, channel);}
if (button6.fallingEdge()) {usbMIDI.sendNoteOn(66, 99, channel);}
if (button6.risingEdge())  {usbMIDI.sendNoteOff(66, 0, channel);}
if (button7.fallingEdge()) {usbMIDI.sendNoteOn(67, 99, channel);}
if (button7.risingEdge())  {usbMIDI.sendNoteOff(67, 0, channel);}
if (button8.fallingEdge()) {usbMIDI.sendNoteOn(68, 99, channel);}
if (button8.risingEdge())  {usbMIDI.sendNoteOff(68, 0, channel);}
if (button9.fallingEdge()) {usbMIDI.sendNoteOn(69, 99, channel);}
if (button9.risingEdge())  {usbMIDI.sendNoteOff(69, 0, channel);}
if (button10.fallingEdge()) {usbMIDI.sendNoteOn(70, 99, channel);}
if (button10.risingEdge())  {usbMIDI.sendNoteOff(70, 0, channel);}
if (button11.fallingEdge()) {usbMIDI.sendNoteOn(71, 99, channel);}
if (button11.risingEdge())  {usbMIDI.sendNoteOff(71, 0, channel);}
if (button12.fallingEdge()) {usbMIDI.sendNoteOn(72, 99, channel);}
if (button12.risingEdge())  {usbMIDI.sendNoteOff(72, 0, channel);}
if (button13.fallingEdge()) {usbMIDI.sendNoteOn(73, 99, channel);}
if (button13.risingEdge())  {usbMIDI.sendNoteOff(73, 0, channel);}
if (button14.fallingEdge()) {usbMIDI.sendNoteOn(74, 99, channel);}
if (button14.risingEdge())  {usbMIDI.sendNoteOff(74, 0, channel);}
if (button15.fallingEdge()) {usbMIDI.sendNoteOn(75, 99, channel);}
if (button15.risingEdge())  {usbMIDI.sendNoteOff(75, 0, channel);}
if (button16.fallingEdge()) {usbMIDI.sendNoteOn(76, 99, channel);}
if (button16.risingEdge())  {usbMIDI.sendNoteOff(76, 0, channel);}
if (button17.fallingEdge()) {usbMIDI.sendNoteOn(77, 99, channel);}
if (button17.risingEdge())  {usbMIDI.sendNoteOff(77, 0, channel);}
if (button18.fallingEdge()) {usbMIDI.sendNoteOn(78, 99, channel);}
if (button18.risingEdge())  {usbMIDI.sendNoteOff(78, 0, channel);}
if (button19.fallingEdge()) {usbMIDI.sendNoteOn(79, 99, channel);}
if (button19.risingEdge())  {usbMIDI.sendNoteOff(79, 0, channel);}
if (button20channel0.fallingEdge()) {usbMIDI.sendNoteOn(80, 99, channel);}
if (button20channel0.risingEdge())  {usbMIDI.sendNoteOff(80, 0, channel);}
if (button20channel1.fallingEdge()) {usbMIDI.sendNoteOn(81, 99, channel);}
if (button20channel1.risingEdge())  {usbMIDI.sendNoteOff(81, 0, channel);}

while (usbMIDI.read()) {}
}
I'm a total newbie when it comes to writing code, I've tried to extrapolate what I could from the USB MIDI page and the sample of code there, but I know I'm missing something. I appreciate all the help in advance
 
you could use i2c or serial, 2 wires plus ground, and communicate over that.
Serial would be best if you want both sides to talk to each other
if your doing long runs, rs485 is better
 
The distance would not be great, probably less than 2 feet from the teensy to the furthest switch on the board. What would I need on the remote end to make this work?
 
you should be able to do serial fine since its under 2 feet, some people prefer rs485, but ive run serial/i2c further, it depends on your terminations and wiring. if your looking for just gpio access, you can use a mcp23017 which has 16 gpios can be run over i2c, or if you want faster SPI you could use a mcp23S17 instead, but youll need 4 wires plus 2 for power, of course, so your balancing 4 wire i2c or 6 wire spi, both can be simple enough for your setup
 
If you want it to be solid under harsh and unexpected conditions, use RS485 and a controller on each side, even if only a short distance.

Sending TTL level signals or I2C on a cable across a stage where you set up in unknown locations is just ask for things to be flakey when you most need them to work.
 
Just to clarify, the enclosures will be on the same pedalboard, more or less permanently attached. It’s purely a function of working with the existing real estate necessitating 2 boxes
 
If you want it to be solid under harsh and unexpected conditions, use RS485 and a controller on each side, even if only a short distance.

Sending TTL level signals or I2C on a cable across a stage where you set up in unknown locations is just ask for things to be flakey when you most need them to work.
If there's a controller in each box then you might consider using MIDI itself to communicate between them. Could be via a MIDI-DIN plug (and two LCs) or it's possible to host usbMIDI from a T3.6 (with an LC on the USB 'device' side).

The new usbMIDI library changes makes communicating arbitrary MIDI between controllers fairly simple (though I haven't personally tested it yet).

This approach would also give you two functioning controllers that could also work separately.

(You might also consider two separate controllers each connected directly to the box running Ableton if there is no need to communicate between them).

Some complex solution just to save buying a second Teensy is unlikely to save you anything in the long run.

There has also been discussion of adding a latching switch to enclosure 2 and have those buttons be able to send either notes or CC Messages (unless there is a way to shift the notes being sent to 12 different notes) but we haven't got to tackling that issue yet.
Adding a bank select (whether A/B or multiple banks) is fairly simple but is much easier and flexible when your controller uses arrays instead of scalar variables to store the configuration.

You could have a CC bank and a Note value bank with an A/B latching switch that pulls a pin HIGH or LOW and your code can use that to switch between sending notes and sending CC.

(More involved options could allow user configuration and mixing CC and Note messages with the same bank.)
 
If it is not a good idea to use Muxes, and it sounds like it’s not, I think the obvious answer is to use another 3.2. The controllers don’t need to talk to each other, they are blindly firing or killing loops and clips. The only feedback may be turning on some LEDs via notes sent from Ableton.
 
If it is not a good idea to use Muxes, and it sounds like it’s not, I think the obvious answer is to use another 3.2. The controllers don’t need to talk to each other, they are blindly firing or killing loops and clips. The only feedback may be turning on some LEDs via notes sent from Ableton.
Yeah if they're not working as a team you might as well split them up and it becomes two simple controllers.

But are you OK with two USB connections? You could put a hub on the pedal board or you could look into hosting one Teensy with another (Teensy 3.6 -- currently the only model that supports usb hosting).


Having a single physical and virtual connection to the DAW would simplify use.

You'll want to look into custom device names if you decide to have two Teensies conectted directly to one computer to avoid having both display the same name.

Your original idea could work, it's a question of simplicity, cost and functionality.


Is it possible to have 2 banks of notes instead of a bank of CC’s and a bank of notes?
Of course, in fact it becomes fairly simple if you use arrays. You can stick to the note handlers and not have to keep track of the status byte.

Here's an example showing how to use arrays in a midi controller https://forum.pjrc.com/threads/45376-Example-code-for-MIDI-controllers-with-Pots-and-Buttons

Search 'midi' & 'banks' and you should find a hint or two how to make bank selection work with arrays.

Edit .... here's one https://forum.pjrc.com/threads/45039-Mode-Possibility?p=146768&viewfull=1#post146768

Are you OK with parameter banks being hard coded in the sketch (i.e. not user configurable?
 
Last edited:
I stole some code from the second thread you linked and tweaked it. I haven't loaded it on to the board yet, but here it is
Code:
#include <Bounce.h>
const int BOUNCE_TIME = 25; // constant bounce time makes it easier to fine tune if the buttons need more/less time
const int PINS[14] = {0,1,2,3,4,5,6,7,8,9,10,11,12,14}; // Pin assignment array, they don't need to be sequiential
const int DIGITAL_PINS = 14; // total digital pin count including two for bank buttons 
const int channel = 1;
const int velocity = 110; // arbitrary 'on' velocity setting for note messages
const int BANKS = 2;
const byte note[][12] = {
  {60,61,62,63,64,65,66,67,68,69,70,71},//C4 to B4
  {72,73,74,75,76,77,78,79,80,81,82,83},//C5 to B5
}; // this is the N x 12 matrix of note values for the bank system
int bank = 0; // this is the bank variable to be incremented or decremented

Bounce btn[] = {
  Bounce(PINS[0], BOUNCE_TIME),
  Bounce(PINS[1], BOUNCE_TIME),
  Bounce(PINS[2], BOUNCE_TIME),
  Bounce(PINS[3], BOUNCE_TIME),
  Bounce(PINS[4], BOUNCE_TIME),
  Bounce(PINS[5], BOUNCE_TIME),
  Bounce(PINS[6], BOUNCE_TIME),
  Bounce(PINS[7], BOUNCE_TIME),
  Bounce(PINS[8], BOUNCE_TIME),
  Bounce(PINS[9], BOUNCE_TIME),
  Bounce(PINS[10], BOUNCE_TIME),
  Bounce(PINS[11], BOUNCE_TIME),
  //Bounce(PINS[12], BOUNCE_TIME),
  //Bounce(PINS[13], BOUNCE_TIME),
  //Bounce(PINS[14], BOUNCE_TIME),
  //Bounce(PINS[15], BOUNCE_TIME)
  };



Bounce bankUp = Bounce(PINS[12], BOUNCE_TIME);
Bounce bankDown = Bounce(PINS[14], BOUNCE_TIME);



void setup() {
  //Serial.begin(9600);
  for (int i = 0;i<DIGITAL_PINS;i++){
    pinMode(PINS[i], INPUT_PULLUP);
  }
}

void loop() {


  for (int i = 0;i<DIGITAL_PINS-1;i++){ // -1 needed so bank buttons run once together 

      if (i<(DIGITAL_PINS-2)){ // for all but the bank buttons...
        btn[i].update();
        if (btn[i].fallingEdge()) {
          usbMIDI.sendNoteOn(note[bank][i], velocity, channel); 
        }
        if (btn[i].risingEdge()) {
          usbMIDI.sendNoteOff(note[bank][i], 0, channel);  
        }
      }else{
        bankUp.update();
        if (bankUp.fallingEdge()) {
          bank++; // increment bank
          if (bank >= BANKS){
            bank = 0;
          }
        }
        bankDown.update();
        if (bankDown.fallingEdge()) {
          bank--; // decrement bank
          if (bank < 0){
            bank = BANKS-1;
          }
        }
      }
  }

  while (usbMIDI.read()) {
  }
}
I'm ok with having the parameter banks being hard coded, from what I understand, as long as we know what notes we are sending to Ableton, we can tell Ableton what we want those notes to do.

We can either put a hub at the pedal board or just run 2 cables back to the rack where the computer is and either put the hub there or go into 2 ports. I think I might be bumping into the limit of USB Cable depending on how its done. It's harder to find short USB A to B cables (granted I haven't spent a lot of time looking) and putting a powered USB hub in for the sake of extending the range would be a pain. So, I'm looking at not much over 16' to work with.

I've already found the section on changing the device name a little while ago. It was kind of funny, I figured I would want to do that anyway, so I went looking for answers on google, only to find the section had been added to the teensy usb midi page at some point between the last time I read it top to bottom and when I decided to google how to change the name.
 
I stole some code from the second thread you linked and tweaked it. I haven't loaded it on to the board yet, but here it is
I forgot about that code. I was just pointing to the hint part but that could work. You really don't need the up and down buttons if there are only two banks - just one button to toggle the bank variable between 0 and 1.
I'm ok with having the parameter banks being hard coded, from what I understand, as long as we know what notes we are sending to Ableton, we can tell Ableton what we want those notes to do.
If you're just going to give sequential numbers you could have it toggle between two calculated offsets and add the loop index number to generate the note value instead of having to hard code them. I.e.:

note = offset + bank*12 + i

If you do it like this bank is essentially 'octave'. Or you can just leave them hard-coded.

We can either put a hub at the pedal board or just run 2 cables back to the rack where the computer is and either put the hub there or go into 2 ports. I think I might be bumping into the limit of USB Cable depending on how its done. It's harder to find short USB A to B cables (granted I haven't spent a lot of time looking) and putting a powered USB hub in for the sake of extending the range would be a pain. So, I'm looking at not much over 16' to work with.
I didn't get that the PC was off stage.
If you're going all MIDI anyway why not go old-school? A MIDI cable should cover that distance handily.
It's a robust low-speed physical layer with ground isolation in the environment it was designed for -- why not?

That's assuming you're OK with a bit of soldering and can build the MIDI interface circuits from Paul's MIDI library page.

You'll need to power separately without USB but, given it's on a guitar board, regulating 9v DC to 5v for the power supply should be easy enough.

I've already found the section on changing the device name a little while ago. It was kind of funny, I figured I would want to do that anyway, so I went looking for answers on google, only to find the section had been added to the teensy usb midi page at some point between the last time I read it top to bottom and when I decided to google how to change the name.
I still don't get it 100%. You have to have the names.c as a separate file for each project where you want to override the weakly defined default string arrays. I've been meaning to try it out with two projects simultaneously but I've not done so yet.
 
OK, so I went to work on the code for the other controller, taking my original code, trying to put in place what I've learned so far, but I've come up against an error that I don't know how to fix, here is the code, I've also tried to put my understanding of what the line does for a lot of the lines as notes.
Code:
#include <Bounce.h>

const int BOUNCE_TIME = 25;            // says whenever you see BOUNCE_TIME, I mean 25ms
const int PINS[6] = {0,1,2,3,4,5};   //array of pins so that I only need one line to set pinMode, also used for setting bounce 
const int DIGITAL_PINS = 6;           //says there is 6 digital pins in the sketch

const int channel = 1;                //sets midi channel to always be channel 1, instead of naming it for each button
const int velocity = 110;             //sets note velocity , as with above
const byte note[] [6] = {48,50,52,53,55,57}; //Notes C3,D3,E3,F3,G3,A3
Bounce buttons[] = {                  //Name the PINS "buttons" and tells the sketch to run BOUNCE on them
Bounce(PINS[0], BOUNCE_TIME),
Bounce(PINS[1], BOUNCE_TIME),
Bounce(PINS[2], BOUNCE_TIME),
Bounce(PINS[3], BOUNCE_TIME),
Bounce(PINS[4], BOUNCE_TIME),
Bounce(PINS[5], BOUNCE_TIME)};


void setup() {
{for (int i = 0; i<DIGITAL_PINS;i++) //puts the array into play, says that [i] refers to the number of pins in the DIGITAL_PINS array and start with 0 
{pinMode(PINS[i], INPUT_PULLUP);}}}   //All the pins numbers, listed in PINS above, are input w/ pullup resistor




void loop() {
for (int i = 0; i<DIGITAL_PINS-1;)   //says that there are 6 buttons for the next lines, starting at 0 because we said in Line 6 that DIGITAL_PINS = 6

{buttons.update();                 //check for a change of state

if (buttons[i].fallingEdge()) {usbMIDI.sendNoteOn(note[i],velocity,channel);}   // if the pin has grounded, play the note defined by the note byte in Line 8, at the velocity from Line4 and channel from line3
if (buttons[i].risingEdge())  {usbMIDI.sendNoteOff(note[i],0,channel);}}        //if the pin has lifted from ground, turn said note off



while (usbMIDI.read()) {}                                              //don't accept incoming MIDI
}
This is the error I get when I verify the code:
Arduino: 1.8.5 (Windows 10), TD: 1.40, Board: "Teensy 3.2 / 3.1, MIDI, 72 MHz, Faster, US English"

Midi_foot_control_6: In function 'void loop()':
Midi_foot_control_6:29: error: request for member 'update' in 'buttons', which is of non-class type 'Bounce [6]'
{buttons.update(); //check for a change of state

^

Midi_foot_control_6:31: error: invalid conversion from 'const byte* {aka const unsigned char*}' to 'uint32_t {aka long unsigned int}' [-fpermissive]
if (buttons.fallingEdge()) {usbMIDI.sendNoteOn(note,velocity,channel);} // if the pin has grounded, play the note defined by the note byte in Line 8, at the velocity from Line4 and channel from line3

^

In file included from C:\Users\Jason_2\Downloads\arduino-1_8_5\arduino-1.8.5\hardware\teensy\avr\cores\teensy3/WProgram.h:59:0,

from C:\Users\Jason_2\Downloads\arduino-1_8_5\arduino-1.8.5\hardware\teensy\avr\cores\teensy3/Arduino.h:3,

from C:\Users\Jason_2\AppData\Local\Temp\arduino_build_970885\sketch\Midi_foot_control_6.ino.cpp:1:

C:\Users\Jason_2\Downloads\arduino-1_8_5\arduino-1.8.5\hardware\teensy\avr\cores\teensy3/usb_midi.h:101:14: note: initializing argument 1 of 'void usb_midi_class::sendNoteOn(uint32_t, uint32_t, uint32_t)'

void sendNoteOn(uint32_t note, uint32_t velocity, uint32_t channel) __attribute__((always_inline)) {

^

Midi_foot_control_6:32: error: invalid conversion from 'const byte* {aka const unsigned char*}' to 'uint32_t {aka long unsigned int}' [-fpermissive]
if (buttons.risingEdge()) {usbMIDI.sendNoteOff(note,0,channel);}} //if the pin has lifted from ground, turn said note off

^

In file included from C:\Users\Jason_2\Downloads\arduino-1_8_5\arduino-1.8.5\hardware\teensy\avr\cores\teensy3/WProgram.h:59:0,

from C:\Users\Jason_2\Downloads\arduino-1_8_5\arduino-1.8.5\hardware\teensy\avr\cores\teensy3/Arduino.h:3,

from C:\Users\Jason_2\AppData\Local\Temp\arduino_build_970885\sketch\Midi_foot_control_6.ino.cpp:1:

C:\Users\Jason_2\Downloads\arduino-1_8_5\arduino-1.8.5\hardware\teensy\avr\cores\teensy3/usb_midi.h:97:14: note: initializing argument 1 of 'void usb_midi_class::sendNoteOff(uint32_t, uint32_t, uint32_t)'

void sendNoteOff(uint32_t note, uint32_t velocity, uint32_t channel) __attribute__((always_inline)) {

^

request for member 'update' in 'buttons', which is of non-class type 'Bounce [6]'

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.
 
I’ll take any help I can get on this, I’m stumped. I’ve found other things on the web about this kind of error, but I don’t know enough to understand how the solutions apply to me
 
It looks like "byte" declaration on note is wrong and should be "int"?? I have a look next time I'm at the my PC.
 
Ok, fixed the button non-class error by adding after buttons, now there is a problem with the conversion from const int or const byte or const uint32_t to uin32_t on the note value (i think, its on the note value anyway, I tried all 3 constants)
Code:
#include <Bounce.h>

const int BOUNCE_TIME = 25;            // says whenever you see BOUNCE_TIME, I mean 25ms
const int PINS[6] = {0,1,2,3,4,5};   //array of pins so that I only need one line to set pinMode, also used for setting bounce 
const int DIGITAL_PINS = 6;           //says there is 6 digital pins in the sketch
Bounce buttons[] = {                  //Name the PINS "buttons" and tells the sketch to run BOUNCE on them
Bounce(PINS[0], BOUNCE_TIME),
Bounce(PINS[1], BOUNCE_TIME),
Bounce(PINS[2], BOUNCE_TIME),
Bounce(PINS[3], BOUNCE_TIME),
Bounce(PINS[4], BOUNCE_TIME),
Bounce(PINS[5], BOUNCE_TIME)};
const int channel = 1;                //sets midi channel to always be channel 1, instead of naming it for each button
const int velocity = 110;             //sets note velocity , as with above
const byte note[] [6] = {48, 50, 52, 53, 55, 57}; //Notes C3,D3,E3,F3,G3,A3



void setup() {
{for (int i = 0; i<DIGITAL_PINS;i++) //puts the array into play, says that [i] refers to the number of pins in the DIGITAL_PINS array and start with 0 
{pinMode(PINS[i], INPUT_PULLUP);}}}   //All the pins numbers, listed in PINS above, are input w/ pullup resistor




void loop() {
for (int i = 0; i<DIGITAL_PINS-1;)   //says that there are 6 buttons for the next lines, starting at 0 because we said in Line 6 that DIGITAL_PINS = 6

{buttons[i].update();                 //check for a change of state

if (buttons[i].fallingEdge()) {usbMIDI.sendNoteOn(note[i],velocity,channel);}   // if the pin has grounded, play the note defined by the note byte in Line 8, at the velocity from Line4 and channel from line3
if (buttons[i].risingEdge())  {usbMIDI.sendNoteOff(note[i],0,channel);} }       //if the pin has lifted from ground, turn said note off



while (usbMIDI.read()) {}                                              //don't accept incoming MIDI
}
Error Message:
Arduino: 1.8.5 (Windows 10), TD: 1.40, Board: "Teensy 3.2 / 3.1, MIDI, 72 MHz, Faster, US English"

Midi_foot_control_6: In function 'void loop()':
Midi_foot_control_6:31: error: invalid conversion from 'const uint32_t* {aka const long unsigned int*}' to 'uint32_t {aka long unsigned int}' [-fpermissive]
if (buttons.fallingEdge()) {usbMIDI.sendNoteOn(note,velocity,channel);} // if the pin has grounded, play the note defined by the note byte in Line 8, at the velocity from Line4 and channel from line3

^

In file included from C:\Users\Jason_2\Downloads\arduino-1_8_5\arduino-1.8.5\hardware\teensy\avr\cores\teensy3/WProgram.h:59:0,

from C:\Users\Jason_2\Downloads\arduino-1_8_5\arduino-1.8.5\hardware\teensy\avr\cores\teensy3/Arduino.h:3,

from C:\Users\Jason_2\AppData\Local\Temp\arduino_build_970885\sketch\Midi_foot_control_6.ino.cpp:1:

C:\Users\Jason_2\Downloads\arduino-1_8_5\arduino-1.8.5\hardware\teensy\avr\cores\teensy3/usb_midi.h:101:14: note: initializing argument 1 of 'void usb_midi_class::sendNoteOn(uint32_t, uint32_t, uint32_t)'

void sendNoteOn(uint32_t note, uint32_t velocity, uint32_t channel) __attribute__((always_inline)) {

^

Midi_foot_control_6:32: error: invalid conversion from 'const uint32_t* {aka const long unsigned int*}' to 'uint32_t {aka long unsigned int}' [-fpermissive]
if (buttons.risingEdge()) {usbMIDI.sendNoteOff(note,0,channel);} } //if the pin has lifted from ground, turn said note off

^

In file included from C:\Users\Jason_2\Downloads\arduino-1_8_5\arduino-1.8.5\hardware\teensy\avr\cores\teensy3/WProgram.h:59:0,

from C:\Users\Jason_2\Downloads\arduino-1_8_5\arduino-1.8.5\hardware\teensy\avr\cores\teensy3/Arduino.h:3,

from C:\Users\Jason_2\AppData\Local\Temp\arduino_build_970885\sketch\Midi_foot_control_6.ino.cpp:1:

C:\Users\Jason_2\Downloads\arduino-1_8_5\arduino-1.8.5\hardware\teensy\avr\cores\teensy3/usb_midi.h:97:14: note: initializing argument 1 of 'void usb_midi_class::sendNoteOff(uint32_t, uint32_t, uint32_t)'

void sendNoteOff(uint32_t note, uint32_t velocity, uint32_t channel) __attribute__((always_inline)) {

^

invalid conversion from 'const uint32_t* {aka const long unsigned int*}' to 'uint32_t {aka long unsigned int}' [-fpermissive]

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.
 
Try dropping 'const' in the declaration for the note array. (And try both 'byte' and 'int'.)

Sorry I'm away from my home machine for a while and can't check myself right now. Anyone else?
 
const byte note[] [6] = {48, 50, 52, 53, 55, 57};

You reduced the array to one dimension on the right-hand side but not the left. S/B

const byte note[6] = {48, 50, 52, 53, 55, 57};


This resolves the compile error (since it's not messing with non-existant values from god-knows-where) but I don't know if your code makes sense otherwise yet.

You seem to have pulled out the banks feature which is what I thought you were looking for :confused:
 
1 controller will have 12 buttons and use banks, 1 will have 6 buttons and not use banks (at least at this point). The concept is that on the 12 button controller one bank will be used to select songs in a set, the second bank will be programmed to fire pad loops, 12 buttons makes the available in any key. The 6 button controller will essentially be transport controls, Fire songs, repeat a section, hard stop the audio and a slow fade and a fast fade I'll make the changes and then load it up and try it.
I see now what you're saying about reducing the size on the right but not the left the [] beside "note" is where it draw's the bank from then [6] tells it how many choices there are.
 
You could also fix it by providing a constant zero value in the bank variable for the 6-button controller:

if (buttons.fallingEdge()) {usbMIDI.sendNoteOn(note[bank],velocity,channel);}
if (buttons.risingEdge()) {usbMIDI.sendNoteOff(note[bank],0,channel);} }


Then your 6 and 12 button controllers can run essentially the same code.

The 12 button would merely need to have some extra code to toggle between the two banks.

You can use a hard-wired switch that toggles a pin HIGH or LOW directly or you can read for a risingEdge of another button to toggle the variable in software.

You don't need to get all this at once. I think you're close on the six button and I hope well on your way to adding a bank feature for the 12 button.

If you need more help getting the rest of the way I'd be happy but I'm away from my Teensy setup a lot lately so there may be delays for things that require me to compile code.

Cheers
 
Last edited:
I uploaded the 12 button program last night and wired all the buttons in temporarily. It worked pretty much as planned and the thing I found that didn’t work was a good thing anyway. The second bank button didn’t seem to do anything. Could be several things, haven’t bothered to troubleshoot it yet, but the other gal button toggles the 2 banks, which was where I was going to head with the design anyway. I need to work out how to have 1 or 2 leds indicate which bank the controller is in yet, but it certainly seems that we’re going in the right direction.
 
Code:
#include <Bounce.h>
const int BOUNCE_TIME = 25; // constant bounce time makes it easier to fine tune if the buttons need more/less time
const int PINS[[COLOR="#FF0000"]13[/COLOR]] = {0,1,2,3,4,5,6,7,8,9,10,11,12[COLOR="#FF0000"]};[/COLOR] // Pin assignment array, they don't need to be sequiential
const int DIGITAL_PINS = [COLOR="#FF0000"]13[/COLOR]; [COLOR="#FF0000"]// total digital pin count including ONLY ONE bank button [/COLOR]
const int channel = 1;
const int velocity = 110; // arbitrary 'on' velocity setting for note messages
[COLOR="#FF0000"]//const int BANKS = 2; // not used now[/COLOR]
const byte note[][12] = {
  {60,61,62,63,64,65,66,67,68,69,70,71},//C4 to B4
  {72,73,74,75,76,77,78,79,80,81,82,83},//C5 to B5
}; // this is the N x 12 matrix of note values for the bank system
int bank = 0; // this is the bank variable to be [COLOR="#FF0000"]toggled[/COLOR]

Bounce btn[] = {
  Bounce(PINS[0], BOUNCE_TIME),
  Bounce(PINS[1], BOUNCE_TIME),
  Bounce(PINS[2], BOUNCE_TIME),
  Bounce(PINS[3], BOUNCE_TIME),
  Bounce(PINS[4], BOUNCE_TIME),
  Bounce(PINS[5], BOUNCE_TIME),
  Bounce(PINS[6], BOUNCE_TIME),
  Bounce(PINS[7], BOUNCE_TIME),
  Bounce(PINS[8], BOUNCE_TIME),
  Bounce(PINS[9], BOUNCE_TIME),
  Bounce(PINS[10], BOUNCE_TIME),
  Bounce(PINS[11], BOUNCE_TIME)[COLOR="#FF0000"]
  };[/COLOR]



Bounce [COLOR="#FF0000"]bankToggle[/COLOR]= Bounce(PINS[12], BOUNCE_TIME); [COLOR="#FF0000"]// one button toggles instead of up and down [/COLOR]




void setup() {
  //Serial.begin(9600);
  for (int i = 0;i<DIGITAL_PINS;i++){
    pinMode(PINS[i], INPUT_PULLUP);
  }
}

void loop() {


  for (int i = 0;i<[COLOR="#FF0000"]DIGITAL_PINS[/COLOR];i++){ [COLOR="#FF0000"]// '-1' no longer needed as we run once for each button instead of up and down together on the same loop[/COLOR]

      if (i<(DIGITAL_PINS-[COLOR="#FF0000"]1[/COLOR])){ // for all but the bank [COLOR="#FF0000"]button (now only one button so subtract 1 and not 2)[/COLOR]
        btn[i].update();
        if (btn[i].fallingEdge()) {
          usbMIDI.sendNoteOn(note[bank][i], velocity, channel); 
        }
        if (btn[i].risingEdge()) {
          usbMIDI.sendNoteOff(note[bank][i], 0, channel);  
        }
      }else{
        [COLOR="#FF0000"]bankToggle[/COLOR].update();
[COLOR="#FF0000"]        if (bankToggle.fallingEdge()) {
            bank = !bank; // toggle bank between 0 and 1
          }     [/COLOR]   
      }
  }

  while (usbMIDI.read()) {
  }
}
You could try this... it was done in a text editor with no compiler so it likely has an error or two but the compiler will likely point them out for you. (I'll test it later in case I've messed up bigger than usual.)

It's much simpler than having a bunch of code that works but is there for no reason.

The logical NOT operator ("!") will turn any non zero number zero and zero into 1 and so will toggle in one line with no conditional logic required.


I know why your second button didn't work:
Bounce bankDown = Bounce(PINS[14], BOUNCE_TIME);
There is nothing in PIN[14] but PIN[13]=14...

You want to skip pin 13 (because its tied to the on-board LED) but not PIN[13] which is the 14th data element in the PIN array but contains the number 14.

... in my code these buttons were PIN[16] and PIN[17] but returned 17 and 18 for the pins they actually referred to.

With a one-button toggle you don't need pin 13 or pin 14.
 
Well I think that code was OK as it compiled fine... but I don't like the toggle button mixed in with the note switches.

Here's a simpler version with an LED indicator for when the upper bank is selected.
Code:
#include <Bounce.h>
const int BOUNCE_TIME = 25; // constant bounce time makes it easier to fine tune if the buttons need more/less time
const int TOGGLEPIN = 12; // Pin assigned to toggle the two banks
const int LEDPIN = 13; // Upper BANK indicator LED 
const int PINS[12] = {0,1,2,3,4,5,6,7,8,9,10,11}; // Note switch pin assignment array 
const int DIGITAL_PINS = 12; // size of the PINS array (no longer includes toggle button!)
const int channel = 1;
const int velocity = 110; // arbitrary 'on' velocity setting for note messages

const byte note[][12] = {
  {60,61,62,63,64,65,66,67,68,69,70,71},//C4 to B4
  {72,73,74,75,76,77,78,79,80,81,82,83},//C5 to B5
}; // this is the N x 12 matrix of note values for the bank system
int bank = 0; // this is the bank variable to be toggled

Bounce btn[] = {
  Bounce(PINS[0], BOUNCE_TIME),
  Bounce(PINS[1], BOUNCE_TIME),
  Bounce(PINS[2], BOUNCE_TIME),
  Bounce(PINS[3], BOUNCE_TIME),
  Bounce(PINS[4], BOUNCE_TIME),
  Bounce(PINS[5], BOUNCE_TIME),
  Bounce(PINS[6], BOUNCE_TIME),
  Bounce(PINS[7], BOUNCE_TIME),
  Bounce(PINS[8], BOUNCE_TIME),
  Bounce(PINS[9], BOUNCE_TIME),
  Bounce(PINS[10], BOUNCE_TIME),
  Bounce(PINS[11], BOUNCE_TIME)
  };
Bounce bankToggle= Bounce(TOGGLEPIN, BOUNCE_TIME); // one button toggles instead of up and down 



void setup() {
  //Serial.begin(9600);
  for (int i = 0;i<DIGITAL_PINS;i++){
    pinMode(PINS[i], INPUT_PULLUP);
  }
  pinMode(TOGGLEPIN, INPUT_PULLUP);
  pinMode(LEDPIN, OUTPUT);
}

void loop() {
  for (int i = 0;i<DIGITAL_PINS;i++){ // loop through each object in the BOUNCE arrray for the note switches (no longer includes TOGGLE)
    btn[i].update();
    if (btn[i].fallingEdge()) {
      usbMIDI.sendNoteOn(note[bank][i], velocity, channel); 
    }
    if (btn[i].risingEdge()) {
      usbMIDI.sendNoteOff(note[bank][i], 0, channel);  
    }
  }
  // check if TOGGLE bank button is pressed (pulled low)
  bankToggle.update();
  if (bankToggle.fallingEdge()) {
    bank = !bank; // toggle bank between 0 and 1
    digitalWrite(LEDPIN, bank);
  }   
  while (usbMIDI.read()) { 
      // midi controllers need to read but ignore incoming to avoid buffer on PC getting full
  }
}
I've set it to the built in LED to test on a T3.0 with a wire from ground to each switch pin and it seems to work as expected.
 
Ok, so the prototype for the 12 button box is complete, I added a line of code to give me a LED when each bank is selected, I also changed them so that neither is on pin 13 so they are full brighness.
Code:
#include <Bounce.h>
const int BOUNCE_TIME = 25; // constant bounce time makes it easier to fine tune if the buttons need more/less time
const int TOGGLEPIN = 12; // Pin assigned to toggle the two banks
const int LEDPIN = 15; // Upper BANK indicator LED 
const int LEDPIN2 = 14; //Lower BANK indicator LED
const int PINS[12] = {0,1,2,3,4,5,6,7,8,9,10,11}; // Note switch pin assignment array 
const int DIGITAL_PINS = 12; // size of the PINS array (no longer includes toggle button!)
const int channel = 1;
const int velocity = 110; // arbitrary 'on' velocity setting for note messages

const byte note[][12] = {
  {60,61,62,63,64,65,66,67,68,69,70,71},//C4 to B4
  {72,73,74,75,76,77,78,79,80,81,82,83},//C5 to B5
}; // this is the N x 12 matrix of note values for the bank system
int bank = 0; // this is the bank variable to be toggled

Bounce btn[] = {
  Bounce(PINS[0], BOUNCE_TIME),
  Bounce(PINS[1], BOUNCE_TIME),
  Bounce(PINS[2], BOUNCE_TIME),
  Bounce(PINS[3], BOUNCE_TIME),
  Bounce(PINS[4], BOUNCE_TIME),
  Bounce(PINS[5], BOUNCE_TIME),
  Bounce(PINS[6], BOUNCE_TIME),
  Bounce(PINS[7], BOUNCE_TIME),
  Bounce(PINS[8], BOUNCE_TIME),
  Bounce(PINS[9], BOUNCE_TIME),
  Bounce(PINS[10], BOUNCE_TIME),
  Bounce(PINS[11], BOUNCE_TIME)
  };
Bounce bankToggle= Bounce(TOGGLEPIN, BOUNCE_TIME); // one button toggles instead of up and down 



void setup() {
  //Serial.begin(9600);
  for (int i = 0;i<DIGITAL_PINS;i++){
    pinMode(PINS[i], INPUT_PULLUP);
  }
  pinMode(TOGGLEPIN, INPUT_PULLUP);
  pinMode(LEDPIN, OUTPUT);
  pinMode(LEDPIN2, OUTPUT);
}

void loop() {
  for (int i = 0;i<DIGITAL_PINS;i++){ // loop through each object in the BOUNCE arrray for the note switches (no longer includes TOGGLE)
    btn[i].update();
    if (btn[i].fallingEdge()) {
      usbMIDI.sendNoteOn(note[bank][i], velocity, channel); 
    }
    if (btn[i].risingEdge()) {
      usbMIDI.sendNoteOff(note[bank][i], 0, channel);  
    }
  }
  // check if TOGGLE bank button is pressed (pulled low)
  bankToggle.update();
  if (bankToggle.fallingEdge()) {
    bank = !bank; // toggle bank between 0 and 1
    digitalWrite(LEDPIN, bank);
    digitalWrite(LEDPIN2, !bank);
 
      // midi controllers need to read but ignore incoming to avoid buffer on PC getting full
  }
}

So after I got the 12 button box done, I turned my attention to the 6 button box.
Code:
#include <Bounce.h>

const int BOUNCE_TIME = 25;            
const int PINS[6] = {0, 1, 2, 3, 4, 5};   
const int DIGITAL_PINS = 6;           
Bounce buttons[] = {                  
Bounce(PINS[0], BOUNCE_TIME),
Bounce(PINS[1], BOUNCE_TIME),
Bounce(PINS[2], BOUNCE_TIME),
Bounce(PINS[3], BOUNCE_TIME),
Bounce(PINS[4], BOUNCE_TIME),
Bounce(PINS[5], BOUNCE_TIME)};
const int channel = 1;                
const int velocity = 110;             
const int note [6] = {48, 49, 50, 51, 52, 53}; //Notes


void setup() {
{for (int i = 0; i<DIGITAL_PINS;i++)  
{pinMode(PINS[i], INPUT_PULLUP);}}}   


void loop() {
for (int i = 0; i<DIGITAL_PINS;)  
{buttons[i].update();                 
if (buttons[i].fallingEdge()) {usbMIDI.sendNoteOn(note[i],velocity,channel);}   
if (buttons[i].risingEdge())  {usbMIDI.sendNoteOff(note[i],0,channel);} }       

while (usbMIDI.read()) {}                                              
}
So, C3 plays as expected, but none of the other notes work. I'm not sure why. I've tried changing the note values, even though I know that shouldn't make a difference. I've tried using a jumper and bypassing the switches, just to verify that isn't a problem. I haven't busted out the multimeter yet, but unless somebody spots something in the code, that's next
 
Status
Not open for further replies.
Back
Top