Building A 25-Key Midi Pedalboard

Status
Not open for further replies.
Those functions send the midi message to USB and a hardware Serial port. The default serial port on a Teensy is Serial1. If necessary, you could edit the MIDI.h file and change it.

Pete
 
Those functions send the midi message to USB and a hardware Serial port. The default serial port on a Teensy is Serial1. If necessary, you could edit the MIDI.h file and change it.

Pete

Oh...so the "serial" code is in the MIDI.h library?!?! I was expecting I'd have to include "serial.Write" code into my sketch. If what you're saying is true then that makes my life a lot easier!

Now, how about the way I added the "do" functions into my code above? Does it appear to be correct?

- brad -
 
Thanks Pete. I will load the revised code and test to make sure all of my "noteOn/noteOff", "ControlChange", and "octave" functions still work the way they are supposed to...and then I'll start wiring up the Midi 5-Din jack to make sure that works.

If all is good, I think the only feature left for me to implement is an external input for power. The PJRC pages for external power seem to outline the steps very nicely so, hopefully I can follow the steps so I can run the Teensy off USB and external power.
 
Whoops...ahead of myself again!

I forgot that I need to resolve the bit of "octave" code that resets to the "base octave" when the up and down switches are pushed together.

Is it enough to change the current code:

Code:
//---------------------------------SET OCTAVE --------------------------------------------

  int up = digitalRead(octaveup);                     // alias "octaveup" pin read as "up"
  int down = digitalRead(octavedown);                 // alias "octavedown" pin read as "down"

  if (up == LOW) {                                    // if "up" button pressed
    if (octave < 6) {
      octave++;                                        // constrain highest note to C8 (108)
    }
    while (up == LOW) {                              // wait until button is released
      up = digitalRead(octaveup);
      delay(20);
    }
  }
  if (down == LOW) {                                 // if "down" button pressed
    if (octave > 1) {
      octave--;                                         // constrain lowest note to C1 (24)
    }
    while (down == LOW) {                             // wait until button is released
      down = digitalRead(octavedown);
      delay(20);
    }
  }

  if (up == LOW && down == LOW) {          // if "up" and "down" buttons both pressed
    octave = 3;                                      // return to base octave
  }


to this:

Code:
//---------------------------------SET OCTAVE --------------------------------------------

  int up = digitalRead(octaveup);                     // alias "octaveup" pin read as "up"
  int down = digitalRead(octavedown);                 // alias "octavedown" pin read as "down"

   if (up == LOW && down == LOW) {                           // if "up" and "down" buttons both pressed
    octave = 3;                                                       // return to base octave
  }

  if (up == LOW) {                                    // if "up" button pressed
    if (octave < 6) {
      octave++;                   // constrain highest note to C8 (108)
    }
    while (up == LOW) {                              // wait until button is released
      up = digitalRead(octaveup);
      delay(20);
    }
  }
  if (down == LOW) {                                 // if "down" button pressed
    if (octave > 1) {
      octave--;                   // constrain lowest note to C1 (24)
    }
    while (down == LOW) {                             // wait until button is released
      down = digitalRead(octavedown);
      delay(20);
    }
  }

or do I need to edit the single button pressed scenarios so that they read something like

"if 'up' is LOW and 'down' is HIGH...do this" and "if 'up' is HIGH and 'down' is LOW...do this"?

- brad -
 
The way it is right now, the code to reset the octave to 3 won't work because it is extremely unlikely that you'd be able to push both buttons in such a way that the code sees them both on at exactly the same time.
I'll come up with a way to handle that. Meanwhile try out the rest of the code, including up and down, and make sure that it is working.
I may have something for you to try in maybe 4 hours.

Pete
 
Those functions send the midi message to USB and a hardware Serial port. The default serial port on a Teensy is Serial1. If necessary, you could edit the MIDI.h file and change it.

Pete

Took a quick look at the MIDI library (MIDI.h) and just want to confirm:

Do I need to edit the MIDI.h file if I plan to use the default "Serial1" port on my Teensy++? The library states (and defines) Serial1 as the default for all Teensy devices but I just want to know if the "Arduino.h" and definition of "CORE_TEENSY" mentioned in the MIDI library are all taken care of when I choose "Teensy" as my device in the Arduino environment...

