USB midi controllers for persons with special needs

Status
Not open for further replies.

greeegouar

New member
Hi everyone, i’m a social worker and i’m doing music creation workshops for persons with special needs.

I have an Ipad with a bunch of apps, a cheap audio interface, some piezos and we are jamming and recording with that.

I’d like them to be able to record samples, to make their own beats live, and to control some effects
but the center i’m working for don’t have any budget for that, so i have to go D.I.Y.

I already had a Teensy ++2.0 and some cigar boxes, i bought another Teensy 3.5 some arcade buttons and knobs and here is the result.

https://photos.app.goo.gl/qujKW2ST2joHimFR9

Now i’m trying to write the code.

Disclaimer: i’m kind of a noob. My first attempt with Teensy is a midi foot controller that works well but the code was totally borrowed from the examples. I just adapted it to my switch number and so they give CCs instead of notes.

So i took the Many_Buttons_Knobs from the examples and tried it with the Teensy 3.5 with just one button and one knob to see i could get it work like that at first.

And it doesn’t.
The button is not recognized by my app and when i’m assigning the knobs, the value 'floats' and gives glitchy readings like in this thread:

https://forum.pjrc.com/threads/48200-Teensy-3-5-Exemple-AnalogControlChange-Problems

Here is the code*:

Code:
//************LIBRARIES USED**************
// include the ResponsiveAnalogRead library for analog smoothing
#include <ResponsiveAnalogRead.h>
// include the Bounce library for 'de-bouncing' switches -- removing electrical chatter as contacts settle
#include <Bounce.h> 
//usbMIDI.h library is added automatically when code is compiled as a MIDI device

// ******CONSTANT VALUES******** 
// customize code behaviour here!
const int channel = 1; // MIDI channel
const int A_PINS = 1; // number of Analog PINS
const int D_PINS = 1; // number of Digital PINS
const int ON_VELOCITY = 99; // note-one velocity sent from buttons (should be 65 to  127)

// define the pins you want to use and the CC ID numbers on which to send them..
const int ANALOG_PINS[A_PINS] = {A14};
const int CCID[A_PINS] = {21};

// define the pins and notes for digital events
const int DIGITAL_PINS[D_PINS] = {0};
const int note[D_PINS] = {60};
const int BOUNCE_TIME = 7; // 5 ms is usually sufficient
const boolean toggled = true;


//******VARIABLES***********
// a data array and a lagged copy to tell when MIDI changes are required
byte data[A_PINS];
byte dataLag[A_PINS]; // when lag and new are not the same then update MIDI CC value


//************INITIALIZE LIBRARY OBJECTS**************
// not sure if there is a better way... some way run a setup loop on global array??
// use comment tags to comment out unused portions of array definitions

// initialize the ReponsiveAnalogRead objects
ResponsiveAnalogRead analog[]{
  {ANALOG_PINS[14],true}/*,
  {ANALOG_PINS[1],true},
  {ANALOG_PINS[2],true},
  {ANALOG_PINS[3],true},
  {ANALOG_PINS[4],true},
  {ANALOG_PINS[5],true},
  {ANALOG_PINS[6],true},
  {ANALOG_PINS[7],true},*/
}; 

// initialize the bounce objects 
Bounce digital[] =   {
  Bounce(DIGITAL_PINS[0],BOUNCE_TIME)/*, 
  Bounce(DIGITAL_PINS[1], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[2], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[3], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[4], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[5], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[6], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[7], BOUNCE_TIME),*/
}; 

//************SETUP**************
void setup() {
// loop to configure input pins and internal pullup resisters for digital section
  for (int i=0;i<D_PINS;i++){
    pinMode(DIGITAL_PINS[i], INPUT_PULLUP);
  }
}

//************LOOP**************
void loop() {
  getAnalogData();
  getDigitalData();
  while (usbMIDI.read()) {
     // controllers must call .read() to keep the queue clear even if they are not responding to MIDI
  }
}


