0% found this document useful (0 votes)
33 views

Code Arduino

This document contains the code for an Arduino program that uses piezo sensors to detect drum hits and trigger MIDI notes. It defines constants for the number of piezo sensors, their MIDI mappings, and signal processing thresholds. Functions are included to read piezo sensor signals, detect peaks, trigger MIDI notes, and send MIDI messages over serial. The main loop processes each piezo sensor signal continuously to detect hits and play corresponding MIDI notes.

Uploaded by

chivas1111
Copyright
© © All Rights Reserved
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
33 views

Code Arduino

This document contains the code for an Arduino program that uses piezo sensors to detect drum hits and trigger MIDI notes. It defines constants for the number of piezo sensors, their MIDI mappings, and signal processing thresholds. Functions are included to read piezo sensor signals, detect peaks, trigger MIDI notes, and send MIDI messages over serial. The main loop processes each piezo sensor signal continuously to detect hits and play corresponding MIDI notes.

Uploaded by

chivas1111
Copyright
© © All Rights Reserved
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 4

/*

* Copyright (c) 2015 Evan Kale


* Email: [email protected]
* Website: www.ISeeDeadPixel.com
* www.evankale.blogspot.ca
*
* This file is part of ArduinoMidiDrums.
*
* ArduinoMidiDrums is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

//Piezo defines
#define NUM_PIEZOS 6
#define SNARE_THRESHOLD 30 //anything < TRIGGER_THRESHOLD is treated as 0
#define LTOM_THRESHOLD 30
#define RTOM_THRESHOLD 30
#define LCYM_THRESHOLD 100
#define RCYM_THRESHOLD 100
#define KICK_THRESHOLD 50
#define START_SLOT 0 //first analog slot of piezos

//MIDI note defines for each trigger


#define SNARE_NOTE 70
#define LTOM_NOTE 71
#define RTOM_NOTE 72
#define LCYM_NOTE 73
#define RCYM_NOTE 74
#define KICK_NOTE 75

//MIDI defines
#define NOTE_ON_CMD 0x90
#define NOTE_OFF_CMD 0x80
#define MAX_MIDI_VELOCITY 127

//MIDI baud rate


#define SERIAL_RATE 31250

//Program defines
//ALL TIME MEASURED IN MILLISECONDS
#define SIGNAL_BUFFER_SIZE 100
#define PEAK_BUFFER_SIZE 30
#define MAX_TIME_BETWEEN_PEAKS 20
#define MIN_TIME_BETWEEN_NOTES 50

//map that holds the mux slots of the piezos


unsigned short slotMap[NUM_PIEZOS];

//map that holds the respective note to each piezo


unsigned short noteMap[NUM_PIEZOS];

//map that holds the respective threshold to each piezo


unsigned short thresholdMap[NUM_PIEZOS];

//Ring buffers to store analog signal and peaks


short currentSignalIndex[NUM_PIEZOS];
short currentPeakIndex[NUM_PIEZOS];
unsigned short signalBuffer[NUM_PIEZOS][SIGNAL_BUFFER_SIZE];
unsigned short peakBuffer[NUM_PIEZOS][PEAK_BUFFER_SIZE];

boolean noteReady[NUM_PIEZOS];
unsigned short noteReadyVelocity[NUM_PIEZOS];
boolean isLastPeakZeroed[NUM_PIEZOS];

unsigned long lastPeakTime[NUM_PIEZOS];


unsigned long lastNoteTime[NUM_PIEZOS];

void setup()
{
Serial.begin(SERIAL_RATE);

//initialize globals
for(short i=0; i<NUM_PIEZOS; ++i)
{
currentSignalIndex[i] = 0;
currentPeakIndex[i] = 0;
memset(signalBuffer[i],0,sizeof(signalBuffer[i]));
memset(peakBuffer[i],0,sizeof(peakBuffer[i]));
noteReady[i] = false;
noteReadyVelocity[i] = 0;
isLastPeakZeroed[i] = true;
lastPeakTime[i] = 0;
lastNoteTime[i] = 0;
slotMap[i] = START_SLOT + i;
}

thresholdMap[0] = KICK_THRESHOLD;
thresholdMap[1] = RTOM_THRESHOLD;
thresholdMap[2] = RCYM_THRESHOLD;
thresholdMap[3] = LCYM_THRESHOLD;
thresholdMap[4] = SNARE_THRESHOLD;
thresholdMap[5] = LTOM_THRESHOLD;

noteMap[0] = KICK_NOTE;
noteMap[1] = RTOM_NOTE;
noteMap[2] = RCYM_NOTE;
noteMap[3] = LCYM_NOTE;
noteMap[4] = SNARE_NOTE;
noteMap[5] = LTOM_NOTE;
}

void loop()
{
unsigned long currentTime = millis();

for(short i=0; i<NUM_PIEZOS; ++i)


{
//get a new signal from analog read
unsigned short newSignal = analogRead(slotMap[i]);
signalBuffer[i][currentSignalIndex[i]] = newSignal;

//if new signal is 0


if(newSignal < thresholdMap[i])
{
if(!isLastPeakZeroed[i] && (currentTime - lastPeakTime[i]) >
MAX_TIME_BETWEEN_PEAKS)
{
recordNewPeak(i,0);
}
else
{
//get previous signal
short prevSignalIndex = currentSignalIndex[i]-1;
if(prevSignalIndex < 0) prevSignalIndex = SIGNAL_BUFFER_SIZE-1;
unsigned short prevSignal = signalBuffer[i][prevSignalIndex];

unsigned short newPeak = 0;

//find the wave peak if previous signal was not 0 by going


//through previous signal values until another 0 is reached
while(prevSignal >= thresholdMap[i])
{
if(signalBuffer[i][prevSignalIndex] > newPeak)
{
newPeak = signalBuffer[i][prevSignalIndex];
}

//decrement previous signal index, and get previous signal


prevSignalIndex--;
if(prevSignalIndex < 0) prevSignalIndex = SIGNAL_BUFFER_SIZE-1;
prevSignal = signalBuffer[i][prevSignalIndex];
}

if(newPeak > 0)
{
recordNewPeak(i, newPeak);
}
}

currentSignalIndex[i]++;
if(currentSignalIndex[i] == SIGNAL_BUFFER_SIZE) currentSignalIndex[i] = 0;
}
}

void recordNewPeak(short slot, short newPeak)


{
isLastPeakZeroed[slot] = (newPeak == 0);

unsigned long currentTime = millis();


lastPeakTime[slot] = currentTime;

//new peak recorded (newPeak)


peakBuffer[slot][currentPeakIndex[slot]] = newPeak;

//1 of 3 cases can happen:


// 1) note ready - if new peak >= previous peak
// 2) note fire - if new peak < previous peak and previous peak was a note ready
// 3) no note - if new peak < previous peak and previous peak was NOT note ready

//get previous peak


short prevPeakIndex = currentPeakIndex[slot]-1;
if(prevPeakIndex < 0) prevPeakIndex = PEAK_BUFFER_SIZE-1;
unsigned short prevPeak = peakBuffer[slot][prevPeakIndex];

if(newPeak > prevPeak && (currentTime -


lastNoteTime[slot])>MIN_TIME_BETWEEN_NOTES)
{
noteReady[slot] = true;
if(newPeak > noteReadyVelocity[slot])
noteReadyVelocity[slot] = newPeak;
}
else if(newPeak < prevPeak && noteReady[slot])
{
noteFire(noteMap[slot], noteReadyVelocity[slot]);
noteReady[slot] = false;
noteReadyVelocity[slot] = 0;
lastNoteTime[slot] = currentTime;
}

currentPeakIndex[slot]++;
if(currentPeakIndex[slot] == PEAK_BUFFER_SIZE) currentPeakIndex[slot] = 0;
}

void noteFire(unsigned short note, unsigned short velocity)


{
if(velocity > MAX_MIDI_VELOCITY)
velocity = MAX_MIDI_VELOCITY;

midiNoteOn(note, velocity);
midiNoteOff(note, velocity);
}

void midiNoteOn(byte note, byte midiVelocity)


{
Serial.write(NOTE_ON_CMD);
Serial.write(note);
Serial.write(midiVelocity);
}

void midiNoteOff(byte note, byte midiVelocity)


{
Serial.write(NOTE_OFF_CMD);
Serial.write(note);
Serial.write(midiVelocity);
}

You might also like