I am assuming it's all good but don't want to assume too much without knowing for sure!

- brad -
 
Choosing Teensy as the target board sets up the CORE_TEENSY definition. Just compile and give it a shot. The worst that happens is that it doesn't work.

Pete
 
I've changed the octave code by moving it into a function (do_octave) and, I hope, the octave reset will now work.
There are still at least two problems with this code. One is that it doesn't use the Bounce library and another is that it uses the delay function.
For now, see if this resets octave to 3 and that pushing the up or down buttons on their own increments or decrements the octave correctly. Then we'll see about refining the code.

Pete

Code:
/*
https://forum.pjrc.com/threads/28816
25 Key Midi Footpedal with
Octave Up/Down, Mod, Sustain, and Volume
Created by Brad Hill on 19-06-2015
based primarily on Teensy "Buttons" with snippets from
MidiHacker's MultiButtonMIDIOctave.ino,
Graham Wykes' Miditzer Pedalboard Scanner for Teensy2.0++ board,
Lionel Cassin's "midi-bass-pedals-using-arduino.html",
G333T's video (https://www.youtube.com/watch?v=9J_tGVLD7UQ),
and various Teensy/Arduino definitions and examples.
This code is released into the Public Domain.
*/


#include <MIDI.h>
#include <Bounce.h>

const int channel = 1;        // the MIDI channel number to send messages
const int ms = 5;             // bounce time in ms (increase for more sensitve switches)
const int d = 25;             // default delay time (ms) for "activity" LED
// 
const int OCTAVE_DELAY = 50;

int LEDU = 0;                 // pin for octave up LED
int LEDD = 1;                 // pin for ocatave down LED

int octaveup = 32;            // pin for octave up switch
int octavedown = 33;          // pin for octave down switch
int octave = 3;               // set base octave

int vpot = 38;                // pin setup for volume pot
int vol;                      // place holder for vpot reading
int vel = 99;                 // fixed note velocity

// Create Bounce objects for each button.  The Bounce object
// automatically deals with contact chatter or "bounce", and
// it makes detecting changes very simple.

Bounce button0 = Bounce(0, ms);
Bounce button1 = Bounce(1, ms);  // 5 = 5 ms debounce time
Bounce button2 = Bounce(2, ms);  // which is appropriate for good
Bounce button3 = Bounce(3, ms);  // quality mechanical pushbuttons
Bounce button4 = Bounce(4, ms);
Bounce button5 = Bounce(5, ms);  // if a button is too "sensitive"
Bounce button6 = Bounce(6, ms);  // to rapid touch, you can
Bounce button7 = Bounce(7, ms);  // increase this time.
Bounce button8 = Bounce(8, ms);
Bounce button9 = Bounce(9, ms);
Bounce button10 = Bounce(10, ms);
Bounce button11 = Bounce(11, ms);
Bounce button12 = Bounce(12, ms);
Bounce button13 = Bounce(13, ms);
Bounce button14 = Bounce(14, ms);
Bounce button15 = Bounce(15, ms);
Bounce button16 = Bounce(16, ms);
Bounce button17 = Bounce(17, ms);
Bounce button18 = Bounce(18, ms);
Bounce button19 = Bounce(19, ms);
Bounce button20 = Bounce(20, ms);
Bounce button21 = Bounce(21, ms);
Bounce button22 = Bounce(22, ms);
Bounce button23 = Bounce(23, ms);
Bounce button24 = Bounce(24, ms);
Bounce button25 = Bounce(25, ms);
Bounce button26 = Bounce(26, ms);
Bounce button27 = Bounce(27, ms);
Bounce button28 = Bounce(28, ms);
Bounce button29 = Bounce(29, ms);
Bounce button30 = Bounce(30, ms);
Bounce button31 = Bounce(31, ms);
Bounce button32 = Bounce(32, ms);
Bounce button33 = Bounce(33, ms);
Bounce button34 = Bounce(34, ms);
Bounce button35 = Bounce(35, ms);
Bounce button36 = Bounce(36, ms);
Bounce button37 = Bounce(37, ms);
Bounce button38 = Bounce(38, ms);
Bounce button39 = Bounce(39, ms);
Bounce button40 = Bounce(40, ms);
Bounce button41 = Bounce(41, ms);
Bounce button42 = Bounce(42, ms);
Bounce button43 = Bounce(43, ms);
Bounce button44 = Bounce(44, ms);
Bounce button45 = Bounce(45, ms);


