Hi everyone!
Here's how to make a USB midi controller for dirt cheap!
This one has has a red breakoutboard that you can attach 16 analog potentiometers to.
The user @SmashedTransistors reminded me that If you choose to utilize the remaining analog inputs on the Teensy then this project will end up adding up to 27 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.
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
Step 6:
Click tools and also set the USB type to MIDI
Step 7:
Delete the "void setup" and "loop setup" code so you have a nice blank page in arduino.
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[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);
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[i],DEC);
Serial.print(" DATA HEX: ");
Serial.println(data[i],HEX);
}
It was made by the user oddson over 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.
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"
Wait a little while and allow the arduino software to verify and compile the code.
Step 10:
Once its done compiling, click "upload"
Step 11:
Plug your fancy new DIY midi controller into the axoloti and enjoy!
Note: this USB midi controller is gunna take up your USB port..not ideal if you want to use a USB keyboard....I'll make another tutorial on how to hardwire one of these directly to the MIDI in pins once I figure it out...many people have attempted to help me so far but I'm pretty dense and haven't been able to get it to work yet....