/* [COLOR="#40E0D0"]Use a Piezo sensor (percussion / drum) to send USB MIDI note on
messages, where the "velocity" represents how hard the Piezo was
tapped.
Connect a Pieze sensor to analog pin A0. This example was tested
with Murata 7BB-27-4L0. Almost any piezo sensor (not a buzzer with
built-in oscillator electronics) may be used. However, Piezo
sensors are easily damaged by excessive heat if soldering. It
is highly recommended to buy a Piezo with wires already attached!
Use a 100K resistor between A0 to GND, to give the sensor a "load".
The value of this resistor determines how "sensitive" the circuit is.
A pair of 1N4148 diodes are recommended to protect the analog pin.
The first diode connects to A0 with its stripe (cathode) and the other
side to GND. The other diode connects its non-stripe (anode) side to
A0, and its stripe (cathode) side to 3.3V.
Sensitivity may also be tuned with the map() function. Uncomment
the Serial.print lines to see the actual analog measurements in the
Arduino Serial Monitor.
You must select MIDI from the "Tools > USB Type" menu
This example code is in the public domain.
**************multi-pad extension and hi-hat alteration by oddson -- un(der)-tested****[/COLOR]
*/
//********************************************************************************* SET PIN OPTIONS**************
const int PINS = 3; // number of piezo signals incoming (does not include HH signal pin)
const int analogPin[PINS] = {A1,A2,A3}; //array of analog PINs used for piezo readings
const int zonePin = A0; // high-hat pedal pin <- I NEED THIS AT 'A9' FOR TESTING AND MAY FORGET TO RETURN TO 'A0'
//********************************************************************************* SET HIGH HAT ZONE CONFIGURATION OPTIONS**************
const int ZONECOUNT = 5 ; // number of zones for FSR as modifier for HH
const int zoneMap[ZONECOUNT] = {[COLOR="#FF0000"]300,500,600,700,850[/COLOR]}; //raw reading value boundaries between zones
//********************************************************************************* SET MIDI CHANNEL AND NOTE VALUES *************************
const int channel = 10; // General MIDI: channel 10 = percussion sounds
const int note[PINS] = {-1,[COLOR="#FF0000"]36,38[/COLOR]}; // note values for each pin - negative value flags to read the HH array instead
const int hhNote[ZONECOUNT] = {[COLOR="#FF0000"]46,2,3,4,42[/COLOR]} ; // note values for flavours of HH from open to closed (no general MIDI for intermediaries so used low values as placeholders)
const int splashNote = [COLOR="#FF0000"]55[/COLOR]; // note value for 'splash' note sent by HH pedal
const int chickNote = [COLOR="#FF0000"]42[/COLOR]; // note value for 'chick' note sent by HH pedal (no general MIDI so set to 'closed hat' for now)
//********************************************************************************* SET TIMING AND THRESHOLD ADJUSTMENT OPTIONS**************
//****PIEZOS
const int peakTrackMillis = 12; // how long to keep reading looking for the peak to become velocity
const int aftershockMillis = 25; // aftershocks & vibration reject
const int thresholdMin = 60; // minimum reading before a note will be generated (too low = phantom notes)
//****HIGH HAT PEDAL
const int zoneRefesh = [COLOR="#FF0000"]20[/COLOR]; // mS between HH pedal updates - hat pedal is low freq. so we can check every few mS.
const int minSplash = [COLOR="#FF0000"]70[/COLOR]; // raw value difference required to fire 'splash'
const int minChick = [COLOR="#FF0000"]70[/COLOR]; // raw value difference required to fire 'chick'
const int deadBandLimit = [COLOR="#FF0000"]50[/COLOR]; // raw value deadband to limit HH updates above noise threshold - can very large with small number of zones
//*************VARIABLES
int zone; // calculated zone
int rawZone; // raw pin reading
int rawZoneLag; // lagged raw reading used to judge change magnitude
int rawDelta; // difference between rawzone readings - used to trigger HH splash / chick
int state[PINS]; // 0=idle, 1=looking for peak, 2=ignore aftershocks
int peak[PINS]; // remember the highest reading
int piezo[PINS]; // current raw readings for piezos
elapsedMillis msec[PINS]; // timers to end states 1 and 2 - separate values for each piezo pin
elapsedMillis zonePoll ; // timer for polling the HH pedal
//*************SETUP
void setup() {
Serial.begin(115200);
while (!Serial && millis() < 2500) /* wait for serial monitor */ ;
Serial.println("Piezo Peak Capture");
}
//*************MAIN LOOP
void loop() {
HHpedal(); // checkZone polls the hi-hat modifer signal
[COLOR="#00FFFF"]// for (int i=0;i<PINS;i++){ // loop through piezo readings
// piezo[i] = analogRead(analogPin[i]); // piezo[] holds raw readings
// peakDetect(i); // check for peaks events and send note events
// }[/COLOR]
while (usbMIDI.read()) {
// MIDI Controllers should discard incoming MIDI messages.
}
}
//*************PEAK DETECT FOR PIEZO SIGNALS
void peakDetect(int i) {
int playNote = note[i];
if (!playNote){ // if it reads the negative flag it looks up the HH note instead
playNote = hhNote[zone] ;
}
switch (state[i]) {
case 0:
if (piezo[i] > thresholdMin) {
peak[i] = piezo[i];
msec[i] = 0;
state[i] = 1;
}
return;
// Peak Tracking state: capture largest reading
case 1:
if (piezo[i] > peak[i]) {
peak[i] = piezo[i];
}
if (msec[i] >= peakTrackMillis) {
int velocity = map(peak[i], thresholdMin, 1023, 1, 127);
usbMIDI.sendNoteOn(playNote, velocity, channel);
msec[i] = 0;
state[i] = 2;
}
return;
// Ignore Aftershock state: wait for things to be quiet again.
default:
if (piezo[i] > thresholdMin) {
msec[i] = 0; // keep resetting timer if above threshold
} else if (msec[i] > aftershockMillis) {
usbMIDI.sendNoteOff(playNote, 0, channel); // can send note-on with vel=0 instead
state[i] = 0; // go back to idle when
}
}
}
//*************HIGH HAT PEDAL SIGNAL HANDLING - AS MODIFIER AND AS NOTE GENERATOR
void HHpedal() {
if (zonePoll>zoneRefesh) { // modifiying pedal is low Freq. so limit reads
rawZone = analogRead(zonePin);
//Serial.println(rawZone);
rawDelta = rawZone - rawZoneLag;
if (abs(rawDelta)>deadBandLimit){ //also limit by change size
int j = 0;
while ( rawZone>zoneMap[j] ) {
j++;
}
zone = j;
int velocity = abs(rawDelta)>>3;
//Serial.println(velocity);
if (rawZoneLag > zoneMap[ZONECOUNT-1] && rawZone < zoneMap[ZONECOUNT-1]) {
// stop 'chick' and play 'splash' if over threshold
usbMIDI.sendNoteOff(chickNote, 0, channel); // can send note-on with vel=0 instead
if (rawDelta + minSplash < 0) { // delta signal is negative when splash is possible
usbMIDI.sendNoteOn(splashNote, velocity, channel);
}
}
if (rawZone > zoneMap[ZONECOUNT-1] && rawZoneLag < zoneMap[ZONECOUNT-1]) {
// stop 'splash' and play 'chick' if over threshold
usbMIDI.sendNoteOff(splashNote, 0, channel); // can send note-on with vel=0 instead
if (rawDelta > minChick) { // delta signal is negative when splash is possible
usbMIDI.sendNoteOn(chickNote, velocity, channel);
}
}
rawZoneLag = rawZone;
}
zonePoll = 0;
//Serial.println(zone);
}
}