//************ANALOG SECTION**************
void getAnalogData(){  
  for (int i=0;i<A_PINS;i++){
    // update the ResponsiveAnalogRead object every loop
    analog[i].update(); 
    // if the repsonsive value has change, print out 'changed'
    if(analog[i].hasChanged()) {
      data[i] = analog[i].getValue()>>3;
      if (data[i] != dataLag[i]){
        dataLag[i] = data[i];
        usbMIDI.sendControlChange(CCID[i], data[i], channel);
      }
    }
  }
}



//************DIGITAL SECTION**************
void getDigitalData(){
  for (int i=0;i<D_PINS;i++){
  digital[i].update();
    if (digital[i].fallingEdge()) {
      usbMIDI.sendNoteOn(note[i], ON_VELOCITY, channel);  
    }
    // Note Off messages when each button is released
    if (digital[i].risingEdge()) {
      usbMIDI.sendNoteOff(note[i], 0, channel);  
    }
  }
}

Here are my connections on breadboard:

https://photos.app.goo.gl/AFBu59C7C8tHgCmu7

I don’t get what i’m doing wrong.

Also i would like the digital pins to "give" CCs as the analog pins and not Notes and i really don't have a clue on how to do that. I tried to move things in the code that seems to be logical to me without really understanding it but all i got was a bunch of errors :).

Thanks a lot in advance for your patience and your help.
 
ok.... since that's my code you're starting with and the project is certainly worthy so I guess I should step up.

Not sure why you're using Many Knobs... for one knob and one button.

But here's your problem (I think... it's late and I'm prone to error)


The pin assignment has been overridden in the code

Code:
const int ANALOG_PINS[A_PINS] = {A14};
...

// initialize the ReponsiveAnalogRead objects
ResponsiveAnalogRead analog[]{
  {ANALOG_PINS[14],true}
};
This is telling the ResponsiveAnalogRead code to read the item at index 14 of the ANALOG_PINS array... problem is it has only one defined member so it's reading garbage from memory.

It should be index 0 not 14 --- to get the one and only element from this array.


// initialize the ReponsiveAnalogRead objects
ResponsiveAnalogRead analog[]{
{ANALOG_PINS[0],true}
};


the other lines should be restored from the commented out section for as many as are required (until I update the code to do this properly). The library used to smooth the values needs to have objects initiated as setup but I didn't know how to do this in a code loop when I wrote this so it's a bit of a kludge... if they are used they have to count from zero to the number of PINs minus one... (5 pins, 0-4)

… changing to CC for the buttons is easy enough.
Code:
//************DIGITAL SECTION**************
void getDigitalData(){
  for (int i=0;i<D_PINS;i++){
  digital[i].update();
    if (digital[i].fallingEdge()) {
      usbMIDI.[COLOR="#FF0000"]sendProgramChange[/COLOR](note[i], ON_VELOCITY, channel);  
    }
    // Note Off messages when each button is released
    if (digital[i].risingEdge()) {
      usbMIDI.[COLOR="#FF0000"]sendProgramChange[/COLOR](note[i], 0, channel);  
    }
  }
}
It should be as simple as changing the sendNoteOff/sendNoteOn to sendProgramChange ... (but again it's late and I'm very prone to error so there might be something I'm forgetting)

Normally I'd rename the array as 'note' is a bit misleading now... but it shouldn't matter as notes and CC are both byte values in the MIDI library.



ON_VELOCITY is set in the early part of the code but you may want 127 instead of 99 that's there now. It's the D2 values send in your 3 byte MIDI. I'd rename that too if I were publishing the code but, again, it should work no matter the name.

I've not seen your image yet... are you planning for more inputs?

My code uses arrays to deal efficiently with an arbitrary number of inputs but for three or less I believe there are simpler code examples.
 
Code:
// initialize the ReponsiveAnalogRead objects
ResponsiveAnalogRead analog[]{
  {A14,true}
};
This also should work and is likely what you were attempting. With this the defined constants are not needed.

Note you should use A14 as analog pin numbering. I think AnalogRead() will use A14 if you feed it 14 but I wouldn't bet on libraries doing the same.



(EDIT - Ah... you likely mean A0, 14 likely does return A0 but I'd use A0 instead.)
 
Last edited:
Thank you so much for your answer!

I'll try to post again a picture of the two controllers. The first one has 18 pots and a joystick for persons who struggle with fine motor skills.
(Sorry for my bad english :) ). The other one has 21 arcade push buttons and 3 pots. 16 buttons to play samples, 5 to control the sampler.

midicontrollers2.jpg

At first i wanted to test the code with just one knob and one button, to see if i could "understand" it a bit and try to modify it.

So thanks to your great advices, i modified my test. So now i have 3 knobs and 3 buttons on my breadboard. I connected them at the right spots following the order of the code and the knobs are working!
That's amazing! I'm getting close :).

My struggle now is to get my buttons working as CCs. I tried the code you gave me but it didn't worked so i tried something else.

Code:
//************DIGITAL SECTION**************
void getDigitalData(){
  for (int i=0;i<D_PINS;i++){
  digital[i].update();
    if (digital[i].fallingEdge()) {
      usbMIDI.[COLOR="#FF0000"]sendControlChange[/COLOR]([COLOR="#FF0000"]CCID[/COLOR][i], ON_VELOCITY, channel);  
    }
    // Note Off messages when each button is released
    if (digital[i].risingEdge()) {
      usbMIDI.[COLOR="#FF0000"]sendControlChange[/COLOR]([COLOR="#FF0000"]CCID[/COLOR][i], 0, channel);  
    }
  }
}

And i believe there is a problem with that part:
Code:
// define the pins you want to use and the CC ID numbers on which to send them..
const int ANALOG_PINS[A_PINS] = {A0,A1,A2};
const int CCID[A_PINS] = {21,22,23};

// define the pins and notes for digital events
const int DIGITAL_PINS[D_PINS] = {0};
[COLOR="#FF0000"]const int note[D_PINS] = {60,61,62};[/COLOR]
const int BOUNCE_TIME = 7; // 5 ms is usually sufficient
const boolean toggled = true;

I don't know how to "associate" the analog pins and the digital pins with the CCs at the begining of the code.

I tried this:
Code:
// define the pins and notes for digital events
const int DIGITAL_PINS[D_PINS] = {0};
const int [COLOR="#FF0000"]CCID[/COLOR][D_PINS] = {60,61,62};
const int BOUNCE_TIME = 7; // 5 ms is usually sufficient
const boolean toggled = true;

But i get this message:
Code:
Arduino : 1.8.12 (Linux), TD: 1.51, Carte : "Teensy 3.5, MIDI, 120 MHz, Faster, French"

Many_Button_Knobs_gREGOU:36: error: redefinition of 'const int CCID [3]'
 const int CCID[D_PINS] = {60,61,62};
                      ^
/home/greeegouar/Arduino/Many_Button_Knobs_gREGOU/Many_Button_Knobs_gREGOU.ino:32:11: note: 'const int CCID [3]' previously defined here
 const int CCID[A_PINS] = {21,22,23};
           ^
redefinition of 'const int CCID [3]'

I think there is a way to tell that "const int CCID" are Analog Pins and Digital Pins but i don't know how.

Okay maybe i'm totally out, i know nothing about programming :).

It's just like being in a foreign country and trying to guess what people are talking about.
I know by experience this can go wrong :D
 
I'm writing a more detailed reply but in the meantime… you are assuming some things that are just names have meaning to the compiler.

CCID is just the name of an array of data... so is notes


It really should just be the MIDI call you make that's different and the error you are really having is in the configuration.

...stay tuned
 
Untested code changes... not even compiled so there may well be an error or two!


Code:
/************LIBRARIES USED**************
// include the ResponsiveAnalogRead library for analog smoothing
#include <ResponsiveAnalogRead.h>
// include the Bounce library for 'de-bouncing' switches -- removing electrical chatter as contacts settle
#include <Bounce.h> 
//usbMIDI.h library is added automatically when code is compiled as a MIDI device

// ******CONSTANT VALUES******** 
// customize code behaviour here!
const int channel = [COLOR="#00FF00"]1[/COLOR]; // MIDI channel
const int A_PINS = [COLOR="#00FF00"]3[/COLOR]; // number of Analog PINS
const int D_PINS = [COLOR="#00FF00"]3[/COLOR]; // number of Digital PINS
const int [COLOR="#FF0000"]ON_VALUE [/COLOR]= [COLOR="#00FF00"]127[/COLOR]; // CC value sent with at button press (should be 65 to  127)

// define the pins you want to use and the CC ID numbers on which to send them..
const int ANALOG_PINS[A_PINS] = {[COLOR="#00FF00"]A0,A1,A2[/COLOR]};
const int [COLOR="#FF0000"]knobs[/COLOR][A_PINS] = {[COLOR="#00FF00"]21,22,23[/COLOR]}; [COLOR="#FF0000"]// should have the same number of elements as A_PINS[/COLOR]

// define the pins and CC numbers for digital events
const int DIGITAL_PINS[D_PINS] = {[COLOR="#00FF00"]0,1,2[/COLOR]};
const int [COLOR="#FF0000"]buttons[/COLOR][D_PINS] = {[COLOR="#00FF00"]60,61,62[/COLOR]};
const int BOUNCE_TIME = [COLOR="#00FF00"]7[/COLOR]; // 5 ms is usually sufficient
const boolean toggled = true;


//******VARIABLES***********
// a data array and a lagged copy to tell when MIDI changes are required
byte data[A_PINS];
byte dataLag[A_PINS]; // when lag and new are not the same then update MIDI CC value


//************INITIALIZE LIBRARY OBJECTS**************
// not sure if there is a better way... some way run a setup loop on global array??
// use comment tags to comment out unused portions of array definitions

// initialize the ReponsiveAnalogRead objects
ResponsiveAnalogRead analog[]{
  {ANALOG_PINS[0],true},
  {ANALOG_PINS[1],true},
  {ANALOG_PINS[2],true}[COLOR="#00FF00"]/*[/COLOR],
  {ANALOG_PINS[3],true},
  {ANALOG_PINS[4],true},
  {ANALOG_PINS[5],true},
  {ANALOG_PINS[6],true},
  {ANALOG_PINS[7],true},...[COLOR="#FF0000"] -- comment used to limit initializing A_PINS by moving start tag[/COLOR]*/
}; 

// initialize the bounce objects 
Bounce digital[] =   {
  Bounce(DIGITAL_PINS[0],BOUNCE_TIME), 
  Bounce(DIGITAL_PINS[1], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[2], BOUNCE_TIME)[COLOR="#00FF00"]/*[/COLOR],
  Bounce(DIGITAL_PINS[3], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[4], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[5], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[6], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[7], BOUNCE_TIME),[COLOR="#FF0000"] -- comment used to limit initializing D_PINS by moving start tag[/COLOR]*/
}; 

//************SETUP**************
void setup() {
// loop to configure input pins and internal pullup resisters for digital section
  for (int i=0;i<D_PINS;i++){
    pinMode(DIGITAL_PINS[i], INPUT_PULLUP);
  }
}

//************LOOP**************
void loop() {
  getAnalogData();
  getDigitalData();
  while (usbMIDI.read()) {
     // controllers must call .read() to keep the queue clear even if they are not responding to MIDI
  }
}


//************ANALOG SECTION**************
void getAnalogData(){  
  for (int i=0;i<A_PINS;i++){
    // update the ResponsiveAnalogRead object every loop
    analog[i].update(); 
    // if the repsonsive value has change, print out 'changed'
    if(analog[i].hasChanged()) {
      data[i] = analog[i].getValue()>>3;
      if (data[i] != dataLag[i]){
        dataLag[i] = data[i];
        usbMIDI.sendControlChange([COLOR="#FF0000"]knobs[/COLOR][i], data[i], channel);
      }
    }
  }
}



