For my stupid pet trick I decided to build a simple acoustic drum machine. I wanted it to be something like the old Rhythm Ace machines that allowed you to toggle between different genres of canned beats with the push of a button. The output consists of a servo hitting a small drum from Borneo (which serves as the bass drum here) and a solenoid hitting a plastic cup filled snail shells(the snare). There are also two LEDs that blink to indicate the tempo (red representing the 1 in the count and yellow the 2,3 &4). While at first I was using a potentiometer to vary the tempo at which it played, I decided to try making a tap tempo interface that calculates the beat based on the length of time between to taps of a button. Basically, it has two variables that take a reading of the millis count at the moments of the taps and calculates the tempo by measuring the time in between.
I did a lot of experimenting to with how to sequence the notes to form particular beats. I wanted to use an array but wasn’t sure how to simulate polyphony with this method. So, instead I manually created a structure which accounts for a note trigger or rest for each of three instruments (in case I want to add one more output) and an LED for four 16th notes each beat. The tempo calculation is adjusted to account for total duration of each beat given these four elements so that the time between taps is accurately reflected in the beat’s tempo.
It’s currently programmed to play two beats, a funk/hip hop beat and a reggaeton beat. Eventually, I’d like to add a fuller array of options.
Here’s the code:
#include <Servo.h> // include the servo library
int potPin = 0; // Analog input pin that the potentiometer is attached to
int potValue = 0; // value read from the pot
int servoPin1 = 9; // PWM pin that the Servo is on. n.b. PWM 0 is on digital pin 9
int solenoidPin = 3; //digital output pin that the solenoid is on
int LED1=10; //set pin for red LED
int LED2=11; //set oin for green LED
int beatButton1=6; //define beat selector buttons
int beatButton2=7;
int beat1=0; //define varibales to determine which beat is playing
int beatButton1State;
int beatButton2State;
int switchPin=8; // pin switch is on and varibale to track its position
int switchState=0;
int oldSwitchState=0;
int buttonPin=13; //pin button is on and varibale to track its state
int buttonState=LOW;
int oldButtonState=LOW;
int playState=0;
int rest;
// tap variables — store the millis information from which the tempo is calculated
unsigned long tap1 =0;
unsigned long tap2 =400;
int tapSet=0;
int LEDblinkInit=0;
unsigned long LEDblinkTime =0;
//define note lengths in relation to tempo
float tempo=(tap2-tap1)/4;
float noteDur4=tempo/2;
float noteDur8=.5*noteDur4;
float noteDur16= .25 *noteDur4;
int snare= solenoidPin; //define the varibale used for triggering the solenoid “snare”
//declare servo 1
Servo bassDrum;
Servo rest2;
void setup() {
// initialize serial communications at 9600 bps:
Serial.begin(9600);
// declare the servo pin as an output:
bassDrum.attach(servoPin1);
//declare input and output pins
pinMode(buttonPin, INPUT);
pinMode(solenoidPin, OUTPUT);
pinMode(LED1,OUTPUT);
pinMode(LED2,OUTPUT);
pinMode(switchPin,INPUT);
pinMode(beatButton1,INPUT);
pinMode(beatButton2,INPUT);
//position servo when the program starts to be ready to play.
bassDrum.write(160);
}
void loop() {
Serial.println(beatButton1State);
checkTempo();
checkPlay();
//what to do if it is not playing
if(playState==0){
buttonState=digitalRead(buttonPin);
//listen for two taps of the tempo button and assign millis values
if(buttonState==HIGH && oldButtonState==LOW && tapSet==0){tap1=millis();
oldButtonState=HIGH;
}
if(buttonState==LOW && oldButtonState==HIGH && tapSet==0){
tapSet=1-tapSet;
oldButtonState=LOW;
}
if(buttonState==HIGH && oldButtonState==LOW && tapSet==1)
{tap2=millis();
oldButtonState=HIGH;
}
if(buttonState==LOW && oldButtonState==HIGH && tapSet==1){
tapSet=1-tapSet;
oldButtonState=LOW;
LEDblinkInit=0;
}
if(LEDblinkInit==0){
for(int LEDblinkCount; LEDblinkCount<2; LEDblinkCount++)
{LEDblink();
LEDblinkInit=1;
}
}
}
//what to do if playing
checkBeat();
//conditions for playing hiphop beat
if(playState==1 && beat1==0){
checkTempo();
hiphopBeat();
}
//conditions for playing reggaeton beat
if(playState==1 && beat1==1){
checkTempo();
reggaetonBeat();
}
}
//define quarter note function
void note4(Servo inst){
inst.write(179);
delay(noteDur4);
inst.write(160);
delay(noteDur4);
checkTempo();
checkPlay();
checkBeat();
Serial.println(potValue);
}
//define 16th note rest
void restNote16(){delay(noteDur16);}
//define LED blink function
void LED(int LEDX){
digitalWrite(LEDX,HIGH);
delay(20);
digitalWrite(LEDX,LOW);
delay(noteDur16*2-20);
checkBeat();
checkPlay();
}
//define 8th note function
void note8(Servo inst){
inst.write(179);
delay(noteDur8);
inst.write(160);
delay(noteDur8);
checkTempo();
checkPlay();
checkBeat();
Serial.println(potValue);
}
//define servo 16th note function
void ServoNote16(Servo inst){
inst.write(179);
delay(noteDur16);
delay(noteDur16);
inst.write(169);
checkTempo();
checkPlay();
checkBeat();
}
//define solenoid 16th note function
void SolNote16(int inst){
digitalWrite(inst,HIGH);
delay(noteDur16);
digitalWrite(inst,LOW);
delay(noteDur16);
checkTempo();
checkPlay();
checkBeat();
}
//function for checking and recalculating tempo and notes durations
void checkTempo(){
tempo=((tap2-tap1)/4);
noteDur4=tempo/2;
noteDur8=.5*noteDur4;
noteDur16= .25 *noteDur4;
}
//function to check if to play or not
void checkPlay(){
switchState=digitalRead(switchPin);
if(switchState == HIGH){
playState=1; }
else playState=0;
}
//function to check which beat to play
void checkBeat(){
beatButton1State=digitalRead(beatButton1);
beatButton2State=digitalRead(beatButton2);
if(beatButton1State==HIGH){
beat1=0;
}
if(beatButton2State== HIGH){
beat1=1;
}
}
//function to make LEds blink to indicate tempo
void LEDblink(){
//beat1
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(LED1);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
//beat2
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(LED2);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
//beat 3
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(LED2);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
//beat4
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(LED2);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
}
//function to create a simple metronome beat
void metronomeBeat(){
//beat 1
ServoNote16(bassDrum); SolNote16(rest); SolNote16(rest); LED(LED1);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
//beat2
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(LED2);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(snare); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
//beat 3
ServoNote16(bassDrum); SolNote16(rest); SolNote16(rest); LED(LED2);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
//beat4
ServoNote16(bassDrum); SolNote16(rest); SolNote16(rest); LED(LED2);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
}
//function to create a reggaeton beat
void reggaetonBeat(){
//beat 1
ServoNote16(bassDrum); SolNote16(rest); SolNote16(rest);LED(LED1);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
//beat2
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(LED2);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(snare); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
//beat 3
ServoNote16(bassDrum); SolNote16(rest); SolNote16(rest); LED(LED2);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
//beat4
ServoNote16(rest2 ); SolNote16(snare); SolNote16(rest); LED(LED2);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
//beat 5
ServoNote16(bassDrum); SolNote16(rest); SolNote16(rest);LED(LED1);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
//beat6
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(LED2);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(snare); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
//beat 7
ServoNote16(bassDrum); SolNote16(rest); SolNote16(rest); LED(LED2);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(snare); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
//beat 8
ServoNote16(rest2 ); SolNote16(snare); SolNote16(rest); LED(LED2);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(snare); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
//beat 9
ServoNote16(bassDrum); SolNote16(rest); SolNote16(rest);LED(LED1);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
//beat10
ServoNote16(bassDrum); SolNote16(rest); SolNote16(rest); LED(LED2);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(snare); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
//beat 11
ServoNote16(bassDrum); SolNote16(rest); SolNote16(rest); LED(LED2);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
//beat12
ServoNote16(bassDrum ); SolNote16(snare); SolNote16(rest); LED(LED2);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
//beat 13
ServoNote16(bassDrum); SolNote16(rest); SolNote16(rest);LED(LED1);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(snare); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
//beat14
ServoNote16(rest2); SolNote16(snare); SolNote16(rest); LED(LED2);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(snare); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
//beat 15
ServoNote16(bassDrum); SolNote16(rest); SolNote16(rest); LED(LED2);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(snare); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(snare); SolNote16(rest); LED(rest);
//beat 16
ServoNote16(rest2 ); SolNote16(snare); SolNote16(rest); LED(LED2);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(snare); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(snare); SolNote16(rest); LED(rest);
}
//function to create a hiphop beat
void hiphopBeat(){
//beat 1
ServoNote16(bassDrum); SolNote16(rest); SolNote16(rest);LED(LED1);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(snare); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(snare); SolNote16(rest); LED(rest);
//beat2
ServoNote16(bassDrum); SolNote16(snare); SolNote16(rest); LED(LED2);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(snare); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
//beat 3
ServoNote16(rest2); SolNote16(snare); SolNote16(rest); LED(LED2);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(bassDrum); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
//beat4
ServoNote16(rest2 ); SolNote16(snare); SolNote16(rest); LED(LED2);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(snare); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
//beat 5
ServoNote16(bassDrum); SolNote16(rest); SolNote16(rest); LED(LED1);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(snare); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
//beat 6
ServoNote16(bassDrum); SolNote16(rest); SolNote16(rest); LED(LED2);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(snare); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
//beat 7
ServoNote16(rest2); SolNote16(snare); SolNote16(rest); LED(LED2);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
//beat 8
ServoNote16(bassDrum); SolNote16(rest); SolNote16(rest); LED(LED2);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(snare); SolNote16(rest); LED(rest);
ServoNote16(rest2); SolNote16(rest); SolNote16(rest); LED(rest);
}
Given your interest in MIDI as well, you might want to check out the MIDI for Arduino example on the phys comp site. There’s also an example in the Arduino example folders.