Teensy Midi Controller Project Advice/Journal

Status
Not open for further replies.
No I guess I'm not understanding it really. I want it to send what it in the array as either D1 or as D2.

So the array can stay. The send mode just togges. My code has the constant CCchan as 0

So you are sending (0, array code, channel )or you are sending (array code, 0, channel)
 
There are 25 different options in five banks of five.

Each one works exactly the same but you can configure the arrays to give different behaviour.

We have three arrays that between them let us send whatever we like. The complication is that the buttons remember a toggle state and so if you want a button that always sends the same message when you you need to put the same value for that address in both ONvalue and OFFvalue arrays

For those where D1 = 0; if the OFFvalue[bank] and ONvalue[bank] values are not the same then that button will toggle between two effect setups - fine if that's what you want but if you want "when I press the first button I always get guitar of doom" then you want to have the same value in ONvalue and OFFvalue arrays.
 
Code:
#include <Bounce.h>

//**********CONSTANTS**********
const int BOUNCE_TIME = 15; // 10ms is usually ok for buttons, bump way up if testing with a wire!
const int LEDPIN = 13; // Upper BANK indicator LED 
const int DIGITAL_PINS = 5; // size of the PINS array 
const int PINS[DIGITAL_PINS] = {0,1,2,3,4}; // set pin numbers of swtiches
const int channel = 1;

const byte CC[][DIGITAL_PINS] = { // D1 values
  {0,0,0,0,0},     // Send D1 = 0 for the whole bank!
  {65,66,67,68,69},
  {70,71,72,73,74},
  {75,76,77,78,79},
  {80,81,82,83,84},
  {85,86,87,88,89}
}; // this is the banks by switches matrix of CC values for the bank system
const int ONvalue[][DIGITAL_PINS] = {   // D2 values when switch is toggled ON
  {22,23,24,25,26},
  {70,71,72,73,74},
  {75,76,77,78,79},
  {80,81,82,83,84},
  {85,86,87,88,89},
  {90,91,92,93,94},
};
const int OFFvalue[][DIGITAL_PINS] = {  // D2 values when switch is toggled OFF
  {22,23,24,25,26}, // if these are the same as the same row in ONvalue then there is no toggle but the same message!
  {5,6,7,8,9},
  {10,11,12,13,14},
  {15,16,17,18,19},
  {20,21,22,23,24},
  {25,26,27,28,29}
};// arbitrary 'off' value for D2 of CC message

const int resetThreshold = 1500; /// mS hold to change bank

//**********VARIABLES/LIBRARY OBJECTS**********
int bank = 0; // this is the bank variable to be toggled
boolean CCstate[DIGITAL_PINS]; // array of current CC on/off toggle state
boolean timerOn; // timer toggle memory tracks whether a new fallingEdge was heard since the last rising; used in bank switching

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),
  };
elapsedMillis toggleReset; // mS clock counter to reset on contact/risgingEdge()

//**********SETUP**********
void setup() {
  //Serial.begin(9600);
  for (int i = 0;i<DIGITAL_PINS;i++){ // set up pins as input and with pullup resistors
    pinMode(PINS[i], INPUT_PULLUP);
  }
  pinMode(LEDPIN, OUTPUT);
}

//**********LOOP**********
void loop() {
  for (int i = 0;i<DIGITAL_PINS;i++){ // loop through each object in the BOUNCE arrray for the note switches
    btn[i].update();
    if (btn[i].fallingEdge()) {
      timerOn = true ;
      toggleReset = 0;
    }
    if (btn[i].risingEdge()) {
      if(toggleReset<resetThreshold){
        if (CCstate[i]){ 
          usbMIDI.sendControlChange(CC[bank][i], ONvalue[bank][i], channel); 
        }else{
          usbMIDI.sendControlChange(CC[bank][i], OFFvalue[bank][i], channel);  
        }
        CCstate[i] = !CCstate[i] ; //set state memory
        timerOn = false ; //turn off timer (resets each cycle)
      }
    }
    if ([COLOR="#FF0000"]digitalRead(PINS[i])==LOW[/COLOR] && toggleReset>resetThreshold){
      toggleReset = 0;
      timerOn = false ;
      bank = i;
      [COLOR="#FF0000"]flash(i+1); [/COLOR]// flash for bank selection 1-5 (for index 0-4)
      //digitalWrite(LEDPIN, bank); // turn off for now...
    }
  }
}

