I am a beginner at Arduino (just started over a week ago). and I am currently trying to make an LED Piano visualizer using Synthesia, a NeoPixel WS2812 LED strip, and my YAMAHA S-90 keyboard where when I press a key on my keyboard, the LED above the pressed key lights up, and when I release the key, the LED above the key turns off. It looks like this video: Testing my Midi-Visualizer with Synthesia - YouTube, except it can also be used with someone playing the piano. My current set up is the following: YAMAHA S-90 -> PC (via USB Midi cable) -> Synthesia -> loopMidi -> Hairless MIDI -> Arduino UNO -> WS2812 LED Strip.
The code that I'm using now is from this forum post by ozguney, and is the 13th reply: MIDI react LED using Arduino. (but im really stuck) - Audio - Arduino Forum. It works fine normally, but like ozguney's problem, if keys are played too fast or if 4+ keys are pressed or released at the same time, some LEDs will either not turn on or will remain on even after noteOn and noteOff. From the replies to the forum and from other posts, I found out that it is because interrupts are turned off for the WS2812, causing some data to not be received by the Arduino UNO. I also found out that the best solution is to use a different LED strip that allows interrupts such as something called a Dot Star. However, I currently do not have the funds to buy a new LED strip, since the WS2812 is the second LED strip I bought (after I made the mistake of buying an LED strip that was not individually addressable).
My question is, is there a way to make the WS2812 allow interrupts? Alternatively, is there a way to make an algorithm such that it fixes the bugs of LEDs being left on? (I'm fine with some LEDs not turning on, but the LEDs being left on is a big no no) Is there a way to make the code in a way that the lack of interrupts does not affect the stream of data? The following is the code I'm using which is from ozguney with added functions so that the LEDs correspond correctly to the keys that are pressed and release:
#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 183
// strip.setPixelColor(4, 120, 255, 40);
// strip.setPixelColor(Number of LED, RedDensity, GreenDensity, BlueDensity);
#define RedDensity 150
#define GreenDensity 199
#define BlueDensity 88
int oct_num = 0;
int num = 0;
int key = 0;
int incomingByte = 0;
//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.
}
void changeNumOn(){
if (incomingByte >= 21 && incomingByte <= 23){
oct_num = 0;
}
else if (incomingByte >= 24 && incomingByte <= 35){
oct_num = 1;
}
else if (incomingByte >= 36 && incomingByte <= 47){
oct_num = 2;
}
else if (incomingByte >= 48 && incomingByte <= 59){
oct_num = 3;
}
else if (incomingByte >= 60 && incomingByte <= 71){
oct_num = 4;
}
else if (incomingByte >= 72 && incomingByte <= 83){
oct_num = 5;
}
else if (incomingByte >= 84 && incomingByte <= 95){
oct_num = 6;
}
else if (incomingByte >= 96 && incomingByte <= 108){
oct_num = 7;
}
if (oct_num == 0){
key = incomingByte - 21;
num = 5 + key*2;
}
else if (oct_num == 1){
key = incomingByte - 24;
num = 12 + key*2;
}
else if (oct_num == 2){
key = incomingByte - 37;
num = 38 + key*2;
}
else if (oct_num == 3){
key = incomingByte - 50;
num = 65 + key*2;
}
else if (oct_num == 4){
key = incomingByte - 63;
num = 90 + key*2;
}
else if (oct_num == 5){
key = incomingByte - 76;
num = 115 + key*2;
}
else if (oct_num == 6){
key = incomingByte - 89;
num = 140 + key*2;
}
else if (oct_num == 7){
key = incomingByte - 102;
num = 165 + key*2;
}
strip.setPixelColor(num, RedDensity, GreenDensity, BlueDensity);
strip.setPixelColor(num + 1, RedDensity, GreenDensity, BlueDensity);
}
void changeNumOff(){
if (incomingByte >= 21 && incomingByte <= 23){
oct_num = 0;
}
else if (incomingByte >= 24 && incomingByte <= 35){
oct_num = 1;
}
else if (incomingByte >= 36 && incomingByte <= 47){
oct_num = 2;
}
else if (incomingByte >= 48 && incomingByte <= 59){
oct_num = 3;
}
else if (incomingByte >= 60 && incomingByte <= 71){
oct_num = 4;
}
else if (incomingByte >= 72 && incomingByte <= 83){
oct_num = 5;
}
else if (incomingByte >= 84 && incomingByte <= 95){
oct_num = 6;
}
else if (incomingByte >= 96 && incomingByte <= 108){
oct_num = 7;
}
if (oct_num == 0){
key = incomingByte - 21;
num = 5 + key*2;
}
else if (oct_num == 1){
key = incomingByte - 24;
num = 12 + key*2;
}
else if (oct_num == 2){
key = incomingByte - 37;
num = 38 + key*2;
}
else if (oct_num == 3){
key = incomingByte - 50;
num = 65 + key*2;
}
else if (oct_num == 4){
key = incomingByte - 63;
num = 90 + key*2;
}
else if (oct_num == 5){
key = incomingByte - 76;
num = 115 + key*2;
}
else if (oct_num == 6){
key = incomingByte - 89;
num = 140 + key*2;
}
else if (oct_num == 7){
key = incomingByte - 102;
num = 165 + key*2;
}
strip.setPixelColor(num, 0, 0 , 0);
strip.setPixelColor(num + 1, 0, 0, 0);
}
// 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) {
for (int i = 21; i <= 108; i++){
if (i == pitch){
incomingByte = pitch;
changeNumOn();
strip.show();
}
}
}
void MyHandleNoteOff(byte channel, byte pitch, byte velocity) {
for (int i = 21; i <= 108; i++){
if (i == pitch){
incomingByte = pitch;
changeNumOff();
strip.show();
}
}
}