And the Marimba Code:
Note the excellent comments for what the variables do!
//*******************************************************************************************************************
// User settable variables
//*******************************************************************************************************************
unsigned char PadNote[8] = {40,41,42,43,44,45,46,47}; // MIDI notes from 0 to 127 (Mid C = 60) // Original = {52,16,66,63,40,65}
int PadCutOff[8] = {20,20,20,20,20,20,20,20}; // Minimum Analog value to cause a drum hit
int MaxPlayTime[8] = {90,90,90,90,90,90,90,90}; // Cycles before a 2nd hit is allowed
#define midichannel 0; // MIDI channel from 0 to 15 (+1 in "real world")
boolean VelocityFlag = true; // Velocity ON (true) or OFF (false)
//*******************************************************************************************************************
// Internal Use Variables
//*******************************************************************************************************************
boolean activePad[8] = {0,0,0,0,0,0,0,0}; // Array of flags of pad currently playing
int PinPlayTime[8] = {0,0,0,0,0,0,0,0}; // Counter since pad started to play
unsigned char status;
int pin = 0;
int hitavg = 0;
Most of these variables are self-explanatory. We will encounter them more specifically later.
void setup()
{
Serial.begin(57600); // connect to the serial port 115200
}
All setup does here is start a fast serial terminal. Note the baudrate mismatch between the comment and the code??? Either should work, just make sure the rate here matches the rate in the serial monitor or the Processing sketch.
Now we are in the main loop.
void loop()
{
for(int pin=0; pin < 8; pin++)
{
We start a for loop that sets pin equal to the numbers 0 through 7.
hitavg = analogRead(pin); // read the input pin
This is where we do an analog read of the input pin. Curiously we read 8 pins even through the Arduino Uno only has 6 analog pins. If the code works like this on an Uno it is likely because reading a non-existant pin returns a value that doesn't mess up the later code, but I don't know for sure what happens in this case.
if((hitavg > PadCutOff[pin]))
{
if((activePad[pin] == false))
{
if(VelocityFlag == true)
{
// hitavg = 127 / ((1023 - PadCutOff[pin]) / (hitavg - PadCutOff[pin])); // With full range (Too sensitive ?)
hitavg = (hitavg / 8) -1 ; // Upper range
}
else
{
hitavg = 127;
}
Now we use some code to make decisions based on the value we read in. If this value was greater than the cutoff set for that pin at the top of the file then we check to see if the pin is already active. If the pin is not already active we check to see if the Velocity flag is true. If it is, then the code sets hitavg to be one less than its previous value divided by 8. If variable velocity mode is not turned on, then hitavg is simply set to be 127, the maximum midi velocity.
MIDI_TX(144,PadNote[pin],hitavg);
PinPlayTime[pin] = 0;
activePad[pin] = true;
At this point the command to play the key is sent. See the note at the bottom for what MIDI_TX does. We also reset the pin's play time and make the pin active so that it will not be re-triggered by the next loop.
else
{
PinPlayTime[pin] = PinPlayTime[pin] + 1;
}
This code runs if the pin was already active. In this case it increments the pin play time so that the note will eventually stop playing.
else if((activePad[pin] == true))
{
PinPlayTime[pin] = PinPlayTime[pin] + 1;
if(PinPlayTime[pin] > MaxPlayTime[pin])
{
activePad[pin] = false;
MIDI_TX(128,PadNote[pin],127);
}
}
This code runs only if the hitAvg was not above the threshold AND the given note is active (so it was previously triggered). In this case we still increment the pin play time, but we also check to see if this time is greater than the maximum set for this pin. If that is the case the pin is reset to inactive and the command to stop the note is sent.
//*******************************************************************************************************************
// Transmit MIDI Message
//*******************************************************************************************************************
void MIDI_TX(unsigned char MESSAGE, unsigned char PITCH, unsigned char VELOCITY)
{
status = MESSAGE + midichannel;
Serial.write(status);
Serial.write(PITCH);
Serial.write(VELOCITY);
The midi transmit commands are sent by this code. It is critical to note that these are not true midi commands, but are instead serial commands that are sent to a serial midi converter that then outputs the midi signal to another application on your computer.
This function takes in a message, pitch, and velocity. It adds the message character and the midichannel (Midi has 16 different channels so that various controllers can be daisy chained and separated on the receiving side) to form a new status parameter. It then sends the status along with the pitch and velocity over serial.
From the code I gather that a Message of 144 will play a note while a 128 will stop the note. The note parameter is the midi-number for the note (See picture below). The velocity corresponds to how fast the keyboard key is pressed on a keyboard and will range from 0 to 127. He uses a message of 144 to stop a note, but sending a velocity 0 message should also accomplish this in theory.