// Declaring the addresses of the button objects in this array
// allows us to deal with them in a for loop
Bounce *buttons[46] = {
  &button0, &button1, &button2, &button3, &button4, &button5, &button6, &button7, &button8, &button9,
  &button10, &button11, &button12, &button13, &button14, &button15, &button16, &button17, &button18, &button19,
  &button20, &button21, &button22, &button23, &button24, &button25, &button26, &button27, &button28, &button29,
  &button30, &button31, &button32, &button33, &button34, &button35, &button36, &button37, &button38, &button39,
  &button40, &button41, &button42, &button43, &button44, &button45
};


// Create functions to send usbMIDI and serial MIDI messages

void do_sendNoteOn(unsigned char note,unsigned char velocity,unsigned char channel)
{
  usbMIDI.sendNoteOn(note, velocity, channel);
  MIDI.sendNoteOn(note, velocity, channel);
}

void do_sendControlChange(unsigned char cmd,unsigned char value,unsigned char channel)
{
  usbMIDI.sendControlChange(cmd, value, channel);
  MIDI.sendControlChange(cmd, value, channel);
}

void do_octave(void)
{
//---------------------------------SET OCTAVE --------------------------------------------
  int up = digitalRead(octaveup);                     // alias "octaveup" pin read as "up"
  int down = digitalRead(octavedown);                 // alias "octavedown" pin read as "down"

  // If both buttons are up, we have nothing to do.
  if((up == HIGH) && (down == HIGH)) return;

  // At least one of the buttons is down.
  // wait for a few milliseconds and then read
  // them both again to give time for both buttons
  // to be down if the user has pushed them both.
  delay(OCTAVE_DELAY);
  
  up = digitalRead(octaveup);
  down = digitalRead(octavedown); 
  // if "up" and "down" buttons both pressed
  // return to base octave
  if ((up == LOW) && (down == LOW)) {
    octave = 3;
  } else {
    // if "up" button pressed
    if (up == LOW) {
      if (octave < 6) {
        octave++;                   // constrain highest note to C8 (108)
      }
    }
    // if "down" button pressed
    if (down == LOW) {
      if (octave > 1) {
        octave--;                   // constrain lowest note to C1 (24)
      }

    }
  }
  // Wait for the button(s) to be released
  while ((digitalRead(octaveup) == LOW) || (digitalRead(octavedown) == LOW)) {
    delay(20);
  }
}

//--------------------------SETUP-----------------------------------------------
//------------------------------------------------------------------------------

void setup() {

 MIDI.begin();  

  // Configure the pins for input mode with pullup resistors.
  // The pushbuttons connect from each pin to ground.  When
  // the button is pressed, the pin reads LOW because the button
  // shorts it to ground.  When released, the pin reads HIGH
  // because the pullup resistor connects to +5 volts inside
  // the chip.  LOW for "on", and HIGH for "off" may seem
  // backwards, but using the on-chip pullup resistors is very
  // convenient.  The scheme is called "active low", and it's
  // very commonly used in electronics... so much that the chip
  // has built-in pullup resistors!

  pinMode(0, OUTPUT);              // LED for "octave up"
  pinMode(1, OUTPUT);              // LED for "octave down"
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);        // TX output for MIDI Jack
  pinMode(4, INPUT_PULLUP);
  pinMode(5, INPUT_PULLUP);
  pinMode(6, OUTPUT);              // Teensy++ 2.0 LED, may need 1k resistor pullup

  // pins 7 to 45 are all INPUT_PULLUP
  for (int i = 7; i <= 45; i++) {
    pinMode(i, INPUT_PULLUP);
  }

  digitalWrite(6, HIGH);                // Set Teensy++ fixed LED to "on"
  digitalWrite(0, LOW);                 // Set "octave up" LED to "off"
  digitalWrite(1, LOW);                 // Set "octave down" LED to "off
}