[COLOR="#FF0000"]void flash(int flashCount){
  int i;
  for (int i = 0;i<flashCount;i++){
    digitalWrite(LEDPIN, HIGH);
    delay(100);
    digitalWrite(LEDPIN, LOW);
    delay(100);
    }
}[/COLOR]

The LED should now flash the number of the bank (index + 1) so the user can tell when it is set and have a clue what it is set to.
 
...above was still buggy and still sending messages after a mode change... :(

I added a second boolean variable for the timing logic that stops the code from sending MIDI following a mode change but also stops the mode change code from running over and over before the next fallingEdge.


Code:
#include <Bounce.h>

//**********CONSTANTS**********
const int BOUNCE_TIME = 15; // 10ms is usually ok for buttons, bump way up if testing with a wire!
const int LEDPIN = 13; // Upper BANK indicator LED 
const int DIGITAL_PINS = 5; // size of the PINS array 
const int PINS[DIGITAL_PINS] = {0,1,2,3,4}; // set pin numbers of swtiches
const int channel = 1;

const byte CC[][DIGITAL_PINS] = { // D1 values
  {0,0,0,0,0},     // Send D1 = 0 for the whole bank!
  {65,66,67,68,69},
  {70,71,72,73,74},
  {75,76,77,78,79},
  {80,81,82,83,84},
  {85,86,87,88,89}
}; // this is the banks by switches matrix of CC values for the bank system

const int ONvalue[][DIGITAL_PINS] = {   // D2 values when switch is toggled ON
  {21,22,23,24,25},
  {127,127,127,127,127},
  {127,127,127,127,127},
  {127,127,127,127,127},
  {127,127,127,127,127}
};
const int OFFvalue[][DIGITAL_PINS] = {  // D2 values when switch is toggled OFF
  {21,22,23,24,25}, // if these are the same as the same row in ONvalue then there is no toggle but the same message!
  {0,0,0,0,0},
  {0,0,0,0,0},
  {0,0,0,0,0},
  {0,0,0,0,0}
};// arbitrary 'off' value for D2 of CC message

const int resetThreshold = 1500; /// mS hold to change bank

//**********VARIABLES/LIBRARY OBJECTS**********
int bank = 0; // this is the bank variable to be toggled
boolean CCstate[DIGITAL_PINS]; // array of current CC on/off toggle state
boolean timerOn; // timer toggle memory tracks whether a new fallingEdge was heard since the last rising; used in bank switching
boolean sendOK; // set to False when mode change occurs and True on all fallingEdges

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),
  };
elapsedMillis toggleReset; // mS clock counter to reset on contact/risgingEdge()

//**********SETUP**********
void setup() {
  //Serial.begin(9600);
  for (int i = 0;i<DIGITAL_PINS;i++){ // set up pins as input and with pullup resistors
    pinMode(PINS[i], INPUT_PULLUP);
  }
  pinMode(LEDPIN, OUTPUT);
}

//**********LOOP**********
void loop() {
  for (int i = 0;i<DIGITAL_PINS;i++){ // loop through each object in the BOUNCE arrray for the note switches
    btn[i].update();
    if (btn[i].fallingEdge()) {
      timerOn = true ;
      sendOK = true;
      toggleReset = 0;
    }
    if (btn[i].risingEdge()) {
      if(sendOK){
        if (CCstate[i]){ 
          usbMIDI.sendControlChange(CC[bank][i], ONvalue[bank][i], channel); 
        }else{
          usbMIDI.sendControlChange(CC[bank][i], OFFvalue[bank][i], channel);  
        }
        CCstate[i] = !CCstate[i] ; //set state memory
        timerOn = false ; //turn off timer (resets each cycle)
      }
    }
    if (timerOn){  
      if (toggleReset>resetThreshold && sendOK){
        if (digitalRead(PINS[i])==LOW) { // 
          sendOK = false; // don't send MIDI following mode change and don't change mode a second time!
          bank = i;
          flash(i+1); // flash for bank selection 1-5 (for index 0-4)
        }
      }      
    }else{
      toggleReset = 0; // reset to zero if timer off
    }

  }
}

void flash(int flashCount){
  int i;
  for (int i = 0;i<flashCount;i++){
    digitalWrite(LEDPIN, HIGH);
    delay(100);
    digitalWrite(LEDPIN, LOW);
    delay(100);
    }
}
 
