Drum Master

DIY Electronic Drum Brain

Master Software

The Master software is what runs on the Arduino controller. In its very simplest form, it polls all 32 analog inputs and 8 digital inputs, reports back to the computer when a hit occurs. To decrease the latency, we actually poll the digital triggers, and only read an analog sensor if a logic high is detected.

The Arduino code as of the time of this writing is included below. This is a Wiring / Processing style program, which is essentially a subset of C, so it should be pretty familiar to most programmers. For more specific information about the language, see the Arduino Reference page.

/*
Drum Master - controller for up to 32 + 8 sensors.
Copyright 2008 Wyatt Olson 
*/

//Analog Pins offset and count
#define A_OFFSET 0
#define A_COUNT 4

//Trigger Pins offset; count is the same as Analog
#define T_OFFSET 2

//Digital Pins offset and count
#define D_OFFSET 6
#define D_COUNT 2

//Multiplexer selector pins.  S2 is MSB; S0 is LSB.
#define S0 10
#define S1 9
#define S2 8



#define SELECTION_DELAY 2  //How long to wait after selecting a new sensor (us).

#define ANALOG_SAMPLES 3  //How many times to read the input

#define ANALOG_REFERENCE EXTERNAL //EXTERNAL or DEFAULT

#define ANALOG_BOUNCE_PERIOD 15  //After a hit, don't report the same sensor for this long (ms).
#define DIGITAL_BOUNCE_PERIOD 200  //After a change of state, don't report changes for this long (ms).

int i, j, s, v, x;

long last_read_time[64];
int last_value[64];
long bank_last_read_time[8];

void setup() {
  //Setup 3.3v reference pin if desired
  analogReference(ANALOG_REFERENCE);
  
  for (i = 0; i < A_COUNT; i++){
    //You don't have to set analog input mode; just set triggers here
    pinMode(i + T_OFFSET, INPUT);
  }
  for (i = 0; i < D_COUNT; i++){
    pinMode(i + D_OFFSET, INPUT);
  }
  
  pinMode(S2, OUTPUT);
  pinMode(S1, OUTPUT);
  pinMode(S0, OUTPUT);

  Serial.begin(115200);
}

void loop() {
  for (i = 0; i < 0x8; i++){  //i == port
    select(i);
    delayMicroseconds(SELECTION_DELAY);
    
    for (j = 0; j < A_COUNT; j++){ // j == bank
      s = address(j, i);      
      
      //Check the last read time, and if the trigger is selected
      if (millis() - last_read_time[s] > ANALOG_BOUNCE_PERIOD && digitalRead(j + T_OFFSET)){
        v = get_velocity(j + A_OFFSET);
        Serial.print(s, HEX);
        Serial.print(":");
        Serial.println(v);
        last_read_time[s] = millis();
        bank_last_read_time[i] = millis();
      }      
    }
    
    j = 4; //Digital pin.  Change this to a loop if we add another.
    s = address(j, i);
    if (millis() - last_read_time[s] > DIGITAL_BOUNCE_PERIOD){
      //Remember that digital switches in drum master are reversed, since they 
      // use pull up resisitors.  Logic 1 is open, logic 0 is closed.  We invert
      // all digital readings to make this easy to keep straight.
      v = !digitalRead(D_OFFSET);
      if (v != last_value[s]){
        Serial.print(s, HEX);
        Serial.print(":");
        Serial.println(v);
        last_read_time[s] = millis();
        last_value[s] = v;
      }
    }
  }
}

/*
 * Sets pins S5 - S0 to select the multiplexer output.
 */
void select(int s){
  digitalWrite(S2, s & 0x4);
  digitalWrite(S1, s & 0x2);
  digitalWrite(S0, s & 0x1);
}

/*
 * Convert from a bank / port tuple to single number for sending to Drum Slave software
 */
int address(int bank, int port){
   return (bank << 3) | port;
}

/*
 * Reads the input a number of times, and returns the maximum.  The number 
 * of times to read the input is defined by ANALOG_SAMPLES
 */
int get_velocity(int channel){
  int max_val = 0;
  for (int t = 0; t < ANALOG_SAMPLES; t++){
    max_val = max(analogRead(channel), max_val); 
  }
  
  return max_val;
}