[photo needed] How to make a midi controller with 16 analog inputs using Teensy LC!

Hi everyone!
Here's how to make a USB midi controller for dirt cheap!
This controller has 16 analog inputs.

what you'll need:

1 Teensy LC ---> buy from pjrc ($11.65)
1 CD74HC4067 breakout board ---> buy from sparkfun ($4.95)
1 to 16 10k linear B potentiometers. ---> buy from ebay (5pc for $1.25)
1 Breadboard -----> buy from ebay ($1.50)
Wire....pennies per ft! buy lots because its always handy to have lots of.

Step 1:
Once you have all these items wire them up together like this...for simplicity sake only 3 potentiometers are shown but you can connect 16, just remember to connect any additional pots to +/- and the center pins of the potentiometers go to the "C" pins on the red breakout board.
i63aWzf.jpg


Step 2:
Install Arduino 1.8.4 (newer versions don't support teensy LC yet :( )
Get it here ---> https://www.arduino.cc/en/Main/OldSoftwareReleases

Step 3:
Install the Teensy loader application
Get it here ---> https://www.pjrc.com/teensy/loader.html

Step 4:
Plug your Teensy into your computer via usb...

Step 5:
Open Arduino 1.8.4 and click "tools" and then set the board type to Teensy LC
mBqmiNm.png


Step 6:
Click tools and also set the USB type to MIDI
qLzFDnu.png


Step 7:
Delete the "void setup" and "loop setup" code so you have a nice blank page in arduino.
ViDcOmL.png

Step 8:
Paste this code into the blank page
//************LIBRARIES USED**************
// include the ResponsiveAnalogRead library for analog smoothing
#include <ResponsiveAnalogRead.h>
//usbMIDI.h library is added automatically when code is compiled as a MIDI device

// ******CONSTANT VALUES********
// customize code behaviour here!
const int muxTimeMin = 500; // minimum micro-seconds between MUX reads
const int channel = 1; // MIDI channel
const int MUX_PINS = 16; // number of MUX Channnels

// define the CC ID numbers on which to send them..

const int CCID[MUX_PINS] = {70,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36};


//******VARIABLES***********
// a data array and a lagged copy to tell when MIDI changes are required
byte data[MUX_PINS];
byte dataLag[MUX_PINS]; // when lag and new are not the same then update MIDI CC value
byte i=0; // global index for MUX channel reads

//mapping of mux to teensy digital pins
int pin_Out_S0 = 4;
int pin_Out_S1 = 3;
int pin_Out_S2 = 2;
int pin_Out_S3 = 1;
int pin_In_Mux1 = A0;


//****** TIMER VARIABLE *** change scale here!
elapsedMicros mux1Updated; // switch to micros to run at speed and tune with muxTimeMin setting above
//elapsedMillis mux1Updated; // switch to millis to troubleshoot

//************INITIALIZE LIBRARY OBJECTS**************
// initialize the ReponsiveAnalogRead objects
ResponsiveAnalogRead analog[]{
{pin_In_Mux1 ,true},
{pin_In_Mux1 ,true},
{pin_In_Mux1 ,true},
{pin_In_Mux1 ,true},
{pin_In_Mux1 ,true},
{pin_In_Mux1 ,true},
{pin_In_Mux1 ,true},
{pin_In_Mux1 ,true},
{pin_In_Mux1 ,true},
{pin_In_Mux1 ,true},
{pin_In_Mux1 ,true},
{pin_In_Mux1 ,true},
{pin_In_Mux1 ,true},
{pin_In_Mux1 ,true},
{pin_In_Mux1 ,true},
{pin_In_Mux1 ,true}
};



//************SETUP**************
void setup() {
//! don't forget to set for output!
pinMode(pin_Out_S0, OUTPUT);
pinMode(pin_Out_S1, OUTPUT);
pinMode(pin_Out_S2, OUTPUT);
pinMode(pin_Out_S3, OUTPUT);
}

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


//************MUX SECTION**************
void nextMUXpin(){
if (mux1Updated>muxTimeMin) {
// update the ResponsiveAnalogRead object every loop
analog.update();
// if the repsonsive value has change, print out 'changed'
if(analog.hasChanged()) {
data = analog.getValue()>>3;
if (data != dataLag){
dataLag = data;
usbMIDI.sendControlChange(CCID, data, channel);
serialPringMIDIdata(); // use to troublshoot
}
}

//reset timer
mux1Updated = 0;
//increment index
i++;
if (i>15) {i=0;}
// set mux control pins for next pass
digitalWrite(pin_Out_S0, HIGH && (i & B00000001));
digitalWrite(pin_Out_S1, HIGH && (i & B00000010));
digitalWrite(pin_Out_S2, HIGH && (i & B00000100));
digitalWrite(pin_Out_S3, HIGH && (i & B00001000));
}
}

// **useful for debugging, comment out function call to run full speed
void serialPringMIDIdata(){
Serial.print(i,DEC);
Serial.print(" :");
Serial.print(HIGH && (i & B00000001),BIN);
Serial.print(HIGH && (i & B00000010),BIN);
Serial.print(HIGH && (i & B00000100),BIN);
Serial.print(HIGH && (i & B00001000),BIN);
Serial.print(" MUX_PIN: ");
Serial.print(i,DEC);
Serial.print(" CC: ");
Serial.print(CCID,DEC);
Serial.print(" DATA HEX: ");
Serial.println(data,HEX);
}


This code was made by the user oddson here at the Teensy forum (https://forum.pjrc.com) ...HERE is a link to the full thread if you're bored and wanna see how he developed it. I made some very small changes to the code he posted in order to make this code work with the wiring in my diagram above. He has mentioned that there is another verson of this code in the thread but I havn't had a chance to try it out yet.

To set the CC values of the C0 pins on the red breakoutboard, change the values in the "const int CCID[MUX_PINS] = {70,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36};" to whatever you want! left to right (70 to 36) are c0 to c15

Step 9:
Click "verify"
UCf5PQJ.png

Wait a little while and allow the arduino software to verify and compile the code.

Step 10:
Once its done compiling, click "upload"
twCl2Hg.png


Step 11:
Plug your fancy new DIY midi controller into whatevers you want and play around with it!

Note: I made this project to increase the number of analog inputs for a cool synth creation board called "Axoloti" you can check it out here: http://www.axoloti.com/ its awesome!
 
I believe it's preferable to power the MUX from Vin (5v) and ground it to the GND pin.

The device is supposed to work better (lower on resistance, more linear output) with the higher supply voltage and it's return should not be to the analog ground (as it may introduce additional noise).

FYI - the other version doesn't use the (excellent!) ResponsiveAnalogRead(RAR) library to keep the voltages stable enough to use for MIDI CC values, relying instead on simple 'dead-band' control where changes less than some threshold are ignored.
 
Can you provide example code with 2+ multiplexers? For example, use your example above for 16 analog inputs with one multiplexer and add a second multiplexer for 16 digital inputs, so on and so forth. Thanks for your help in advance. Cheers.
 
Sorry I thought you were asking the OP to do this but now I realize that's my code so I guess you're asking for me to do this.

I'm don't have the compiler handy ATM but here's my attempt from just a text editor (which means it almost certainly will contain an error or two):
Code:
//************LIBRARIES USED**************
// include the ResponsiveAnalogRead library for analog smoothing
#include <ResponsiveAnalogRead.h>
//usbMIDI.h library is added automatically when code is compiled as a MIDI device

// ******CONSTANT VALUES******** 
// customize code behaviour here!
const int muxTimeMin = 500; // minimum micro-seconds between MUX reads 
const int channel = 1; // MIDI channel
const int MUX_PINS = 16; // number of MUX Channnels

// define the CC ID numbers on which to send them..

const int CCID1[MUX_PINS] = {21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36};

const int CCID2[MUX_PINS] = {41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56};


//******VARIABLES***********

// a data array and a lagged copy to tell when MIDI changes are required
byte data1[MUX_PINS];
byte data1Lag[MUX_PINS]; // when lag and new are not the same then update MIDI CC value

//amd again for second MUX
byte data2[MUX_PINS];
byte data2Lag[MUX_PINS]; // ditto

byte i=0; // global index for MUX channel reads

//mapping of mux to teensy digital pins
int pin_Out_S0 = 0;
int pin_Out_S1 = 1;
int pin_Out_S2 = 2;
int pin_Out_S3 = 3;
int pin_In_Mux1 = A1;
int pin_In_Mux2 = A2;


//****** TIMER VARIABLE *** change scale here!
elapsedMicros muxUpdated; // switch to micros to run at speed and tune with muxTimeMin setting above
//elapsedMillis muxUpdated; // switch to millis to troubleshoot 

//************INITIALIZE LIBRARY OBJECTS**************
// initialize the ReponsiveAnalogRead objects
ResponsiveAnalogRead analog1[]{
  {pin_In_Mux1 ,true},
  {pin_In_Mux1 ,true},
  {pin_In_Mux1 ,true},
  {pin_In_Mux1 ,true},
  {pin_In_Mux1 ,true},
  {pin_In_Mux1 ,true},
  {pin_In_Mux1 ,true},
  {pin_In_Mux1 ,true},
  {pin_In_Mux1 ,true},
  {pin_In_Mux1 ,true},
  {pin_In_Mux1 ,true},
  {pin_In_Mux1 ,true},
  {pin_In_Mux1 ,true},
  {pin_In_Mux1 ,true},
  {pin_In_Mux1 ,true},
  {pin_In_Mux1 ,true}
}; 

ResponsiveAnalogRead analog2[]{
  {pin_In_Mux2 ,true},
  {pin_In_Mux2 ,true},
  {pin_In_Mux2 ,true},
  {pin_In_Mux2 ,true},
  {pin_In_Mux2 ,true},
  {pin_In_Mux2 ,true},
  {pin_In_Mux2 ,true},
  {pin_In_Mux2 ,true},
  {pin_In_Mux2 ,true},
  {pin_In_Mux2 ,true},
  {pin_In_Mux2 ,true},
  {pin_In_Mux2 ,true},
  {pin_In_Mux2 ,true},
  {pin_In_Mux2 ,true},
  {pin_In_Mux2 ,true},
  {pin_In_Mux2 ,true}
}; 


//************SETUP**************
void setup() {
  //! don't forget to set for output!
  pinMode(pin_Out_S0, OUTPUT);
  pinMode(pin_Out_S1, OUTPUT);
  pinMode(pin_Out_S2, OUTPUT);
  pinMode(pin_Out_S3, OUTPUT);
}

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


//************MUX SECTION**************
void nextMUXpin(){  
  if (muxUpdated>muxTimeMin) {  
    // update the ResponsiveAnalogRead object every loop

// read PIN i of MUX 1
    analog1[i].update(); 
    // if the repsonsive value has change, print out 'changed'
    if(analog1[i].hasChanged()) {
      data1[i] = analog1[i].getValue()>>3;
      if (data1[i] != data1Lag[i]){
        data1Lag[i] = data1[i];
        usbMIDI.sendControlChange(CCID1[i], data1[i], channel);
      }
    }  


// read PIN i of MUX 2
    analog2[i].update(); 
    // if the repsonsive value has change, print out 'changed'
    if(analog2[i].hasChanged()) {
      data2[i] = analog2[i].getValue()>>3;
      if (data2[i] != data2Lag[i]){
        data2Lag[i] = data2[i];
        usbMIDI.sendControlChange(CCID2[i], data2[i], channel);
      }
    }

    //reset timer
    muxUpdated = 0; 
    //increment index
    i++;
    if (i>15)   {i=0;}      
    // set mux control pins for next pass
    digitalWrite(pin_Out_S0, HIGH && (i & B00000001));
    digitalWrite(pin_Out_S1, HIGH && (i & B00000010));
    digitalWrite(pin_Out_S2, HIGH && (i & B00000100));
    digitalWrite(pin_Out_S3, HIGH && (i & B00001000));
  }
}
I'll compile and troubleshoot it when I get a chance or you can have a go at it.

If there were enough MUX I'd switch to a two-dimensional array system loop through each MUX instead of having separate data structures for each.
 
I'll compile and troubleshoot it when I get a chance or you can have a go at it...
Nice it compiled first time... I almost always miss terminating semi-colons or getting the braces wrong on control structures.

But there is still (potentially) troubleshooting if there is a logical error in the coding I've added.

I don't have the gear to do full testing and even to do a basic functionality test I have to fake the one MUX breakout board I have to look like two and to ground all the MUX but the input or two with pots on them.

So I'll wait to hear whether it works or not before wiring it up.
 
I've just taken an interest in building a midi controller as I need one with a whole bunch of pots, so this thread caught my eye. I have extremely limited coding experience, so this will be super helpful. Cheers!

However, I've been wondering a couple of things. Please bear with my newb-ishness:

1. What code would be added to utilize the remaining analog inputs on the board, to bring the total number of potentiometers up to 27? I've been comparing this code to other, simpler (non-multiplexer using) projects and they're so different, I have no idea how to even start to go about it.

2. On that note, other examples of code I've looked at seem to divide the readings from the pots by 8, in order to make it within the range that midi uses. I can't see where that's happening in this code, which is also confusing me.

Again, I obviously have no idea what I'm doing regarding the coding side of things, so any help getting this going would be very much appreciated. Already a huge time saver having the code for 16 pots handed to me, so I feel perhaps a bit greedy asking to boost it up to 27.
 
2. On that note, other examples of code I've looked at seem to divide the readings from the pots by 8, in order to make it within the range that midi uses. I can't see where that's happening in this code, which is also confusing me.

It's done here:

Code:
      data1[i] = analog1[i].getValue()>>3;

The ">>3" means to shift the bits by 3 positions, which is a very efficient way to divide by 8.
 
1. What code would be added to utilize the remaining analog inputs on the board, to bring the total number of potentiometers up to 27? I've been comparing this code to other, simpler (non-multiplexer using) projects and they're so different, I have no idea how to even start to go about it.

Many simple controllers use separate variables for each control and have long, but fairly easy to follow conditional logic structures testing each to look for new events to trigger midi.

Once you get a lot of controls arrays of data and a common logic test structure keep the code tight and easy to write and maintain. It also makes it simpler to add features like mux support. But you need to understand indexed loops and data arrays.

Add in having to control the mux itself and the code starts to look quite different from a simple controller that tests each pin with separate statements.

27 pots could be done with two 16 channel using the code I posted above and just leave a few mux pins grounded so they don't generate noise signals. You could also use 1 mux and a bunch of pins directly.... but mixing mux'd and direct pins would need two different data structures or some clever way to merge them together. I could cludge together the non-clever version pretty quickly if you are in tested (but I can't test it as I'm away from my Teensy desk).
 
Oh... but if you're noob to this then please start with a couple simpler projects first before getting adding MUX into the mix.

Your comments hint you have a clue about what's going on but it's very common for people to be too ambitious in their first midi project.
 
It's done here:

Code:
      data1[i] = analog1[i].getValue()>>3;

The ">>3" means to shift the bits by 3 positions, which is a very efficient way to divide by 8.

Thanks, wouldn't have figured this out just from scouring through the code repeatedly.

oddson:

Thanks for the information, and offer of a solution. I'm certainly interested.

Haha, yep I'm aware of over ambition when it comes to new projects. This will in fact be my second midi controller after I finish my current project, for which I used a guide with provided code. I just altered it slightly to add some more buttons, but it was much easier for me to understand than the code found here. When I saw this thread I took interest because code was provided, and I could focus on the physical aspect of the build. Then I released how practical this controller would be for me with additional pots. And then, "how cool would it be if all the pots have LED lights activated when turned". At that point I have to say no, take a step back for now. :p
 
I'm happy to provide ready-to-run sketches for stock features.

I have a standard structure that allows for easy extension of features
https://forum.pjrc.com/threads/45376-Example-code-for-MIDI-controllers-with-Pots-and-Buttons

It's not as simple as some because it relies on arrays, loops and index variables but these give it flexibility.

And the code in this thread, while still untested, should support 32 mux channels.

But I'm not a free development service so if you want fancy features you'll have to learn a bit of coding.

But also don't underestimate the physical build and getting your wiring correct. Especially with mux and all those wires.
 
I'm somewhat familiar with arrays and loops from doing a bit of learning (relatively simple) game development, but looking at code I didn't write personally can be a bit of a headspin still. I'll save that code from the thread and have a proper look through it until I understand it better.

Yeah, the build is likely going to have some problems, which is why I'm starting with the smaller project (much less controls/wires) before the one in this thread. Have some soldering experience from building a guitar recently, but haven't soldered wires to a board before. Have watched plenty of youtube vids, but it looks like a delicate process that will take practice.

Thanks again.
 
So, another question. Can you provide additional code that would incorporate three sixteen channel mux - two for analog )pot) input and one for digital(pushbutton) input? Thanks.
 
I believe the additions are something like these:

Code:
#include <Bounce.h>  // need the bounce library to stabilize signals from switch contacts

....

const int pin_In_Mux3 = 4; // data pin of 'digital' MUX


...

const BOUNCE_TIME = 15; // debounce time -- higher is more stable, lower more responsive

...

const int note[MUX_PINS] = {48,49,50,54,52,53,54,55,56,57,58,59}; // note values for MUX3 (digital section)

...

// initialize the bounce objects all to the same MUX data pin
Bounce digital[] =   {
  Bounce(pin_In_Mux3,BOUNCE_TIME), 
  Bounce(pin_In_Mux3,BOUNCE_TIME), 
  Bounce(pin_In_Mux3,BOUNCE_TIME), 
  Bounce(pin_In_Mux3,BOUNCE_TIME), 
  Bounce(pin_In_Mux3,BOUNCE_TIME), 
  Bounce(pin_In_Mux3,BOUNCE_TIME), 
  Bounce(pin_In_Mux3,BOUNCE_TIME), 
  Bounce(pin_In_Mux3,BOUNCE_TIME), 
  Bounce(pin_In_Mux3,BOUNCE_TIME), 
  Bounce(pin_In_Mux3,BOUNCE_TIME), 
  Bounce(pin_In_Mux3,BOUNCE_TIME), 
  Bounce(pin_In_Mux3,BOUNCE_TIME), 
  Bounce(pin_In_Mux3,BOUNCE_TIME), 
  Bounce(pin_In_Mux3,BOUNCE_TIME), 
  Bounce(pin_In_Mux3,BOUNCE_TIME), 
  Bounce(pin_In_Mux3,BOUNCE_TIME)
}; 

...

// read PIN i of MUX 3 (DIGITAL!)
  digital[i].update();
    if (digital1[i].fallingEdge()) {
      usbMIDI.sendNoteOn(note[i], ON_VELOCITY, channel);  
    }
    // Note Off messages when each button is released
    if (digital1[i].risingEdge()) {
      usbMIDI.sendNoteOff(note[i], 0, channel);  
    }
  }

I'll paste them into the sketch when I'm at the compiler next and see if it compiles but I'm not going to do much (if any) testing.

(These are lifted almost 'as is' from my Pots and Buttons example code https://forum.pjrc.com/threads/45376-Example-code-for-MIDI-controllers-with-Pots-and-Buttons)
 
So the digital section is for noteOn / noteOff messages with on at contact and off at release. That's what you want?
 
There were the usual number of missing semi-colon's and inconsistant variable names (digital or digital1 for the data array?) but it was pretty simple to get it to compile.

Then I read through and reorganized the variables and constants a bit so hopefully you can figure out how to configure it.
Code:
//************LIBRARIES USED**************
// include the ResponsiveAnalogRead library for analog smoothing
#include <ResponsiveAnalogRead.h>
#include <Bounce.h>  // need the bounce library to stabilize signals from switch contacts
//usbMIDI.h library is added automatically when code is compiled as a MIDI device

// ******CONSTANT VALUES******** 
// customize code behaviour here!

//**TIMING -- higher is more stable, lower more responsive
const int muxTimeMin = 500; // minimum micro-seconds between MUX reads - 500 = half a millisecond!
const int BOUNCE_TIME = 15; // max time before the physical contacts of switches settle. 

//**HARDWARE
const int MUX_PINS = 16; // number of MUX Channnels
//mux control out pin assignement
const int pin_Out_S0 = 0;
const int pin_Out_S1 = 1;
const int pin_Out_S2 = 2;
const int pin_Out_S3 = 3;
//data from mux pin assignement
const int pin_In_Mux1 = A1;
const int pin_In_Mux2 = A2;
const int pin_In_Mux3 = 4; // data pin of 'digital' MUX

//**MIDI 
const int channel = 1; // MIDI channel
const int CCID1[MUX_PINS] = {21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36}; // CC (D1) values for analog MUX one
const int CCID2[MUX_PINS] = {41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56}; // CC (D1) values for analog MUX two
const int note[MUX_PINS] = {48,49,50,54,52,53,54,55,56,57,58,59}; // note values for MUX3 (digital section)
const int ON_VELOCITY = 105; // note velocity for note on events


//******VARIABLES***********

// a data array and a lagged copy to tell when MIDI changes are required
byte data1[MUX_PINS];
byte data1Lag[MUX_PINS]; // when lag and new are not the same then update MIDI CC value

//amd again for second MUX
byte data2[MUX_PINS];
byte data2Lag[MUX_PINS]; // ditto

//third mux don't need memory!

//NB - index variable i is incremented and rolled over manually inside the main loop so that on each pass one MUX pin is read.
byte i=0; // global index for MUX channel reads 


//****** TIMER VARIABLE *** change scale here!
elapsedMicros muxUpdated; // switch to micros to run at speed and tune with muxTimeMin setting above
//elapsedMillis muxUpdated; // switch to millis to troubleshoot 

//************INITIALIZE LIBRARY OBJECTS**************
// initialize the ReponsiveAnalogRead objects
ResponsiveAnalogRead analog1[]{
  {pin_In_Mux1 ,true},
  {pin_In_Mux1 ,true},
  {pin_In_Mux1 ,true},
  {pin_In_Mux1 ,true},
  {pin_In_Mux1 ,true},
  {pin_In_Mux1 ,true},
  {pin_In_Mux1 ,true},
  {pin_In_Mux1 ,true},
  {pin_In_Mux1 ,true},
  {pin_In_Mux1 ,true},
  {pin_In_Mux1 ,true},
  {pin_In_Mux1 ,true},
  {pin_In_Mux1 ,true},
  {pin_In_Mux1 ,true},
  {pin_In_Mux1 ,true},
  {pin_In_Mux1 ,true}
}; 

ResponsiveAnalogRead analog2[]{
  {pin_In_Mux2 ,true},
  {pin_In_Mux2 ,true},
  {pin_In_Mux2 ,true},
  {pin_In_Mux2 ,true},
  {pin_In_Mux2 ,true},
  {pin_In_Mux2 ,true},
  {pin_In_Mux2 ,true},
  {pin_In_Mux2 ,true},
  {pin_In_Mux2 ,true},
  {pin_In_Mux2 ,true},
  {pin_In_Mux2 ,true},
  {pin_In_Mux2 ,true},
  {pin_In_Mux2 ,true},
  {pin_In_Mux2 ,true},
  {pin_In_Mux2 ,true},
  {pin_In_Mux2 ,true}
}; 
// initialize the bounce objects all to the same MUX data pin
Bounce digital[] =   {
  Bounce(pin_In_Mux3,BOUNCE_TIME), 
  Bounce(pin_In_Mux3,BOUNCE_TIME), 
  Bounce(pin_In_Mux3,BOUNCE_TIME), 
  Bounce(pin_In_Mux3,BOUNCE_TIME), 
  Bounce(pin_In_Mux3,BOUNCE_TIME), 
  Bounce(pin_In_Mux3,BOUNCE_TIME), 
  Bounce(pin_In_Mux3,BOUNCE_TIME), 
  Bounce(pin_In_Mux3,BOUNCE_TIME), 
  Bounce(pin_In_Mux3,BOUNCE_TIME), 
  Bounce(pin_In_Mux3,BOUNCE_TIME), 
  Bounce(pin_In_Mux3,BOUNCE_TIME), 
  Bounce(pin_In_Mux3,BOUNCE_TIME), 
  Bounce(pin_In_Mux3,BOUNCE_TIME), 
  Bounce(pin_In_Mux3,BOUNCE_TIME), 
  Bounce(pin_In_Mux3,BOUNCE_TIME), 
  Bounce(pin_In_Mux3,BOUNCE_TIME)
}; 

//************SETUP**************
void setup() {
  //! don't forget to set for output!
  pinMode(pin_Out_S0, OUTPUT);
  pinMode(pin_Out_S1, OUTPUT);
  pinMode(pin_Out_S2, OUTPUT);
  pinMode(pin_Out_S3, OUTPUT);
}

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


//************MUX SECTION**************
void nextMUXpin(){  
  if (muxUpdated>muxTimeMin) {  
    // update the ResponsiveAnalogRead object every loop

// read PIN i of MUX 1
    analog1[i].update(); 
    // if the repsonsive value has change, print out 'changed'
    if(analog1[i].hasChanged()) {
      data1[i] = analog1[i].getValue()>>3;
      if (data1[i] != data1Lag[i]){
        data1Lag[i] = data1[i];
        usbMIDI.sendControlChange(CCID1[i], data1[i], channel);
      }
    }  


// read PIN i of MUX 2
    analog2[i].update(); 
    // if the repsonsive value has change, print out 'changed'
    if(analog2[i].hasChanged()) {
      data2[i] = analog2[i].getValue()>>3;
      if (data2[i] != data2Lag[i]){
        data2Lag[i] = data2[i];
        usbMIDI.sendControlChange(CCID2[i], data2[i], channel);
      }
    }

// read PIN i of MUX 3 (DIGITAL!)
    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);  
      }
    }
    
    //reset timer
    muxUpdated = 0; 
    //increment index
    i++;
    if (i>15)   {i=0;}      
    // set mux control pins for next pass
    digitalWrite(pin_Out_S0, HIGH && (i & B00000001));
    digitalWrite(pin_Out_S1, HIGH && (i & B00000010));
    digitalWrite(pin_Out_S2, HIGH && (i & B00000100));
    digitalWrite(pin_Out_S3, HIGH && (i & B00001000));
  }

There is a very strong probability that errors remain. If we're lucky they are of the 'every-so-often' variety and not the 'nothing is working' type.

I'm very limited in being able to test this so I make no promises should there be any crippling errors when you go to try it out; other than I'll do what I can with what time I can spare. :)
 
Everything compiled and thank you for creating both CC events and note on/note off. This will take me a couple of weeks to actually build. I will post the results because as a musician, this is a midi controller I would be very interested in building to control my DAW, i.e. Cantabile, Reaper, etc.

Colin
 
Any chance you could add a youtube video or at least a couple photos?

We don't have a lot of requirements to show this on the home page & blog, but there must be at least a photo of the actual build.
 
It seems that the digital section of this is outputting all the notes when any button is pressed form the circuit I am testing. I have each button wired directly into the MUX inputs then the other terminal going to 5V (GND didn't work?). I'm assuming this has something to do with pullup resistors. Any help would be greatly appreciated.
 
Attention, the Teensy LC is NOT 5V tolerant. 5V will kill it. See the backside of the card.
Use 3V instead.
 
Back
Top