velocity sensitive piezo trigger

Discussion in 'Programmer's Corner' started by seayaker, Feb 17, 2018.

  1. seayaker

    Thread Starter Active Member

    Jan 27, 2009
    36
    0
    Is there a way to modify this code to make it velocity sensitive? This is the only code I found that works with my board (Teensy 3.6). I have a piezo connected to (A0) that triggers a midi note but only at one volume, The value of the piezo varies from 50-150 depending how hard it's hit. Can this be read and sent as a midi velocity message?



    Code (C):
    1. /*
    2.    MIDIUSB_test.ino
    3.  
    4.    Created: 4/6/2015 10:47:08 AM
    5.    Author: gurbrinder grewal
    6.    Modified by Arduino LLC (2015) & Grumpy Mike
    7. */
    8.  
    9. #include "MIDIUSB.h"
    10.  
    11. // First parameter is the event type (0x09 = note on, 0x08 = note off).
    12. // Second parameter is note-on/note-off, combined with the channel.
    13. // Channel can be anything between 0-15. Typically reported to the user as 1-16.
    14. // Third parameter is the note number (48 = middle C).
    15. // Fourth parameter is the velocity (64 = normal, 127 = fastest).
    16.  
    17. void noteOn(byte channel, byte pitch, byte velocity) {
    18.   midiEventPacket_t noteOn = {0x09, 0x90 | channel, pitch, velocity};
    19.   MidiUSB.sendMIDI(noteOn);
    20. }
    21.  
    22. void noteOff(byte channel, byte pitch, byte velocity) {
    23.   midiEventPacket_t noteOff = {0x08, 0x80 | channel, pitch, velocity};
    24.   MidiUSB.sendMIDI(noteOff);
    25. }
    26.  
    27. void setup() {
    28.   Serial.begin(115200);
    29. }
    30.  
    31. // First parameter is the event type (0x0B = control change).
    32. // Second parameter is the event type, combined with the channel.
    33. // Third parameter is the control number number (0-119).
    34. // Fourth parameter is the control value (0-127).
    35.  
    36. void loop() {
    37.   int val;
    38.   val = analogRead(A0);
    39.   if (val > 600) { // if it is greater than the threshold
    40.     noteOn(0, 50, 127); // send a note on message the 68 is the pitch of the note
    41.     MidiUSB.flush(); // send the MIDI message
    42.     while (analogRead(A0) > 600) { } // wait here until the signal has dropped
    43.     noteOff(0, 50, 127); // send the note off message
    44.     MidiUSB.flush(); // send the MIDI message
    45.   }
    Mod edit: code tags
     
    Last edited by a moderator: Feb 22, 2018
  2. MrSoftware

    Well-Known Member

    Oct 29, 2013
    1,047
    291
    I only skimmed, but if I skimmed correctly then the 3rd parameter to noteOn() is the "velocity" or volume. Your variable "val" is the analog value read from your piezo input pin. Right now you only use that variable once in an if() as a binary on/off. Instead you need to pass "val" as the 3rd parameter into noteOn(), BUT FIRST you need to find out what the max and min values that noteOn() will take and multiply "val" by some factor that will give you a number within the range that is OK for noteOn().
     
  3. JohnInTX

    Moderator

    Jun 26, 2012
    3,332
    1,670
    To amplify on that a bit, you might implement a peak-detector. Once you get above the threshold at line 39, continue to sample the piezo using analogRead(A0) in a tight loop. Compare each new value with the previous one. If its larger, store that as previous value and read again. Eventually the new value will be less than the previous one as the piezo signal drops. When that happens, the 'previous' value is your 'peak' and you can use it to specify the volume, maybe with some scaling as @MrSoftware describes.
    Whether you can get this all done in 'Arduino time' without losing the beat I don't know. Don't forget to reset the 'previous' value on each hit.

    Good luck!
     
  4. seayaker

    Thread Starter Active Member

    Jan 27, 2009
    36
    0
    Can you tell me why this doesn't work? This sketch was modified to use 21 pins but still only works with 1 A0, anybody know whats wrong?

    const int channel = 10; // General MIDI: channel 10 = percussion sounds
    const int PINS = 22; // number of signals incoming
    const int note[PINS] = {36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57}; // array of MIDI note values for read signals

    const int analogPin[PINS] = {A0,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15,A16,A17,A18,A19,A20,A21}; //array of analog PINs
    const int thresholdMin = 60; // minimum reading, avoid noise and false starts
    const int peakTrackMillis = 12;
    const int aftershockMillis = 25; // aftershocks & vibration reject

    int state[PINS]; // 0=idle, 1=looking for peak, 2=ignore aftershocks
    int peak[PINS]; // remember the highest reading
    int piezo[PINS];
    elapsedMillis msec[PINS]; // timer to end states 1 and 2

    void setup() {
    Serial.begin(115200);
    while (!Serial && millis() < 2500) /* wait for serial monitor */ ;
    Serial.println("Piezo Peak Capture");
    }


    void loop() {


    for (int i=0;i<PINS;i++){
    piezo = analogRead(analogPin);

    int voltage=piezo;

    switch (state) {
    // IDLE state: wait for any reading is above threshold. Do not set
    // the threshold too low. You don't want to be too sensitive to slight
    // vibration.
    case 0:
    if (voltage > thresholdMin) {
    //Serial.print("begin peak track ");
    //Serial.println(voltage);
    peak = voltage;
    msec = 0;
    state = 1;
    }
    return;

    // Peak Tracking state: capture largest reading
    case 1:
    if (voltage > peak) {
    peak = voltage;
    }
    if (msec >= peakTrackMillis) {
    //Serial.print("peak = ");
    //Serial.println(peak);
    int velocity = map(peak, thresholdMin, 1023, 22, 127);
    usbMIDI.sendNoteOn(note, velocity, channel);
    msec = 0;
    state = 2;
    }
    return;

    // Ignore Aftershock state: wait for things to be quiet again.
    default:
    if (voltage > thresholdMin) {
    msec = 0; // keep resetting timer if above threshold
    } else if (msec > aftershockMillis) {
    usbMIDI.sendNoteOff(note, 0, channel);
    state = 0; // go back to idle when
    }
    }
    }
    // Add other tasks to loop, but avoid using delay() or waiting.
    // You need loop() to keep running rapidly to detect Piezo peaks!

    // MIDI Controllers should discard incoming MIDI messages.
    // http://forum.pjrc.com/threads/24179-Teensy-3-Ableton-Analog-CC-causes-midi-crash
    while (usbMIDI.read()) {
    // ignore incoming messages
    }
    }


    void peakDetect(int voltage) {
    }
     
    Last edited: Feb 24, 2018
Loading...