So I've been working on a setup that involves taking MIDI input and using

So I’ve been working on a setup that involves taking MIDI input and using that to control an LED strip (currently working with an APA102 strip), but am having some trouble figuring out how to get the LEDs to display more synchronously.

As a test, I’ve setup a simplified test where I have each MIDI note corresponding to a single LED on the strip (rather than some of the more complex wave functions I’ve been using) - note value 0 turns on/off LED position 0, value 1 controls LED position 1, etc.

When I have the loop run FastLED.show() by itself, the strip displays all the LEDs correctly (i.e. no MIDI messages dropped), up to 25 notes - anything more than that, and MIDI messages get dropped (i.e. an LED not turning on). Problem is, there is a noticeable delay between each note, and so you can see each LED light up one by one in order.

As an experiment, I tried putting a conditional around the show function:

    if (!MIDI.read()) { FastLED.show(); }

…which I know is not ideal, but it looks like I do get a more synchronous result. There’s still a slight delay between LEDs lighting up, but it’s definitely much better than before. The problem now is that random MIDI messages get missed regularly. Furthermore, the Arduino will crash occasionally, which I still have yet to figure out the reason why.

It seems like without the “if” statement, the Arduino is at least still reading all the MIDI correctly and queuing the data up, but is taking time to display everything. Having the “if” statement for some reason makes the output side faster, but in turn other problems get introduced.

(Side note - I know having a million “if” statements is not ideal, but I’ve tried messing around with using “switch/case” statements instead and still seem to get the same issue, so it doesn’t seem to be a huge factor here.)

Furthermore, based on a suggestion from the Arduino forums, I tried adding an extra “shown” boolean:

if (!MIDI.read() && ! shown) { FastLED.show(); shown = true}

…which resulted in no MIDI notes missed, and is definitely speedier than FastLED.show(), but still has a visible delay. On top of that, this doesn’t really work if I want to use any functions that require regular updating of the LEDs to display the animation sequences correctly.

Any ideas??

What micro are you using to receive the MIDI with? Just a wild guess, but maybe something to do with interrupts

Interrupts should be OK since he’s using APA102’s. In the meantime a MIDI -> FastLED routine would be pretty cool.

@Daniel_Khim Can you post your code to http://gist.github.com so we can see if there’s something else perhaps slowing things down somewhere?

Also, this sounds like a cool project and I’d be interested to learn more about the setup.

Oh, I am on a Mega. I took some video of what happens with different lines of code, along with the number of simultaneous MIDI messages it seems to be able to handle without messages being missed (oddly, the number seems to have gone down from the last time I messed around with it; used to be 25…) :

FastLED.show(); (23 messages)

I don’t seem to be able to put more than one video in the post, so I guess I’ll have to split it up…

(!MIDI.read()) {
FastLED.show();
}
(22 messages? Not entirely sure, as it misses all the ones in between anyways)

if (!MIDIread) {
FastLED.show();
MIDIread = false;
}
(25 messages)

Oh, forgot to mention in the last one, I ended up storing the MIDI.read() value as a boolean, which seemed to stabilize the dropouts. As you can see comparing the four iterations, it’s definitely speedier, but still delayed. Also forgot to mention, the whole thing is in an infinity mirror I’ve been built, so hence the endless LEDs. :slight_smile:

if (!MIDIread && !shown) {
FastLED.show();
shown = true;
MIDIread = false;
}
(28 messages)

@marmil Sure thing!
https://gist.github.com/batmundo/2ebadfc3faee5694ba50ca36d35fd194

Just to confirm, which MIDI library are you using?

