Arduino LDR MIDI Piano

I always meant to go back to my Arduino LDR Pianola and extend it to more notes, but so far haven’t quite got there.  But this projects uses a multiplexer to link up eight LDRs to an Arduino and use it as a simple “keyboard” MIDI controller.

Warning! I strongly recommend using old or second hand equipment for your 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

The Circuit

Arduino-LDR-Piano_bb

The LDR is used as a replacement for a potentiometer (as previously described here) and the multiplexer allows the Arduino to choose one of the LDRs to read at a time using a single Arduino analog input.  As there are eight channels on the multiplexer, three digital signals are needed to select one of the eight channels to connect to A0.

The channels are selected as follows:

LDR    S2  S1  S0
 0      0   0   0
 1      0   0   1
 2      0   1   0
 3      0   1   1
 4      1   0   0
 5      1   0   1
 6      1   1   0
 7      1   1   1

As you may spot the coding of S0 to S2 is the binary equivalent of the channel number (0 to 7).

If you are using the Sparkfun breakout, it is worth noting that VEE does not need to be connected – it is internally connected to GND already; and that E also doesn’t need to be connected – again it is internally connected to GND, which in this case means “active” – i.e. the multiplexer is enabled all the time.

If you were planning on using several of these multiplexers in a project, the E pin allows you to choose which is active at a time.

If you don’t have a breakout board, but are just using a 4051 chip directly, you can read more about the 4051 8-way multiplexer here.

If you want more inputs you can look into using a 4067 16-way multiplexer as described here.

You can arrange the LDRs however you wish.  I’ve followed the circuit as shown above, but rearranged the LDRs across two breadboards into a circular design with the multiplexer in the centre as you can see below.

IMG_5450

The Code

The basic idea is to have a “note” triggered by waving your hand over an LDR.  The LDR therefore needs to give a “covered or not covered” indication as if it was a touchless switch.  To do this, there are a few things to consider:

  • We need some idea of what “not covered” is.
  • We need to be able to spot when a particular threshold is reached which means we can now treat the LDR as being “covered”.

There are two parts to this.  First, I’ve written a LDR equivalent of digitalWrite which returns a HIGH or LOW depending on if the LDR is covered or not.  The thresholds to use are stored in the cal[] array (more on that in a moment).

bool ldrDigitalRead (int ldr) {
  int ldrval = muxAnalogRead(ldr);
  if (ldrval < cal[ldr]) {
    return HIGH;
  } else {
    return LOW;
  }
}

The function muxAnalogRead is an equivalent to analogRead that knows how to select one of the channels from the multiplexer and then read the analog input appropriately.

int muxAnalogRead (int mux) {
  for (int i=0; i<3; i++) {
    if (mux & (1<<i)) {
      digitalWrite(muxpins[i], HIGH);
    } else {
      digitalWrite(muxpins[i], LOW);
    }
  }
  return analogRead(MUXALG);
}

This codes exploits the binary equivalence of S0 to S2 and the mux/channel number (0 to 7).  Essentially it will drive the digital pin associated with S0 to S2 HIGH if the equivalent bit is set in the “mux” value.

The final piece relates to how I work out the threshold values to use and store in the cal[] array.  As the lighting conditions are likely to be different every time the Arduino is turned in, before doing anything else I perform a series of dummy reads from each LDR and calculate an average reading for each.  Then I take off 20% (i.e. a fifth) from the average and use that as my threshold.  This means the thresholds for each LDR might be different.  This is all performed at the end of the setup() code.

for (int j=0; j<16; j++) {
  for (int i=0; i<NUMKEYS; i++) {
    int ldrval = muxAnalogRead(i);
    cal[i] += ldrval;
  }
  delay(200);
}
for (int i=0; i<NUMKEYS; i++) {
  cal[i] = cal[i]/16;
  cal[i] = cal[i] - cal[i]/5;
}

There is a short delay between each read to get better coverage for the average.  My code includes a TEST mode that prints out the calibration data to the serial port. Here is an example – notice how one of the LDRs reads much lower than the rest, but it doesn’t matter.

ArduinoLdrPiano - calibration