//************DIGITAL SECTION**************
void getDigitalData(){
  for (int i=0;i<D_PINS;i++){
  digital[i].update();
	// CC On messages D2=ON_VALUE
    if (digital[i].fallingEdge()) {
      usbMIDI.[COLOR="#0000FF"]sendControlChange[/COLOR]([COLOR="#FF0000"]buttons[/COLOR][i], [COLOR="#FF0000"]ON_VALUE[/COLOR], channel);  
    }
    // CC Off messages D2=0
    if (digital[i].risingEdge()) {
      usbMIDI.[COLOR="#0000FF"]sendControlChange[/COLOR]([COLOR="#FF0000"]buttons[/COLOR][i], 0, channel);  
    }
  }
}
red highlights the name changes and green the setup elements you should understand to make it work...

To be clear this will be momentary behaviour with the buttons. If you want latching CC behaviour -- press for on and press again for off -- there's a handful of changes in the DIGITAL SECTION that are required.
 
Last edited:
Based on @oddson's example, chiseled out of a larger project, tidied up and tested. Buttons do Note#, CC# or Toggle CC#.
Hope is helpful for a worthy cause.
Code:
/* Works on T3.2, Usb type = Midi
 * Based on Many_Buttons_Knobs example by Leif Oddson
 * https://forum.pjrc.com/threads/45376
 * and some bits nicked from Notes and Volts
 * 
 * With some additions by MatrixRat to provide some Per-element definitions
 * Pots (or other analog sensors) can send CCs, MSB/LSB CCs, or NRPNs
 * Analog inputs scalable for sensors that do not emit full 0v - 3.3v range.
 * 
 * Buttons can send NoteOn/NoteOff, CC# on press, CC# on press/release or Toggle CC#.
 * Button Pressed or Released values configurable per element
 * No NRPN support for buttons as have not needed 'em.
 */
#include <ResponsiveAnalogRead.h>
#include <Bounce.h>

const int      NUM_POTS  = 4; // number of Analog PINS
const int      POT_PINS             [NUM_POTS] = {  A2,   A0,    A1,     A3}; // Specify which pins are connected to Pots
const uint16_t POT_CONTROLLER_NUMBER[NUM_POTS] = {   1,    4,    15,   1234}; // CC#, Note# or we might be sending NRPN and need a 14-bit value here.
const uint16_t POT_INPUT_CENTER     [NUM_POTS] = { 400,  511,   511,    511}; // Useful for Center detent pots were detent spot is not at electrical center.
const uint16_t POT_DEADZONE_WIDTH   [NUM_POTS] = {  40,    0,     0,      0}; // Allows a dead zone to give us room to climb out of the detent before value changes.
const uint16_t POT_INPUT_MINIMUM    [NUM_POTS] = {   0,    0,     0,      0}; // Useful for pots where wiper does not reach track Min.
const uint16_t POT_INPUT_MAXIMUM    [NUM_POTS] = {1023, 1023,  1023,   1020}; //  "     "   "     "     "     "   "    "     "   Max.
const uint16_t POT_OUTPUT_MINIMUM   [NUM_POTS] = {   0,    0,     0,      0}; // Specify Output range Minimum.
const uint16_t POT_OUTPUT_MAXIMUM   [NUM_POTS] = { 127,  127,   255,   1023}; // Specify output range Maximum
const byte     POT_OUTPUT_TYPE      [NUM_POTS] = {   1,    1,     2,      3}; // 0=Muted, 1=7-bitCC, 2=MSB LSB CC, 3= NRPN.
const byte     POT_OUTPUT_CHANNEL   [NUM_POTS] = {  16,   16,    16,     16};
//******VARIABLES***********
uint16_t data   [NUM_POTS];
uint16_t dataLag[NUM_POTS]; // when lag and new are not the same then update MIDI CC value

ResponsiveAnalogRead analog[] {
  {POT_PINS[0], true},
  {POT_PINS[1], true},
  {POT_PINS[2], true},
  {POT_PINS[3], true}
};
//************************************************************