arduino_midi_library (https://github.com/FortySevenEffects/arduino_midi_library)

Are there better ones out there to use?

Anytime I throw in a 3rd party library in my code (like the IR or button ones I use), I document in the code exactly where to find that library. Just a recommentation.

Ahh, gotcha. This is my first foray into programming, so there are many practices I have yet to learn. :wink:

So any thoughts on why there would possibly be this delay on the displaying side? Does FastLED.show() have some kind of built in timer or something that could cause this when dealing with serial input? I know interrupts get disabled for WS2813 chips, but I’m using an APA102 strip, so I’d think that shouldn’t be an issue. Unless…because interrupts aren’t disabled with APA102s, maybe they’re somehow interfering?

I don’t see anything obvious that would be slowing things down. One small thing that did come to mind though, you have lines such as:

if (midiNote[1][60] == 1) { leds_C1[0] = CRGB::Blue;}
else if (midiNote[1][60] == 0) { leds_C1[0] = CRGB::Black;}

Could that be simplified a bit to:

if (midiNote[1][60] == 1) { leds_C1[0] = CRGB::Blue;}
else { leds_C1[0] = CRGB::Black;}

It’s either 1 or it’s not 1 (ie. 0) correct? Seems like if it’s not 1, you don’t need a second check to see if it’s 0, right? (Or maybe I’m not remembering enough of how MIDI works. Been awhile since I last messed with it.)

True! The “else if” is probably unnecessary. I don’t remember if I had a specific reason for that…I should just use “else”.

@Daniel_Khim

I reckon your loop is too big/complex, and therefore things get lost. Check the “callbacks” example file of the library you mentioned. It handles on/off so no real need for newnote or assigning boolean.They also suggest keeping things lean in the loop.

To simplify, you could try:

/* transpose note to LED position; offset by 60 in your case (because note[60] = led[0], etc). Careful not to go out of bounds → “Bad Things Happen” /

ledIndex = note – 60;

/ For ON, get remainder as always same 3 colours in same order. /

colourIndex = ledIndex % 3;

/ Use CHSV as more flexible (plus, could e.g. use velocity on brightness…brightness = 2 * velocity; //quick remap 0-127 to 0-254).
Get colour/hue from an array elsewhere (byte colourLUT[3]={160,0,96};// B/R/G)./

leds[ledIndex] = CHSV(colourLUT[colourIndex],saturation,brightness);

/ for OFF*/

leds[ledIndex] = CRGB::Black;

There’s probably other/better ways of getting about it (modulo being a bit “heavy”, maybe directly fetching from an array with all the colours is better???).

I’ve found an implementation which uses the callback methods of your lib. No idea if it works as I don’t have Midi. Will require careful checking + editing.
Indeed, colour seems to be controlled by “continuous controllers” (whatever these are) via the handleControlChange callback.
There’s also a lot of unnecessary Neopixel code, and that seemingly high baudrate. no idea what hairless is though.

@matt_p
Using CHSV doesn’t really apply for my testing purposes here - I mean, I’m sure CHSV would work fine, but this code is a small part of a much larger project where I’m using MIDI to do things like:

if (midiNote[setChannel][0] == 1) { rainbow (leds_S1, NUM_LEDS_S); }
if (midiNote[setChannel][1] == 1) { rainbow (leds_S2, NUM_LEDS_S); }

void rainbow(CRGBSet ledSet, int NUM_LEDS)
{
EVERY_N_MILLISECONDS( 20 ) { gHue++; } // slowly cycle the “base color” through the rainbow
fill_rainbow( ledSet, NUM_LEDS, gHue, 7); // FastLED’s built-in rainbow generator
}

…where different MIDI notes are controlling different subdivisions of the LED strip with different animations sequences I’ve come up with using FastLED functions. Again, were I a more knowledgable coder, I’d probably use switch/case instead (getting there eventually), but trying out switch/case vs the if statements in the MIDI-troubleshooting-code did not really seem to have much of an impact.

That said, I think you’re right - it might be worth snooping around the MIDI library to try and understand better what’s going on under the hood and to see if there might be a better way to optimize, or perhaps even see if something might be getting in the way…

I guess I should try to determine whether the problem is on the MIDI side or the FastLED side. Not sure how to even go about figuring that out. :stuck_out_tongue: