Feb 13, 2013

A while back, Fuzzy Wobble outlined the construction of a MIDI controller, and is even building a brain for the Teensy++. This brain should prove very useful when it is released.

In the meantime, something similar must be built.


(Sharp eyes will notice that Chip A is soldered into the wrong pins. This has been corrected.)

Version 1.5 of this brain includes a slightly cleaner layout than the original. Standoffs raise it up a few millimeters, while right angle header pins connect the necessary controls without increasing vertical space requirements.

The Teensy++ only has 8 analog inputs, and this project requires quite a few more, a multiplex chip is used to read analog input and send it to the microcontroller. The Texas Instruments CD4067BE multiplex chips provide 16 analog inputs/outputs per chip, while only requiring 1 analog and 4 digital per chip to the microcontroller.

The code for the multiplex chip sends a binary digit via pins ABCD, querying the state of the appropriate pin. The chip then sends the analog value to one of the microcontroller’s analog inputs. This happens very quickly, of course. The microcontroller’s job is to convert that analog data into useful MIDI data. It is briefly described in the code.

Please feel free to use this code in your own project, or continue following. Future posts may be easier to understand.

Psuedocode:
>Send binary 0000 to the mux chip
>Receive analog data from pin 0
>Send binary 0001 to the mux chip
>Receive analog data from pin 1
>(repeat for all pins, and loop)

Actual code:

/*-----------------------------------------------------------------------------------
Pot Mux Module

This sketch is based on Skot McDonald's code, found at http://artifactory.org.au/ .
It is also based on example sketches from http://www.arduino.cc .

It tells a CD4067BE analog multiplexer to send data from 1-16 analog sources (knobs)
attached to a single analog input. It then sends usb midi data out, with each knob
assigned CC# based on the sequence in the cc4knob array.

Be careful if you use an "Auto Format" function, as it breaks the arrays!

http://www.fakecomputermusic.com
-----------------------------------------------------------------------------------*/

//Sets up which pins are used
#define muxPinA 10
#define muxPinB 11
#define muxPinC 12
#define muxPinD 13
#define analogReadPin 38

#define midiChannel 1

// Sets pot smoothing tolerances
#define sensorTolerance 16
#define ccTolerance 2

int knobAmount = 3; //How many knob are available. Don't forget to change the array!
int cc4knob[3] = {1, 2, 3}; //CC1, CC2, CC3 ...

//example for 16 knobs:
//int cc4knob[16] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};

int ccValue[8]; // Value of the knob (MIDI CC range: [0,127]
int sensorValue[8]; // value from the analog input (Analogue Input range [0,1023])

// Sets inital values for bitReads
int r0 = 0;
int r1 = 0;
int r2 = 0;
int r3 = 0;

//==============================================================================
void setup()
{
// Setup the 4 input selection control pins
pinMode(muxPinA, OUTPUT);
pinMode(muxPinB, OUTPUT);
pinMode(muxPinC, OUTPUT);
pinMode(muxPinD, OUTPUT);

pinMode (analogReadPin, INPUT);

Serial.begin(9600);
}

//==============================================================================

void loop()
{
for (int i = 0; i < knobAmount; i++) { // Loads values into "r" variables r0 = bitRead(i,0); r1 = bitRead(i,1); r2 = bitRead(i,2); r3 = bitRead(i,3); // Writes bits to each pin, based on "r" digitalWrite(muxPinA, r0); digitalWrite(muxPinB, r1); digitalWrite(muxPinC, r2); digitalWrite(muxPinD, r3); int newSensorValue = analogRead(analogReadPin); // Smoothing if (abs(newSensorValue - sensorValue[i]) > sensorTolerance) // Checks to see if knob has been moved
{
sensorValue[i] = newSensorValue;
int newCCValue = sensorValue[i] / 8; // Divides value by 8 for MIDI (0-127)

if (abs(newCCValue - ccValue[i]) > ccTolerance)
{
ccValue[i] = newCCValue;
usbMIDI.sendControlChange(cc4knob[i], newCCValue, midiChannel); // Sends USB MIDI
} //if abs(newCCvalue...
} // ifabs(newSensorValue...
} // for knobAmount...
} //void loop