//--------------------------MAIN LOOP-------------------------------------
//------------------------------------------------------------------------

void loop() {

  // Update all the buttons.  There should not be any long
  // delays in loop(), so this runs repetitively at a rate
  // faster than the buttons could be pressed and released.

  for (int i = 0; i <= 45; i++) {
    buttons[i]->update();
  }


  do_octave();


  vol = analogRead(vpot);                             // Read velocity from the volume pot
  vel = map(vol, 0, 1023, 0, 127);                    // change the velocity range
  // from "pot range" (0-1023)
  // to "MIDI range" (0-127)


  //----------------------READ BUTTON PINS FOR NOTE ON--------------------------------------------------

  // Check each button from 7 - 31 for "falling" edge.
  // Send a MIDI Note On message when each button presses
  // Update the Joystick buttons only upon changes.
  // falling = high (not pressed - voltage from pullup resistor)
  //           to low (pressed - button connects pin to ground)

  for (int i = 7; i <= 31; i++) {
    if (buttons[i]->fallingEdge()) {
      digitalWrite(6, LOW);
      do_sendNoteOn(i + 5 + (octave * 12), vel, channel); // C
      delay(d);
      digitalWrite(6, HIGH);
    }
  }


  //----------------------READ BUTTON PINS FOR SUSTAIN AND MODULATION--------------

  // Check sus button for "falling" edge.
  // Send a MIDI CC message when button is pressed
  // Update the Joystick buttons only upon changes.
  // falling = high (not pressed - voltage from pullup resistor)
  //           to low (pressed - button connects pin to ground)

  if (button35.fallingEdge()) {
    do_sendControlChange(64, 127, channel);      // (type=64=sus, value=127=on, MIDI channel)
  }

  // Check mod button for "falling" edge.
  // Send a MIDI CC message when the button is pressed
  // Update the Joystick buttons only upon changes.
  // falling = high (not pressed - voltage from pullup resistor)
  //           to low (pressed - button connects pin to ground)

  if (button34.fallingEdge()) {
    do_sendControlChange(1, 64, channel);      // (type=1=mod, value=64, MIDI channel)
  }

  // Check mod button for "rising" edge.
  // Send a MIDI CC message when button is not pressed
  // Update the Joystick buttons only upon changes.
  // falling = high (not pressed - voltage from pullup resistor)
  //           to low (pressed - button connects pin to ground)

  if (button34.risingEdge()) {
    do_sendControlChange(1, 0, channel);      // (type=1=mod, value=0=off, MIDI channel)
  }

  // Check sus button for "rising" edge.
  // Send a MIDI CC message when button is not pressed
  // Update the Joystick buttons only upon changes.
  // rising = low (pressed - button connects pin to ground)
  //          to high (not pressed - voltage from pullup resistor)

  if (button35.risingEdge()) {
    do_sendControlChange(64, 0, channel);      // (type=64=sus, value=0=off, MIDI channel)
  }


  //---------------READ BUTTON PINS FOR NOTE OFF-----------------------------------------

  // Check each button for "rising" edge
  // Send a MIDI Note Off message when each button releases
  // For many types of projects, you only care when the button
  // is pressed and the release isn't needed.
  // rising = low (pressed - button connects pin to ground)
  //          to high (not pressed - voltage from pullup resistor)


  for (int i = 7; i <= 31; i++) {
    if (buttons[i]->risingEdge()) {
      digitalWrite(6, LOW);
      do_sendNoteOn(i + 5 + (octave * 12), 0, channel); // C
      delay(d);
      digitalWrite(6, HIGH);
    }
  }


  // MIDI Controllers should discard incoming MIDI messages.
  // http://forum.pjrc.com/threads/24179-Teensy-3-Ableton-Analog-CC-causes-midi-crash

  while (usbMIDI.read()) {               // ignore incoming messages
  }
}
 