const int BOUNCE_TIME = 7; // 5 ms is usually sufficient
const int NUM_BUTTONS = 4; // number of Buttons connected to digital PINS

const int  BUTTON_PINS             [NUM_BUTTONS] = {  8,  11,  12,    3};// Which Pin is a Button on?
const byte BUTTON_CHANNEL          [NUM_BUTTONS] = { 16,  16,  16,   16};// What channel is the button sending on?
const int  BUTTON_CONTROLLER_NUMBER[NUM_BUTTONS] = {104, 103, 102,  105};// Could be CC# or Note#
const int  BUTTON_ON_VALUE         [NUM_BUTTONS] = {127, 127, 127,  127};// Specify a button pressed value
const int  BUTTON_OFF_VALUE        [NUM_BUTTONS] = {  0,   0,   0,    0};// Specify a button released value
const byte BUTTON_OUTPUT_TYPE      [NUM_BUTTONS] = {  1,   2,   4,    3};// 0=Muted, 1=Note On/Off, 2=CC Press, 3=CC Press/Release, 4=Toggle
int        BUTTON_TOGGLED          [NUM_BUTTONS]; //Array to hold toggled state

// initialize the bounce objects
  Bounce digital[] =   {
  Bounce(BUTTON_PINS[0], BOUNCE_TIME),
  Bounce(BUTTON_PINS[1], BOUNCE_TIME),
  Bounce(BUTTON_PINS[2], BOUNCE_TIME),
  Bounce(BUTTON_PINS[3], BOUNCE_TIME),
};

//*******************************************************************

void setup() {
  // loop to configure input pins and internal pullup resisters for digital section
  for (int i = 0; i < NUM_BUTTONS; i++) {
    pinMode(BUTTON_PINS[i], INPUT_PULLUP);
  }
}
//**********************************************

void loop() {
  while (usbMIDI.read()) {
    // controllers must call .read() to keep the queue clear even if they are not responding to MIDI
  }
  getDigitalData();
  getAnalogData();
}

//************ANALOG SECTION**************
void getAnalogData()
{
  for (int i = 0; i < NUM_POTS; i++) {
    analog[i].update();
    if (!analog[i].hasChanged())
      continue;
//With some help from @NominalAnimal

    const int32_t  OUTPUT_CENTER = (POT_OUTPUT_MINIMUM[i] + POT_OUTPUT_MAXIMUM[i]) / 2;
    const int32_t  input = analog[i].getValue();

    if (input <= POT_INPUT_MINIMUM[i]) {
      data[i] = POT_OUTPUT_MINIMUM[i];
    } else if (input < POT_INPUT_CENTER[i] - POT_DEADZONE_WIDTH[i]) {
      data[i] = map(input, POT_INPUT_MINIMUM[i], POT_INPUT_CENTER[i] - POT_DEADZONE_WIDTH[i], POT_OUTPUT_MINIMUM[i], OUTPUT_CENTER);
    } else if (input <= POT_INPUT_CENTER[i] + POT_DEADZONE_WIDTH[i]) {
      data[i] = OUTPUT_CENTER;
    } else if (input < POT_INPUT_MAXIMUM[i]) {
      data[i] = map(input, POT_INPUT_CENTER[i] + POT_DEADZONE_WIDTH[i], POT_INPUT_MAXIMUM[i], OUTPUT_CENTER, POT_OUTPUT_MAXIMUM[i]);
    } else {
      data[i] = POT_OUTPUT_MAXIMUM[i];
    }
    if (data[i] != dataLag[i]) {
      dataLag[i] = data[i];
      
      uint16_t  potmessage = data[i];      //has what the pot has just given us
  // Note we're using a uint16_t because we might be sending values higher than 127 with MSB/LSB CCs or NRPNs
  // and the following dance pulls out MSB/LSB and tosses out bits 14 and 15    
      byte     valueLSB   = (potmessage & 0b0000000001111111);
      byte     valueMSB   = (potmessage & 0b0011111110000000)  >> 7;
  // Similarly, we might be sending an NRPN 14-bit Controller number    
      byte     controlLSB = (POT_CONTROLLER_NUMBER[i]    & 0b0000000001111111);// POT_CONTROLLER_NUMBER[i], a uint16_t holds Control#
      byte     controlMSB = (POT_CONTROLLER_NUMBER[i]    & 0b0011111110000000) >> 7;

      switch (POT_OUTPUT_TYPE[i])// from POT_OUTPUT_TYPE definition
      {
        case 0:
          //muted, do nothing
          break;
        case 1:   // Sending 7-bit CC
          usbMIDI.sendControlChange   (controlLSB, valueLSB, (POT_OUTPUT_CHANNEL[i]));
          break;
        case 2:
          usbMIDI.sendControlChange    (controlLSB, valueMSB, (POT_OUTPUT_CHANNEL[i]));
          usbMIDI.sendControlChange    (controlLSB + 32, valueLSB, (POT_OUTPUT_CHANNEL[i]));
          break;
        case 3:
          usbMIDI.sendControlChange(99, controlMSB, (POT_OUTPUT_CHANNEL[i]));
          usbMIDI.sendControlChange(98, controlLSB, (POT_OUTPUT_CHANNEL[i]));
          usbMIDI.sendNrpnValue(data[i], (POT_OUTPUT_CHANNEL[i]));
          break;
      }
    }
  }
}
//************DIGITAL SECTION**************

