From ea2abab132365c8cd5a2bdfc9ee8758f3b729207 Mon Sep 17 00:00:00 2001 From: skutamac Date: Wed, 8 Feb 2017 22:31:39 +0800 Subject: [PATCH 1/3] Added velocity scaling Added Velocity scaling for each piezo to change how the velocity responds to how hard you hit the pads. --- ArduinoMidiDrums.ino | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/ArduinoMidiDrums.ino b/ArduinoMidiDrums.ino index 8eade8f..1e6d54c 100644 --- a/ArduinoMidiDrums.ino +++ b/ArduinoMidiDrums.ino @@ -30,6 +30,14 @@ #define KICK_THRESHOLD 50 #define START_SLOT 0 //first analog slot of piezos +//Piezo scaling defines +#define SNARE_SCALE 20 // 100 is 100% of raw value - that is no scaling +#define LTOM_SCALE 50 // < 100 scales the velocity down so that you have to hit harder to get maximum velocity +#define RTOM_SCALE 50 // > 100 scales the velocity up so you get maximum velocity with softer hits +#define LCYM_SCALE 50 +#define RCYM_SCALE 50 +#define KICK_SCALE 100 + //MIDI note defines for each trigger #define SNARE_NOTE 70 #define LTOM_NOTE 71 @@ -100,6 +108,13 @@ void setup() thresholdMap[3] = LCYM_THRESHOLD; thresholdMap[4] = SNARE_THRESHOLD; thresholdMap[5] = LTOM_THRESHOLD; + + velScale[0] = KICK_SCALE; + velScale[1] = RTOM_SCALE; + velScale[2] = LCYM_SCALE; + velScale[3] = LCYM_SCALE; + velScale[4] = SNARE_SCALE; + velScale[5] = LTOM_SCALE; noteMap[0] = KICK_NOTE; noteMap[1] = RTOM_NOTE; @@ -187,7 +202,7 @@ void recordNewPeak(short slot, short newPeak) { noteReady[slot] = true; if(newPeak > noteReadyVelocity[slot]) - noteReadyVelocity[slot] = newPeak; + noteReadyVelocity[slot] = newPeak * velScale[slot] / 100; } else if(newPeak < prevPeak && noteReady[slot]) { From 54b5c302afc6c366bbcfc33c38770aff3b541500 Mon Sep 17 00:00:00 2001 From: skutamac Date: Wed, 10 Oct 2018 18:29:31 +0800 Subject: [PATCH 2/3] Update ArduinoMidiDrums.ino --- ArduinoMidiDrums.ino | 481 ++++++++++++++++++++++--------------------- 1 file changed, 241 insertions(+), 240 deletions(-) diff --git a/ArduinoMidiDrums.ino b/ArduinoMidiDrums.ino index 1e6d54c..1ccd559 100644 --- a/ArduinoMidiDrums.ino +++ b/ArduinoMidiDrums.ino @@ -1,241 +1,242 @@ -/* - * Copyright (c) 2015 Evan Kale - * Email: EvanKale91@gmail.com - * 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 . - */ - -//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 - -//Piezo scaling defines -#define SNARE_SCALE 20 // 100 is 100% of raw value - that is no scaling -#define LTOM_SCALE 50 // < 100 scales the velocity down so that you have to hit harder to get maximum velocity -#define RTOM_SCALE 50 // > 100 scales the velocity up so you get maximum velocity with softer hits -#define LCYM_SCALE 50 -#define RCYM_SCALE 50 -#define KICK_SCALE 100 - -//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 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 * velScale[slot] / 100; - } - 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); -} +/* + * Copyright (c) 2015 Evan Kale + * Email: EvanKale91@gmail.com + * 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 . + */ + +//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 + +//Piezo scaling defines +#define SNARE_SCALE 20 // 100 is 100% of raw value - that is no scaling +#define LTOM_SCALE 50 // < 100 scales the velocity down so that you have to hit harder to get maximum velocity +#define RTOM_SCALE 50 // > 100 scales the velocity up so you get maximum velocity with softer hits +#define LCYM_SCALE 50 +#define RCYM_SCALE 50 +#define KICK_SCALE 100 +#define unsigned short velScale[NUM_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 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 * velScale[slot] / 100; + } + 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); +} From a024406a89a591a68f4f89c75af942d68f119609 Mon Sep 17 00:00:00 2001 From: skutamac Date: Wed, 10 Oct 2018 18:38:35 +0800 Subject: [PATCH 3/3] Update ArduinoMidiDrums.ino --- ArduinoMidiDrums.ino | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ArduinoMidiDrums.ino b/ArduinoMidiDrums.ino index 1ccd559..4867591 100644 --- a/ArduinoMidiDrums.ino +++ b/ArduinoMidiDrums.ino @@ -37,7 +37,6 @@ #define LCYM_SCALE 50 #define RCYM_SCALE 50 #define KICK_SCALE 100 -#define unsigned short velScale[NUM_PIEZOS]; //MIDI note defines for each trigger #define SNARE_NOTE 70 @@ -68,6 +67,9 @@ unsigned short slotMap[NUM_PIEZOS]; //map that holds the respective note to each piezo unsigned short noteMap[NUM_PIEZOS]; +//map that holds the respective scales for each pad +unsigned short velScale[NUM_PIEZOS]; + //map that holds the respective threshold to each piezo unsigned short thresholdMap[NUM_PIEZOS];