midi controller

Status
Not open for further replies.
Back to square A, I don't know how to add pointometers to the buttons sketch (which is the only one that works with the chain selector). I would be happy to forget the lights for now and just add pots to the buttons.
 
I finally get what the chain selector is after a quick search.

What you need is another array that holds what value is sent with the CC message instead of just off and on.

Then you can configure buttons on the same CC number but different values.

I'll need some time at a compiler and I'm not near one currently.

The other remaining issue is whether they latch or just fire the CC message when pressed and there is no OFF value sent and whether this is the same for all buttons or the behaviour of some buttons is still on-when-pressed or latching.
 
So each and every button sends a CC number and value, always the same and only on press and not on release?

So not latching and not ON when pressed and OFF when released. All buttons. Correct?
 
Code:
/* bespoke code example

   By Leif Oddson
   https://forum.pjrc.com/threads/56935-midi-controller

 
*/


//************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 = 6; // number of Analog PINS
[COLOR="#FF0000"]const int D_PINS = 12; // number of Digital PINS[/COLOR]

// 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,A3,A4,A5};
const int CCID[A_PINS] = {21,22,23,24,25,26};
[COLOR="#FF0000"]
// define the pins and notes for digital events
const int DIGITAL_PINS[D_PINS] = {0,1,2,3,4,5,6,7,8,9,10,11};
const int CCchainID[D_PINS] = {60,60,60,60,60,60,70,70,70,70,70,70};
const int CCchainVal[D_PINS] = {0,25,50,75,100,127,0,25,50,75,100,127};[/COLOR]
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},*/
}; 

// 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),
  Bounce(DIGITAL_PINS[8], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[9], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[10], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[11], 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(); // commented out to avoid garbage MIDI until you are ready with the analog voltage dividers
  getDigitalData();
  while (usbMIDI.read()) {
     // controllers must call .read() to keep the queue clear even if they are not responding to MIDI
  }
}


//************ANALOG SECTION**************   uncomment call from loop to make active when you are ready!
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.sendControlChange(CCchainID[i],CCchainVal[i],channel);
    }
  }
}
Here's an example that compiled but I don't have a Teensy handy to even do breadboard testing.

It's currently configured to support two sets of six buttons where each chain is a set of buttons and the second array holds the map points for the chain and the first array holds the two different CC numbers for the two chains.
 
For the lights? I would think press on latch. then unlatch when another button is pressed. The software seams to work with just note on note off. only problem is it also plays notes on the instruments as well. I'll have to try the code tomorrow. have a goodnight.
 
Well it loads but, same as others, it only registers the first button on the chain selector. Only difference is before when I hit the second button while holding down the first it would change the first, now it does nothing. The first button says cc#60 When I use the buttons sketch it says note C3 #48 to F3 #53.
 
Last edited:
Author of the MIDI Controller library here.

Going back to the original post, to use multiple potentiometers and buttons, you would use something like this:

Code:
#include <MIDI_Controller.h>

AnalogCC faders[] = {
    {A0, MIDI_CC::Channel_Volume, 1}, // Create a new instance of class 'AnalogCC' on pin A0, controller number 0x07 (channel volume), on MIDI channel 1.
    {A1, MIDI_CC::Channel_Volume, 2},
    {A2, MIDI_CC::Channel_Volume, 3},
    {A3, MIDI_CC::Channel_Volume, 4},
    {A4, MIDI_CC::Channel_Volume, 5},
    {A5, MIDI_CC::Channel_Volume, 6},
    {A6, MIDI_CC::Channel_Volume, 7},
    {A7, MIDI_CC::Channel_Volume, 8},
    // ...
};

DigitalCC buttons[] = {
    {2, 0x20, 1}, // Create a new instance of class 'DigitalCC' on pin 2, controller number 0x20, on MIDI channel 1.
    {3, 0x21, 1},
    {4, 0x22, 1},
    // ...
}

void setup() { }

void loop() { // Refresh all inputs
    MIDI_Controller.refresh();
}

If it still doesn't work, could you please post the exact code you tried, settings used in the IDE, and the exact error messages. This will help me to fix the library if necessary.

Thanks,
Pieter
 
Thank you. I missed a semicolon right before "void setup () ..." (I posted this on mobile).

If you add the semicolon after the bracket } before "void setup", does it compile?
 
This is making things to confusing, I have my breadboard set up for Odsons code, 6 buttons and 6 pots, If you want to contribute read the posts and understand where we are now or send something to try with that setup
 
The code I posted can be used with that setup.

If you want the exact code, try this:

Code:
#include <MIDI_Controller.h>

AnalogCC potentiometers[] = {
    {A0, MIDI_CC::Channel_Volume, 1}, // Create a new instance of class 'AnalogCC' on pin A0, controller number 0x07 (channel volume), on MIDI channel 1.
    {A1, MIDI_CC::Channel_Volume, 2},
    {A2, MIDI_CC::Channel_Volume, 3},
    {A3, MIDI_CC::Channel_Volume, 4},
    {A4, MIDI_CC::Channel_Volume, 5},
    {A5, MIDI_CC::Channel_Volume, 6},
};

DigitalCC buttons[] = {
    {2, 0x20, 1}, // Create a new instance of class 'DigitalCC' on pin 2, controller number 0x20, on MIDI channel 1.
    {3, 0x21, 1},
    {4, 0x22, 1},
    {5, 0x23, 1},
    {6, 0x24, 1},
    {7, 0x25, 1},
};

void setup() { }

void loop() { // Refresh all inputs
    MIDI_Controller.refresh();
}
This code expects 6 potentiometers on pins A0-A5, and 6 switches between pins 2-7 and ground. If you have them connected to different pins, just change them in the code.

The switches are debounced, and potentiometers are filtered.
 
I'm sorry, without more information, I cannot possibly help you.

Does it not send the correct MIDI messages, or does it not send any messages at all?
 
Well it loads but, same as others, it only registers the first button on the chain selector. Only difference is before when I hit the second button while holding down the first it would change the first, now it does nothing. The first button says cc#60 When I use the buttons sketch it says note C3 #48 to F3 #53.
You have to configure it... and you're going to have to start trying to read the code.

Forget the lights for now.

My code should let you configure any number of pins to send any arbitrary CC message when buttons cofigured to pull the pin to ground when pressed.

But you need to configure it and Abelton to work together and that assuming I've even figured out what you are trying to do (or trying to get me to do for you).
 
Code:
  //************LOOP**************
void loop() {
[COLOR="#0000FF"]  // [/COLOR]getAnalogData(); // commented out to avoid garbage MIDI until you are ready with the analog voltage dividers
  getDigitalData();
  while (usbMIDI.read()) {
     // controllers must call .read() to keep the queue clear even if they are not responding to MIDI
  }
}
....and remove the two slashes to make the analog section work once you've sorted out the buttons. But only with the pot's in place.
 
Could you at least just show me how to add 6 pots to this code?
Code:
/* Buttons to USB MIDI Example

   You must select MIDI from the "Tools > USB Type" menu

   To view the raw MIDI data on Linux: aseqdump -p "Teensy MIDI"

   This example code is in the public domain.
*/

#include <Bounce.h>

// the MIDI channel number to send messages
const int channel = 1;

// 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, 5);
Bounce button1 = Bounce(1, 5);  // 5 = 5 ms debounce time
Bounce button2 = Bounce(2, 5);  // which is appropriate for good
Bounce button3 = Bounce(3, 5);  // quality mechanical pushbuttons
Bounce button4 = Bounce(4, 5);
Bounce button5 = Bounce(5, 5);  // if a button is too "sensitive"
Bounce button6 = Bounce(6, 5);  // to rapid touch, you can
Bounce button7 = Bounce(7, 5);  // increase this time.
Bounce button8 = Bounce(8, 5);
Bounce button9 = Bounce(9, 5);
Bounce button10 = Bounce(10, 5);
Bounce button11 = Bounce(11, 5);

void setup() {
  // 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, INPUT_PULLUP);
  pinMode(1, INPUT_PULLUP);
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  pinMode(4, INPUT_PULLUP);
  pinMode(5, INPUT_PULLUP);
  pinMode(6, INPUT_PULLUP);  // Teensy++ 2.0 LED, may need 1k resistor pullup
  pinMode(7, INPUT_PULLUP);
  pinMode(8, INPUT_PULLUP);
  pinMode(9, INPUT_PULLUP);
  pinMode(10, INPUT_PULLUP);
  pinMode(11, INPUT_PULLUP); // Teensy 2.0 LED, may need 1k resistor pullup
}

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.
  button0.update();
  button1.update();
  button2.update();
  button3.update();
  button4.update();
  button5.update();
  button6.update();
  button7.update();
  button8.update();
  button9.update();
  button10.update();
  button11.update();

  // Check each button 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)
  if (button0.fallingEdge()) {
    usbMIDI.sendNoteOn(60, 99, channel);  // 60 = C4
  }
  if (button1.fallingEdge()) {
    usbMIDI.sendNoteOn(61, 99, channel);  // 61 = C#4
  }
  if (button2.fallingEdge()) {
    usbMIDI.sendNoteOn(62, 99, channel);  // 62 = D4
  }
  if (button3.fallingEdge()) {
    usbMIDI.sendNoteOn(63, 99, channel);  // 63 = D#4
  }
  if (button4.fallingEdge()) {
    usbMIDI.sendNoteOn(64, 99, channel);  // 64 = E4
  }
  if (button5.fallingEdge()) {
    usbMIDI.sendNoteOn(65, 99, channel);  // 65 = F4
  }
  if (button6.fallingEdge()) {
    usbMIDI.sendNoteOn(66, 99, channel);  // 66 = F#4
  }
  if (button7.fallingEdge()) {
    usbMIDI.sendNoteOn(67, 99, channel);  // 67 = G4
  }
  if (button8.fallingEdge()) {
    usbMIDI.sendNoteOn(68, 99, channel);  // 68 = G#4
  }
  if (button9.fallingEdge()) {
    usbMIDI.sendNoteOn(69, 99, channel);  // 69 = A5
  }
  if (button10.fallingEdge()) {
    usbMIDI.sendNoteOn(70, 99, channel);  // 70 = A#5
  }
  if (button11.fallingEdge()) {
    usbMIDI.sendNoteOn(71, 99, channel);  // 71 = B5
  }

  // 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)
  if (button0.risingEdge()) {
    usbMIDI.sendNoteOff(60, 0, channel);  // 60 = C4
  }
  if (button1.risingEdge()) {
    usbMIDI.sendNoteOff(61, 0, channel);  // 61 = C#4
  }
  if (button2.risingEdge()) {
    usbMIDI.sendNoteOff(62, 0, channel);  // 62 = D4
  }
  if (button3.risingEdge()) {
    usbMIDI.sendNoteOff(63, 0, channel);  // 63 = D#4
  }
  if (button4.risingEdge()) {
    usbMIDI.sendNoteOff(64, 0, channel);  // 64 = E4
  }
  if (button5.risingEdge()) {
    usbMIDI.sendNoteOff(65, 0, channel);  // 65 = F4
  }
  if (button6.risingEdge()) {
    usbMIDI.sendNoteOff(66, 0, channel);  // 66 = F#4
  }
  if (button7.risingEdge()) {
    usbMIDI.sendNoteOff(67, 0, channel);  // 67 = G4
  }
  if (button8.risingEdge()) {
    usbMIDI.sendNoteOff(68, 0, channel);  // 68 = G#4
  }
  if (button9.risingEdge()) {
    usbMIDI.sendNoteOff(69, 0, channel);  // 69 = A5
  }
  if (button10.risingEdge()) {
    usbMIDI.sendNoteOff(70, 0, channel);  // 70 = A#5
  }
  if (button11.risingEdge()) {
    usbMIDI.sendNoteOff(71, 0, channel);  // 71 = B5
  }

  // 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
  }
}
 
If I add pots to that code it will do what my original example code already does.

My code at post 55 should work when configured. Unless I still don't understand chains and controlling with CC values.

I don't know that you are up to programming with loops and arrays yet.
 
The code at #55 doesn't work with the chain selector. as I tried to explain in post #57. it only sends cc 60. I don't know what makes it work or where it differs from your code but the buttons code in #67 is the only one I've found that works with the chain selector and I've been searching for days. If I could just add some pots to that sketch I could get up and running. If you know how to add an analog section Please show me. I've been trying this also for days. You're right I am not up to programming with loops and arrays.
 
Status
Not open for further replies.
Back
Top