LED Strip for Digital MIDI Piano

Hi everyone.

I’m pretty new to Arduino and a bit of a noob when it comes to coding having only ever really used MATLAB.

Anyway I’m trying to make an LED strip respond to MIDI input from my digital piano. I want each note to light up a corresponding specific LED (I’ve laid the strip behind the keys so i looks like the keys are lighting up as you play them).

I’m using a WS2812B individually addressable LED strip and the FastLED library.

#include <MIDI.h>
#include <FastLED.h>

#define numLED      144
#define pinLED      7
#define typeLED     WS2812B
#define colourOrder GRB
#define brightness  128

CRGB leds[numLED];

MIDI_CREATE_DEFAULT_INSTANCE();

void setup() {
  
  LEDS.addLeds<typeLED, pinLED, colourOrder>(leds, numLED);
  FastLED.setBrightness(brightness);
  MIDI.begin(MIDI_CHANNEL_OMNI);
  MIDI.setHandleNoteOn(handleNoteOn);
  MIDI.setHandleNoteOff(handleNoteOff);

}

void loop() {
  MIDI.read();
 }

void handleNoteOn(byte channel, byte pitch, byte velocity) { 
for (byte i=30; i<=101; i++){
  if (i==pitch){
    int S = (-2)*i + 203; //turning the pitch value into the corresponding LED to light up
    leds[S].setRGB( 30, 140, 255);
    FastLED.show();
  }
}
}

void handleNoteOff(byte channel, byte pitch, byte velocity) { 
for (byte i=30; i<=101; i++){
  if (pitch==i){
    int R = (-2)*i + 203;  //turning the pitch value into the corresponding LED to turn off
    leds[R].setRGB( 0, 0, 0);
    FastLED.show();
  }
}
}

Here is my code. Originally I had 100+ switch cases for each pitch value, but then I started using a for loop and if statement instead.

It works fine for the most part.

The problems arise when I play chords in quick succession. Often, but not always, seemingly random LEDs that aren’t being played will turn themselves on and stay lit up until I play that key (i.e turn the key on and off again).

I’ve been trying to fix this problem for a few days now and have gotten nowhere.

Any help or pointers or anything will be greatly appreciated, like I said I’m a bit of a noob with this.

Thanks!

This problem comes up here very often. The reason is that you cannot receive MIDI data and display WS2812B at the same time. While the Arduino is busy sending the data to the LEDs, it misses incoming MIDI bytes, corrupting the MIDI messages, and turning on/off random notes, missing notes, etc.

Two possible solutions: 1. get a more powerful board with hardware peripherals that can be used for the WS2812B (UART or I²S, for example), or 2. get a better LED strip that doesn't have such strict timing requirements.

Pieter

Ah right I see, thanks Pieter.

What do you mean by strict timing requirements of the LEDs?

What do you mean by strict timing requirements of the LEDs?

The data sent to the LED has to have quite a fast and precise stream of pulses sent to it. For example the fastest pulse has to be 0.35uS with a tolerance of +/- 150nS.

In order to do this the libraries turn off the interrupts on the Arduino. In order to receive MIDI data the interrupts need to be on, so if the MIDI data arrives while data is being sent to the LEDs then the MIDI data is missed.

A better LED strip is based on the ADA102 LED, sometimes also known as Dot Star LEDs. This just requires a sequence of logic levels to control them which does not need accurate timing, so they can be driven with the interrupts enabled.

Your loops are pointless and wasting CPU cycles:
change:

for (byte i=30; i<=101; i++){
  if (pitch==i){
    int R = (-2)*i + 203;  //turning the pitch value into the corresponding LED to turn off
    leds[R].setRGB( 0, 0, 0);
    FastLED.show();
  }
}

to:

if (pitch >= 30 && pitch <= 101)
{
  int R = -2*pitch + 203;  //turning the pitch value into the corresponding LED to turn off
  leds[R].setRGB( 0, 0, 0);
  FastLED.show();
}

You can also share the code between note on and note off, and just pass the RGB values in
differently for each.

If you drive the LEDs with interrupts enabled, the LED update will occasionally get corrupted
but will sort itself out next time, which might be less annoying that having corrupt midi data.

Grumpy_Mike:
A better LED strip is based on the ADA102 LED, sometimes also known as Dot Star LEDs. This just requires a sequence of logic levels to control them which does not need accurate timing, so they can be driven with the interrupts enabled.

Thanks for the explanation! I'll look more into these LEDs.

MarkT:
If you drive the LEDs with interrupts enabled, the LED update will occasionally get corrupted
but will sort itself out next time, which might be less annoying that having corrupt midi data.

Thanks for the cleaner code. How could I try driving the LEDs with interrupts enabled? Do I need to edit the library?

Do I need to edit the library?

Yes.