Holy s... it's hard to match leds to music

so i wanted to play around and do a beautiful costume animation to match a short 2min music tone ... i see it in my head how it's going to go, how all the lds are going to light up in each part of the music
what part will be shown and how it will be shown .. of the strip

then i came to the programming... and oh boy... it's not as easy as i thought

first of all i had to come up with a way to start the loop and the music in always 100% of the time in the same mili second

so just for testings,(becaouse i still dont have a speaker module it's on the way)
i did a timer to count to 0 and then i start the animation and play the song at the same second

and i had a big array saying just sings ,like, r for red, g for green, stuff like that
and i tried advancing that array every half a second ..
and just to see if i can get the led to always change color in same second of music

and it +- worked, i guess i dont always start the song exactly at same mili second so it's not always 100% accurate, the only way to do it will be to have an external sound module connected to the arduino and not play music from pc or something.

but i mean.. even ... even if that will work. it will change the whole led strip...
making complex animations going on and off.. and rainbow here in that time.. and stars there in that time, and exactly show this from that to that.. .and so forth.. that i had in mind
oh boy.. that would be a nightmare to write and match the music i assume

in the head it sounds simple enough... to do some parts of led strip to light up in nice animations to match the music but.. in reality.. to write something like that would be very very complicated

i almost thought about getting some external buttons (10-15 buttons) connected to the arduino that each one of them shows different animation in different parts of the arduino, some do black to the lights etc...
and then press them to match the music and somehow record that into an array that i will show in the end
maybe even that will be much more simple then tyring to figure out all of that.. but i mean

if someone here did it ? RESPECT is all i have to say

here is the code i started doing but i mean
i'm really starting to give in to this project... it's way too hard then i thought
it will only be easy if i do like very very very simple light sequences.... like all of the led full color etc.

here is my code that i started doing

#include <FastLED.h>
#include <IRremote.h>

FASTLED_USING_NAMESPACE

#if defined(FASTLED_VERSION) && (FASTLED_VERSION < 3001000)
#warning "Requires FastLED 3.1 or later; check github for latest code."
#endif

int BRIGHTNESS = 96;
int DELEY_THREASHOLD = 300;
int animationDeleyCounter = 0;
#define DATA_PIN    7 // led pin
const int RECV_PIN = 4; // IR pin

char *framesArray[] = {"countDown", "countDown", "countDown", "countDown", "g", "g", "g", "g", "g", "g", "g", "g", "g", "g", 
  "r", "r", "b", "b", "b", "g", "g", "g", "g", "g", "g", "g", "g", "g", "g", 
  "r", "r", "b", "b", "b"};
int frame = 0;

//#define CLK_PIN   4
#define LED_TYPE    WS2812B
#define COLOR_ORDER GRB
#define NUM_LEDS    300
CRGB leds[NUM_LEDS];

#define FRAMES_PER_SECOND  120

// Define IR Receiver and Results Objects
IRrecv irrecv(RECV_PIN);
decode_results results;

void setup() {
  // Serial Monitor @ 9600 baud
  Serial.begin(9600);
  // Enable the IR Receiver
  irrecv.enableIRIn();
  
  delay(3000); // 3 second delay for recovery
  
  // tell FastLED about the LED strip configuration
  FastLED.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
  //FastLED.addLeds<LED_TYPE,DATA_PIN,CLK_PIN,COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);

  // set master brightness control
  FastLED.setBrightness(BRIGHTNESS);
}


void loop()
{  
  test();
  FastLED.show();
  FastLED.delay(500);
 
  frame = frame + 1;
  
}

void test() {  
  if (framesArray[frame] == "countDown"){
    for( int i = 0; i < NUM_LEDS; i++) {
      leds[frame] = CRGB( 255, 0, 0);
    }
  } else if (framesArray[frame] == 0){
    for( int i = 0; i < NUM_LEDS; i++) {
      leds[i] = CRGB( 0, 0, 0);
    }
  }else if (framesArray[frame] == "b"){
    for( int i = 0; i < NUM_LEDS; i++) {
      leds[i] = CRGB( 0, 0, 255);
    }
  }else if (framesArray[frame] == "g"){
    for( int i = 0; i < NUM_LEDS; i++) {
      leds[i] = CRGB( 0, 255, 0);
    }
  } else if (framesArray[frame] == "r"){
    for( int i = 0; i < NUM_LEDS; i++) {
      leds[i] = CRGB( 255, 0, 0);
    }
  }

}

 

Character arrays cannot be compared like this in C

  if (framesArray[frame] == "countDown"){

Instead, you must use

  if (strcmp(framesArray[frame], "countDown") == 0){

that's not true
my compare works, run the code .

You are wrong. You are comparing references / pointers and not char arrays.

It "works" because it passes comparing only the first character of the array, 'c'. If you compared "ca" with "cb" you would see no difference.

Also nobody here can "run the code" without having 300 LEDs connected.

FastLED disables interrupts while updating the LEDs, which causes millis and all related timing to be highly inaccurate.

You can never achieve 120 frames per second with 300 LEDs.

I would take a music-production-software recording two tracks for the music and then record a third track with pulses of constant frequency some kind of a short "beep" that occurs each time your LED-animation shall proceed to the next step.

This beep-channel is feeded into the microcontroller into one IO-pin and the code on the microcontroller is running a fast running loop that waits for the beep-induced signals to rush in.

This would enable to have the music and the animation in perfect synchronisation
transferring the data to 300 LEDs needs some time. I haven't done any calculations how much time it needs.

@the fastled-experts: do these WS2812-drivers offer a buffer where the buffer can be filled with a pre-defined pattern an then a special-command switches from actual shown pattern to the buffered pattern?

To transfer the data at highest possible speed the LED-chips offer I would use a teensy 4.0 600 MHz 32 bit microcontroller
https://www.pjrc.com/store/teensy40.html

best regards Stefan

1 Like

also not true.
changed it now to ca and cb and it goes to different statements.
please refrain form giving false information.

First real answer to the actual post i asked among the 5 answers here.

I liked what you wrote and it's a great idea !
is that how people do that ? like if someone puts leds on hies house for haloween and wants to sync it to music they do so much work also to that beep track ?

could you explain a bit more on what you mean with beep track and feed it to the arduino ?

Also wouldn't a teensy by like 100+ usd board ?

if (framesArray[frame] == "countDown"){

What an attitude! If this compares strings successfully, it is not because of this line but because of some other logic in your program. I think, if you're not receptive to this kind of advice, you will find it very hard to get help here.

this discution is not related to the original question i wrote,
you said it only "works" because so you have attitude first.

if you want to check the code copy paste from the code i posted here (i added full code in first reply) and see.

again this is not helping or relating to the original post.

I am just functioning on the assumption that you would want a working program, regardless of what else you need. I guess I was wrong.

The compiler recognizes the array as static / constant and therefore most of it is optimized away and multiple pointers points to the same address in memory. These addresses are compared, not the strings located there.

void setup()
{
  const char* str1 = "foo";
  const char* str2 = "foo";
  const char* str3 = "foobar";

  Serial.begin(9600);
  Serial.print("str1 = ");
  Serial.println((int)str1);
  Serial.print("str2 = ");
  Serial.println((int)str2);
  Serial.print("str3 = ");
  Serial.println((int)str3);
  if (str1 == str2) Serial.println("str1 and str2 are equal"); //Will print
  if (str1 == str3) Serial.println("str1 and str3 are equal"); //Will not print
}

Code is untested but I'm sure that str1 and str2 prints the same addresses, which are compared in the code.

No I guess for such applications there is a sound-signal-input and whenever the sound-signal is higher than a threshold-value to animation moves on one step. This solutions makes the light blink in rhytm but it does not keep it in total sync to a certain pattern.

if you click the link you see that the teensy 4.0 is $20

I haven't done something like that. It is just that I know the basic principle of how a music-production software works. To get a third and separated channel could be realisied somehow with a dolby surround-channel.
If it is OK to have the music mono on one channel you could use the second channel for the beep-signals
This can be done with almost any recording software like for example audacity

audacity offers mark, cut, and paste of parts of a track
So as a start you would import the digitised music into audacity play it back with speaker connected directly to the sound-output of your computer and then have a microphone to record the "switch-animation-signal" on a new track while the music is playing.

A direct connection to your computer is essential. Any bluetooth device uses buffering which means you hear the music 0,2 to 1 seconds later than it is played on the computer.

I'm not a specialist in this field. You should ask in a forum that has this kind of stuff as their central subject. Maybe digitised music in a *.MP3-file or *.WAV file can be combined with Midi-signals and then you would use the midi-signals to create the LED-animation pulses.

best regards Stefan

1 Like

Your code raises a warning because you are casting a pointer to a char into an int. However, this compiles:

#include <stdio.h>

const char* str1 = "foo";
const char* str2 = "foo";
const char* str3 = "foobar";

int main (void)
{
    printf ("str1 == %i, address == %p\n", *str1,    str1);
    printf ("str2 == %i, address == %p\n",  str2[0], str2);
    printf ("str3 == %i, address == %p\n", *str3,    str3);
    
    if (str1 == str2) printf ("str1 and str2 are equal.\n");
    if (str1 == str3) printf ("str1 and str3 are equal.\n");
    
    
    return 0;
}

and the output is:

str1 == 102, address == 0x555d5c435824
str2 == 102, address == 0x555d5c435824
str3 == 102, address == 0x555d5c435828
str1 and str2 are equal.

We interpret 2 things as an int here: a dereferenced pointer to a char (*str1) or the first element of a char array (str2[0]). In this context, they are the same thing and the output is the same. *str3 is also the same as the other 2 because all strings happen to begin with an 'f', that is ASCII char number 102 when interpreted as an int. We can also notice that the addresses of str1 ans str2 are the same, but the address of str3 is different. So, (str1 == str2) succeeds because it compares pointer addresses, not int values. (str1 == str3) fails for the same reason.

A pointer address IS an (unsigned) integer, comparing pointers is a numeric comparison.

Yes, yes, I meant int values form the previous 3 lines of output, i.e. 102 in this case. But anyway, I doubt that the OP is much interested in this at this point...

This seems to be a software for music and light syncin.

http://www.vixenlights.com/
Though I haven't looked up if it can run without a PC and how palying the music is done

You could ask this as the first question in their forum:

Is Vixen able to playback a *.mp3-music-file in perfect synchronisation with a defined and complex lighting-sequence?
If yes does this require a Windows Computer as a must or can it be run on a Raspberry Pi or even on an Arduino stand-alone?

best regards Stefan

1 Like

Yes, that's the normal way to use FastLED. The "buffer" is the array of CRGB objects. FastLED.show() is the display function.

The speed is likely limited by the required LED data transfer protocol, not the processor's speed.

Regarding code like this:

OP is doing it wrong no matter how stubbornly he insists otherwise.