Last edited:
Code:
    while (usbMIDI.read()) {
    // controllers must call .read() to keep the queue clear even if they are not responding to MIDI
    }
this fragment belongs in all controllers... if your USB connection was passing MIDI to Teensy then that could account for the freeze-ups you were getting as the connections event queue fills with unread messages.

It should run once per main loop so it goes right before the closing parenthesis of the loop().

Apologies for the added frustration if that was the cause of your freeze ups. For a fairly simple controller I sure made a lot of mistakes. ;)
 
If you are not using to play sounds (where synchronization is important) then you can have the CC messages that change the DAW sent only on the release of the button.

With that change I think you'll get much closer to an ideal setup as you can supress the CC associated with the button when you're holding it to change the bank.


I suggest we take the A/B bank example from my first post here and change it as follows:

Note on/off becomes CC 127/0
Send CC only on releasing the witch (risingEdge) and only if timer is below 2000 mS
Reset timer on fallingEdge - start counting the timer only when a switch is down
If timer > 2000 mS when risingEdge is detected then toggle mode/bank and do not send CC for the button pressed

FYI - with this scheme we could make it so it changes mode if ANY button is held for >2000ms.

If this sounds OK to you let me know and I'll make a version with these changes later tonight.


yeah that sounds right for everything except the whole on and off thing.

I am confused and not sure if you are understanding what i am hoping to do.

I want Mode 1 to send CC 0 codes. so i have the constant CCchan set to 0.

in mode 1 when you press switch it sends code (CCchan, CC[bank],channel)

so it sends (0, whatever is in array, 0)

I want Mode 2 to just switch CCchan and CC[bank]

so Mode 2 will send (whatever is in array for bank, 0 ,)


Code starts in mode 1 and is switched to mode 2 on short press.

Short press sends (CCchan, CC[bank]) and also sets to Mode 2.


Long press sets bank and sets mode back to mode 1.

Do you get what im going for here?
 
...Do you get what im going for here?

God I hope so 'cause it's a bit late in the game for a fundamental design change.

All five modes work the same way but the way you configure the arrays should give the behaviour I think you are describing.

Code:
const byte CC[][DIGITAL_PINS] = { // D1 values
 [COLOR="#FF0000"] {0,0,0,0,0},     // Send D1 = 0 for the whole bank![/COLOR]
  {65,66,67,68,69},
  {70,71,72,73,74},
  {75,76,77,78,79},
  {80,81,82,83,84},
  {85,86,87,88,89}
}; // this is the banks by switches matrix of CC values for the bank system

This line of code is the part of the array definition that defines D1 for Bank1 and as they are all set to 0 every message sent from from bank 1 will have D1 = 0.

D2 will be defined by the ONvalue and OFFvalue arrays that are needed to give toggled values for the other four modes.

But for mode 1 (as I understand you) we don't want D2 to alternate between two values.

Rather than design mode 1 to work differently than the others we can get the behaviour if we set the values in both arrays to be the same.



Code:
const int ONvalue[][DIGITAL_PINS] = {   // D2 values when switch is toggled ON
  [COLOR="#FF0000"]{21,22,23,24,25},[/COLOR]
  {127,127,127,127,127},
  {127,127,127,127,127},
  {127,127,127,127,127},
  {127,127,127,127,127}
};
const int OFFvalue[][DIGITAL_PINS] = {  // D2 values when switch is toggled OFF
  [COLOR="#FF0000"]{21,22,23,24,25}, [/COLOR]// if these are the same as the same row in ONvalue then there is no toggle but the same message!
  {0,0,0,0,0},
  {0,0,0,0,0},
  {0,0,0,0,0},
  {0,0,0,0,0}
};// arbitrary 'off' value for D2 of CC message

So even though the sketch is keeping track of an ON and OFF state (in the CCstate[] array) the output is the same for either state.

So with this configuration button 1 when released while in mode 1 will generate CC with D1=0 and D2=21 regardless of how many times it's pressed as long as it's in mode 1.

While in the other modes the D1 is different for each button and D2 toggles between off=0 and on=127.
 
I don't know what is wrong with just changing the order of the code based on the value of a toggle
I have no idea what this means.

Why the need for even tracking on and off state? It's extraneous
Are you saying you don't want D2 to toggle off and on for any mode? Then it is extraneous. Otherwise it's needed to remember which value to send on the next risingEdge.

