Ambitious MIDI DotStar project runs poorly

Status
Not open for further replies.

sargentpilcher

Well-known member
Hello all,

I have a rather ambitious light project where I am trying to light up a strip of LED's using MIDI notes. I've spent the last 3 months learning electronics and code to culminate in a bit of a dissapointment and I'm hoping I can do something about it.

I am using the Teensy 3.6, and I got the best LED strip I could, the 144 strip of DotStars as I read they have higher refresh rates for persistence of vision (Not that I need that, but it sounded fancy). I wrote some code that would assign each MIDI note to it's own individual R/G/B value for every LED, coming out to 432 MIDI notes, requiring 4 channels of MIDI to light up the entire strip. When all was written and finally working, the thing ran super slow. My first instinct for what was wrong was the fact that it was 2,500 lines of code (432 for variables and about 5 lines of code each to make each one do its thing). So I spent the last 2 weeks trimming that down, and through a ton of help by user Oddson, helped me figure out how to use an array to bring 2,500 lines of code down to 45. It went from 7% of storage, to 2% of storage. The only problem is that it still runs super slow when you throw enough MIDI data at it. For example wanting to light up the entire strip, sending 432 MIDI On messages at once makes it look like a giant loading bar as the LED's light up across the strip.

I want this to work for live music performance, so this kind of lag is unacceptable for my purposes, and I was hoping to see if you thought there was anything that I could do to make it run better. I don't know very well how the dotstars work, but I've seen Teensy running thousands of LED's like here https://youtu.be/a1UGDOdKcVg?t=1m53s and here https://www.youtube.com/watch?v=cyGIW3KFrtw (An LCD screen, but it's the same thing right? Hundreds/thousands of LED's? I'm trying to do 144, so why is this so much laggier? Would an Octo adapter help? I noticed some people using them but I don't understand what it does, or under what circumstances it would be useful.

I really want to get this project off the ground and I want to get it running as smoothly as possible. Like smooth enough to have all the LED's light up rythmically with music. I want every light to shine when a kick drum hits and then turn off just as quick. This "Loading bar" just won't do. Any advice, help, or recomendations would be greatly appreciated so much.

Code:
 #include <Adafruit_DotStar.h> 
#define NUMPIXELS 144 //Dotstar pixels
#define DATAPIN    38
#define CLOCKPIN   37

byte colorMatrix[16*42][3] ;
unsigned int light; 

Adafruit_DotStar  strip1 = Adafruit_DotStar(NUMPIXELS, DATAPIN, CLOCKPIN, DOTSTAR_BRG); 

void setup(){
  usbMIDI.setHandleNoteOn(OnNoteOn);
    usbMIDI.setHandleNoteOff(OnNoteOff);
  strip1.begin();
  strip1.show(); 
}

void OnNoteOn(byte channel, byte note, byte velocity){
  light = (channel*42)-(42) + note/3; 
  colorMatrix[light][note%3] = velocity*2;
  strip1.setPixelColor(light,colorMatrix[light][0],colorMatrix[light][1],colorMatrix[light][2]);
}

void OnNoteOff(byte channel, byte note, byte velocity){
  light = (channel*42)-(42) + note/3;
  colorMatrix[light][note%3] = 0;
  strip1.setPixelColor(light,colorMatrix[light][0],colorMatrix[light][1],colorMatrix[light][2]);
}

void loop(){
  usbMIDI.read();
  strip1.show();
}
 
Calling strip1.show() every time loop() runs is probably slowing everything down quite a lot.

Try something like this:

Code:
void loop() {
  while (usbMIDI.read()) {
    // keep reading until all incoming messages read
  }
  strip1.show();
}

Or maybe even something like this, where you set the boolean to true if you've changed any pixels.

Code:
bool show_required = false;

void loop() {
  while (usbMIDI.read()) {
    // do nothing, but keep reading until all incoming messages read
  }
  if (show_required) {
    strip1.show();
    show_required = false;
  }
}

Hopefully the idea is simple enough... you want to avoid doing the time-consuming show to the pixels when more data is still arriving.
 
In addition to Paul's recommendations, my guess is that a lot of the slowness you're seeing is due to the Adafruit Dotstar library you're using. You've configured it to use pins 37 & 38 as clock and data; these aren't hardware SPI pins so the library uses software bit banging to send the pulses out. Ultimately the code uses digitalWrite()s to send the data, which is about the slowest way to twiddle bits on a Teensy.

You'll get a speedup if you use the hardware SPI pins to send the data (13 for clock and 11 for data) but for a real performance boost you'll also want to use the FastLED library instead of Adafrult's Dotstar. It won't take much to rewrite your code, the biggest change will be

Code:
strip1.setPixelColor(light,colorMatrix[light][0],colorMatrix[light][1],colorMatrix[light][2]);

to something like

Code:
leds[light].red = colorMatrix[light][0];
leds[light].green = colorMatrix[light][1];
leds[light].blue = colorMatrix[light][2];
 
Awesome 3 things to try out! Thank you guys! I'm gonna get started on researching and implementing these, but in the mean time I'm still open for more suggestions if anybody else chimes in. Thank you guys!
 
Holy shit Paul this thing runs like a fuckin' CHAMP now!!! Your first idea was all it took. I copy pasted it in, and holy shit, no lag, instantaneous. THANK YOU!!!! Next step I'm buying 3 more strips to see if I can push it that hard! This is awesome!
 
Status
Not open for further replies.
Back
Top