MIDI react LED using Arduino. (but im really stuck)

This is the project I want to do:

Equipments: Arduino UNO, WS2812b Strip LED, 88 Key Piano.

When the pressing notes on piano the LED strip giving you feedback which note you are pressing. I'm stuck in the programming.

I connect my Piano to my PC via USB Cable. And I use Hairless MIDI for the communicate Arduino and PC. So they are communicate fine(when i press a note tx,rx leds are lighting.)

I tried tons of codes MIDI.h, MIDIUSB.h, serialbegins etc... but I failed.

Can you guys guide me? I cant even light a LED pressing by any midi note.

This is my MOST SIMPLE code but its not working.

#include <MIDI.h>
MIDI_CREATE_DEFAULT_INSTANCE();


void handleNoteOn(byte channel, byte pitch, byte velocity){   
    digitalWrite(6, HIGH);
}


void handleNoteOff(byte channel, byte pitch, byte velocity){
    digitalWrite(6, LOW);
}


void setup(){
    pinMode(6, OUTPUT;)
    MIDI.setHandleNoteOn(handleNoteOn);
    MIDI.setHandleNoteOff(handleNoteOff);
    MIDI.begin(MIDI_CHANNEL_OMNI);
}


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

I wanna send my Midi Messages(coming from piano) via HairlessMIDI to Arduino's LED. What codes am I using for it?

I write new code its working but does not working for every note for example pitch=49 or c#3

The led is blinking when i press the note. How do i improve it?

byte statusByte;
byte dataByte1;
byte dataByte2;
int led = 7;


void setup(){
  pinMode(7,OUTPUT);
  Serial.begin(115200);
}


void loop(){
      dataByte1 = Serial.read();
      if (dataByte1 >= 0 && dataByte1 <= 127){
          digitalWrite(led, HIGH);
          delay(100);
          digitalWrite(led, LOW);
  }
}

I write new code its working but does not working for every note for example pitch=49 or c#3

A MIDI note on message is three bytes, that code simply looks at all the bytes in the package and treats them the same. You will get a flashing light both on the note number and the velocity value.

You have to read all three bytes and then look only at those you need.

Use the code here MIDI Glockenspiel only light an LED instead of firing the solenoid.

Using the MIDI library, this should be trivial. If you want help with that, post your best attempt.

If you're using many LEDs, you might not have enough Arduino pins. A solution would be to use shift registers.
I'm currently working on a library that has many different MIDI Interfaces to chose from (including one that supports Hairless), as well as easy to use libraries for shift registers.

Arduino Control Surface Library

Here's an example that seems to do what you asked for.

Piano-Keys-Control-Surface.ino:

---



~~~
[color=#95a5a6]/**
  • @example Piano-Keys-Control-Surface.ino
  • This is an example of the ShiftRegisterOut class of the Control-Surface library.
  • Connect three daisy-chained shift registers to pins 11 (ST_CP), 12 (DS) and 10 (SH_CP).
  • Connect 24 LEDs (+ current limiting resistors) to the outputs of the shift registers.
  • 10 >──────────────┬─────────────────────────────┬─────────────────────────────┐
  • ┎━━━━━━━━━━┷━━━━━━━━━━━┓      ┎━━━━━━━━━━┷━━━━━━━━━━━┓      ┎━━━━━━━━━━┷━━━━━━━━━━━┓
  • ┃        SH_CP         ┃      ┃        SH_CP         ┃      ┃        SH_CP         ┃
  • 12 >───┨ Data in     Data out ┠──────┨ Data in     Data out ┠──────┨ Data in     Data out ┃
  • ┃        ST_CP         ┃      ┃        ST_CP         ┃      ┃        ST_CP         ┃
  • ┗━━━━━━━━━━┯━━━━━━━━━━━┛      ┗━━━━━━━━━━┯━━━━━━━━━━━┛      ┗━━━━━━━━━━┯━━━━━━━━━━━┛
  • 11 >──────────────┴─────────────────────────────┴─────────────────────────────┘
  • The 24 LEDs will correspond to MIDI notes 48 - 71 (C3 - B4).
  • Any note played with a velocity higher than 63 will turn on the LED.
  • Written by Pieter P, 13-07-2018
  • [u]https://github.com/tttapa/Control-Surface[/u]
    */[/color]

#include <Control_Surface.h>

// USBMIDI_Interface midi; // For boards that have a native USB interface
HairlessMIDI_Interface midi; // For use with the Hairless MIDI<->Serial Bridge (@115200 baud)

constexpr pin_t dataPin  = 11;  // Pin connected to DS of 74HC595
constexpr pin_t clockPin = 13;  // Pin connected to SH_CP of 74HC595
constexpr pin_t latchPin = 10;  // Pin connected to ST_CP of 74HC595

constexpr uint8_t baseNote = 48; // C3
constexpr uint8_t numberOfNotes = 24; // two octaves

// Create a new shift register output connected to pins 11, 13 and 10,
// shift the data out with the most significant bit first.
// There are 24 (= 3·8) outputs in total (three 8-bit shift registers).
ShiftRegisterOut ShiftReg(dataPin, clockPin, latchPin, MSBFIRST, numberOfNotes);

void setupcolor=#000000[/color] {
 midi.begincolor=#000000[/color];
 ShiftReg.begincolor=#000000[/color];
}

void handleMIDIMessage(const MIDI_message_matcher midimsg) {
 if (midimsg.channel+1 != 1) // Only listen to channel 1
   return;
 uint8_t value;
 switch color=#000000[/color] { // Only listen to MIDI Note events
   case NOTE_ON: value = midimsg.data2; break; // Read velocity
   case NOTE_OFF: value = 0; break;
   default: return; // Ignore other events
 }
 uint8_t note = midimsg.data1; // MIDI note number
 if (note < baseNote) // This note is too low to display
   return;
 note -= baseNote; // Subtract offset
 if (note >= numberOfNotes) // This note is too high to display
   return;
 bool state = value >= 64; // Velocities below 64 are turned off
 ShiftReg.digitalWrite(note, state); // Turn on/off the appropriate LED
}

void loopcolor=#000000[/color] {
 if (midi.readcolor=#000000[/color] == CHANNEL_MESSAGE)
   handleMIDIMessagecolor=#000000[/color];
}
~~~

|

Pieter

@ozguney, please do not cross-post. Threads merged.

PieterP:
Using the MIDI library, this should be trivial. If you want help with that, post your best attempt.

If you're using many LEDs, you might not have enough Arduino pins. A solution would be to use shift registers.
I'm currently working on a library that has many different MIDI Interfaces to chose from (including one that supports Hairless), as well as easy to use libraries for shift registers.

Arduino Control Surface Library

Here's an example that seems to do what you asked for.

Piano-Keys-Control-Surface.ino:

---



~~~
[color=#95a5a6]/**
  • @example Piano-Keys-Control-Surface.ino
  • This is an example of the ShiftRegisterOut class of the Control-Surface library.
  • Connect three daisy-chained shift registers to pins 11 (ST_CP), 12 (DS) and 10 (SH_CP).
  • Connect 24 LEDs (+ current limiting resistors) to the outputs of the shift registers.
  • 10 >──────────────┬─────────────────────────────┬─────────────────────────────┐           
    *        ┎━━━━━━━━━━┷━━━━━━━━━━━┓      ┎━━━━━━━━━━┷━━━━━━━━━━━┓      ┎━━━━━━━━━━┷━━━━━━━━━━━┓
    *        ┃        SH_CP        ┃      ┃        SH_CP        ┃      ┃        SH_CP        ┃
  • 12 >───┨ Data in    Data out ┠──────┨ Data in    Data out ┠──────┨ Data in    Data out ┃
    *        ┃        ST_CP        ┃      ┃        ST_CP        ┃      ┃        ST_CP        ┃
    *        ┗━━━━━━━━━━┯━━━━━━━━━━━┛      ┗━━━━━━━━━━┯━━━━━━━━━━━┛      ┗━━━━━━━━━━┯━━━━━━━━━━━┛
  • 11 >──────────────┴─────────────────────────────┴─────────────────────────────┘
  • The 24 LEDs will correspond to MIDI notes 48 - 71 (C3 - B4).
  • Any note played with a velocity higher than 63 will turn on the LED.
  • Written by Pieter P, 13-07-2018
  • [u]https://github.com/tttapa/Control-Surface[/u]
    */[/color]

#include <Control_Surface.h>

// USBMIDI_Interface midi; // For boards that have a native USB interface
HairlessMIDI_Interface midi; // For use with the Hairless MIDI<->Serial Bridge (@115200 baud)

constexpr pin_t dataPin  = 11;  // Pin connected to DS of 74HC595
constexpr pin_t clockPin = 13;  // Pin connected to SH_CP of 74HC595
constexpr pin_t latchPin = 10;  // Pin connected to ST_CP of 74HC595

constexpr uint8_t baseNote = 48; // C3
constexpr uint8_t numberOfNotes = 24; // two octaves

// Create a new shift register output connected to pins 11, 13 and 10,
// shift the data out with the most significant bit first.
// There are 24 (= 3·8) outputs in total (three 8-bit shift registers).
ShiftRegisterOut ShiftReg(dataPin, clockPin, latchPin, MSBFIRST, numberOfNotes);

void setupcolor=#000000[/color] {
  midi.begincolor=#000000[/color];
  ShiftReg.begincolor=#000000[/color];
}

void handleMIDIMessage(const MIDI_message_matcher midimsg) {
  if (midimsg.channel+1 != 1) // Only listen to channel 1
    return;
  uint8_t value;
  switch color=#000000[/color] { // Only listen to MIDI Note events
    case NOTE_ON: value = midimsg.data2; break; // Read velocity
    case NOTE_OFF: value = 0; break;
    default: return; // Ignore other events
  }
  uint8_t note = midimsg.data1; // MIDI note number
  if (note < baseNote) // This note is too low to display
    return;
  note -= baseNote; // Subtract offset
  if (note >= numberOfNotes) // This note is too high to display
    return;
  bool state = value >= 64; // Velocities below 64 are turned off
  ShiftReg.digitalWrite(note, state); // Turn on/off the appropriate LED
}

void loopcolor=#000000[/color] {
  if (midi.readcolor=#000000[/color] == CHANNEL_MESSAGE)
    handleMIDIMessagecolor=#000000[/color];
}
~~~

|

Pieter

I will using a LED Strip. So just 1 OUTPUT is enough for me. Am I right?

I will using a LED Strip.

So nice if you to let us know at the start, it only makes previous answers useless.

Also mixing addressable LED strips of this type with the WS2812 controller, will not work reliably because when the LEDs are being fed their data the interrupts are turned off which means you could miss incoming MIDI bytes making the whole thing not work.

The only soloution I see is to use the sort of addressable LED strip that needs two outputs, data and clock and then write your own library that does not disable the interrupts when sending the data. The data write process for this types is interruptible. These LEDs are sometimes called dot star.

Grumpy_Mike:
Also mixing addressable LED strips of this type with the WS2812 controller, will not work reliably because when the LEDs are being fed their data the interrupts are turned off which means you could miss incoming MIDI bytes making the whole thing not work.

Would this be a problem all the time? Or only when the UART's RX buffer is full?

Thanks everybody i write some codes. Its work perfectly BUT I HAVE SOME PROBLEMS...

When I press 3-4 notes at the same time HairlessMIDI only send several data to the LED Strip. Its causes to some LEDs are not lighting when I press chords. OR its keep lighting even my hand pressing button. How can I fix it?

I think Hairless MIDI cant send 3-4 notes signal at the same time. Is there a way to fix it?

ozguney:
Thanks everybody i write some codes. Its work perfectly BUT I HAVE SOME PROBLEMS...

You ask us to debug some code you wrote but didn't post. I'm not a psychic.

ozguney:
I think Hairless MIDI cant send 3-4 notes signal at the same time.

That's bull. It can send as many notes as you'd like.

this is the problem.

#include <MIDI.h>  // Add Midi Library
#include <Adafruit_NeoPixel.h> // Add Led Library

//define NeoPixel Pin and Number of LEDs
#define PIN 6
#define NUM_LEDS 88

//    strip.setPixelColor(4, 120, 255, 40);
//    strip.setPixelColor(Number of LED, RedDensity, GreenDensity, BlueDensity);
#define RedDensity    150
#define GreenDensity  199
#define BlueDensity   88

//create a NeoPixel strip
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, PIN, NEO_GRB + NEO_KHZ800);

//Create an instance of the library with default name, serial port and settings
MIDI_CREATE_DEFAULT_INSTANCE();

void setup() {
  
  strip.begin(); // start the strip and blank it out
  strip.show();
  
  MIDI.begin(1); // Initialize the Midi Library on channel 1
  Serial.begin(115200);  // Hairless MIDI speed

  MIDI.setHandleNoteOn(MyHandleNoteOn); // This is important!! This command
  // tells the Midi Library which function you want to call when a NOTE ON command
  // is received. In this case it's "MyHandleNoteOn".
  MIDI.setHandleNoteOff(MyHandleNoteOff); // This command tells the Midi Library 
  // to call "MyHandleNoteOff" when a NOTE OFF command is received.
}

void loop() { // Main loop
  MIDI.read(); // Continuously check if Midi data has been received.   
}


// MyHandleNoteOn/Off are the functions that will be called by the Midi Library
// when a MIDI Note message is received.
// It will be passed bytes for Channel, Pitch, and Value
// It checks if the MIDI Note Pitch is within the Note Range 36 (C1) to 51 (D#2)
// If it is, it lights up the corresponding LED (LEDs 1 thru 16)
void MyHandleNoteOn(byte channel, byte pitch, byte velocity) {
  switch (pitch) {
    case 21:
      strip.setPixelColor(1, RedDensity, GreenDensity, BlueDensity);
      strip.show();
        break;
    case 22:
      strip.setPixelColor(2, RedDensity, GreenDensity, BlueDensity);
      strip.show();
        break;
    case 23:
      strip.setPixelColor(3, RedDensity, GreenDensity, BlueDensity);
      strip.show();
        break;
    case 24:
      strip.setPixelColor(4, RedDensity, GreenDensity, BlueDensity);
      strip.show();
        break;
    case 25:
      strip.setPixelColor(5, RedDensity, GreenDensity, BlueDensity);
      strip.show();
        break;
    case 26:
      strip.setPixelColor(6, RedDensity, GreenDensity, BlueDensity);
      strip.show();
        break;
.
.
.
.
.
.
.

    case 105:
      strip.setPixelColor(85, RedDensity, GreenDensity, BlueDensity);
      strip.show();
        break;
    case 106:
      strip.setPixelColor(86, RedDensity, GreenDensity, BlueDensity);
      strip.show();
        break;
    case 107:
      strip.setPixelColor(87, RedDensity, GreenDensity, BlueDensity);
      strip.show();
        break;
    case 108:
      strip.setPixelColor(88, RedDensity, GreenDensity, BlueDensity);
      strip.show();
        break;

  }
}

void MyHandleNoteOff(byte channel, byte pitch, byte velocity) {
  switch (pitch) {
    case 21:
      strip.setPixelColor(1, 0, 0, 0);
      strip.show();
        break;
    case 22:
      strip.setPixelColor(2, 0, 0, 0);
      strip.show();
        break;
    case 23:
      strip.setPixelColor(3, 0, 0, 0);
      strip.show();
        break;
    case 24:
      strip.setPixelColor(4, 0, 0, 0);
      strip.show();
        break;
    case 25:
      strip.setPixelColor(5, 0, 0, 0);
      strip.show();
        break;
    case 26:
      strip.setPixelColor(6, 0, 0, 0);
      strip.show();
        break;
.
.
.
.
.
.
.
.
        break;
    case 104:
      strip.setPixelColor(84, 0, 0, 0);
      strip.show();
        break;
    case 105:
      strip.setPixelColor(85, 0, 0, 0);
      strip.show();
        break;
    case 106:
      strip.setPixelColor(86, 0, 0, 0);
      strip.show();
        break;
    case 107:
      strip.setPixelColor(87, 0, 0, 0);
      strip.show();
        break;
    case 108:
      strip.setPixelColor(88, 0, 0, 0);
      strip.show();
        break;

  }
}