There are other ways we could design something that can generate the MIDI you are looking for and if this was part of a more configurable system with the end user able to set CC values then the three arrays would be awkward and some different configuration storage system night be preferable where each botton-mode combination's settings are all in the same place.

If you don't want toggle behaviour in any mode at all then this sketch has some extraneous code you could remove. Or you can just fill out the on and off arrays with the same values.
 
There are other ways we could design something that can generate the MIDI you are looking for and if this was part of a more configurable system with the end user able to set CC values then the three arrays would be awkward and some different configuration storage system night be preferable where each botton-mode combination's settings are all in the same place. ...

Jeez... was my comma key broken?

What I mean is the current design is a bit quirky but does what you need.

If a user were scrolling through menus to set things then the settings should be together and they should not have to guess that they need to set D1 to 0 and D2 to the same in two places... but since this is hard coded the strangeness factor should be tolerable.

It's a performance tool hard-coded to your specs. If it were a general purpose tool you would want to configure it differently but at that point I think you would no longer want mode selection from timing as it effectively gives up the risingEdge of the switch signal from initiating events.

It's fine for setting presets or changing whole scenes but not for noteOn/Off where you want the risingEdge for NoteOn() triggering.

If you are using a timer reset from risingEdge you can't also be sending notes from that edge without doing both when you mean to do only one. I hope that makes sense.

If you did need noteOn/Off behaviour you would need to move mode selection off the event switches to up/down switches (for example).
 
I see. So really we should be writing the project with that in mind. For it to be a general purpose tool that can be customized for specific use. I like the idea of user being able to program buttons like you mentioned, I'd like to explore that further.

If I take your meaning correctly we should not be using rising edge for toggles. Rather using specific pins for up down etc. correct?

Let's explore it that way as I am hoping to add many more controls than just five switches.

I hope to have maybe 20 or more for various functions
 
If I take your meaning correctly we should not be using rising edge for toggles. Rather using specific pins for up down etc. correct?
For a more general approach that allowed note-like behaviour then 'yes' because you need both signals the buttons can send for sending the midi message as note-on/off pair.

A single 'mode' button can cycle through a list incrementing one way or two buttons can give you up/down selection.
 
For a more general approach that allowed note-like behaviour then 'yes' because you need both signals the buttons can send for sending the midi message as note-on/off pair.

A single 'mode' button can cycle through a list incrementing one way or two buttons can give you up/down selection.

that would be the better way
 
I hope this project will come into completion soon. I also love to build one. If i only understand the codes i will also help. But my little brain only understand what the thread starter is trying to make as a fellow musician.
 
This project is a tweak of a fairly general scheme for adding a bank feature to simple sketch. It has more to do with configuring the system for specific behaviour (i.e. a bank system on only part of the output) than about bank systems in general.

If you have specific design objectives you don't know how to achieve you might want to start a thread in this forum asking for specific advice.
 
This project is a tweak of a fairly general scheme for adding a bank feature to simple sketch. It has more to do with configuring the system for specific behaviour (i.e. a bank system on only part of the output) than about bank systems in general.

If you have specific design objectives you don't know how to achieve you might want to start a thread in this forum asking for specific advice.

reviving this to just get back to basics.

For now I want to just send 5 preset CC values for CC1.

i need this to change something with an index of 8 15.875
 
