piezo velocity

Status
Not open for further replies.
Still trying to get pin A0 to change the notes of pin A1,

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);
}

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 < 10) { 
      noteOn(0, 36, 127); 
      MidiUSB.flush(); 
      while (analogRead(A0) < 10) { }
      noteOff(0, 36, 127);
      MidiUSB.flush(); 
    } 
    
  }
    int val;
  val = analogRead(A1);
  if (val > 400) {
    if (A0 val > 300); {
      send note 38
    }
    else if (A0 val > 50 < 300) {
      send note 39
    }
    else if (A0 val < 50) {
      send note 40
      velocity = map (val, 300, 1023, 30, 127);
      noteOn(0, 51, velocity);
      MidiUSB.flush();
      while (analogRead(A1) > 400) { }
      noteOff(0, 51, 127);
      MidiUSB.flush();
    }
  }]
 
This is my first post to the forum and I signed up specifically to thank Oddson for his code in post #36!! It's much appreciated :) It works really well and the comments in the code explain things enough for me to understand it.

I have limited coding knowledge but I can always learn just enough to help me achieve most of what I set out to do. This code will be used to make an vibraphone midi controller with a Teensy 3.6.

Paul's reoccurring advice to get the basics working one step at a time has also been invaluable!

Thanks everyone :)
 
Hey Thanx for the shout out...

I've wondered if active filters with low cutoff frequencies would allow much shorter scanning windows that would reduce latency and improve accuracy when many signals are read via multiplexers.

The current settings in the code gives 12 ms of latency and effectively limit double stops to 32 ms apart which seems very limiting for a percussion instrument.

A proxy envelop signal (rectified and low passed) should allow shorter scan and 'ignore' windows but I don't know if decent performance can be had without resorting to all that circuitry.
 
Hey Thanx for the shout out...

I've wondered if active filters with low cutoff frequencies would allow much shorter scanning windows that would reduce latency and improve accuracy when many signals are read via multiplexers.

The current settings in the code gives 12 ms of latency and effectively limit double stops to 32 ms apart which seems very limiting for a percussion instrument.

A proxy envelop signal (rectified and low passed) should allow shorter scan and 'ignore' windows but I don't know if decent performance can be had without resorting to all that circuitry.

It makes sense to me that analogue filtering could create a shorter note so that the coding could run faster.

I also had the idea of a matrix... I’ve opened enough keyboards (of both varieties) to understand how the hardware works, if not the coding yet. The plan would be to use two piezos per wooden note. Velocity could be calculated either combined or prioritize one of the piezos. The cost of the extra hardware works out extremely cheap.

Is there anything glaringly dumb you would foresee in that setup?
 
It makes sense to me that analogue filtering could create a shorter note so that the coding could run faster.
The idea is to produce something like an envelop signal so that intensity is read directly without requiring multiple reads to happen across a peak in the signal.

I was more than a little vague but I was assuming the signal would be rectified and then filtered.

I'm not sure what you mean by 'shorter' notes unless you are talking about removing potential re-triggers from the signal tail, which filtering should do.



I also had the idea of a matrix... I’ve opened enough keyboards (of both varieties) to understand how the hardware works, if not the coding yet. The plan would be to use two piezos per wooden note. Velocity could be calculated either combined or prioritize one of the piezos. The cost of the extra hardware works out extremely cheap.
Keyboards use two offset switches to measure the time difference which is inversely proportional to the speed of the key as it travels between the offsets of the switches.

I can't see what a second piezo would do for you.
 
Ye, with ‘shorter’ notes I was referring to signal tail. Essentially clean up the analogue input to reduce code run time.

Our wires are definitely crossed with the matrix idea :)

From what I understand a matrix reduces the input pin requirements. A1 A2 A3 A4 A5 A6 A7 A8 A9 can become A1 A2 A3 B1 B2 B3 C1 C2 C3 and will reduce 9 inputs to 6.

The use of two piezos would only to trigger two inputs (eg A and 1 or B and 3) of the matrix NOT read velocity like the tradition two contact approach under a keyboard keybed. Velocity would be read as per your piezo input code in this post.

Hope that clarifies? I’m away from my Teensy for this week but it’s something I’m more than happy to dive into when I get back to see if I can prove the concept to myself
 
No...you still don't have me.

I get the matrix thing but not what two sensors per bar will do for you.
 
Could I wire the piezos in a matrix system with one per bar? I thought I needed to trigger two inputs per note in a matrix system and have them connected to ground.

Maybe I’m being really dumb and I can simply split the signal of one piezo to the two correct inputs and ground!?

I’m not sure how polyphony would work either in a matrix. But this is along way down the road from where I currently stand in my project! I’ve only just finished learning your code for two inputs which I will scale to 20ish. Baby steps!
 
Could I wire the piezos in a matrix system with one per bar?
I'm no expert but the matrix configuration is only a means of scanning multiple signals (usually HIGH and LOW from pull down switches).

(What follows assumes you are polling rather than using interupts https://www.pjrc.com/teensy/interrupts.html
I don't know how interrupts would work with mux or with a matrix)

I thought I needed to trigger two inputs per note in a matrix system and have them connected to ground.
There typically are two but it's unrelated to the concept of a scanning matrix and is only about calculating velocity from time differences.


Maybe I’m being really dumb and I can simply split the signal of one piezo to the two correct inputs and ground!?
...unless I'm sorely mistaken there is no reason to do this.

I’m not sure how polyphony would work either in a matrix.
Speed and diodes.... you are scanning each input in sequence but tracking the signals of all sensors across time. Even with digital switches there is something similar going on with contact bounce. The diodes prevent the signals from travelling thru alternate routes but limit the signal to a single polarity, so you would need to bias the signal.

The key is speed. You scan at a rate sufficient to capture the shape of all the signal envelopes without any external trigger.



But this is along way down the road from where I currently stand in my project! I’ve only just finished learning your code for two inputs which I will scale to 20ish. Baby steps!
I would skip the matrix and use multiple mux instead even though it should work with a biased and conditioned signal.


With the setup Paul outlines you only add one pin for each new mux... (see the mux section here: https://www.pjrc.com/teensy/td_midi.html)

With 16 channel mux you can double the count with just one extra control pin.

This post links to some hopefully relevant threads for when you get to that point.
https://forum.pjrc.com/threads/52856-MIDI-and-MUX?p=181888&viewfull=1#post181888
 
Thanks for the reply and links Oddson! I’ve skim read Pauls page before but will give it a deeper read to try understand mux. I get the basic concept of using extra hardware to read extra inputs through one on the Teensy.
 
There are also GPIO extender chips that communicate via protocols like I2C but I personally don't feel it's worth the overhead when index loops with multiplexers extends array-based code so readily.

Also while writing my last post it occurred to me how something like what you are suggesting could be done using interrupt programming instead of sequential polling (hence the caveat).

You still would not require a second sensor, rather an analog comparitor could trigger a flip-flop to set an interrupt flag when some threshold is crossed so that when the interrupt routine is run it would read only the relevant pin(s).

E.g. you could poll by a row or column in the matrix based on your external interrupt.

You may have been thinking along these sorts of lines but there is still no point to two piezo sensors per bar.

Logically their signals would be nearly identical and any differences would be unpredictable and therefore of no use (unless maybe as audio signals).

Good luck in your endevours
 
Last edited:
Having loads of fun with this project! It's running really smooth and I've managed to add my own octave/transpose coding with IF Else so I can use the same kind of piezo inputs instead of regular push buttons. It's mega useful as I don't have to swap from mallets to fingers during a performance. Pure assumption but I imagine that would also keep the code loop time efficient.

I'm looking to move on to multiplexing with the 74HC4051 but I have two questions...

1) I have a Teensy 3.6 that is 3.3v but all the info I've read suggests a 5v supply. Will 3.3v be ok or are there any simple routes to supply 5v?

2) I have protection with two diodes & two resistors on each input... will I need to keep that on all piezos to multiplexers (x8 per mux) OR can I put one between the multiplexer and Teensy to cover those 8 inputs?

I'm guessing simple answers for both but unlike coding I'm not keen on experimenting too much with the risk of frying an awesome Teensy!
 
Teensy 3.6 uses 3.3 v for signals but you can still power MUX from the 5 v pin from the USB supply. Some mux only need 3.3 supply.

Not sure about having no voltage protection for the mux... they are much more robust so it may be ok.
 
Ah sorry Oddson, the USB host 5v... I completely overlooked that on my reference card. My (basic) mistake! Thanks.

I’ve done a lot of searching in regards to protection on every input PRE mux or one set POST mux between itself and the Teensy but still drawing a blank. I’m learning a lot in a short space of time but the vast majority of what’s found in data sheets still looks alien to me unfortunately. I guess it all depends on how the mux handles the potential peak voltage sent from the piezo?

...the good thing is I’ve really taken time to try understand you original code in detail. The use of ‘i’ had me stumped for a while but once I got over that the logical flow isn’t too hard to follow and modify.
 