i didnt paste cuz its too long(over 9k characters). but there is the code.

Take a look at the code I posted, understand it, and change your code to get rid of the gigantic switches.

PieterP:
Take a look at the code I posted, understand it, and change your code to get rid of the gigantic switches.

I try to analyze the code you wrote, but I have some confusion,

I use WS2812b its directly connect to Arduino via DataPin and there is no clockpin and latch pin. I dont have any components like shield or etc.
I use Arduino Uno and when I try to load the arduino i get "exit status 1 Error compiling for board Arduino/Genuino Uno." error. I think I got this error because I dont have 74HC595.

Thank you PieterP and Mike for attend to me :slight_smile: I started programming arduino for 2 weeks. You guys gave me a lot of things more than 2 weeks.

The source of the problem is timing. When I press more then one note at the same time(i mean chord) Arduino lighting only 1 LED.

#include <MIDI.h>  // Add Midi Library
#include <Adafruit_NeoPixel.h> // Add Led Library

//define NeoPixel Pin and Number of LEDs
#define PIN 6
#define NUM_LEDS 88

//    strip.setPixelColor(4, 120, 255, 40);
//    strip.setPixelColor(Number of LED, RedDensity, GreenDensity, BlueDensity);
#define RedDensity    150
#define GreenDensity  199
#define BlueDensity   88

//create a NeoPixel strip
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, PIN, NEO_GRB + NEO_KHZ800);

//Create an instance of the library with default name, serial port and settings
MIDI_CREATE_DEFAULT_INSTANCE();

void setup() {
  
  strip.begin(); // start the strip and blank it out
  strip.show();
  
  MIDI.begin(1); // Initialize the Midi Library on channel 1
  Serial.begin(115200);  // Hairless MIDI speed

  MIDI.setHandleNoteOn(MyHandleNoteOn); // This is important!! This command
  // tells the Midi Library which function you want to call when a NOTE ON command
  // is received. In this case it's "MyHandleNoteOn".
  MIDI.setHandleNoteOff(MyHandleNoteOff); // This command tells the Midi Library 
  // to call "MyHandleNoteOff" when a NOTE OFF command is received.
}

void loop() { // Main loop
  MIDI.read(); // Continuously check if Midi data has been received.   
}


// MyHandleNoteOn/Off are the functions that will be called by the Midi Library
// when a MIDI Note message is received.
// It will be passed bytes for Channel, Pitch, and Value
// It checks if the MIDI Note Pitch is within the Note Range 36 (C1) to 51 (D#2)
// If it is, it lights up the corresponding LED (LEDs 1 thru 16)
void MyHandleNoteOn(byte channel, byte pitch, byte velocity) {
    strip.setPixelColor(pitch-20, RedDensity, GreenDensity, BlueDensity);
    strip.show();

  }

void MyHandleNoteOff(byte channel, byte pitch, byte velocity) {
      strip.setPixelColor(pitch-20, 0, 0, 0);
      strip.show();
  }

I really shortened the code. But its still stucking when i press chords.

i tried that,

Synthesia output is connected to HairlessMIDI's input and when synthesia press chord(working too symmetrical) only one Led is lighting.

What if pitch is less than 20 or greater than 107?

Do all the MIDI notes of the chord show up in the Hairless log? You might be missing notes because the Neopixel library turns off interrupts, as Mike predicted.

PieterP:
What if pitch is less than 20 or greater than 107?

Do all the MIDI notes of the chord show up in the Hairless log? You might be missing notes because the Neopixel library turns off interrupts, as Mike predicted.

HairlessMIDI "Serial in" problem.