Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 7 of 7

Thread: USB midi controllers for persons with special needs

  1. #1
    Junior Member
    Join Date
    Nov 2020
    Posts
    2

    USB midi controllers for persons with special needs

    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...hange-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.

  2. #2
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,392
    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.sendProgramChange(note[i], ON_VELOCITY, channel);  
        }
        // Note Off messages when each button is released
        if (digital[i].risingEdge()) {
          usbMIDI.sendProgramChange(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.

  3. #3
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,392
    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 by oddson; 11-26-2020 at 06:27 AM.

  4. #4
    Junior Member
    Join Date
    Nov 2020
    Posts
    2
    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.

    Click image for larger version. 

Name:	midicontrollers2.jpg 
Views:	12 
Size:	356.9 KB 
ID:	22634

    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.sendControlChange(CCID[i], ON_VELOCITY, channel);  
        }
        // Note Off messages when each button is released
        if (digital[i].risingEdge()) {
          usbMIDI.sendControlChange(CCID[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};
    const int note[D_PINS] = {60,61,62};
    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 CCID[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

  5. #5
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,392
    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

  6. #6
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,392
    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 = 1; // MIDI channel
    const int A_PINS = 3; // number of Analog PINS
    const int D_PINS = 3; // number of Digital PINS
    const int ON_VALUE = 127; // 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] = {A0,A1,A2};
    const int knobs[A_PINS] = {21,22,23}; // should have the same number of elements as A_PINS
    
    // define the pins and CC numbers for digital events
    const int DIGITAL_PINS[D_PINS] = {0,1,2};
    const int buttons[D_PINS] = {60,61,62};
    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[0],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},... -- comment used to limit initializing A_PINS by moving start tag*/
    }; 
    
    // 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), -- comment used to limit initializing D_PINS by moving start tag*/
    }; 
    
    //************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(knobs[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.sendControlChange(buttons[i], ON_VALUE, channel);  
        }
        // CC Off messages D2=0
        if (digital[i].risingEdge()) {
          usbMIDI.sendControlChange(buttons[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 by oddson; 11-26-2020 at 07:12 PM.

  7. #7
    Senior Member
    Join Date
    Aug 2019
    Location
    Melbourne Australia
    Posts
    204
    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;
          }
        }
      }
    }

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •