How to change midi notes using buttons (usb midi)?

Status
Not open for further replies.

SMJLeo

Member
Hello, this is my first post here, so please forgive my extremely low knowledge about teensy and arduino.

Basically, I wanted to buy a Midi Fighter (which is a 16 button midi controller), but since I love electronics and DIY, I thought about making one with teensy and some arcade buttons. Because of my budget, I am going to get a Teensy LC.
I am going to 3D print the frame and I have some decent knowledge about hardware, so I am not concerned about it. The thing that I am concerned, though, is software. Using Teensyduino, I have created this code so far (though I do need to edit the Midi value, I put them in randomly because I didn't have time)
Code:
#include <Bounce.h>

const int channel = 1;

Bounce button1 = Bounce(0, 5);
Bounce button2 = Bounce(1, 5);  
Bounce button3 = Bounce(2, 5);  
Bounce button4 = Bounce(3, 5);  
Bounce button5 = Bounce(4, 5);
Bounce button6 = Bounce(5, 5);  
Bounce button7 = Bounce(6, 5);  
Bounce button8 = Bounce(7, 5);  
Bounce button9 = Bounce(8, 5);
Bounce button10 = Bounce(9, 5);
Bounce button11 = Bounce(10, 5);
Bounce button12 = Bounce(11, 5);
Bounce button13 = Bounce(12, 5);
Bounce button14 = Bounce(13, 5);
Bounce button15 = Bounce(14, 5);
Bounce button16 = Bounce(15, 5);
Bounce button17 = Bounce(16, 5);
Bounce button18 = Bounce(17, 5);


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

void loop() {

  button1.update();
  button2.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();


  if (button1.fallingEdge()) {
    usbMIDI.sendNoteOn(81, 99, channel);  // 61 = C#4
  }
  if (button2.fallingEdge()) {
    usbMIDI.sendNoteOn(80, 99, channel);  // 62 = D4
  }
  if (button3.fallingEdge()) {
    usbMIDI.sendNoteOn(79, 99, channel);  // 63 = D#4
  }
  if (button4.fallingEdge()) {
    usbMIDI.sendNoteOn(78, 99, channel);  // 64 = E4
  }
  if (button5.fallingEdge()) {
    usbMIDI.sendNoteOn(77, 99, channel);  // 65 = F4
  }
  if (button6.fallingEdge()) {
    usbMIDI.sendNoteOn(76, 99, channel);  // 66 = F#4
  }
  if (button7.fallingEdge()) {
    usbMIDI.sendNoteOn(75, 99, channel);  // 67 = G4
  }
  if (button8.fallingEdge()) {
    usbMIDI.sendNoteOn(74, 99, channel);  // 68 = G#4
  }
  if (button9.fallingEdge()) {
    usbMIDI.sendNoteOn(73, 99, channel);  // 69 = A5
  }
  if (button10.fallingEdge()) {
    usbMIDI.sendNoteOn(72, 99, channel);  // 70 = A#5
  }
  if (button11.fallingEdge()) {
    usbMIDI.sendNoteOn(71, 99, channel);  // 71 = B5
  }
  if (button12.fallingEdge()) {
    usbMIDI.sendNoteOn(70, 99, channel);  // 71 = B5
  }
  if (button13.fallingEdge()) {
    usbMIDI.sendNoteOn(69, 99, channel);  // 71 = B5
  }
  if (button14.fallingEdge()) {
    usbMIDI.sendNoteOn(68, 99, channel);  // 71 = B5
  }
  if (button15.fallingEdge()) {
    usbMIDI.sendNoteOn(67, 99, channel);  // 71 = B5
  }
  if (button16.fallingEdge()) {
    usbMIDI.sendNoteOn(66, 99, channel);  // 71 = B5
  }
  if (button17.fallingEdge()) {
    usbMIDI.sendNoteOn(65, 99, channel);  // 71 = B5
  }
  if (button18.fallingEdge()) {
    usbMIDI.sendNoteOn(64, 99, channel);  // 71 = B5
  }
  if (button1.risingEdge()) {
    usbMIDI.sendNoteOff(81, 0, channel);  // 61 = C#4
  }
  if (button2.risingEdge()) {
    usbMIDI.sendNoteOff(80, 0, channel);  // 62 = D4
  }
  if (button3.risingEdge()) {
    usbMIDI.sendNoteOff(79, 0, channel);  // 63 = D#4
  }
  if (button4.risingEdge()) {
    usbMIDI.sendNoteOff(78, 0, channel);  // 64 = E4
  }
  if (button5.risingEdge()) {
    usbMIDI.sendNoteOff(77, 0, channel);  // 65 = F4
  }
  if (button6.risingEdge()) {
    usbMIDI.sendNoteOff(76, 0, channel);  // 66 = F#4
  }
  if (button7.risingEdge()) {
    usbMIDI.sendNoteOff(75, 0, channel);  // 67 = G4
  }
  if (button8.risingEdge()) {
    usbMIDI.sendNoteOff(74, 0, channel);  // 68 = G#4
  }
  if (button9.risingEdge()) {
    usbMIDI.sendNoteOff(73, 0, channel);  // 69 = A5
  }
  if (button10.risingEdge()) {
    usbMIDI.sendNoteOff(72, 0, channel);  // 70 = A#5
  }
  if (button11.risingEdge()) {
    usbMIDI.sendNoteOff(71, 0, channel);  // 71 = B5
  }

  if (button12.risingEdge()) {
    usbMIDI.sendNoteOff(70, 0, channel);  // 71 = B5
  }
  if (button13.risingEdge()) {
    usbMIDI.sendNoteOff(69, 0, channel);  // 71 = B5
  }
  if (button14.risingEdge()) {
    usbMIDI.sendNoteOff(68, 0, channel);  // 71 = B5
  }
  if (button15.risingEdge()) {
    usbMIDI.sendNoteOff(67, 0, channel);  // 71 = B5
  }
  if (button16.risingEdge()) {
    usbMIDI.sendNoteOff(66, 0, channel);  // 71 = B5
  }
  if (button17.risingEdge()) {
    usbMIDI.sendNoteOff(65, 0, channel);  // 71 = B5
  }
  if (button18.risingEdge()) {
    usbMIDI.sendNoteOff(64, 0, channel);  // 71 = B5
  }

  while (usbMIDI.read()) {
  }
}

Notice how there are 18 buttons, instead of 16. What I wanted to do was to use those extra 2 buttons as a bank shifter, as I am going to use this in Ableton. In Ableton's drum rack, there are a lot of "pages", and here are some pictures of it. The one starting with C2 is the default page, and I shifted the pages upwards, one by one. They are configured quite weirdly. The question that I'm wondering is: is there a way to make all of the midi notes go up/low for a certain value when I press a button? Any help will be greatly appreciated.
 
It's essentially a 'bank' or 'scene' selector?

Very feasible but it would be much neater if done with arrays, which seem to intimidate new coders.

The basic issue is you need the note value to be in a variable that was set when the bank is selected.

A bank system can be done with a 2-dimensional array but that's probably more complex than we should look at right now.

I would start by rewriting the code as arrays so that you can load new CC or note values into the midi event message code:

So:

Bounce button1 = Bounce(0, 5);

would become:


Bounce button[0] = Bounce(Pin[0], DEBOUNCE_TIME);

Edit - this is not correct. ...see below.

(you will find coding simpler if you start with zero so the indexing is the same as the numbering)

Pin[0] is the zeroth element of an array of pin assignments... (you can skip this if you intend to use pins 0-17 in sequence) -- you would need to define these values in the initialization part of your code.

DEBOUNCE_TIME is a constant defined in the opening lines of the code. Then you can adjust responsiveness vs. stability depending on how quickly your switch contacts quite down.

Your pin definitions (if you go to an arrary on this too) would become

pinMode(Pin[0], INPUT_PULLUP);

...which you can the apply a loop to (if you like or once you're able) so that you only need three lines of code for any number of pins.

Button update would become:

button[0].update();
Edit - 'button' looks like it might be a reserved word.

and rising/falling edge stuff would look like this:

if (button[0].fallingEdge()) {
usbMIDI.sendNoteOn(Note[0], velocity, channel);
}


Where velocity and channel are either variables (once you get fancy) or constant declarations similar to the DEBOUNCE_TIME value above.

Once you know how to apply a loop to these the code becomes very concise.

From here the trick is to get different Note values to load depending on the saved state value for the current bank number that is set.

A two-dimensional array for notes will make coding 'simpler' to manage but not so simple to learn perhaps. (See https://forum.pjrc.com/threads/40662-Need-help-with-Midi-banks?p=126526&viewfull=1#post126526 if you're curious now.)

Were you looking to learn how to code this yourself or were you hoping there is existing code out there you can use?
 
Last edited:
...From here the trick is to get different Note values to load depending on the saved state value for the current bank number that is set.
...should mention the bank up/down control with the two additional buttons is very easy to manage (depending on what you need to make the note assignment thing work).

As these buttons are completely different I would give them separate names from the main buttons; bankUp and bankDown perhaps.

As bank-select events don't need an 'off' message you only need to look for the fallingEdge:

Code:
if (bankUp.fallingEdge()) {
   bank++ // increment bank
   if (bank >= BANKS){
      bank = 0;
   }
 }
if (bankDown.fallingEdge()) {
   bank-- // decrement bank
   if (bank <= 0){
      bank = BANKS-1;
   }
 }

'bank' would be declared as an global integer variable in initialization portion of your code and is used to store the currently selected bank.
BANKS is a constant for the total number of banks supported.
bankUp and bankDown would need to be declared as bounce objects just like the 16 other buttons.
 
Were you looking to learn how to code this yourself or were you hoping there is existing code out there you can use?

Both. I was hoping that I could understand how and I could see it being used in a practical way. But thank you so much for the detailed explanation.
 
Code:
#include <Bounce.h>
const int BOUNCE_TIME = 5; // constant bounce time makes it easier to fine tune if the buttons need more/less time
const int PINS[18] = {0,1,2,3,4,5,6,7,8,9,10,11,12,[COLOR="#FF0000"]14,15,16,17,18[/COLOR]}; // Pin assignment array, they don't need to be sequiential
const int DIGITAL_PINS = 18; // total digital pin count including two for bank buttons 
const int channel = 1;
const int velocity = 99; // arbitrary 'on' velocity setting for note messages
const int BANKS = 5;
const byte note[][16] = {
[COLOR="#0000FF"]  {28,29,30,31,24,25,26,27,20,21,22,23,16,17,18,19},
  {44,45,46,47,40,41,42,43,36,37,38,39,32,33,34,35},
  {60,61,62,63,56,57,58,59,52,53,54,55,48,49,50,51},
  {76,77,78,79,72,73,74,75,68,69,70,71,64,65,66,67},
  {92,93,94,95,88,89,90,91,84,85,86,87,80,81,82,83}[/COLOR]
}; // this is the N x 16 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[16], BOUNCE_TIME);
Bounce bankDown = Bounce(PINS[17], BOUNCE_TIME);



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

void loop() {
[COLOR="#FF0000"]  //bankUp.update();
 // bankDown.update(); // move right before fallingEdge check[/COLOR]

  for (int i = 0;i<DIGITAL_PINS[COLOR="#FF0000"]-1[/COLOR];i++){[COLOR="#FF0000"] // -1 needed so bank buttons run once together [/COLOR]

      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{
        [COLOR="#FF0000"]bankUp.update();[/COLOR]
        if (bankUp.fallingEdge()) {
          bank++; // increment bank
          if (bank >= BANKS){
            bank = 0;
          }
        }
        [COLOR="#FF0000"]bankDown.update();[/COLOR]
        if (bankDown.fallingEdge()) {
          bank--; // decrement bank
          if ([COLOR="#FF0000"]bank < 0[/COLOR]){
            bank = BANKS-1;
          }
        }
      }
  }

  while (usbMIDI.read()) {
  }
}
Ok... here is some semi-tested code that does a bank system... to test I plugged a T3.0 into a mini-breadboard and took a wire between ground and connected to the pins via the breadboard to trigger falling and rising edges...

It seems to work but testing the increment/decrement like that is a bit iffy so I'm not 100% sure whether the overflow wrap stuff works on 'bank'
 
Last edited:
Thank you so much! Since I have the buttons and the frame set up, I will test this out when my Teensy LC and my wires arrive.
 
I think if (bank <= 0){ should be if (bank < 0){ otherwise you can't select bank zero...

Let me know if you have trouble with anything of if you can't figure out what any part is doing but want to know. :)

Edit... a couple other problems too... adjustments in red.
 
Last edited:
For those of you who are reading this thread and willing to use this code for your own project:
because of how Ableton drum rack works, you need put the code below instead of the existing 16x notes.

Code:
const byte note[][16] = {
  {28,29,30,31,24,25,26,27,20,21,22,23,16,17,18,19},
  {44,45,46,47,40,41,42,43,36,37,38,39,32,33,34,35},
  {60,61,62,63,56,57,58,59,52,53,54,55,48,49,50,51},
  {76,77,78,79,72,73,74,75,68,69,70,71,64,65,66,67},
  {92,93,94,95,88,89,90,91,84,85,86,87,80,81,82,83}
 
There were a couple issues with the bank buttons in my original code (see red changes)...

Also... the internal pull-up on PIN13 makes the LED come on dimly and the button does not work... :(

I feel like this is something I should have known about already but I've never used that pin with a pullup before.

I don't see a work-around so I'll just skip this pin in the assignment (this is where having an array for them makes that easy).
 
Umm... okay. I just got my Teensy LC along with my breadboard and some jumper wires.
I ran the code on Arduino IDE and checked that my computer recognized it as a "Teensy Midi". Next, I connected a jumper wire on "G" and "0", Held both wires and nothing happened in both Logic Pro X and Ableton Live 9. Am I doing something wrong?
 
Do you have a MIDI monitoring program?


Computer seeing Teensy MIDI means you're most of the way there....

You only need to touch the pin to ground for a human instant and the code will fire some sort of midi... maybe I've read the details incorrectly... but with a wire grounding a pin on a breadboard it's not a hardware problem... and if your computer sees a MIDI device it's not likely on that side so it's likely the code.

I only ever checked that midi was firing of the correct type and on and off notes worked. There may be an offset problem in reading the arrays correctly.

But can you tell me if any MIDI is firing and if so what value is D1 (note)?
 
Last edited:
Just tested the code again... works for me... sends note on and off for note=28 on channel 1 when I touch a grounded wire to pin 0 (prior to messing with the bank setting).

That should be E1 by normal octave naming. Not sure what's happening on yours.

Touching up the pin sequence output as expected as well..

Bank buttons seem to work too...
 
Huh, I will check it once I get home which is around 9 hours later. Do you think it's because I've got a Teensy LC instead of 3.0?

Also, I forgot to mentioned that I forgot to get Teensy with pins, so I've connected the jumper wire through the teensy to the breadboard. Will that work? I did check by touching the actual pins as well, so that is not the problem.
 
Huh, took a little longer to get home than I expected.

Anyway, the computer doesn't seem to detect any midi notes coming out, even though it detects the device itself. Do you think it is the problem that I mentioned above, or a defective Teensy?
Or electric static maybe? It may have destroyed the Teensy right when I first touched it.
 
UPDATE: IT WORKED! It was my fault for using a defected cable. Haha.
It doesn't work as I was expecting though, for some reason. I probably will need to edit the midi values again. But for now, it is great! Thank you so much for the help!
 
Status
Not open for further replies.
Back
Top