void getDigitalData() {

  for (int i = 0; i < NUM_BUTTONS; i++) {
    digital[i].update();
    if (digital[i].fallingEdge()) {
      // Button is pressed
      switch (BUTTON_OUTPUT_TYPE[i]) {
        case 0:
          //Do nothing, MUTED
          break;
        case 1: //Note
          usbMIDI.sendNoteOn (BUTTON_CONTROLLER_NUMBER[i], (BUTTON_ON_VALUE[i]), (BUTTON_CHANNEL[i]));
          break;
        case 2: //PRESS
          usbMIDI.sendControlChange   (BUTTON_CONTROLLER_NUMBER[i], (BUTTON_ON_VALUE[i]), (BUTTON_CHANNEL[i]));
          break;
        case 3: //CC PRESS - RELEASE
          usbMIDI.sendControlChange   (BUTTON_CONTROLLER_NUMBER[i], (BUTTON_ON_VALUE[i]), (BUTTON_CHANNEL[i]));
          break;
        case 4: //Toggle
          if (BUTTON_TOGGLED[i] == 0) {
            usbMIDI.sendControlChange   (BUTTON_CONTROLLER_NUMBER[i], (BUTTON_ON_VALUE[i]), (BUTTON_CHANNEL[i]));
            BUTTON_TOGGLED[i] = 1;
          }
          else if (BUTTON_TOGGLED[i] == 1)
          {
            usbMIDI.sendControlChange   (BUTTON_CONTROLLER_NUMBER[i], (BUTTON_OFF_VALUE[i]), (BUTTON_CHANNEL[i]));
            BUTTON_TOGGLED[i] = 0;
          }
          break;
      }
    }
    if (digital[i].risingEdge()) {
      switch (BUTTON_OUTPUT_TYPE[i]) {
        case 0:
          //Do nothing - MUTED
          break;
        case 1:// Send Note Off
          usbMIDI.sendNoteOff (BUTTON_CONTROLLER_NUMBER[i], (BUTTON_OFF_VALUE[i]), (BUTTON_CHANNEL[i]));
          break;
        case 2: // Don't Send CC Release
          // MUTED
          break;
        case 3:  //  Send CC - RELEASE
          usbMIDI.sendControlChange   (BUTTON_CONTROLLER_NUMBER[i], (BUTTON_OFF_VALUE[i]), (BUTTON_CHANNEL[i]));
          break;
        case 4: // Dummy for TOGGLE
          break;
      }
    }
  }
}
 
Status
Not open for further replies.
Back
Top