Thanks so much for all your effort...and for reminding me of what Paul told me in one of the first replies ("don't over-think things"...as you say, the worst thing that can happen is that it doesn't work).

I will test your new "octave" code on my Teensy right now and see how it works. If you are anything like me, I would imagine you are now determined to make this work (and, again, I appreciate your efforts on my behalf...especially for a section of code that I definitely don't have the skills and/or knowledge to really make work). Having said that, I will throw it out there right now that this "reset" option is NOT mandatory...the octave up and octave up buttons do their individual jobs VERY well in the previous sketches and I suspect it would be a rare occasion where I would NEED to "reset". In other words, if this function makes things too clumsy and/or complicated, I can definitely live without it.

By the way, if it means anything at all, this is the full section of the "octave" part of code I cut the "reset" part from:

Code:
constrain(keysLast, 0x18, 0x60);                              //limit keyboard from C1 to C7
   for(int i = 0; i < 3; i++){                                      //loop for modifier keys
    changeButtonLast[i] = changeButton[i];                           //update modifier key state
    changeButton[i] = digitalRead(changePins[i]);                    //read state of modifier keys
    if(changeButton[2] && changeButton[i] == HIGH && changeButton[i] != 
changeButtonLast[i]){                                            //if modifier buttons 1 or 2 are pressed while modifier button 3 is held down
     changekeys(singleChanges[i], keysLast);                     //change keyboard base up or down in half steps
     }
     if(changeButton[0] && changeButton[1] == HIGH){             //if modifier buttons 1 and 2 are pressed together simultaneously
       keysLast = keysBase;                                      //revert keyboard base to C4
     }
     if(changeButton[i] == HIGH && changeButtonLast[i] != changeButton[i] &&
 changeButton[2] == LOW){                                         //if modifier buttons 1 or 2 are pressed while modifier button 3 is released
       changekeys(octaveChanges[i], keysLast);                   //change keyboard base up or down in octaves
     }   
}

Note that in this example, the user had implemented 3 "modifier" buttons...the third being something like a "shift" button that allows for octave shifts AND half step shifts.

- brad -
 
Peter's most recent version of the octave switching code...including the "reset" by pressing both octave switches at the same time...seems to be working just fine based on a quick test today.
 
With *HUGE* thanks to el_supremo, everyone else who chimed in on the forum, and all the folks behind Teensy, I FINALLY finished my 25-note midi pedal.

I've already tested it with soft-synths and hardware MIDI keyboards using USB and the "old school" 5-pin jack and it works like a charm! Slide potentiometer controls velocity, octave switches shift up and down (triggering a bi-colour LED for octave status), and the external "modulation" and "sustain" switches do exactly what I had hoped!

One thing I noticed; however, is that even though the 5-pin MIDI connection works well with hardware and software synths, the output does NOT show up in MIDI-OX. I was a little nervous since that was my first test but, fortunately, that seems to be the only issue.

Needless to say, I am absolutely thrilled with how this turned out and, again, I thank everyone for all the kind and generous support along the way.

Here are a few photos:

Final Top.jpg

Final Inside.jpg

Final Teensy.jpg



And here is the final working code:

Code:
/*
https://forum.pjrc.com/threads/28816
25 Key Midi Footpedal with
Octave Up/Down, Mod, Sustain, and Volume
Created by Brad Hill on 19-06-2015
based primarily on Teensy "Buttons" with snippets from
MidiHacker's MultiButtonMIDIOctave.ino,
Graham Wykes' Miditzer Pedalboard Scanner for Teensy2.0++ board,
Lionel Cassin's "midi-bass-pedals-using-arduino.html",
G333T's video (https://www.youtube.com/watch?v=9J_tGVLD7UQ),
and various Teensy/Arduino definitions and examples.
This code is released into the Public Domain.
*/


#include <MIDI.h>
#include <Bounce.h>

const int channel = 1;        // the MIDI channel number to send messages
const int ms = 5;             // bounce time in ms (increase for more sensitve switches)
const int d = 25;             // default delay time (ms) for "activity" LED
// 
const int OCTAVE_DELAY = 50;

int LEDU = 0;                 // pin for octave up LED
int LEDD = 1;                 // pin for ocatave down LED

int octaveup = 32;            // pin for octave up switch
int octavedown = 33;          // pin for octave down switch
int octave = 3;               // set base octave

int vpot = 38;                // pin setup for volume pot
int vol;                      // place holder for vpot reading
int vel = 99;                 // fixed note velocity

// Create Bounce objects for each button.  The Bounce object
// automatically deals with contact chatter or "bounce", and
// it makes detecting changes very simple.

Bounce button0 = Bounce(0, ms);
Bounce button1 = Bounce(1, ms);  // 5 = 5 ms debounce time
Bounce button2 = Bounce(2, ms);  // which is appropriate for good
Bounce button3 = Bounce(3, ms);  // quality mechanical pushbuttons
Bounce button4 = Bounce(4, ms);
Bounce button5 = Bounce(5, ms);  // if a button is too "sensitive"
Bounce button6 = Bounce(6, ms);  // to rapid touch, you can
Bounce button7 = Bounce(7, ms);  // increase this time.
Bounce button8 = Bounce(8, ms);
Bounce button9 = Bounce(9, ms);
Bounce button10 = Bounce(10, ms);
Bounce button11 = Bounce(11, ms);
Bounce button12 = Bounce(12, ms);
Bounce button13 = Bounce(13, ms);
Bounce button14 = Bounce(14, ms);
Bounce button15 = Bounce(15, ms);
Bounce button16 = Bounce(16, ms);
Bounce button17 = Bounce(17, ms);
Bounce button18 = Bounce(18, ms);
Bounce button19 = Bounce(19, ms);
Bounce button20 = Bounce(20, ms);
Bounce button21 = Bounce(21, ms);
Bounce button22 = Bounce(22, ms);
Bounce button23 = Bounce(23, ms);
Bounce button24 = Bounce(24, ms);
Bounce button25 = Bounce(25, ms);
Bounce button26 = Bounce(26, ms);
Bounce button27 = Bounce(27, ms);
Bounce button28 = Bounce(28, ms);
Bounce button29 = Bounce(29, ms);
Bounce button30 = Bounce(30, ms);
Bounce button31 = Bounce(31, ms);
Bounce button32 = Bounce(32, ms);
Bounce button33 = Bounce(33, ms);
Bounce button34 = Bounce(34, ms);
Bounce button35 = Bounce(35, ms);
Bounce button36 = Bounce(36, ms);
Bounce button37 = Bounce(37, ms);
Bounce button38 = Bounce(38, ms);
Bounce button39 = Bounce(39, ms);
Bounce button40 = Bounce(40, ms);
Bounce button41 = Bounce(41, ms);
Bounce button42 = Bounce(42, ms);
Bounce button43 = Bounce(43, ms);
Bounce button44 = Bounce(44, ms);
Bounce button45 = Bounce(45, ms);


// Declaring the addresses of the button objects in this array
// allows us to deal with them in a for loop
Bounce *buttons[46] = {
  &button0, &button1, &button2, &button3, &button4, &button5, &button6, &button7, &button8, &button9,
  &button10, &button11, &button12, &button13, &button14, &button15, &button16, &button17, &button18, &button19,
  &button20, &button21, &button22, &button23, &button24, &button25, &button26, &button27, &button28, &button29,
  &button30, &button31, &button32, &button33, &button34, &button35, &button36, &button37, &button38, &button39,
  &button40, &button41, &button42, &button43, &button44, &button45
};


// Create functions to send usbMIDI and serial MIDI messages

void do_sendNoteOn(unsigned char note,unsigned char velocity,unsigned char channel)
{
  usbMIDI.sendNoteOn(note, velocity, channel);
  MIDI.sendNoteOn(note, velocity, channel);
}

void do_sendControlChange(unsigned char cmd,unsigned char value,unsigned char channel)
{
  usbMIDI.sendControlChange(cmd, value, channel);
  MIDI.sendControlChange(cmd, value, channel);
}

void do_octave(void)
{
//---------------------------------SET OCTAVE --------------------------------------------
  int up = digitalRead(octaveup);                     // alias "octaveup" pin read as "up"
  int down = digitalRead(octavedown);                 // alias "octavedown" pin read as "down"

  // If both buttons are up, we have nothing to do.
  if((up == HIGH) && (down == HIGH)) return;

  // At least one of the buttons is down.
  // wait for a few milliseconds and then read
  // them both again to give time for both buttons
  // to be down if the user has pushed them both.
  delay(OCTAVE_DELAY);
  
  up = digitalRead(octaveup);
  down = digitalRead(octavedown); 
  // if "up" and "down" buttons both pressed
  // return to base octave
  if ((up == LOW) && (down == LOW)) {
    octave = 3;
  } else {
    // if "up" button pressed
    if (up == LOW) {
      if (octave < 6) {
        octave++;                   // constrain highest note to C8 (108)
      }
    }
    // if "down" button pressed
    if (down == LOW) {
      if (octave > 1) {
        octave--;                   // constrain lowest note to C1 (24)
      }

    }
  }
  // Wait for the button(s) to be released
  while ((digitalRead(octaveup) == LOW) || (digitalRead(octavedown) == LOW)) {
    delay(20);
  }
}

//--------------------------SETUP-----------------------------------------------
//------------------------------------------------------------------------------

void setup() {

 MIDI.begin();  

  // Configure the pins for input mode with pullup resistors.
  // The pushbuttons connect from each pin to ground.  When
  // the button is pressed, the pin reads LOW because the button
  // shorts it to ground.  When released, the pin reads HIGH
  // because the pullup resistor connects to +5 volts inside
  // the chip.  LOW for "on", and HIGH for "off" may seem
  // backwards, but using the on-chip pullup resistors is very
  // convenient.  The scheme is called "active low", and it's
  // very commonly used in electronics... so much that the chip
  // has built-in pullup resistors!

  pinMode(0, OUTPUT);              // LED for "octave up"
  pinMode(1, OUTPUT);              // LED for "octave down"
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);        // TX output for MIDI Jack
  pinMode(4, INPUT_PULLUP);
  pinMode(5, INPUT_PULLUP);
  pinMode(6, OUTPUT);              // Teensy++ 2.0 LED, may need 1k resistor pullup

  // pins 7 to 45 are all INPUT_PULLUP
  for (int i = 7; i <= 45; i++) {
    pinMode(i, INPUT_PULLUP);
  }

  digitalWrite(6, HIGH);                // Set Teensy++ fixed LED to "on"
  digitalWrite(0, LOW);                 // Set "octave up" LED to "off"
  digitalWrite(1, LOW);                 // Set "octave down" LED to "off
}



//--------------------------MAIN LOOP-------------------------------------
//------------------------------------------------------------------------

void loop() {

  // Update all the buttons.  There should not be any long
  // delays in loop(), so this runs repetitively at a rate
  // faster than the buttons could be pressed and released.

  for (int i = 0; i <= 45; i++) {
    buttons[i]->update();
  }


  do_octave();


   if(octave > 3){                                    // if the octave is above base
     digitalWrite(LEDU,HIGH);                         // turn on "octave up" LED
   } else {                                           // otherwise leave it off
     digitalWrite(LEDU,LOW);
   }
   if(octave < 3){                                    // if the current octave is below base
     digitalWrite(LEDD,HIGH);                         // turn on the "octave down" LED
   } else {                                           // otherwise leave it off
     digitalWrite(LEDD,LOW);
   }
    

  vol = analogRead(vpot);                             // Read velocity from the volume pot
  vel = map(vol, 0, 1023, 0, 127);                      // change the velocity range
  // from "pot range" (0-50)
  // to "MIDI range" (0-127)


  //----------------------READ BUTTON PINS FOR NOTE ON--------------------------------------------------

  // Check each button from 7 - 31 for "falling" edge.
  // Send a MIDI Note On message when each button presses
  // Update the Joystick buttons only upon changes.
  // falling = high (not pressed - voltage from pullup resistor)
  //           to low (pressed - button connects pin to ground)

  for (int i = 7; i <= 31; i++) {
    if (buttons[i]->fallingEdge()) {
      digitalWrite(6, LOW);
      do_sendNoteOn(i + 5 + (octave * 12), vel, channel); // C
      delay(d);
      digitalWrite(6, HIGH);
    }
  }


  //----------------------READ BUTTON PINS FOR SUSTAIN AND MODULATION--------------

  // Check sus button for "falling" edge.
  // Send a MIDI CC message when button is pressed
  // Update the Joystick buttons only upon changes.
  // falling = high (not pressed - voltage from pullup resistor)
  //           to low (pressed - button connects pin to ground)

  if (button35.fallingEdge()) {
    do_sendControlChange(64, 127, channel);      // (type=64=sus, value=127=on, MIDI channel)
  }

  // Check mod button for "falling" edge.
  // Send a MIDI CC message when the button is pressed
  // Update the Joystick buttons only upon changes.
  // falling = high (not pressed - voltage from pullup resistor)
  //           to low (pressed - button connects pin to ground)

  if (button34.fallingEdge()) {
    do_sendControlChange(1, 64, channel);      // (type=1=mod, value=64, MIDI channel)
  }

  // Check mod button for "rising" edge.
  // Send a MIDI CC message when button is not pressed
  // Update the Joystick buttons only upon changes.
  // falling = high (not pressed - voltage from pullup resistor)
  //           to low (pressed - button connects pin to ground)

  if (button34.risingEdge()) {
    do_sendControlChange(1, 0, channel);      // (type=1=mod, value=0=off, MIDI channel)
  }

  // Check sus button for "rising" edge.
  // Send a MIDI CC message when button is not pressed
  // Update the Joystick buttons only upon changes.
  // rising = low (pressed - button connects pin to ground)
  //          to high (not pressed - voltage from pullup resistor)

  if (button35.risingEdge()) {
    do_sendControlChange(64, 0, channel);      // (type=64=sus, value=0=off, MIDI channel)
  }


  //---------------READ BUTTON PINS FOR NOTE OFF-----------------------------------------

  // Check each button for "rising" edge
  // Send a MIDI Note Off message when each button releases
  // For many types of projects, you only care when the button
  // is pressed and the release isn't needed.
  // rising = low (pressed - button connects pin to ground)
  //          to high (not pressed - voltage from pullup resistor)


  for (int i = 7; i <= 31; i++) {
    if (buttons[i]->risingEdge()) {
      digitalWrite(6, LOW);
      do_sendNoteOn(i + 5 + (octave * 12), 0, channel); // C
      delay(d);
      digitalWrite(6, HIGH);
    }
  }


  // MIDI Controllers should discard incoming MIDI messages.
  // http://forum.pjrc.com/threads/24179-Teensy-3-Ableton-Analog-CC-causes-midi-crash

  while (usbMIDI.read()) {               // ignore incoming messages
  }
}
 
Thanks! Oddly enough, MIDI-OX recognizes output from the USB connection but NOT the 5-pin MIDI jack. Thankfully, both outputs work with hardware and software synths but I'd like to know why the old school MIDI output doesn't show up in the MIDI-OX monitor.
 
...I also just discovered something that I would like to consider a "feature" in the code (as opposed to a "bug"):

If you shift up or down an octave while playing a note, that note will "hold" until you return to the same octave and hit the note again. This allows you to build chords and/or harmony by hitting one note, shifting an octave, playing another note, shifting, etc., etc.

It threw me at first but, now that I am aware of it, I quite like it!
 
With the 5-pin jack connected to the FP-10 which is then connected to the PC, it should be the FP10 that shows up in MIDI-OX. Does MIDI-OX see the FP10 as a device?

Pete
 
Yes...MIDI-OX shows that connection as "PRESONUS FP-10 MIDI". So it sees the connection is there, it just doesn't recognize the output of my board THROUGH the Firepod. Incidentally, that cable normally connects my Roland TD-8 drum module to the FirePod and when I plug it back into the Roland, MIDI-OX sees/displays all kinds of activity!
 
Last edited:
Status
Not open for further replies.
Back
Top