...above was still buggy and still sending messages after a mode change... :(

I added a second boolean variable for the timing logic that stops the code from sending MIDI following a mode change but also stops the mode change code from running over and over before the next fallingEdge.


Code:
#include <Bounce.h>

//**********CONSTANTS**********
const int BOUNCE_TIME = 15; // 10ms is usually ok for buttons, bump way up if testing with a wire!
const int LEDPIN = 13; // Upper BANK indicator LED 
const int DIGITAL_PINS = 5; // size of the PINS array 
const int PINS[DIGITAL_PINS] = {0,1,2,3,4}; // set pin numbers of swtiches
const int channel = 1;

const byte CC[][DIGITAL_PINS] = { // D1 values
  {0,0,0,0,0},     // Send D1 = 0 for the whole bank!
  {65,66,67,68,69},
  {70,71,72,73,74},
  {75,76,77,78,79},
  {80,81,82,83,84},
  {85,86,87,88,89}
}; // this is the banks by switches matrix of CC values for the bank system

const int ONvalue[][DIGITAL_PINS] = {   // D2 values when switch is toggled ON
  {21,22,23,24,25},
  {127,127,127,127,127},
  {127,127,127,127,127},
  {127,127,127,127,127},
  {127,127,127,127,127}
};
const int OFFvalue[][DIGITAL_PINS] = {  // D2 values when switch is toggled OFF
  {21,22,23,24,25}, // if these are the same as the same row in ONvalue then there is no toggle but the same message!
  {0,0,0,0,0},
  {0,0,0,0,0},
  {0,0,0,0,0},
  {0,0,0,0,0}
};// arbitrary 'off' value for D2 of CC message

const int resetThreshold = 1500; /// mS hold to change bank

//**********VARIABLES/LIBRARY OBJECTS**********
int bank = 0; // this is the bank variable to be toggled
boolean CCstate[DIGITAL_PINS]; // array of current CC on/off toggle state
boolean timerOn; // timer toggle memory tracks whether a new fallingEdge was heard since the last rising; used in bank switching
boolean sendOK; // set to False when mode change occurs and True on all fallingEdges

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),
  };
elapsedMillis toggleReset; // mS clock counter to reset on contact/risgingEdge()

//**********SETUP**********
void setup() {
  //Serial.begin(9600);
  for (int i = 0;i<DIGITAL_PINS;i++){ // set up pins as input and with pullup resistors
    pinMode(PINS[i], INPUT_PULLUP);
  }
  pinMode(LEDPIN, OUTPUT);
}

//**********LOOP**********
void loop() {
  for (int i = 0;i<DIGITAL_PINS;i++){ // loop through each object in the BOUNCE arrray for the note switches
    btn[i].update();
    if (btn[i].fallingEdge()) {
      timerOn = true ;
      sendOK = true;
      toggleReset = 0;
    }
    if (btn[i].risingEdge()) {
      if(sendOK){
        if (CCstate[i]){ 
          usbMIDI.sendControlChange(CC[bank][i], ONvalue[bank][i], channel); 
        }else{
          usbMIDI.sendControlChange(CC[bank][i], OFFvalue[bank][i], channel);  
        }
        CCstate[i] = !CCstate[i] ; //set state memory
        timerOn = false ; //turn off timer (resets each cycle)
      }
    }
    if (timerOn){  
      if (toggleReset>resetThreshold && sendOK){
        if (digitalRead(PINS[i])==LOW) { // 
          sendOK = false; // don't send MIDI following mode change and don't change mode a second time!
          bank = i;
          flash(i+1); // flash for bank selection 1-5 (for index 0-4)
        }
      }      
    }else{
      toggleReset = 0; // reset to zero if timer off
    }

  }
}

void flash(int flashCount){
  int i;
  for (int i = 0;i<flashCount;i++){
    digitalWrite(LEDPIN, HIGH);
    delay(100);
    digitalWrite(LEDPIN, LOW);
    delay(100);
    }
}


I just tried this and im getting 15 16 17 18 19 as my D2 values. not sure how that is possible
 
I think those are hex values for 21-25 which is the non-zero row both the on and off values for D2.

I don't recall much about this thread at the moment so I can't recall the 'why' but isn't this what you wanted?
 
If you meant to have those values be hex just type '0x' in front of each one (or convert them to decimals 33-37).
 
You know what I was reading the hex on the input monitor in midiox instead of the output monitor.

Everything is working fine. I changed the first row in the bank matrix to reflect the D2s that I need and changed the CC channel to 21 because I had some assignment conflicts in my DAW.

From there everything worked great. In this use case I did not need the toggles so I didn't test that.
 
So wanting to start working on this again to expand the number of switches and come up with a GUI for code programability. Do you know where I can start oddson?
 
A lot of this thread is about switching modes via timing from the same switches that generate the MIDI messages.

As a result it only sends on risingEdge as switches are released.

And it has toggle behaviour assumed

So unless you are ok with those limitations I suspect you would start from a general bank system and the add the GUI rather that start with this code.

Where to start, therefore, is selecting the user feedback mechanism and then learning to program whatever display you choose.

Once you can sketch out a 'hello world' on your display then you can look to integrating with midi code.

You'd also want to learn EEPROM access since you will likely want to save user configuration data.

But I think this thread has run its course as it's very specific.
 
Status
Not open for further replies.
Back
Top