Forum Rule: Always post complete source code & details to reproduce any issue!
Page 1 of 3 1 2 3 LastLast
Results 1 to 25 of 69

Thread: piezo velocity

  1. #1
    Senior Member
    Join Date
    Feb 2018
    Posts
    154

    piezo velocity

    I'm building a drum pad using a piezo connected to (A0), I found this code that works well with the T3.6 but is not velocity sensitive. Is there any way to modify it so it reads the value of the piezo hit and sends it as midi velocity?

    HTML Code:
    /*
       MIDIUSB_test.ino
    
       Created: 4/6/2015 10:47:08 AM
       Author: gurbrinder grewal
       Modified by Arduino LLC (2015) & Grumpy Mike
    */
    
    #include "MIDIUSB.h"
    
    // First parameter is the event type (0x09 = note on, 0x08 = note off).
    // Second parameter is note-on/note-off, combined with the channel.
    // Channel can be anything between 0-15. Typically reported to the user as 1-16.
    // Third parameter is the note number (48 = middle C).
    // Fourth parameter is the velocity (64 = normal, 127 = fastest).
    
    void noteOn(byte channel, byte pitch, byte velocity) {
      midiEventPacket_t noteOn = {0x09, 0x90 | channel, pitch, velocity};
      MidiUSB.sendMIDI(noteOn);
    }
    
    void noteOff(byte channel, byte pitch, byte velocity) {
      midiEventPacket_t noteOff = {0x08, 0x80 | channel, pitch, velocity};
      MidiUSB.sendMIDI(noteOff);
    }
    
    void setup() {
      Serial.begin(115200);
    }
    
    // First parameter is the event type (0x0B = control change).
    // Second parameter is the event type, combined with the channel.
    // Third parameter is the control number number (0-119).
    // Fourth parameter is the control value (0-127).
    
    void loop() {
      int val;
      val = analogRead(A0);
      if (val > 600) { // if it is greater than the threshold
        noteOn(0, 50, 127); // send a note on message the 68 is the pitch of the note 
        MidiUSB.flush(); // send the MIDI message
        while (analogRead(A0) > 600) { } // wait here until the signal has dropped
        noteOff(0, 50, 127); // send the note off message
      }
      MidiUSB.flush(); // send the MIDI message
    
      
      }

  2. #2
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    21,473
    In Arduino, click File Examples Teensy USB MIDI Piezo.

  3. #3
    Senior Member
    Join Date
    Feb 2018
    Posts
    154
    is this what you mean? I added #include "MIDIUSB.h" and got it to compile but all it does is play a note for ever until I hit the piezo again then it starts over with after some delay

    include "MIDIUSB.h"

    const int channel = 10; // General MIDI: channel 10 = percussion sounds
    const int note = 38; // General MIDI: note 38 = acoustic snare

    const int analogPin = A0;
    const int thresholdMin = 60; // minimum reading, avoid noise and false starts
    const int peakTrackMillis = 12;
    const int aftershockMillis = 25; // aftershocks & vibration reject


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


    void loop() {
    int piezo = analogRead(analogPin);
    peakDetect(piezo);
    // 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-...ses-midi-crash
    while (usbMIDI.read()) {
    // ignore incoming messages
    }
    }


    void peakDetect(int voltage) {
    // "static" variables keep their numbers between each run of this function
    static int state; // 0=idle, 1=looking for peak, 2=ignore aftershocks
    static int peak; // remember the highest reading
    static elapsedMillis msec; // timer to end states 1 and 2

    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, 1, 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
    }
    }
    }[/CODE]

  4. #4
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    21,473
    Maybe your piezo is different? Or maybe you have a different load resistor? Blind guessing, since I can't see your setup.

    Perhaps try adjusting the 3 configuration parameters? Or maybe uncomment the Serial.print() lines to get more info about what's actually happening?

  5. #5
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,325
    Quote Originally Posted by edrummer View Post
    is this what you mean? I added #include "MIDIUSB.h" and got it to compile ....
    You don't need to use this library with Teensy.

    But it also should not effect whether it compiles or not...

    Instead you select "MIDI" from the Tools->USB Type menu but I think you must have done that to get it to compile with those USBMidi.sendNoteOn messages.

    Are you saying it plays a note at startup and it sticks until played again and then another fires and sticks?

    FYI it's much easier to troubleshoot MIDI sketches if you have software that can tell you exactly what midi your computer is receiving from Teensy. Search for a 'midi monitor' - MIDIOX is often used for this.

    Also, are you voltage limiting the signal before it gets to your Teensy? Piezo discs can generate voltages well in excess of what is safe for Teensy.

  6. #6
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,325
    FYI it's much easier to troubleshoot MIDI sketches if you have software that can tell you exactly what midi your computer is receiving from Teensy.
    Paul's point about using serial print may be more helpful as your problem may stem from the signal peak issues. Is it possible you are reading a DC offset voltage that is above the threshold all the time?

    Some details on your hardware might be in order

  7. #7
    Senior Member
    Join Date
    Feb 2018
    Posts
    154
    It did stick on 1 note the first time I tried it, I tweeked the parameters and got it to kind of work but it's so slow it I don't think it's going to work for me. The sketch in #1 works fine with all my soft ware, with very little latency. I had success with this sketch on a different board but I had to use Hairless which caused problems with the ports.

    Code:
    #include "MIDIUSB.h"
    
    // First parameter is the event type (0x09 = note on, 0x08 = note off).
    // Second parameter is note-on/note-off, combined with the channel.
    // Channel can be anything between 0-15. Typically reported to the user as 1-16.
    // Third parameter is the note number (48 = middle C).
    // Fourth parameter is the velocity (64 = normal, 127 = fastest).
    
      
    void noteOn(byte channel, byte pitch, byte velocity) {
      midiEventPacket_t noteOn = {0x09, 0x90 | channel, pitch, velocity};
      MidiUSB.sendMIDI(noteOn);
    }
    
    void noteOff(byte channel, byte pitch, byte velocity) {
      midiEventPacket_t noteOff = {0x08, 0x80 | channel, pitch, velocity};
      MidiUSB.sendMIDI(noteOff);
    }
    #include "MIDIUSB.h"
    
    //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);
    }
    Click image for larger version. 

