Arduino Piezo MIDI Controller

This project uses piezo sensors to build a simple “drum” MIDI controller.  This is a relatively simple build, but there are a number of excellent examples of doing this “properly” out on the Internet. Here are some that are particularly great:

Warning! I strongly recommend using an old or second hand keyboard for your MIDI experiments.  I am not responsible for any damage to expensive instruments!

These are the key Arduino tutorials for the main concepts used in this project:

If you are new to Arduino, see the Getting Started pages.

Parts list

  • Arduino Uno
  • 5x piezo sensors
  • 5x 1MΩ resistors
  • 5x Zener diodes rated at 5.1V (I used 1N4733A)
  • MIDI out module (optional, see Arduino MIDI Interfaces)
  • MIDI synthesizer, sound module, or similar (I used my Arduino MIDI VS1053 Synth)
  • Breadboard and jumper wires

The Circuit

There are basically five copies of the circuit described in the Knock tutorial but with the addition of zener diode as recommended by Marco’s project.  I built mine using a proto shield (I finally found a Fritzing part for them provided by an Adafruit customer!) and wired each sensor circuit to the analog input pins A0 to A5.

I did think about putting it together directly with the Arduino MIDI VS1053 Synth as in shield form like this it should sit nicely on top, but in the interests of keeping some simple partitioning in both hardware and code, I kept it separate for now.

The output is using the Arduino’s serial port, so can be tapped off TX (pin 1) which can either go off to a MIDI out module or in my case, directly to the RX (pin 0) of the other Arduino with the VS1053 synth shield.

All that is required then is to mount the sensors somehow. I taped mine to the back of plastic hot chocolate tub lids as follows:

This kept things very simple, but isn’t very robust.  In particular having a good interface between your sensor and the surface is important, as it reducing the direct force on the sensor itself.  Neither things of which I’ve done in the above!  The other projects I’ve listed really do this properly. If you want a proper drum sensor, have a look (and admire) Marco’s build.

The Code

The code to handle piezo sensors is relatively straight forward.  The basic principle, as described in the Knock tutorial, is to read the analog port and when the value rises above a certain threshold, treat it as being “triggered”.  The trick is to avoid re-triggering quickly as the signal from the sensor will bounce around a fair bit.

To do that for a single input is fairly easy – once triggered, just don’t read it again for a short while.  But to keep track of what is going on for several sensors at the same time gets a bit more fiddly.

My approach is largely as follows:

For each time round the Arduino's loop:
  Read one of the analog ports
  For each sensor we're monitoring:
    IF the sensor was activated previously THEN
      Has our timeout for that sensor expired?
      IF so, then send a MIDI noteOff command
    ELSE IF the sensor is the one we're reading THEN
      Is the value over the THRESHOLD for triggering?
      IF so, then record the current time in milliseconds
         and send a MIDI noteOn command

When the sensor is triggered I read the current millisecond counter using millis() which returns the number of milliseconds since the Arduino was turned on. When it comes to checking the sensor, if the latest reading of the millisecond timer is still within the “excluded” time, I don’t try to read it again.

The millis() call returns an unsigned long, that is a number between 0 and 4,294,967,295.  This means that timer will eventually wrap around back to zero after 50 years or so, so for these purposes it works fine. I also use the expiry of the “excluded” time to trigger a MIDI note off.

I only read one analog port at a time as the reading itself takes a bit of processing time, so I share it out in between processing the other sensors expiry.

All well and good so far, but how do you choose the thresholds for triggering and expiry times?  That will depend on your sensor, how its mounted, how hard it can be hit, and how much flexibility of movement in the sensor afterwards.

The best way is to include a “calibration” mode, which is something I’ve done.  If you remove the comment (“//”) from following two lines in the code:

//#define DEBUG     1   // Will print MIDI information to serial port rather than send over MIDI.
//#define CALIBRATE 1   // NB: Need both DEBUG and CALIBRATE to calibrate sensors.

Then the code will collect the readings from one of the sensors and output them all to the serial port as a string of numbers.  Now the Arduino IDE has a neat feature that I don’t see mentioned very much, but to be honest I’ve not really used much myself either, but is really useful for this kind of thing.  The Serial Plotter.  Find it under “Tools” – “Serial Plotter”, match the baud rate (I’ve used 115200 in this example) and off you go.

This will take a stream of numbers from the serial port and plot them on a graph.  There is a great tutorial on how to use it from Adafruit here.

With this enabled, I can take some readings and get an idea for what levels are being generated when the sensors hit. What I can’t do is estimate the time they are taking to die away again – the plotter just plots numbers, although I could probably do some guestimating from the clock cycle time of the Arduino if I really needed to know (although at this point, breaking out a real oscilloscope to the sensor’s signal might be easier).

Here are some plots from some of the sensors.

As you can see, there is a lot of variation and noise in the signals.  This is probably down to my crude taping of the sensors to the lids and the way they flex after being struck.  A better (i.e. I mean some) mechanical design would help here.

But from this, I can see a threshold of 300 would probably trigger nicely. I initially set the exclude time to 50mS but that was proving too short, causing repeat triggers for a single hit.  In the end I’ve gone with 100mS which is a good mix of responsiveness and “debouncing”.

In terms of MIDI handling, I didn’t bother with the MIDI library for this one.  I only have to send note on/off messages so I’ve just done that directly by printing out values to the serial port initialised at the MIDI baud rate of 31250 as per the Arduino MIDI tutorial.

In addition to the CALIBRATE mode, there is a DEBUG mode.  When enabled without CALIBRATE it won’t send data over MIDI, but will print the messages being produced to the serial terminal.  I leant something I didn’t know when doing this – I wanted to show the command in hexadecimal as the lowest part is the MIDI channel.  Turns out the Arduino Serial.print command can do simple formatting for numbers, so I can just use:

Serial.print (cmd, HEX);

Being a drum controller, it will transmit on MIDI channel 10, which comes out in the commands as 0xn9 – recall that MIDI channels are named 1 to 16, but are represented by the numbers 0 to 15 (0x0 to 0xF in hex) in the actual protocol.  So a “note on” for channel 10 is 0x99 and a “note off” for channel 10 is 0x89.

Find it on GitHub here.

Closing Thoughts

This is about the simplest piezo drum controller possible. It would be nice to put some proper effort into the mechanical side of the build and have some good, responsive sensors.  I’ve only included five here, but the Arduino has six analog ports that can be used directly, and with the use of analog multiplexers that can be expanded significantly.

I’ve set it up as a drum trigger, but there is no reason why it couldn’t send actual note values too.  In fact I’ve always fancied building a piezo-MIDI xylophone synthesizer.

2020-07-19 14.49.14


6 thoughts on “Arduino Piezo MIDI Controller

  1. How to make drum sound based on the hit on the piezo like when I hit the piezo a little the drum sound will come with sound a little too and when the piezo is hit hard then the drum sound will sound loud too?
    It’s like padcutoff or something?
    Thanks in advance


    1. Technically it is possible to take the amplitude of the signal from the piezo via the analogRead() call and use that to set a velocity for the MIDI note messages, but I just use a fixed velocity and am using the piezo just as a trigger.

      You’d have to experiment to see what range of values you get back. The calibrate mode may help a little. I suspect you’d have to set some fixed, known ranges and choose maybe 3 or 4 fixed velocities to use for the ranges, but I’ve not tried it myself.

      Do let me know if you give it a go and let me know how you get on.



      1. i combine the sketch from this
        it’s work only just led in pin 4 arduino with vs1003 sketch the blink brightness when i hit piezo with hard and dimm when i hit soft but the drum sound not change still same

        for (int sensor=0; sensor timeon[sensor])) {
        // This sensor was previously activated

        if((activePad[sensor] == false)) {

        if(VelocityFlag == true)
        // sensor = 127 / ((1023 – timeon[pin]) / (hitavg – timeon[pin])); // With full range (Too sensitive ?)
        sensorPin = (sensorPin / 8) -1 ; // Upper range
        sensorPin = 127;

        timeon[sensor] = 0;
        activePad[sensor] = true;


        else {
        PinPlayTime[sensor] = PinPlayTime[sensor] + 1;
        else if((activePad[sensor] == true))

        PinPlayTime[sensor] = PinPlayTime[sensor] + 1;

        // This sensor can be read
        if(PinPlayTime[sensor] > MaxPlayTime[sensor])
        activePad[sensor] = false;
        // and has been read



      2. That’s a little hard to follow. If you email me ( your whole sketch I’ll have a look.



Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s