The MIDI handling looks for transitions – covered to not covered; not covered to covered – to generate MIDI note OFF or ON events as required.  The notes generated are preset at the start.

Find it on GitHub here.

Closing Thoughts

In the video I’m once again driving my MT-32, using the Harmo-Pan voice.

I’d quite like to build this into a breadboard and maybe even extend it to use more LDRs. I quite like the idea of a “circular” controller, but not sure the physical layout on the breadboard is particularly optimal at the moment, but it isn’t a bad starting point for now.

At present, the LDRs are treated as a simple on/off.  It might be interesting to use the intensity as the source for another parameter – possible key velocity, after-touch or even pitch bend.  At present the notes are set to a standard major scale but of course there is massive variety possible from this point onwards.

Kevin

12 thoughts on “Arduino LDR MIDI Piano

  1. Hey kevin, awesome project. I’ve done everything correctly both hardware wise and software wise. Even tho I can see the Rx and Tx leds on the arduino blinking everytime i put my hand on an ldr, i dont receive and midi through the midi output. I’ve also tried to use hairless midi, and i keep geeting this error. +6.13 – Warning: got a status byte when we were expecting 1 more data bytes, sending possibly incomplete MIDI message 0xc0. Any ideas on what is it going wrong ?

    Like

    1. Hi there.

      Are you using my code exactly as is? What hardware are you using – an Uno? How are you connecting the Arduino to MIDI – are you using an off-the-shelf MIDI module or a DIY option?

      Assuming all that is ok, nothing immediately springs to mind, but I think the key now is trying to work out which bit in the chain Arduino->MIDI module->MIDI Lead->PC->Driver->MIDI Software seems to be struggling. I’d probably start trying some of the following:
      * If you load a test sketch that only sends a MIDI note on and note off does that work?
      * Are there any additional serial statements in your sketch that change the serial baud rate?
      * Do you know your MIDI lead works ok with other MIDI gear into your PC?
      * If you use something like MIDIOx what is it showing you it is receiving?
      * Is your MIDI module ok for use with the flavour of Arduino you’re using – e.g. 5V for Uno, etc?
      * Have you used your MIDI module with another Arduino and do you know it works?

      Those are the kinds of things I think I’d be trying at this point.

      Let me know how you get on.

      Kevin

      Like

      1. Hi there and thanks for your quick answer and this project as well.

        I’m using your code exactly as it is, I did tweak it a bit changing the serial baud rate when i tried to connect it with the hairless midi software after i had no success with the midi out-midi lead connection. But i havent tweaked anything else and im using your code and your schematic exactly as it is. I also tried rebuilding the whole thing with new components so I dont think this is a hardware issue.
        I’m using an Arduino Uno yes, I’ll try sending just a midi note on and note off, but im pretty positive this will work since ive done it in the past as well.
        There are no additional statements so far.
        The MIDI lead is working with other MIDI Gear yes.
        The DIY Midi out module i made is a simple one. Pin 4 of the female midi -> 220k resistor -> 5V // Pin5 -> Tx of the Uno // Pin2-> Ground.

        I have tried to both drive an Arturia keystep ( Have already checked of the Midi channel im using) and a Behringer Model D. But i havent used this midi out circuit to any other project since ive been doing everything connecting them with Hairless Midi and LoopBe sending the MIDI data to Ableton.

        Do you think that the problem is probably the Midi out circuit that i’ve made?
        Is there a reason that this LDR Midi piano wont communicate with Hairless Midi as well? Is it mandatory that i use a midi out module ?

        Thank you for your quick answer, I really appreciate it.

        Like

      2. Are you only using a single resistor in your MIDI out circuit? MIDI is a current loop and specifies a 220R resistor on both pins. It maybe that the current isn’t quite right with just one resistor? Just one idea… more here: https://diyelectromusic.wordpress.com/2021/05/29/midi-connections-cheat-sheet/

        Actually – do you really mean 220k?? It should be using 220 ohm resistors not 220,000…?

        I seem to recall Hairless MIDI can’t talk the MIDI baud rate (31250Hz) so you have to set up a different baud rate? But I’m a bit hazy, as I don’t really use Hairless MIDI. I think Hairless is to connect to a serial port (not a MIDI port)? Are you using the “Serial over USB” feature of the Arduino? If so, then you’ll definitely need a different baud rate and in this case I don’t quite understand why you need additional MIDI hardware for the Arduino?

        However if that was just a test and you are using MIDI hardware on the Arduino to a PC MIDI lead (like the Roland UM-ONE I use) then it is all on the MIDI hardware – assuming that there are no Serial.print statements in the code to confuse things?

        Sorry, that is all that springs to mind right now – it might help to see a photo/diagram of your setup? I’m still not totally clear what is connecting to what…

        Keep at it – I’m sure we’ll get there!
        Kevin

        Like

  2. I meant 220 ohm yes you are right, that was a misstyping.
    Ok millionthanks for all the help, i’ll have to try out some things that you also suggested, and if i dont get there, I’ll let you know here as well and also show you some photos.

    Million thanks Kevin.
    I’ll let you know how it went.
    Chears

    Liked by 1 person

    1. Ok i tried everything again, i also added 2 220 ohm resistors, and ficed the midi out circuit as the one you suggested. I still can’t make it work.

      This time i did no tweeks at the code trying to make it communicate with hairless midi. But still i can see any midi notes being sent to my DAW.

      So to be more clear this is how my setup is.

      Arduino circuit as you made it -> Midi out circuit -> Midi in of my arturia keystep which can work as a midi interface as well and not only as midi keybord -> pc through the usb port of arturia to a usb port of my computer. Is there any mistakes, that im doing with the setup ?

      Like

    1. Ok, these are the things I’d be doing at this point then:
      1) First of all, double check the MIDI IN/OUT cabling – I know it sounds silly, but I’ve chased my tail too many times with the MIDI IN and OUT the wrong way round (I’ve had cables labelled “MIDI OUT” which means it is the “out” for the device, so needs plugging into a MIDI IN, and others labelled “To MIDI OUT” which is the “in” for the device to be connected to the MIDI OUT!!)
      2) Can the DIY MIDI interface work with another MIDI DIN device – ideally a keyboard or sound generator?
      3) Can you load up a simple sketch using minimal software (i.e. no MIDI library)? Something like the one at the end of my comment.
      4) Do you have another MIDI DIN device to verify the Arturia as a MIDI interface?
      5) If you run MIDIOx does it see the Arturia directly as a MIDI interface? If so, it should be able to show you everything it receives.
      6) I trust your DAW will accept MIDI on any channel? The sketch I believe sends on channel 1.

      Is your DAW seeing the Arturia directly as a USB MIDI device or are you trying to link it with Hairless MIDI? Hairless MIDI expects a raw serial port over which MIDI is sent, not an actual USB MIDI device. I’d expect the Arturia to present a MIDI USB port not a serial-over-USB port, so I don’t know what Hairless MIDI would make of an actual USB MIDI device. Your DAW should see the Arturia directly I’d imagine?

      Simple MIDI Out test:

      void setup() {
        Serial.begin(31250);
      }
      
      void loop() {
         Serial.write(0x90); Serial.write(60); Serial.write(127);
         delay(500);
         Serial.write(0x80); Serial.write(60); Serial.write(0);
         delay(500);   
      }
      

      I’ve tested this on my Arduino, hooked up to an off the shelf MIDI module, connected to my Roland UM-ONE firing data into MIDIOx which can see the UM-ONE directly as a USB MIDI device. This is my typical setup for this kind of thing.

      Keep at it!

      Kevin

      Like

      1. hey Kevin! just bought a midi to usb interface, and actually that was the problem. seems like the arturia keystem doesnt work as a midi interface or at least there’s something i was doing wrong trying to use it as a midi in interface. Anyway it worked! Thank you for all the help, and also all these fast answers you gave me, and cheers for this project man, I already have plans for this deivice 😀

        Keep up the good work,
        Y.

        Like

      2. Oh great news! I wonder what was going wrong then with the Arturia… how odd. Thanks for letting me know. I look forward to hearing about what you get up to.

        Good luck!

        Kevin

        Like

    1. Everything should be in the link to GitHub in the “code” section of the post. Give me a shout again if you find there is something missing 🙂

      Kevin

      Like

Leave a comment