Name:	midi m.PNG 
Views:	58 
Size:	41.9 KB 
ID:	12971 is this midi?

  8. #8
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    21,473
    Quote Originally Posted by edrummer View Post
    is this midi?
    Yes, it is indeed MIDI, but you're sending the MIDI bytes to the Arduino Serial Monitor.

    You almost certainly meant to use Serial1 rather than Serial in these places:

    Code:
      Serial.begin(SERIAL_RATE);
    Code:
    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);
    }
    Or if you intended to send MIDI messages to your PC, you must use usbMIDI.setNoteOn() and usbMIDI.setNoteOff().

  9. #9
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    21,473
    From your questions and code, my guess is you're reading quite a lot of info which was written for regular Arduino boards. Most is good, but Teensy has far more capability than boards like Arduino Uno. On Uno, there is only one Serial.

    On Teensy, you get Serial which talks to the Arduino Serial Monitor, and you get 6 more Serial1, Serial2, etc which are the hardware serial pins. You ALSO get usbMIDI which can talk MIDI over USB to your PC. All of these can work simultaneously on Teensy 3.6. That's a massive step up in capability compared to Uno where you basically get just one Serial. Usually this makes things easier, because you can always use the Arduino Serial Monitor even while you're sending and receiving MIDI.

    But having 7 different Serial and also MIDI at the same time is a lot more than Arduino Uno. If you read other websites where people write info for Uno, please keep in mind you're using a far more powerful board. Usually that power makes things easier, but it's also not as simple as everything being only one "Serial".

  10. #10
    Senior Member
    Join Date
    Feb 2018
    Posts
    154
    I get this error when I try to change it, 'class usb_midi_class' has no member named 'setNoteOn', I don't know enough about code to make a lot of corrections.

  11. #11
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    21,473
    Quote Originally Posted by edrummer View Post
    I don't know enough about code to make a lot of corrections.
    It's ok to be a beginner. We can help you, but only if you show us the code that isn't working (eg, the "forum rule").

  12. #12
    Senior Member
    Join Date
    Feb 2018
    Posts
    154
    The code in#7 I thought that was what you meant in post#8. I was trying to get the code in 7 to work with the T3.6

  13. #13
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    21,473
    I copied the code from #7 into Arduino and clicked Verify. No errors. Nothing like "I get this error when I try to change it, 'class usb_midi_class' has no member named 'setNoteOn'"

  14. #14
    Senior Member
    Join Date
    Feb 2018
    Posts
    154
    Does it work with a teensy? The code will compile with no changes but it doesn't work, Doesn't play a note. thought you that what you meant by ''Or if you intended to send MIDI messages to your PC, you must use usbMIDI.setNoteOn() and usbMIDI.setNoteOff().''

  15. #15
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    21,473
    Quote Originally Posted by edrummer View Post
    Does it work with a teensy?
    No, the code in #7 is written for Arduino Uno, not Teensy.

    As written you are sending bytes to the Arduino Serial Monitor. I tried to explain this in message #9. Those 2 functions near the end are sending 3 bytes to "Serial", which always talks *only* to the Arduino Serial Monitor when using Teensy. The data you meant to be MIDI messages appears as weird characters in the Arduino Serial Monitor!

    Moreover, you are including MIDIUSB.h, which is not harmful but also not very helpful when using Teensy. I suggest removing MIDIUSB.h. On Teensy, the USB MIDI is selected from Arduino's Tools > USB Type menu. You do *NOT* need to include anything else. Just select it from that menu. Stop trying to include the stuff that's used for non-Teensy boards! Doing that is only making everything harder for you...

    On Teensy, use usbMIDI.sendNoteOn(note, velocity, channel) to send USB MIDI to your computer. Details here:

    https://www.pjrc.com/teensy/td_midi.html

    If you are unsure how this works, I highly recommend starting with the examples from File > Examples > Teensy > USB_MIDI. The Buttons example is a good place to start. That will give you *working* code for sending note on/off messages. Copy that code into your program.

  16. #16
    Senior Member
    Join Date
    Feb 2018
    Posts
    154
    So I was able to get this to work by changing the resistor, Can the sketch be modified for multiple pads?

  17. #17
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,325
    Can the sketch be modified for multiple pads?
    Typically the way to move to multiple controls is to change variables and constants to arrays where needed and add a for( i=0,i<N,i++) type loop to read through each with the index variable.

    That way you run the same code N times.

    Alternatively you can just add more variables and copy the functional part of your sketch N times and make all those variable name changes manually. If N is small enough or if the controls are used very differently within the sketch this isn't a bad option for code readability. But if you're making an tuned-percussion controller then you definitely need to use arrays.

    Knowing what your current sketch is would help (there's a bunch of code in this thread and I'm not 100% sure I know which one you mean).

  18. #18
    Senior Member
    Join Date
    Feb 2018
    Posts
    154
    Thanks, it's this one, I just want to make 22 pins with piezos to fire notes 36-58 the same way it does now. If one way would be better as far as not adding latency then that would be best. Other than that they can all be the same,I can adjust velocity in the software.

    Code:
    /* 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.
    */
    
    const int channel = 10;  // General MIDI: channel 10 = percussion sounds
    const int note = 38;     // General MIDI: note 38 = acoustic snare
    
    const int analogPin = A0;
    const int thresholdMin = 60;  // minimum reading, avoid noise and false starts
    const int peakTrackMillis = 12;
    const int aftershockMillis = 25; // aftershocks & vibration reject
    
    
    void setup() {
      Serial.begin(115200);
      while (!Serial && millis() < 2500) /* wait for serial monitor */ ;
      Serial.println("Piezo Peak Capture");
    }
    
    
    void loop() {
      int piezo = analogRead(analogPin);
      peakDetect(piezo);
      // 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) {
      // "static" variables keep their numbers between each run of this function
      static int state;  // 0=idle, 1=looking for peak, 2=ignore aftershocks
      static int peak;   // remember the highest reading
      static elapsedMillis msec; // timer to end states 1 and 2
    
      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, 1, 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
          }
      }
    }

  19. #19
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,325
    I've highlighted in red the variables/constants that would need to be arrays to hold different values for different signals.

    Code:
    const int channel = 10;  // General MIDI: channel 10 = percussion sounds
    const int note= 35 ;   
    
    const int analogPin = A0;
    const int thresholdMin = 60;  // minimum reading, avoid noise and false starts
    const int peakTrackMillis = 12;
    const int aftershockMillis = 25; // aftershocks & vibration reject
    
    
    void setup() {
      Serial.begin(115200);
      while (!Serial && millis() < 2500) /* wait for serial monitor */ ;
      Serial.println("Piezo Peak Capture");
    }
    
    
    void loop() {
      int piezo = analogRead(analogPin);
      peakDetect(piezo);
      // 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) {
      // "static" variables keep their numbers between each run of this function
      static int state;  // 0=idle, 1=looking for peak, 2=ignore aftershocks
      static int peak;   // remember the highest reading
      static elapsedMillis msec; // timer to end states 1 and 2
    
      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, 1, 127); // do you really want velocity = 1 at threshold?
            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
          }
      }
    }

    To keep things simple for now I'd move the peak-detection code and analogread() call into the same programing structure to make accessing the arrays a bit simpler.

    The main loop is tiny so I'd likely just pull the peak detect code back into the main loop.

    I could try my hand at making the required changes but I'm not in a position to build a test rig with even one piezo at present so it would be a casual testing at best.

  20. #20
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,325
    Oh.... since this code requires 3.3 volts at the pin to give 127 velocity I hope you have some signal conditioning to limit the possibility of damage to Teensy?

    Piezo transients can damage uC pins if not limited with at least an in-series resistor but some schemes are much more robust with external clamping diodes.

    Not an EE so I'm not sure how safe you need to be but if you're bashing a piezo with a stick I'm thinking you want to be protected from plausible spike voltages.

  21. #21
    Senior Member
    Join Date
    Feb 2018
    Posts
    154
    Thanks very much! I'll work on this a little later. I don't know about the velocity at 1 threshold, I just copied the code as is. What do you suggest?

  22. #22
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,325
    You can tweak the velocity mapping based on the actual readings you see when you're pounding on it...

    My point was more about making sure you read up a bit in signal protection from piezo discs and microcontroller inputs.

    I'm also not sure you want linear mapping all the way to 1 when the threshold is met as it usually is inaudible if it's mapped to volume. But like I say you can tweak the map line later but not if your Teensy's analog pins are fried.

  23. #23
    Senior Member
    Join Date
    Feb 2018
    Posts
    154
    Yes I do have the pins protected with 3.3 diodes. I'm just not sure how to do this, the code is like a foreign language to me. For example do I replace const int note= 35 ; with int [22] note={36,37,38,39, and so on?};
    Last edited by edrummer; 02-24-2018 at 04:06 AM.

  24. #24
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,325
    I'll write some code but you'll have to understand it to debug it.

    You're close... it's more like this:

    const int note[22] = {35,36,37,....,54};

  25. #25
    Senior Member
    Join Date
    Feb 2018
    Posts
    154
    IS THIS CORRECT?

    const int note [22] = {36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,52,5 3,54,55,56,57,58};

    const int pin [22] = {A0,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14 ,A15,A16,A17,A18,A19,A20,A21,A22};

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •