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


13 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.



  2. Hey 🙂 I could use ur help at this project. I’m using it for uni and only getting started with arduino. I think i put everything together correctly and the controller and the sound module work on their own and i connected them. I don’t get how i can assign the sounds to a piezo sensor. I put the numbers from the controller code of the drums to the list of midi channels in the code of the sound module and there is an error. I’d appreciate ur help


    1. I’m sorry, but I don’t quite follow what you’ve updated. Is the code being used as is? If so then each piezo will result in a single MIDI note message for the configured MIDI note to be sent out on the MIDI_CHANNEL channel. The default configuration assigns five piezo triggers to the following MIDI notes: 42, 35, 38, 47, 49 and uses MIDI channel 10. Channel 10 is usually the drum channel and these will correspond to specific drum instruments (as listed in the comments) if the sound module is following the General MIDI specification.

      What sound module are you using? When you say you put the “numbers… to the list of midi channels in the code of the sound module” I’m not quite sure what you mean. Are you changing the configuration of the sound module or the Arduino code?

      One point of confusion is that some devices use MIDI channels 1 to 16, whilst some might use 0 to 15. It is actually 0 to 15 “on the wire” but most devices use 1 to 16 in manuals, menus, interfaces, etc. So the drum channel is 10, but it will be sent “on the wire” as 9.

      A similar point of confusion can occur with drum note numbers too I’m afraid – some will use the 0 to 127 range (which again are the actual numbers “on the wire” used in the protocol) but some will use a “user friendly” 1 to 128 range, mirroring how Program Change messages work! I seem to recall not being able to find any guidance online, so just used the 0 to 127 numbers for drum notes.

      So, to help further, I’d really need to know what sound module you’re using, what you are changing (Arduino or sound module), and what the actual error is 🙂

      Then I’ll do my best!



      1. I’m sorry for the confusing comment. I just started using it. I’m using this one:

        maybe i’m confused because i thought i had to run the code for the sound module and the code for the controller at the same time(?)

        right now there is no sound coming out but arduinos serial monitor is showing me that there is a reaction if i press the piezo sensor.


      2. Ah I see. And are you trying to use both with the same Arduino? If so, then yes, you will need a single sketch to run code to do both things at the same time.

        So how are you using the VS1053 – are you using it in “MP3” mode as a sample player or in MIDI mode as a General MIDI module?

        I’ve used piezos with a sample-playing type thing before here:

        I’ve used the VS1053 in a “player” mode here:

        And I’ve used the VS1053 in MIDI mode here: with the details of the actual code used explained here:

        I’ve also used a similar module (the VS1003) as a simple “drum machine” here:

        As you can see, I probably have the information somewhere for most of what you’re trying to do, just probably not in the same sketch!

        Let me know in detail what you’re trying to do, what you’ve tried, and what isn’t working and I’ll see what I can do! But ultimately, yes, you’ll need to combine some of these different techniques to get a piezo-driven VS1053 drum module all from the same Arduino – but it should be possible 🙂



  3. Is there a possibility that i could send you what i build + the code (which i didn’t change), so you could see everything i’ve done?


    1. Yes feel free – just email me diyelectromusic at gmail, or msg me somehow and I can send you a discord invite if that is more your thing?

      But I’ll still need to know what happens when “there is an error” and I still need to know how you’re wanting to use the VS1053 and if you’re trying to do both from the same Arduino. Basically, all my questions still need an answer if I’m to help other than with generic comments 🙂

      And as I say, if you’ve not changed any of the code, then it won’t work, as I’ve not done a project that supports what you want to do exactly from what I understand about what you’ve said so far.



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