Please help me synch music with LED strip

Hello!

Here i am again with my 126 LED (WS2812B) project. I want to slowly cycle 6 color rainbow pattern through it. Code for which i have written below.

#include <FastLED.h>
#define LED_PIN 12
#define NUM_LEDS 126

CRGB leds[NUM_LEDS];

uint8_t paletteIndex = 0;

DEFINE_GRADIENT_PALETTE ( My_Rainbow_gp ) {
  0,     255,   0,   0, //RED
  42.5,  255, 255,   0, //YELLOW
  85,      0, 255,   0, //GREEN
  127.5,   0, 255, 255, //CYAN
  170,     0,   0, 255, //BLUE
  212.5, 255,   0, 255, //MAGENTA
  255,   255,   0,   0
};

CRGBPalette256 myPal = My_Rainbow_gp;

void setup() {
  FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, NUM_LEDS);
  FastLED.setBrightness(50);
}

void loop() {
  fill_palette(leds, NUM_LEDS, paletteIndex, 255 / NUM_LEDS, myPal, 255, LINEARBLEND);

  EVERY_N_MILLISECONDS(30){
    paletteIndex++;
  }
  
  FastLED.show();
}

Now, i want to sync brightness of LEDs with the songs that i am playing. A song has audible frequency range of 20Hz to 20KHz which i want to spread across 126 LEDs. First LEDs should response low frequency range; and as we move towards last LEDs, they should response high frequency range. So that will be like, when a song is playing a bass-drum/kick, first LEDs should glow brighter than rest LEDs of the strip; and when only singer is singing and bass-drum is not playing, then only mid LEDs should glow brighter. I hope you get a clear idea of what i am saying here.

If you still not, then please check the video linked below, which exactly explains what i wanted to say above. In this video, you can hear and see voice of the vocalist between 00:46 to 00:54, bass and snares between 00:55 to 01:04 and high-hats between 01:05 to 01:06....

And below are some more example which explains the same...

Please help me finish this project. Thank you :slight_smile:

This is not quite what you are trying to do, it should give you lotsa terms to google.

This is common project, I am sure there are many examples closer and closer to what you want.

I googled

  music to led frequency graph

play around with the search terms, add Arduino for focus.

a7

1 Like

What you're trying to build is called a spectrum analyzer. Or actually, a spectrum analyzer effect. A real spectrum analyzer is an expensive piece of lab/test equipment. :wink:

...I have not built one, but I know a lot about audio and I have made sound-activated lighting effects.

There are FFT (or FHT) libraries that will give you the amplitude of multiple frequency bands. (In this context the frequency-bands are called "bins".) Then you can do whatever you want with that data.

There are some trade-offs and it might not be practical to get 126 frequency-bands/bins (if that's what you want).

Usually bins are combined (at least at the higher frequencies because the bins are "linear" but we perceive frequency & pitch logarithmically/proportionally. i.e. We might have a frequency-band from 50-100Hz (one octave) but we probably don't need a band from 10050 to 10100Hz (a fraction of an octave). Of course, we also perceive loudness logarithmically/proportionally and decibels are logarithmic.

If you can live with only 7 frequency bands, there is a chip called the MSGEQ7 that takes a line-level signal and gives you 7 (multiplexed) outputs with a different-varying DC voltage for each band. That makes the software a whole lot easier since the processor can focus on running the display. (Addressable displays and FFT/FHT are both processor-intensive.)

How are you going to "read" the sound? You can use a microphone board or you can make direct connection to a line-level signal, but a direct audio signal has to be biased because the ADC can't read the negative-half of the waveform. Without the negative-half you'll have bad distortion which will totally foul-up your frequency display. And, the Arduino can be damaged by negative voltages.

A microphone by-itself won't work. A microphone board made for the Arduino will have a built-in preamp and biased output.

Hello a7,

Thanks for your effort. The example that you gave me says...

“In order to sync colored lights to music, we are going to continually capture intervals of sound and automatically assign a color to their pitch and brightness to their intensity (volume).”

Unfortunately, i don’t want to assign brightness of LED to volume of a song/music. (I hope you already know that, volume is measured in db, while frequency is measured in Hz.) Instead i want frequency (20Hz to 20,000Hz) to manipulate brightness of LED strip.

For example, i have strip of 126 LEDs. So i want to assign brightness of first 42 LEDs with bass frequency range (20Hz to 300Hz), next 42 LEDs with mid frequency range (300Hz to 5000Hz), and last 42 LEDs with high frequency range (5000Hz to 20000Hz).

I have searched on youtube but i had never find the one which i was looking for. Please share me a video link of what i explained and required in my very first post, i will be very thankful. And i am quite sure that, this is going to be the future and most teenagers will own something similar in their homes when they play their fav songs.

Here is how I synced a LED strip to music using a MSGEq7 and a Adafruit Electret Microphone Amplifier - MAX9814 with Auto Gain Control [ADA1713]. Using a ESP32.

#include <WiFi.h>
#include <PubSubClient.h>
#include "certs.h"
#include "sdkconfig.h"
#include "esp32/ulp.h"
#include "driver/rtc_io.h"
#include "esp_system.h" //This inclusion configures the peripherals in the ESP system.
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/timers.h"
#include "freertos/event_groups.h"
#include <Adafruit_NeoPixel.h>
#include "AudioAnalyzer.h"
////
/* define event group and event bits */
EventGroupHandle_t eg;
#define evtDo_AudioReadFreq       ( 1 << 0 ) // 1
////
QueueHandle_t xQ_LED_Info;
QueueHandle_t xQ_LstripOn;
QueueHandle_t xQ_LstripMode;
////
const int LED_COUNT = 108; //total number of leds in the strip
////
// When we setup the NeoPixel library, we tell it how many pixels, and which pin to use to send signals.
Adafruit_NeoPixel leds = Adafruit_NeoPixel( LED_COUNT, 26, NEO_GRB + NEO_KHZ800 );
//
WiFiClient wifiClient;
PubSubClient MQTTclient(mqtt_server, mqtt_port, wifiClient);
////
SemaphoreHandle_t sema_MQTT_KeepAlive;
////
void ULP_BLINK_RUN(uint32_t us);
////
void setup()
{
  ULP_BLINK_RUN(100000);
  eg = xEventGroupCreate();
  ////
  int FreqVal[7]; // used to set queue size
  xQ_LED_Info = xQueueCreate ( 1, sizeof(FreqVal) );
  xQ_LstripOn = xQueueCreate( 1, sizeof(bool) ); // sends a queue copy of the structure
  xQ_LstripMode = xQueueCreate( 1, sizeof(int) );
  ////
  sema_MQTT_KeepAlive = xSemaphoreCreateBinary();
  xSemaphoreGive( sema_MQTT_KeepAlive );
  ////
  // setting must be set before a mqtt connection is made
  MQTTclient.setKeepAlive( 90 ); // setting keep alive to 90 seconds
  connectToWiFi();
  connectToMQTT();
  //////////////////////////////////////////////////////////////////////////////////////////////
  xTaskCreatePinnedToCore( MQTTkeepalive, "MQTTkeepalive", 7000, NULL, 5, NULL, 1 );
  xTaskCreatePinnedToCore( fDo_AudioReadFreq, "fDo_ AudioReadFreq", 30000, NULL, 3, NULL, 1 );
  xTaskCreatePinnedToCore( fDo_LEDs, "fDo_ LEDs", 30000, NULL, 3, NULL, 1 );
  xTaskCreatePinnedToCore( fDoLstripMode, "fDoLstripMode", 2000, NULL, 3, NULL, 1 );
  xTaskCreatePinnedToCore( fDoLstripOn, "fDoLstripOn", 2000, NULL, 3, NULL, 1 );
  xEventGroupSetBits( eg, evtDo_AudioReadFreq );
} // setup()
////
void fDoLstripMode( void *pvParameters )
{
  int iMode = 0;
  for (;;)
  {
    if (xQueueReceive( xQ_LstripMode, &iMode,  portMAX_DELAY) == pdTRUE)
    {
      log_i( "Mode queue received %d", iMode );
    }
    //log_i( "memory fDoLstripMode %d",  uxTaskGetStackHighWaterMark(NULL) );
  }
  vTaskDelete ( NULL );
}
////
void fDoLstripOn( void *pvParameters )
{
  bool bOn = false;
  for (;;)
  {
    if (xQueueReceive( xQ_LstripOn, &bOn,  portMAX_DELAY) == pdTRUE)
    {
      log_i( "On queue received %d", bOn );
    }
    //log_i( "memory fDoLstripOn %d",  uxTaskGetStackHighWaterMark(NULL) );
  }
  vTaskDelete ( NULL );
}
////
void loop() {} // void loop
////
void fMQTT_Disconnect( )
{
  MQTTclient.disconnect();
}
////
void GetTheTime()
{
  char* ntpServer = "2.us.pool.ntp.org";
  int gmtOffset_sec = -(3600 * 7 );
  int daylightOffset_sec = 3600;
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  printLocalTime();
}
////
// http://www.cplusplus.com/reference/ctime/strftime/
////
void MQTTkeepalive( void *pvParameters )
{
  for (;;)
  {
    //log_i( " mqtt keep alive run." );

    if ( (wifiClient.connected()) && (WiFi.status() == WL_CONNECTED) )
    {
      xSemaphoreTake( sema_MQTT_KeepAlive, portMAX_DELAY ); //
      MQTTclient.loop();
      xSemaphoreGive( sema_MQTT_KeepAlive );
    }
    else {
      log_i( "MQTT keep alive found MQTT status %s WiFi status %s", String(wifiClient.connected()), String(WiFi.status()) );
      if ( !(WiFi.status() == WL_CONNECTED) )
      {
        connectToWiFi();
      }
      connectToMQTT();
    }
    vTaskDelay( 200 );
  }
  vTaskDelete ( NULL );
}
////
int getHour()
{
  struct tm timeinfo;
  getLocalTime(&timeinfo);
  char _time[ 5 ];
  strftime( _time, 80, "%T", &timeinfo );
  return String(_time).toInt();
}
////
void printLocalTime() {
  struct tm timeinfo;
  getLocalTime(&timeinfo);
  char _time[ 80 ];
  strftime( _time, 80, "%T", &timeinfo );
  log_i( "%s", _time);
  //  }
}
////
void connectToMQTT()
{
  log_i( "connect to mqtt" );
  while ( !MQTTclient.connected() )
  {
    MQTTclient.connect( clientID, mqtt_username, mqtt_password );
    log_i( "connecting to MQTT" );
    vTaskDelay( 250 );
  }
  log_i("MQTT Connected");
  MQTTclient.setCallback( mqttCallback );
  MQTTclient.subscribe( mqtt_topic );
}
////
void connectToWiFi()
{
  log_i( " Begin Connect to wifi" );
  while ( WiFi.status() != WL_CONNECTED )
  {
    WiFi.disconnect();
    WiFi.begin( SSID, PASSWORD );
    log_i(" waiting on wifi connection" );
    vTaskDelay( 4000 );
  }
  log_i( "End connected to WiFi" );
  WiFi.onEvent( WiFiEvent );
  GetTheTime();
}
////
static void mqttCallback(char* topic, byte * payload, unsigned int length)
{
  int i = 0;
  String temp = "";
  for ( i; i < length; i++) {
    temp += ((char)payload[i]);
  }
  //log_i( " topic %s payload %s", topic, temp );
  if ( (String)topic == topicLstripOn )
  {
    if ( temp == "0" )
    {
      bool bOn = false;
      xQueueOverwrite( xQ_LstripOn, (void *)&bOn );
    } else {
      bool bOn = true;
      xQueueOverwrite( xQ_LstripOn, (void *)&bOn );
    }
  }
  if ( (String)topic == topicLstripMode )
  {
    int i = temp.toInt();
    xQueueOverwrite( xQ_LstripMode, (void *)&i );
  }
} // void mqttCallback(char* topic, byte* payload, unsigned int length)
////
void fDo_LEDs( void *pvParameters )
{
  const int Brightness = 200;
  const int SEG = 6; // how many parts you want to separate the led strip into
  const int ledCount = LED_COUNT; //total number of leds in the strip
  int iFreqVal[7];
  int j;
  leds.begin(); // Call this to start up the LED strip.
  clearLEDs( ledCount );  // This function, defined below, de-energizes all LEDs...
  leds.show();  // ...but the LEDs don't actually update until you call this.
  leds.setBrightness( Brightness ); //  1 = min brightness (off), 255 = max brightness.
  for (;;)
  {
    if (xQueueReceive( xQ_LED_Info, &iFreqVal,  portMAX_DELAY) == pdTRUE)
    {
      j = 0;
      //assign different values for different parts of the led strip
      for (j = 0; j < ledCount; j++)
      {
        if ( (0 <= j) && (j < (ledCount / SEG)) )
        {
          //log_i( "segment 0 %d", iFreqVal[0] );
          set( j, iFreqVal[0], ledCount, SEG ); // set the color of led
        }
        else if ( ((ledCount / SEG) <= j) && (j < (ledCount / SEG * 2)) )
        {
          set( j, iFreqVal[0], ledCount, SEG );
        }
        else if ( ((ledCount / SEG * 2) <= j) && (j < (ledCount / SEG * 3)) )
        {
          set( j, iFreqVal[0], ledCount, SEG );
        }
        else if ( ((ledCount / SEG * 3) <= j) && (j < (ledCount / SEG * 4)) )
        {
          set( j, iFreqVal[0], ledCount, SEG );
        }
        else if ( ((ledCount / SEG * 4) <= j) && (j < (ledCount / SEG * 5)) )
        {
          set( j, iFreqVal[0], ledCount, SEG );
        }
        else
        {
          set( j, iFreqVal[0], ledCount, SEG );
        }
      }
      leds.show();
    }
    xEventGroupSetBits( eg, evtDo_AudioReadFreq );
  }
  vTaskDelete( NULL );
} // void fDo_ LEDs( void *pvParameters )
////
void fDo_AudioReadFreq( void *pvParameters )
{
  int FreqVal[7];
  const int NOISE = 10; // noise that you want to chop off
  const int A_D_ConversionBits = 4096; // arduino use 1024, ESP32 use 4096
  Analyzer Audio = Analyzer( 5, 15, 36 );//Strobe pin ->15  RST pin ->2 Analog Pin ->36
  Audio.Init(); // start the audio analyzer
  int64_t EndTime = esp_timer_get_time();
  int64_t StartTime = esp_timer_get_time(); //gets time in uSeconds like Arduino Micros
  for (;;)
  {
    xEventGroupWaitBits (eg, evtDo_AudioReadFreq, pdTRUE, pdTRUE, portMAX_DELAY);
    //EndTime = esp_timer_get_time() - StartTime;
    // log_i( "TimeSpentOnTasks: %d", EndTime );
    Audio.ReadFreq(FreqVal);
    for (int i = 0; i < 7; i++)
    {
      FreqVal[i] = constrain( FreqVal[i], NOISE, A_D_ConversionBits );
      FreqVal[i] = map( FreqVal[i], NOISE, A_D_ConversionBits, 0, 255 );
      // log_i( "Freq %d Value: %d", i, FreqVal[i]);//used for debugging and Freq choosing
    }
    xQueueSend( xQ_LED_Info, ( void * ) &FreqVal, 0 );
    //StartTime = esp_timer_get_time();
  }
  vTaskDelete( NULL );
} // fDo_ AudioReadFreq( void *pvParameters )
////
//the following function set the led color based on its position and freq value
//
void set(byte position, int value, int ledCount, int segment)
{
  int valueLowLimit = 20;
  // segment 0, red
  if ( (0 <= position) && (position < ledCount / segment) ) // segment 0 (bottom to top)
  {
    if ( value <= valueLowLimit )
    {
      leds.setPixelColor( position, 0, 0, 0 );
    }
    else
    {
      leds.setPixelColor( position, leds.Color( value , 0, 0) );
    }
  }
  else if ( (ledCount / segment <= position) && (position < ledCount / segment * 2) ) // segment 1 yellow
  {
    if ( value <= valueLowLimit )
    {
      leds.setPixelColor(position, leds.Color(0, 0, 0));
    }
    else
    {
      leds.setPixelColor(position, leds.Color( value, value, 0)); // works better to make yellow
    }
  }
  else if ( (ledCount / segment * 2 <= position) && (position < ledCount / segment * 3) ) // segment 2 pink
  {
    if ( value <= valueLowLimit )
    {
      leds.setPixelColor(position, leds.Color(0, 0, 0));
    }
    else
    {
      leds.setPixelColor(position, leds.Color( value, 0, value * .91) ); // pink
    }
  }
  else if ( (ledCount / segment * 3 <= position) && (position < ledCount / segment * 4) ) // seg 3, green
  {
    if ( value <= valueLowLimit )
    {
      leds.setPixelColor(position, leds.Color( 0, 0, 0));
    }
    else //
    {
      leds.setPixelColor( position, leds.Color( 0, value, 0) ); //
    }
  }
  else if ( (ledCount / segment * 4 <= position) && (position < ledCount / segment * 5) ) // segment 4, leds.color( R, G, B ), blue
  {
    if ( value <= valueLowLimit )
    {
      leds.setPixelColor(position, leds.Color( 0, 0, 0));
    }
    else //
    {
      leds.setPixelColor(position, leds.Color( 0, 0, value) ); // blue
    }
  }
  else // segment 5
  {
    if ( value <= valueLowLimit )
    {
      leds.setPixelColor(position, leds.Color( 0, 0, 0));
    }
    else
    {
      leds.setPixelColor( position, leds.Color( value, value * .3, 0) ); // orange
    }
  }
} // void set(byte position, int value)
////
void clearLEDs( int ledCount)
{
  for (int i = 0; i < ledCount; i++)
  {
    leds.setPixelColor(i, 0);
  }
} // void clearLEDs()
////
void WiFiEvent(WiFiEvent_t event)
{
  // log_i( "[WiFi-event] event: %d\n", event );
  switch (event) {
    //    case SYSTEM_EVENT_WIFI_READY:
    //      log_i("WiFi interface ready");
    //      break;
    //    case SYSTEM_EVENT_SCAN_DONE:
    //      log_i("Completed scan for access points");
    //      break;
    //    case SYSTEM_EVENT_STA_START:
    //      log_i("WiFi client started");
    //      break;
    //    case SYSTEM_EVENT_STA_STOP:
    //      log_i("WiFi clients stopped");
    //      break;
    case SYSTEM_EVENT_STA_CONNECTED:
      log_i("Connected to access point");
      break;
    case SYSTEM_EVENT_STA_DISCONNECTED:
      log_i("Disconnected from WiFi access point");
      break;
    //    case SYSTEM_EVENT_STA_AUTHMODE_CHANGE:
    //      log_i("Authentication mode of access point has changed");
    //      break;
    //    case SYSTEM_EVENT_STA_GOT_IP:
    //      log_i ("Obtained IP address: %s",  WiFi.localIP() );
    //      break;
    //    case SYSTEM_EVENT_STA_LOST_IP:
    //      log_i("Lost IP address and IP address is reset to 0");
    //      //      vTaskDelay( 5000 );
    //      //      ESP.restart();
    //      break;
    //    case SYSTEM_EVENT_STA_WPS_ER_SUCCESS:
    //      log_i("WiFi Protected Setup (WPS): succeeded in enrollee mode");
    //      break;
    //    case SYSTEM_EVENT_STA_WPS_ER_FAILED:
    //      log_i("WiFi Protected Setup (WPS): failed in enrollee mode");
    //      //      ESP.restart();
    //      break;
    //    case SYSTEM_EVENT_STA_WPS_ER_TIMEOUT:
    //      log_i("WiFi Protected Setup (WPS): timeout in enrollee mode");
    //      break;
    //    case SYSTEM_EVENT_STA_WPS_ER_PIN:
    //      log_i("WiFi Protected Setup (WPS): pin code in enrollee mode");
    //      break;
    //    case SYSTEM_EVENT_AP_START:
    //      log_i("WiFi access point started");
    //      break;
    //    case SYSTEM_EVENT_AP_STOP:
    //      log_i("WiFi access point  stopped");
    //      //      WiFi.mode(WIFI_OFF);
    //      //      esp_sleep_enable_timer_wakeup( 1000000 * 2 ); // 1 second times how many seconds wanted
    //      //      esp_deep_sleep_start();
    //      break;
    //    case SYSTEM_EVENT_AP_STACONNECTED:
    //      log_i("Client connected");
    //      break;
    case SYSTEM_EVENT_AP_STADISCONNECTED:
      log_i("WiFi client disconnected");
    //      break;
    //    case SYSTEM_EVENT_AP_STAIPASSIGNED:
    //      log_i("Assigned IP address to client");
    //      break;
    //    case SYSTEM_EVENT_AP_PROBEREQRECVED:
    //      log_i("Received probe request");
    //      break;
    //    case SYSTEM_EVENT_GOT_IP6:
    //      log_i("IPv6 is preferred");
    //      break;
    //    case SYSTEM_EVENT_ETH_GOT_IP:
    //      log_i("Obtained IP address");
    //      break;
    default: break;
  }
}
//////////////////////////////////////////////
/*
  Each I_XXX preprocessor define translates into a single 32-bit instruction. So you can count instructions to learn which memory address are used and where the free mem space starts.

  To generate branch instructions, special M_ preprocessor defines are used. M_LABEL define can be used to define a branch target.
  Implementation note: these M_ preprocessor defines will be translated into two ulp_insn_t values: one is a token value which contains label number, and the other is the actual instruction.

*/
void ULP_BLINK_RUN(uint32_t us)
{
  size_t load_addr = 0;
  RTC_SLOW_MEM[12] = 0;
  ulp_set_wakeup_period(0, us);
  const ulp_insn_t  ulp_blink[] =
  {
    I_MOVI(R3, 12),                         // #12 -> R3
    I_LD(R0, R3, 0),                        // R0 = RTC_SLOW_MEM[R3(#12)]
    M_BL(1, 1),                             // GOTO M_LABEL(1) IF R0 < 1
    I_WR_REG(RTC_GPIO_OUT_REG, 26, 27, 1),  // RTC_GPIO2 = 1
    I_SUBI(R0, R0, 1),                      // R0 = R0 - 1, R0 = 1, R0 = 0
    I_ST(R0, R3, 0),                        // RTC_SLOW_MEM[R3(#12)] = R0
    M_BX(2),                                // GOTO M_LABEL(2)
    M_LABEL(1),                             // M_LABEL(1)
    I_WR_REG(RTC_GPIO_OUT_REG, 26, 27, 0),// RTC_GPIO2 = 0
    I_ADDI(R0, R0, 1),                    // R0 = R0 + 1, R0 = 0, R0 = 1
    I_ST(R0, R3, 0),                      // RTC_SLOW_MEM[R3(#12)] = R0
    M_LABEL(2),                             // M_LABEL(2)
    I_HALT()                                // HALT COPROCESSOR
  };
  const gpio_num_t led_gpios[] =
  {
    GPIO_NUM_2,
    // GPIO_NUM_0,
    // GPIO_NUM_4
  };
  for (size_t i = 0; i < sizeof(led_gpios) / sizeof(led_gpios[0]); ++i) {
    rtc_gpio_init(led_gpios[i]);
    rtc_gpio_set_direction(led_gpios[i], RTC_GPIO_MODE_OUTPUT_ONLY);
    rtc_gpio_set_level(led_gpios[i], 0);
  }
  size_t size = sizeof(ulp_blink) / sizeof(ulp_insn_t);
  ulp_process_macros_and_load( load_addr, ulp_blink, &size);
  ulp_run( load_addr );
} // void ULP_BLINK_RUN(uint32_t us)
//////////////////////////////////////////////

Works real well. Perhaps the code will be useful or not.

I did say that.

Sry, I thought you were bringing more to the table.

You have received my brief and several detailed responses, you don’t seem to be able to see the relationship between the way you are expressing your problem and the solutions we are pointing you at.

Unless you find exactly what you want done already by someone else, you are going to have to learn quite a bit before you see any success.

This project or something like it has been done to death, keep googling and keep learning.

Good luck. I do hope you plan on becoming neither rich nor famous with this endeavour, because you will not.

a7

Hello Doug!

No, i don't want something like this...

Instead i want something like this...

BUT i want audio frequency range of a song to control brightness of my LED strip. I don’t want loudness of a song, (which is it’s volume) to control LED strip, as it is demonstrated in the last video above.

OK, that can only make sense if

  • you heavily reduce the dynamic range of the audio signal (compress)

  • determine frequency levels using what we been talking about and (FFT or other analysis)

  • choose a threshold for exists or doesn't exist by bands

In a regular audio signal, all frequencies are going to be present at some level, so volume will very much enter into this.

a7

Sorry, it's not clear what you want... That's OK, you can do whatever you want!!!

And... A spectrum analyzer displays both...

A "regular" spectrum analyzer is like a bunch of VU meters (volume meters) with one for each frequency band. Since you're talking about 3-bands it could show the dB level for the bass, mids, and highs. Normally the louder the sound in each band the more LEDs are turned-on. It's a bar-graph and the LEDs are or off and when the sound in the particular band is louder, more LEDs are on (the rightness doesn't change).

In the 1970s we had something called a Color Organ. It had 3 or 4 colors with 3 or 4 frequency bands. They usually just switched on & off but a regular light bulb will be dim if it's only on for a fraction of a second.

A COUPLE OF RECOMMENDATIONS -
"Develop" your project a little at a time. And work on the input (reading the audio) and output (LED display) separately before putting everything together.

Get something working minimally and then add one or two lines of code at a time. It takes a certain minimum amount of code to do anything with addressable LEDs. So start with something simple (I assume you have found some examples) and go from there. You should be able to make any patterns you want before you try to make it respond to audio. And when you're "almost ready" for audio, you can "fake" the audio data.

For the audio, start by just reading the volume before worrying about frequency. (If you use the MSGEQ7 chip you can't read the overall volume but you might want to start with just one band... Maybe the bass, etc.)

Start the audio part by just reading the data and displaying the numbers on the serial monitor (like the Analog Read Serial Example). In fact, the Analog Read Serial Example is a great start to the audio input part of your project! But, take-out the delay.

It's also helpful to make some test-tones, which you can generate with Audacity. As you know, music (or any real-world sound) is constantly changing in frequency and amplitude so constant test-tones are much better for testing & troubleshooting.

And in case you don't know... Even with a constant-tone you are "sampling" a waveform that's constantly changing with a positive peak, and negative peak, and two zero crossings every cycle. Your readings will "look random" but you should be able to tell the difference between loud sounds and quiet sounds or no sound. (This doesn't apply with the MSGEQ7 because it puts-out DC.)

Also take advantage of the Serial Monitor for testing, troubleshooting, and debugging. You can print-out variable values. You can also print-out little helpful messages like "reading analog" or "making all LEDs red", etc. Without that, it's impossible to know what your program is really doing, when it's not doing the "right thing".

And since you only want 3-bands, I would recommend the MSGEQ7 instead of FFT/FHT. The software for FFT is at least 100 times more complicated (although it's a library so you don't have to write all of it yourself). And this will free-up the processor for running the LEDs. Even with the MSGEQ7 your code will probably have to pause from reading the audio for a few milliseconds every time the display is updated.

Not sure how to help but be aware that between probably 8kHz and 20kHz the strip won't do anything. Songs almost never approach frequencies past 8kHz.

EDIT - This is 8kHz. I would be impressed if you've seen a song go higher than it.

P.S.
Just to get off-the-ground, take a look at my World's Simplest Lighting Effect.

The hardware is as-simple as it gets... You just need an input-bias circuit or a microphone board, and it blinks the built-in LED.

It simply turns the LED on whenever the loudness is above the (moving) average and off when below average. That means it automatically adjusts to the loudness and you get lots of "LED action" with loud or quiet songs, etc.

The code is fully commented so hopefully you can understand what it's doing.

The highest note from an orchestra (from a piccolo) is about 8kkHz but almost all music contains harmonics & overtones above 8kHz. If you low-pass filter to 8kHz music will sound "dull" (if you have "normal" hearing. :wink: )

The highest frequencies are "weak" but for a lighting effect you can make it more-sensitive to high frequencies.

Interesting. I'm not an audiophile and I've only minorly messed with spectrograms, so my experience is quite limited. I just figured that my relatively good hearing (up to 22kHz) would pick out anything above 8kHz but I guess I didn't factor in volume.

Yes, you’re right that, volume level of different frequencies will manipulate the brightness of strip; But i do not want the overall volume level to control strip as it is shown in the video below...

Yeah, it’s like the one in the video below, am i right?

But i am not interested in creating something like that. Instead i want different frequencies to manipulate brightness level of a single LED strip containing 126 LEDs. Is it possible with MSGEQ7? If yes, then can you please show me a circuit diagram?

What i have...

  1. 126 ws2812b LEDs soldered in custom shape
  2. Arduino Nano (Original!)
  3. Windows7 (64 bit) laptop which runs Arduino IDE
  4. Power supply
  5. No experience of neither electronics nor of c++. But still i will try, don’t worry.

Solved, OK.

Talk about one LED.

Let’s say it has slot 38 and you want it to correspond to 440 Hz.

Tell us if that’s right and woukd be a statement to make bout all the LEDs in the strip.

How should #38 behave?

Dimmer or brighter according to how much volume there is at 440. Or a band around 440.

Is this correct?

Can you see the resemblance and correspondence between the bar graph spectrum meter and what you want to do?

Use the bar graph calculations and use the number of LEDs in the column of the bar graph to instead

use that same number to adjust the brightness of one pixel that now represents the entire column, not through height, but by brightness.

a7

1 Like

You mean, we are going to select 38th LED of the strip and going to associate it with 440Hz, am i right?

Yes, please make a common statement so i can use it for all rest 125 LEDs, finishing the code.

Yes, 38th LED should go brighter, if higher dB are present at 440 Hz; and should go dimmer, if lower dB are present at 440 Hz. That is exactly how i want it to behave!

Does this mean a chart/graph like this?

image

Thank you very much A7.

I meant, in my references to the bar graph, the LED bar graph spectrum analyser / display devices that many ppl build and show off on the internets.

This is the kind of software you need to understand and adapt for your purpose.

Read all the advice here: you have been variously directed to most of the ways this can be done. The determination of the amount of sound energy in a given band of frequencies.

In those bar graph spectrum LED displays, those numbers are informing how many LEDs in a given column (frequency band) are to be illuminated.

This is where, instead, you decide how bright to make the one LED representing that coulumn, that is to say, that frequency band.

a7

Yes, i get it! Thank you very much a7!

Do you know any IC such as MSGEQ7 but with around 126 frequency band?

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.