A mux will have a supply voltage range and if your peaks are not wildly outside of that (since it's a low impedence transient) it's very unlikely to fry the mux. (Even if you're only powered at 3.3v.)

But I'm not an EE so no guarantee from me.

Arrays and incremented loop variables add a bit of abstraction but simplify things greatly when the signal count climbs.
 
My 74hc4051 breakout boards arrived and I’ve had a few successes with mux coding but mainly through copying pre-made codes online.

When I’ve tried to modify the code below to include multiple mux piezo inputs I quickly find myself in a huge mess. I’ve tried for a few weeks now and appreciate folk on this forum want us to mainly find our own way... BUT I’m at a point where I really needed some guidance. If there’s such a thing I’ve read way too much from mixed sources and become brain tangled!

To me the basic idea is I need to modify the analogPin array to read the mux inputs. Listing analog inputs was very easy to understand with this baseline code... but adding the correct mux addressing is where I come unstuck.

I understand how to connect multiple 74hc4051s correctly confirmed with demo codes found online and I’ve successfully modified this code to include octave switching, sustain pedals etc so I’m not completely beyond help!

Any advice and direction would be very much appreciated! I’ve learnt a lot in a relatively short space of time but this is currently beyond me 😒

Oddsons original code I’m using below for quick reference!

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.
   *multi-pad extension by oddson (under-tested)*
*/

const int channel = 10;  // General MIDI: channel 10 = percussion sounds
const int PINS = 3;     // number of signals incoming

const int note[PINS] = {36,37,38};     // array of MIDI note values for read signals

const int analogPin[PINS] = {A0,A1,A3}; //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]; // timers 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++){
    //delay(20);
    piezo[i] = analogRead(analogPin[i]);
 
  peakDetect(i);
  // 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 i) {

        //Serial.println(state[i]);

  switch (state[i]) {
    // 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 (piezo[i] > thresholdMin) {
        //Serial.print("begin peak track ");
        //Serial.println(piezo[i]);
        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) {
        //Serial.print("peak = ");
        //Serial.println(peak);
        int velocity = map(peak[i], thresholdMin, 1023, 1, 127);
        usbMIDI.sendNoteOn(note[i], 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(note[i], 0, channel);
        state[i] = 0; // go back to idle when
      }
  }
}
 
...Oddsons original code ....
I only did the extention to multiple input.

What specifically are you trying to achieve right now and what is the final goal?

The first step should be to read from one mux.

For that your index variable 'i' needs to increment to the number of mux channels (8) instead of 'PINS'.

Then you need to set the control pins for the mux based on the current value of i.

The control bits are set from the binary values of the least-three bits

0 = b000
1 = b001
2 = b010
...
7 = b111

This post includes links to other mux extentions as well as a further bit of explanation....
https://forum.pjrc.com/threads/52856-MIDI-and-MUX?p=181888&viewfull=1#post181888


Once you can get data via a single mux you can perhaps start a new thread in project advice on how best to achieve your full project.
 
My only goal right now is to change this...

Piezo -> protection circuit -> teensy (works fantastic with the code posted above!)

To this...

Piezo -> protection circuit -> MUX 74hc4051 -> teensy.

The physical connections I have no issue wiring correctly (including all empty mux inputs to ground) but pointing the code to the right place via mux is my struggle.

I’ll spend some time trying to absorb your advice above and will probably need to post a follow up if that’s ok.

Thanks again Oddson!
 
Had to make an account just to Thank you guys for having this conversation! i was wondering how to make Piezo_DrumA0 sketch register multiple pads on a Teensy4 with no need for 'Hairless'.
Thanks to oddsons code i got 4 pads running after a quick mod. (this is literally my first venture into Arduino and also.. drumming)

Here is my modded code (for those that just want to copy it over and run it)
[also, sorry to necro post im just happy to get something positive out of this Covid situation]



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.
   *multi-pad extension by oddson (under-tested)*
*/

const int channel = 10;  // General MIDI: channel 10 = percussion sounds
const int PINS = 4;     // number of signals incoming

const int note[PINS] = {36,37,38,39};     // array of MIDI note values for read signals

const int analogPin[PINS] = {A0,A1,A2,A3}; //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]; // timers 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++){
    //delay(20);
    piezo[i] = analogRead(analogPin[i]);
 
  peakDetect(i);
  // 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.
  // [url]http://forum.pjrc.com/threads/24179-Teensy-3-Ableton-Analog-CC-causes-midi-crash[/url]
  while (usbMIDI.read()) {
    // ignore incoming messages
  }
}


void peakDetect(int i) {

        //Serial.println(state[i]);

  switch (state[i]) {
    // 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 (piezo[i] > thresholdMin) {
        //Serial.print("begin peak track ");
        //Serial.println(piezo[i]);
        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) {
        //Serial.print("peak = ");
        //Serial.println(peak);
        int velocity = map(peak[i], thresholdMin, 1023, 1, 127);
        usbMIDI.sendNoteOn(note[i], 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(note[i], 0, channel);
        state[i] = 0; // go back to idle when
      }
  }
}
 
hello,

I am new in the forum, although I bought teensy 3.2 years ago, and it still working well.

I finally got the time to work on this, I have connected several piezo to teensy 3.2 and the code works great,

I'm trying to take it up a notch by adding its own sound module (with the audio board), has someone done this?

I just want to trigger sample sound so it doesn't need to connect to software or other hardware to produce sound.

if there are links, that would be greatly appreciated

thanks
 
Status
Not open for further replies.
Back
Top