ESP32 Stereo audio spectrum visualizer with amplifier
Make audio come to life. Get the mood on and "See the music" suitable for gaming and music.
Components and supplies
ESP32S
Through Hole Resistor, 500 ohm
Resistor 10k ohm
2.6k ohm resistor
Capacitor 10 µF
Rotary Potentiometer, 10 kohm
XL6009 DC-DC Adjustable Step Up Voltage Booster Converter Module
WS2812 Addressable LED Strip
Capacitor 47 µF
1.5k ohm resistor
UA741CP
Micro Switch
11k ohm resistor
Audio / Video Cable Assembly, 3.5mm Slim Stereo Plug to 3.5mm Slim Stereo Jack
Tools and machines
Plier, Long Nose
Wire Stripper & Cutter, 18-10 AWG / 0.75-4mm² Capacity Wires
Solder Wire, Lead Free
Plier, Cutting
Soldering iron (generic)
Multitool, Screwdriver
Apps and platforms
Pspice
Project description
Code
Stereo ESP32 audio visualizer
arduino
1#include <FastLED.h> 2#include <arduinoFFT.h> 3#include <EasyButton.h> 4#include 5 <EEPROM.h> 6 7#define samples 512 8#define sampling_freq 40000 9#define 10 Noise_filter 1300 // change this value as needed 11#define Left_AudioIn 36 12 // you can use different pins for the ADC but make sure that they do not 13 conflict 14#define Right_AudioIn 35 15#define max_brightness 200 // define 16 the max brightness of all the leds DOES NOT APPLY TO ALL MODES 17#define basebrightness 18 15 // used to set the minimum brightness 19#define NUM_LEDS 30 20#define 21 LEFT_LED_PINOUT 22 22#define RIGHT_LED_PINOUT 23 23#define peak 255 //define 24 the peak of fft results 25#define button_1 33 //choose pin 33 as the 26 button to swtich modes. You can choose any pin you like but be aware of your circuit 27 and which pins are useable 28#define EEPROM_size 512 // define the number 29 of bytes that will be used for eeprom storage 30 31const float Lamp =1.7; // 32 extra amp for channel tuning may change these values depending on your situation 33 to balance the audio channels 34const float Ramp =1.3; 35 36#define amp_0 200 37 // used to control the amplification to divide the value of the bands 38 after fft 39#define amp_1 200 40#define amp_2 200 // you 41 can chnage these values to adjust the output of the FFT 42#define amp_3 150 43#define 44 amp_4 150 45#define amp_5 120 46#define amp_6 120 47#define amp_7 120 48#define 49 amp_8 120 50#define amp_9 100 51#define amp_10 80 52#define amp_11 80 53#define 54 amp_12 50 55#define amp_13 40 56#define amp_14 40 57 58 59unsigned int amp[] 60 ={amp_0, amp_1, amp_2, amp_3, amp_4, amp_5, amp_6, amp_7, // Create an array 61 to store the amplitude adjustment values 62 amp_8, amp_9, amp_10, 63 amp_11, amp_12, amp_13, amp_14,}; 64 65unsigned int sampling_period_us; // 66 create a 16bit unsigned integer value to store the sampling period 67 68int LbandValues[] 69 = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; //the bandvalues will store the data that has 70 been processed from the arduino fft library 71int RbandValues[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; 72 73 74int LoldbandValues[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; //store the previous 75 band values 76int RoldbandValues[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; 77 78double 79 LvReal [samples]; // the arrays that will store the initial data created from 80 fft 81double LvImag [samples]; 82double RvReal [samples]; 83double RvImag [samples]; 84 85unsigned 86 long newTime, oldTime; // used to time the sampling for of signals 87 88uint8_t 89 hue =0; //the hue integer number that will range from 0-255 90 91int average[2]; 92 // average will be used for the _amp modes 93int old_average[2]; 94int 95 peak_amp[2]; 96 97 98arduinoFFT FFTL =arduinoFFT(LvReal,LvImag, samples, sampling_freq); 99 // FFT magic starts here 100arduinoFFT FFTR =arduinoFFT(RvReal,RvImag, samples, 101 sampling_freq); 102 103EasyButton mode_button(button_1); // set button 104 to be used to change modes 105 106bool mode_switch_call = false; 107bool palette_flag 108 =true; 109bool band_flag =false; 110 111uint8_t mode_num =0; 112 113CRGB leds[2][NUM_LEDS]; 114 // FastLED magic 115 116int brightness[2][NUM_LEDS]; 117 118CRGBPalette16 119 TWICE_pal =CRGBPalette16( //TWICE Colors (PS: its a Kpop girl group with 120 a color theme dedicated to them) 121 CHSV(32,205,200), CHSV(16,210,200), 122 123 CHSV(245,210,200), CHSV(237,255,200) 124 ); 125CRGBPalette16 Rainbow_pal =CRGBPalette16( 126 //Rainbow colors 127 CHSV(0,255,255), CHSV(85,255,255), 128 CHSV(171,255,255), 129 CHSV(255,255,255) 130 ); 131CRGBPalette16 Ocean_pal =CRGBPalette16( //Ocean 132 colors 133 CRGB(0,0,255), CRGB(0,128,255), 134 CRGB(200,200,200) 135 ); 136CRGBPalette16 137 Temp_pal =CRGBPalette16( //Temp colors 138 CRGB(0,0,255), CRGB(255,0,0), 139 CRGB(255,255,0) 140 ); 141 142CRGBPalette16 Poison_pal =CRGBPalette16( //Poison 143 colors 144 CRGB(0,255,0), CRGB(0,0,255), CRGB(255,0,80) 145 ); 146 147void mode_switch() 148 // this function is called when a button press is detected 149{ 150 151 mode_num = (mode_num + 1)%7; // the mod numbers needs to be altered based 152 on the number of modes currently available 153 palette_flag = true; 154 155} 156 157void 158 setup() { 159 160 pinMode(Right_AudioIn, INPUT); 161 pinMode(Left_AudioIn, INPUT); 162 163 EEPROM.begin(EEPROM_size); 164 delay(3000); 165 mode_num =EEPROM.read(1); // 166 Reads the current mode saved in EEPROM address 1 to choose mode before running. 167 168 169 mode_button.begin(); 170 FastLED.addLeds <WS2812B, LEFT_LED_PINOUT, GRB> 171 (leds[0], NUM_LEDS); 172 FastLED.addLeds <WS2812B, RIGHT_LED_PINOUT, GRB> (leds[1], 173 NUM_LEDS); 174 FastLED.setCorrection(TypicalSMD5050); 175 176 sampling_period_us 177 = round (1000000*(1/sampling_freq)); 178} 179 180void loop() { 181 mode_button.read(); 182 183 if(mode_button.wasPressed()==true) 184 { 185 mode_switch(); 186 mode_switch_call 187 =false; 188 } 189 190 for (int i=0; i<samples;i++) 191 { 192 newTime =micros(); 193 194 LvReal[i]=analogRead(Left_AudioIn); 195 LvImag[i]= 0; 196 RvReal[i] =analogRead(Right_AudioIn); 197 198 RvImag[i]=0; 199 while ((micros()-newTime) < sampling_period_us) // used 200 to time the sampling rate 201 { 202 } 203 } 204 FFTL.DCRemoval(); //removes 205 the DC offset 206 207 FFTL.Windowing(FFT_WIN_TYP_HAMMING, FFT_FORWARD); //FFT 208 magic happening!! 209 FFTL.Compute(FFT_FORWARD); 210 FFTL.ComplexToMagnitude(); 211 212 213 FFTR.DCRemoval(); 214 FFTR.Windowing(FFT_WIN_TYP_HAMMING, FFT_FORWARD); 215 216 FFTR.Compute(FFT_FORWARD); 217 FFTR.ComplexToMagnitude(); 218 219 //Analyse 220 FFT results 221 for(int i=1; i < (samples/2); i++) 222 { 223 if (RvReal[i]> 224 Noise_filter ) //crude noise filter 225 { 226 if (i<=1) 227 { 228 229 RbandValues[0] = (int)RvReal[i]; 230 } 231 if (i>1 && i<=2 232 ) 233 { 234 RbandValues[1] = (int)RvReal[i]; 235 } 236 if 237 (i>2 && i<=3 ) 238 { 239 RbandValues[2] = (int)RvReal[i]; 240 241 } 242 if (i>3 && i<=4 ) 243 { 244 RbandValues[3] 245 = (int)RvReal[i]; 246 } 247 if (i>4 && i<=5 ) 248 { 249 RbandValues[4] 250 = (int)RvReal[i]; 251 } 252 if (i>5 && i<=7 ) 253 { 254 RbandValues[5] 255 = (int)RvReal[i]; 256 } 257 if (i>7 && i<=10 ) 258 { 259 RbandValues[6] 260 = (int)RvReal[i]; 261 } 262 if (i>10 && i<=15 ) 263 { 264 RbandValues[7] 265 = (int)RvReal[i]; 266 } 267 if (i>15 && i<=21 ) 268 { 269 RbandValues[8] 270 = (int)RvReal[i]; 271 } 272 if (i>21 && i<=29 ) 273 { 274 RbandValues[9] 275 = (int)RvReal[i]; 276 } 277 if (i>29 && i<=42 ) 278 { 279 RbandValues[10] 280 = (int)RvReal[i]; 281 } 282 if (i>42 && i<=59 ) 283 { 284 RbandValues[11] 285 = (int)RvReal[i]; 286 } 287 if (i>59 && i<=84 ) 288 { 289 RbandValues[12] 290 = (int)RvReal[i]; 291 } 292 if (i>84 && i<=120 ) 293 { 294 295 RbandValues[13] = (int)RvReal[i]; 296 } 297 if (i>120 && i<=170 298 ) 299 { 300 RbandValues[14] = (int)RvReal[i]; 301 } 302 } 303 304 if(LvReal[i] > Noise_filter) 305 { 306 if (i<=1) 307 { 308 LbandValues[0] 309 = (int)LvReal[i]; 310 } 311 if (i>1 && i<=2 ) 312 { 313 LbandValues[1] 314 = (int)LvReal[i]; 315 } 316 if (i>2 && i<=3 ) 317 { 318 LbandValues[2] 319 = (int)LvReal[i]; 320 } 321 if (i>3 && i<=4 ) 322 { 323 LbandValues[3] 324 = (int)LvReal[i]; 325 } 326 if (i>4 && i<=5 ) 327 { 328 LbandValues[4] 329 = (int)LvReal[i]; 330 } 331 if (i>5 && i<=7 ) 332 { 333 LbandValues[5] 334 = (int)LvReal[i]; 335 } 336 if (i>7 && i<=10 ) 337 { 338 LbandValues[6] 339 = (int)LvReal[i]; 340 } 341 if (i>10 && i<=15 ) 342 { 343 LbandValues[7] 344 = (int)LvReal[i]; 345 } 346 if (i>15 && i<=21 ) 347 { 348 LbandValues[8] 349 = (int)LvReal[i]; 350 } 351 if (i>21 && i<=29 ) 352 { 353 LbandValues[9] 354 = (int)LvReal[i]; 355 } 356 if (i>29 && i<=42 ) 357 { 358 LbandValues[10] 359 = (int)LvReal[i]; 360 } 361 if (i>42 && i<=59 ) 362 { 363 LbandValues[11] 364 = (int)LvReal[i]; 365 } 366 if (i>59 && i<=84 ) 367 { 368 LbandValues[12] 369 = (int)LvReal[i]; 370 } 371 if (i>84 && i<=120 ) 372 { 373 374 LbandValues[13] = (int)LvReal[i]; 375 } 376 if (i>120 && i<=170 377 ) 378 { 379 LbandValues[14] = (int)LvReal[i]; 380 } 381 } 382 383 } 384 for( int i =0; i <=14; i++) //adjust the values of the output. 385 { 386 387 388 LbandValues[i] =LbandValues[i]*Lamp/amp[i]; 389 RbandValues[i] =RbandValues[i]*Ramp/amp[i]; 390 391 392 393 394 if(LbandValues[i]>= peak) 395 { 396 LbandValues[i] 397 =peak; 398 } 399 if(RbandValues[i]>= peak) 400 { 401 RbandValues[i] 402 =peak; 403 } 404 405 LbandValues[i] =map(LbandValues[i],0, peak,0,max_brightness); 406 // adjusted band values 407 RbandValues[i] =map(RbandValues[i],0, peak,0,max_brightness); 408 409 410 if (LoldbandValues[i] >= LbandValues[i]) 411 { 412 LbandValues[i] 413 =(LoldbandValues[i]*2+LbandValues[i])/3; //weighted average to slow down 414 decay 415 } 416 if (RoldbandValues[i] >= RbandValues[i]) 417 { 418 RbandValues[i] 419 =(RoldbandValues[i]*2+RbandValues[i])/3; 420 } 421 422 if(band_flag ==true) 423 // some modes will use these to make the 424 lights move smoother 425 { 426 if (LoldbandValues[i] <= LbandValues[i]) 427 428 { 429 LbandValues[i] =(LoldbandValues[i]*1+LbandValues[i])/2; //weighted 430 average to slow down increment 431 } 432 if (RoldbandValues[i] <= RbandValues[i]) 433 434 { 435 RbandValues[i] =(RoldbandValues[i]*1+RbandValues[i])/2; 436 } 437 438 } 439 LbandValues[i] += basebrightness; 440 RbandValues[i] += basebrightness; 441 442 443 LoldbandValues[i] =LbandValues[i]; //save the current band value 444 to be used in future band averaging 445 RoldbandValues[i] =RbandValues[i]; 446 447 } 448 449 for(int i=0; i<NUM_LEDS; i++) 450 { 451 if (i<=1) // 452 the brightness array values will determine the brightness of each leds. 453 { 454 455 brightness[0][i] =LbandValues[0]; 456 brightness[1][i] =RbandValues[0]; 457 458 } 459 if (i>1 && i<=3) 460 { 461 brightness[0][i] =LbandValues[1]; 462 463 brightness[1][i] =RbandValues[1]; 464 } 465 if(i>3 && i<=5) 466 467 { 468 brightness[0][i] =LbandValues[2]; 469 brightness[1][i] 470 =RbandValues[2]; 471 } 472 if(i>5 && i<=7) 473 { 474 brightness[0][i] 475 =LbandValues[3]; 476 brightness[1][i] =RbandValues[3]; 477 } 478 if(i>7 479 && i<=9) 480 { 481 brightness[0][i] =LbandValues[4]; 482 brightness[1][i] 483 =RbandValues[4]; 484 } 485 if(i>9 && i<=11) 486 { 487 brightness[0][i] 488 =LbandValues[5]; 489 brightness[1][i] =RbandValues[5]; 490 } 491 if(i>11 492 && i<=13) 493 { 494 brightness[0][i] =LbandValues[6]; 495 brightness[1][i] 496 =RbandValues[6]; 497 } 498 if(i>13 && i<=15) 499 { 500 brightness[0][i] 501 =LbandValues[7]; 502 brightness[1][i] =RbandValues[7]; 503 } 504 if(i>15 505 && i<=17) 506 { 507 brightness[0][i] =LbandValues[8]; 508 brightness[1][i] 509 =RbandValues[8]; 510 } 511 if(i>17 && i<=19) 512 { 513 brightness[0][i] 514 =LbandValues[9]; 515 brightness[1][i] =RbandValues[9]; 516 } 517 if(i>19 518 && i<=21) 519 { 520 brightness[0][i] =LbandValues[10]; 521 brightness[1][i] 522 =RbandValues[10]; 523 } 524 if(i>21 && i<=23) 525 { 526 brightness[0][i] 527 =LbandValues[11]; 528 brightness[1][i] =RbandValues[11]; 529 } 530 if(i>23 531 && i<=25) 532 { 533 brightness[0][i] =LbandValues[12]; 534 brightness[1][i] 535 =RbandValues[12]; 536 } 537 if(i>25 && i<=27) 538 { 539 brightness[0][i] 540 =LbandValues[13]; 541 brightness[1][i] =RbandValues[13]; 542 } 543 if(i>27 544 && i<=29) 545 { 546 brightness[0][i] =LbandValues[14]; 547 brightness[1][i] 548 =RbandValues[14]; 549 } 550 551 } 552 553 switch (mode_num) //choose 554 modes 555 { 556 case 0: 557 if(palette_flag ==true) 558 { 559 EEPROM.put(1,mode_num); 560 561 EEPROM.commit(); 562 band_flag =false; 563 } 564 palette_flag 565 = false; 566 default_rainbow(); 567 break; 568 case 1: 569 if(palette_flag==true) 570 571 { 572 EEPROM.put(1,mode_num); 573 EEPROM.commit(); 574 band_flag 575 =false; 576 } 577 palette_flag =false; 578 TWICE(); 579 break; 580 581 case 2: 582 if(palette_flag==true) 583 { 584 EEPROM.put(1,mode_num); 585 586 EEPROM.commit(); 587 band_flag =false; 588 } 589 palette_flag 590 =false; 591 Ocean(); 592 break; 593 case 3: 594 if(palette_flag==true) 595 596 { 597 EEPROM.put(1,mode_num); 598 EEPROM.commit(); 599 band_flag 600 =false; 601 } 602 palette_flag =false; 603 Poison(); 604 break; 605 606 case 4: 607 if(palette_flag==true) 608 { 609 EEPROM.put(1,mode_num); 610 611 EEPROM.commit(); 612 band_flag =true; 613 } 614 palette_flag 615 =false; 616 Temp(); 617 break; 618 case 5: 619 if(palette_flag==true) 620 621 { 622 EEPROM.put(1,mode_num); 623 EEPROM.commit(); 624 band_flag 625 =true; 626 } 627 palette_flag =false; 628 Temp_amp(); 629 break; 630 631 case 6: 632 if(palette_flag==true) 633 { 634 EEPROM.put(1,mode_num); 635 636 EEPROM.commit(); 637 band_flag =true; 638 } 639 palette_flag 640 =false; 641 Rainbow_amp(); 642 break; 643 break; 644 } 645 646} 647 648void 649 default_rainbow () // 650 the functions that are used to generate the patterns 651{ 652 for(int i=0; i< 653 NUM_LEDS; i++) 654 { 655 leds[1][i] =ColorFromPalette(Rainbow_pal, hue+i*8,brightness[1][i],LINEARBLEND); 656 657 leds[0][i] =ColorFromPalette(Rainbow_pal, hue+i*8,brightness[0][i],LINEARBLEND); 658 659 hue = inoise8(15*beatsin8(5,10,50),15*beatsin8(10,20,40),millis()/10); 660 661 } 662 hue++; 663 FastLED.show(); 664} 665 666void TWICE() 667{ 668 669 for(int i=0; i<NUM_LEDS; i++) 670 { 671 leds[1][i] =ColorFromPalette(TWICE_pal, 672 hue+i*8,brightness[1][i],LINEARBLEND); 673 leds[0][i] =ColorFromPalette(TWICE_pal, 674 hue+i*8,brightness[0][i],LINEARBLEND); 675 hue = inoise8(i*beatsin8(5,10,50),i*beatsin8(10,20,40),millis()/7); 676 677 } 678 hue++; 679 FastLED.show(); 680} 681 682void Ocean() 683{ 684 for(int 685 i=0; i<NUM_LEDS; i++) 686 { 687 leds[1][i] =ColorFromPalette(Ocean_pal, hue,brightness[1][i],NOBLEND); 688 689 leds[0][i] =ColorFromPalette(Ocean_pal, hue,brightness[0][i],NOBLEND); 690 hue 691 = inoise8(i*beatsin8(5,10,50),i*beatsin8(10,20,40),millis()/7); 692 } 693 hue++; 694 695 FastLED.show(); 696} 697 698void Poison() 699{ 700 for(int i=0; i<NUM_LEDS; 701 i++) 702 { 703 leds[1][i] =ColorFromPalette(Poison_pal, hue,brightness[1][i],NOBLEND); 704 705 leds[0][i] =ColorFromPalette(Poison_pal, hue,brightness[0][i],NOBLEND); 706 707 hue = inoise8(i*beatsin8(5,10,50),i*beatsin8(10,20,40),millis()/7); 708 } 709 710 hue++; 711 FastLED.show(); 712} 713 714void Temp () 715{ 716 for(int i=0; i<NUM_LEDS; 717 i++) 718 { 719 leds[1][i] =ColorFromPalette(Temp_pal, 0+brightness[1][i]-basebrightness,brightness[1][i]/4,LINEARBLEND); 720 721 leds[0][i] =ColorFromPalette(Temp_pal, 0+brightness[0][i]-basebrightness,brightness[0][i]/4,LINEARBLEND); 722 723 } 724 FastLED.show(); 725} 726 727void Temp_amp () 728{ 729 for(int i=0; i<11; 730 i++) 731 { 732 average[0] += (LbandValues[i]-basebrightness); 733 average[1] 734 += (RbandValues[i]-basebrightness); 735 } 736 average[0] =average[0]/50-6; 737 738 average[1] =average[1]/50-6; 739 740 average[0] =(2*average[0]+old_average[0])/3; 741 742 average[1] =(2*average[1]+old_average[1])/3; 743 744 if (average[0] >=29) 745 746 { 747 average[0] =29; 748 } 749 if(average[1] >=29) 750 { 751 average[1] 752 =29; 753 } 754 fill_palette(leds[0],NUM_LEDS, hue,8,Temp_pal,10,LINEARBLEND); 755 756 fill_palette(leds[1],NUM_LEDS, hue,8,Temp_pal,10,LINEARBLEND); 757 fill_palette(leds[0],average[0], 758 hue,8,Temp_pal,50,LINEARBLEND); 759 fill_palette(leds[1],average[1], hue,8,Temp_pal,50,LINEARBLEND); 760 761 762 old_average[0] =average[0]; 763 old_average[1] =average[1]; 764 765 if(peak_amp[0]<= 766 average[0]) 767 { 768 peak_amp[0] =average[0]; 769 } 770 if(peak_amp[1]<= average[1]) 771 772 { 773 peak_amp[1] =average[1]; 774 } 775 if(peak_amp[0]>=0) 776 { 777 leds[0][peak_amp[0]] 778 =ColorFromPalette(Temp_pal, hue+peak_amp[0]*8,50,LINEARBLEND); 779 } 780 if(peak_amp[1]>=0) 781 782 { 783 leds[1][peak_amp[1]] =ColorFromPalette(Temp_pal, hue+peak_amp[0]*8,50,LINEARBLEND); 784 785 } 786 hue++; 787 EVERY_N_MILLISECONDS(100) 788 { 789 peak_amp[0]-=1; 790 791 peak_amp[1]-=1; 792 } 793 FastLED.show(); 794} 795 796void Rainbow_amp () 797{ 798 799 for(int i=0; i<11; i++) 800 { 801 average[0] += (LbandValues[i]-basebrightness); 802 803 average[1] += (RbandValues[i]-basebrightness); 804 } 805 average[0] =average[0]/50-6; 806 807 average[1] =average[1]/50-6; 808 809 average[0] =(2*average[0]+old_average[0])/3; 810 811 average[1] =(2*average[1]+old_average[1])/3; 812 813 if (average[0] >=29) 814 815 { 816 average[0] =29; 817 } 818 if(average[1] >=29) 819 { 820 average[1] 821 =29; 822 } 823 fill_palette(leds[0],NUM_LEDS, hue,8,Rainbow_pal,10,LINEARBLEND); 824 825 fill_palette(leds[1],NUM_LEDS, hue,8,Rainbow_pal,10,LINEARBLEND); 826 fill_palette(leds[0],average[0], 827 hue,8,Rainbow_pal,50,LINEARBLEND); 828 fill_palette(leds[1],average[1], hue,8,Rainbow_pal,50,LINEARBLEND); 829 830 831 832 833 old_average[0] =average[0]; 834 old_average[1] =average[1]; 835 836 837 if(peak_amp[0]<= average[0]) 838 { 839 peak_amp[0] =average[0]; 840 } 841 if(peak_amp[1]<= 842 average[1]) 843 { 844 peak_amp[1] =average[1]; 845 } 846 if(peak_amp[0]>=0) 847 848 { 849 leds[0][peak_amp[0]] =ColorFromPalette(Rainbow_pal, hue +peak_amp[0]*8,50,LINEARBLEND); 850 851 } 852 if(peak_amp[1]>=0) 853 { 854 leds[1][peak_amp[1]] =ColorFromPalette(Rainbow_pal, 855 hue +peak_amp[1]*8,50,LINEARBLEND); 856 } 857 hue++; 858 EVERY_N_MILLISECONDS(100) 859 860 { 861 peak_amp[0]-=1; 862 peak_amp[1]-=1; 863 } 864 FastLED.show(); 865}
Stereo ESP32 audio visualizer
arduino
1#include <FastLED.h> 2#include <arduinoFFT.h> 3#include <EasyButton.h> 4#include <EEPROM.h> 5 6#define samples 512 7#define sampling_freq 40000 8#define Noise_filter 1300 // change this value as needed 9#define Left_AudioIn 36 // you can use different pins for the ADC but make sure that they do not conflict 10#define Right_AudioIn 35 11#define max_brightness 200 // define the max brightness of all the leds DOES NOT APPLY TO ALL MODES 12#define basebrightness 15 // used to set the minimum brightness 13#define NUM_LEDS 30 14#define LEFT_LED_PINOUT 22 15#define RIGHT_LED_PINOUT 23 16#define peak 255 //define the peak of fft results 17#define button_1 33 //choose pin 33 as the button to swtich modes. You can choose any pin you like but be aware of your circuit and which pins are useable 18#define EEPROM_size 512 // define the number of bytes that will be used for eeprom storage 19 20const float Lamp =1.7; // extra amp for channel tuning may change these values depending on your situation to balance the audio channels 21const float Ramp =1.3; 22 23#define amp_0 200 // used to control the amplification to divide the value of the bands after fft 24#define amp_1 200 25#define amp_2 200 // you can chnage these values to adjust the output of the FFT 26#define amp_3 150 27#define amp_4 150 28#define amp_5 120 29#define amp_6 120 30#define amp_7 120 31#define amp_8 120 32#define amp_9 100 33#define amp_10 80 34#define amp_11 80 35#define amp_12 50 36#define amp_13 40 37#define amp_14 40 38 39 40unsigned int amp[] ={amp_0, amp_1, amp_2, amp_3, amp_4, amp_5, amp_6, amp_7, // Create an array to store the amplitude adjustment values 41 amp_8, amp_9, amp_10, amp_11, amp_12, amp_13, amp_14,}; 42 43unsigned int sampling_period_us; // create a 16bit unsigned integer value to store the sampling period 44 45int LbandValues[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; //the bandvalues will store the data that has been processed from the arduino fft library 46int RbandValues[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; 47 48int LoldbandValues[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; //store the previous band values 49int RoldbandValues[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; 50 51double LvReal [samples]; // the arrays that will store the initial data created from fft 52double LvImag [samples]; 53double RvReal [samples]; 54double RvImag [samples]; 55 56unsigned long newTime, oldTime; // used to time the sampling for of signals 57 58uint8_t hue =0; //the hue integer number that will range from 0-255 59 60int average[2]; // average will be used for the _amp modes 61int old_average[2]; 62int peak_amp[2]; 63 64 65arduinoFFT FFTL =arduinoFFT(LvReal,LvImag, samples, sampling_freq); // FFT magic starts here 66arduinoFFT FFTR =arduinoFFT(RvReal,RvImag, samples, sampling_freq); 67 68EasyButton mode_button(button_1); // set button to be used to change modes 69 70bool mode_switch_call = false; 71bool palette_flag =true; 72bool band_flag =false; 73 74uint8_t mode_num =0; 75 76CRGB leds[2][NUM_LEDS]; // FastLED magic 77 78int brightness[2][NUM_LEDS]; 79 80CRGBPalette16 TWICE_pal =CRGBPalette16( //TWICE Colors (PS: its a Kpop girl group with a color theme dedicated to them) 81 CHSV(32,205,200), CHSV(16,210,200), 82 CHSV(245,210,200), CHSV(237,255,200) 83 ); 84CRGBPalette16 Rainbow_pal =CRGBPalette16( //Rainbow colors 85 CHSV(0,255,255), CHSV(85,255,255), 86 CHSV(171,255,255), CHSV(255,255,255) 87 ); 88CRGBPalette16 Ocean_pal =CRGBPalette16( //Ocean colors 89 CRGB(0,0,255), CRGB(0,128,255), 90 CRGB(200,200,200) 91 ); 92CRGBPalette16 Temp_pal =CRGBPalette16( //Temp colors 93 CRGB(0,0,255), CRGB(255,0,0), CRGB(255,255,0) 94 ); 95 96CRGBPalette16 Poison_pal =CRGBPalette16( //Poison colors 97 CRGB(0,255,0), CRGB(0,0,255), CRGB(255,0,80) 98 ); 99 100void mode_switch() // this function is called when a button press is detected 101{ 102 mode_num = (mode_num + 1)%7; // the mod numbers needs to be altered based on the number of modes currently available 103 palette_flag = true; 104 105} 106 107void setup() { 108 109 pinMode(Right_AudioIn, INPUT); 110 pinMode(Left_AudioIn, INPUT); 111 EEPROM.begin(EEPROM_size); 112 delay(3000); 113 mode_num =EEPROM.read(1); // Reads the current mode saved in EEPROM address 1 to choose mode before running. 114 115 mode_button.begin(); 116 FastLED.addLeds <WS2812B, LEFT_LED_PINOUT, GRB> (leds[0], NUM_LEDS); 117 FastLED.addLeds <WS2812B, RIGHT_LED_PINOUT, GRB> (leds[1], NUM_LEDS); 118 FastLED.setCorrection(TypicalSMD5050); 119 120 sampling_period_us = round (1000000*(1/sampling_freq)); 121} 122 123void loop() { 124 mode_button.read(); 125 if(mode_button.wasPressed()==true) 126 { 127 mode_switch(); 128 mode_switch_call =false; 129 } 130 131 for (int i=0; i<samples;i++) 132 { 133 newTime =micros(); 134 LvReal[i]=analogRead(Left_AudioIn); 135 LvImag[i]= 0; 136 RvReal[i] =analogRead(Right_AudioIn); 137 RvImag[i]=0; 138 while ((micros()-newTime) < sampling_period_us) // used to time the sampling rate 139 { 140 } 141 } 142 FFTL.DCRemoval(); //removes the DC offset 143 144 FFTL.Windowing(FFT_WIN_TYP_HAMMING, FFT_FORWARD); //FFT magic happening!! 145 FFTL.Compute(FFT_FORWARD); 146 FFTL.ComplexToMagnitude(); 147 148 FFTR.DCRemoval(); 149 FFTR.Windowing(FFT_WIN_TYP_HAMMING, FFT_FORWARD); 150 FFTR.Compute(FFT_FORWARD); 151 FFTR.ComplexToMagnitude(); 152 153 //Analyse FFT results 154 for(int i=1; i < (samples/2); i++) 155 { 156 if (RvReal[i]> Noise_filter ) //crude noise filter 157 { 158 if (i<=1) 159 { 160 RbandValues[0] = (int)RvReal[i]; 161 } 162 if (i>1 && i<=2 ) 163 { 164 RbandValues[1] = (int)RvReal[i]; 165 } 166 if (i>2 && i<=3 ) 167 { 168 RbandValues[2] = (int)RvReal[i]; 169 } 170 if (i>3 && i<=4 ) 171 { 172 RbandValues[3] = (int)RvReal[i]; 173 } 174 if (i>4 && i<=5 ) 175 { 176 RbandValues[4] = (int)RvReal[i]; 177 } 178 if (i>5 && i<=7 ) 179 { 180 RbandValues[5] = (int)RvReal[i]; 181 } 182 if (i>7 && i<=10 ) 183 { 184 RbandValues[6] = (int)RvReal[i]; 185 } 186 if (i>10 && i<=15 ) 187 { 188 RbandValues[7] = (int)RvReal[i]; 189 } 190 if (i>15 && i<=21 ) 191 { 192 RbandValues[8] = (int)RvReal[i]; 193 } 194 if (i>21 && i<=29 ) 195 { 196 RbandValues[9] = (int)RvReal[i]; 197 } 198 if (i>29 && i<=42 ) 199 { 200 RbandValues[10] = (int)RvReal[i]; 201 } 202 if (i>42 && i<=59 ) 203 { 204 RbandValues[11] = (int)RvReal[i]; 205 } 206 if (i>59 && i<=84 ) 207 { 208 RbandValues[12] = (int)RvReal[i]; 209 } 210 if (i>84 && i<=120 ) 211 { 212 RbandValues[13] = (int)RvReal[i]; 213 } 214 if (i>120 && i<=170 ) 215 { 216 RbandValues[14] = (int)RvReal[i]; 217 } 218 } 219 if(LvReal[i] > Noise_filter) 220 { 221 if (i<=1) 222 { 223 LbandValues[0] = (int)LvReal[i]; 224 } 225 if (i>1 && i<=2 ) 226 { 227 LbandValues[1] = (int)LvReal[i]; 228 } 229 if (i>2 && i<=3 ) 230 { 231 LbandValues[2] = (int)LvReal[i]; 232 } 233 if (i>3 && i<=4 ) 234 { 235 LbandValues[3] = (int)LvReal[i]; 236 } 237 if (i>4 && i<=5 ) 238 { 239 LbandValues[4] = (int)LvReal[i]; 240 } 241 if (i>5 && i<=7 ) 242 { 243 LbandValues[5] = (int)LvReal[i]; 244 } 245 if (i>7 && i<=10 ) 246 { 247 LbandValues[6] = (int)LvReal[i]; 248 } 249 if (i>10 && i<=15 ) 250 { 251 LbandValues[7] = (int)LvReal[i]; 252 } 253 if (i>15 && i<=21 ) 254 { 255 LbandValues[8] = (int)LvReal[i]; 256 } 257 if (i>21 && i<=29 ) 258 { 259 LbandValues[9] = (int)LvReal[i]; 260 } 261 if (i>29 && i<=42 ) 262 { 263 LbandValues[10] = (int)LvReal[i]; 264 } 265 if (i>42 && i<=59 ) 266 { 267 LbandValues[11] = (int)LvReal[i]; 268 } 269 if (i>59 && i<=84 ) 270 { 271 LbandValues[12] = (int)LvReal[i]; 272 } 273 if (i>84 && i<=120 ) 274 { 275 LbandValues[13] = (int)LvReal[i]; 276 } 277 if (i>120 && i<=170 ) 278 { 279 LbandValues[14] = (int)LvReal[i]; 280 } 281 } 282 } 283 for( int i =0; i <=14; i++) //adjust the values of the output. 284 { 285 286 LbandValues[i] =LbandValues[i]*Lamp/amp[i]; 287 RbandValues[i] =RbandValues[i]*Ramp/amp[i]; 288 289 290 291 if(LbandValues[i]>= peak) 292 { 293 LbandValues[i] =peak; 294 } 295 if(RbandValues[i]>= peak) 296 { 297 RbandValues[i] =peak; 298 } 299 300 LbandValues[i] =map(LbandValues[i],0, peak,0,max_brightness); // adjusted band values 301 RbandValues[i] =map(RbandValues[i],0, peak,0,max_brightness); 302 303 if (LoldbandValues[i] >= LbandValues[i]) 304 { 305 LbandValues[i] =(LoldbandValues[i]*2+LbandValues[i])/3; //weighted average to slow down decay 306 } 307 if (RoldbandValues[i] >= RbandValues[i]) 308 { 309 RbandValues[i] =(RoldbandValues[i]*2+RbandValues[i])/3; 310 } 311 312 if(band_flag ==true) // some modes will use these to make the lights move smoother 313 { 314 if (LoldbandValues[i] <= LbandValues[i]) 315 { 316 LbandValues[i] =(LoldbandValues[i]*1+LbandValues[i])/2; //weighted average to slow down increment 317 } 318 if (RoldbandValues[i] <= RbandValues[i]) 319 { 320 RbandValues[i] =(RoldbandValues[i]*1+RbandValues[i])/2; 321 } 322 } 323 LbandValues[i] += basebrightness; 324 RbandValues[i] += basebrightness; 325 326 LoldbandValues[i] =LbandValues[i]; //save the current band value to be used in future band averaging 327 RoldbandValues[i] =RbandValues[i]; 328 } 329 330 for(int i=0; i<NUM_LEDS; i++) 331 { 332 if (i<=1) // the brightness array values will determine the brightness of each leds. 333 { 334 brightness[0][i] =LbandValues[0]; 335 brightness[1][i] =RbandValues[0]; 336 } 337 if (i>1 && i<=3) 338 { 339 brightness[0][i] =LbandValues[1]; 340 brightness[1][i] =RbandValues[1]; 341 } 342 if(i>3 && i<=5) 343 { 344 brightness[0][i] =LbandValues[2]; 345 brightness[1][i] =RbandValues[2]; 346 } 347 if(i>5 && i<=7) 348 { 349 brightness[0][i] =LbandValues[3]; 350 brightness[1][i] =RbandValues[3]; 351 } 352 if(i>7 && i<=9) 353 { 354 brightness[0][i] =LbandValues[4]; 355 brightness[1][i] =RbandValues[4]; 356 } 357 if(i>9 && i<=11) 358 { 359 brightness[0][i] =LbandValues[5]; 360 brightness[1][i] =RbandValues[5]; 361 } 362 if(i>11 && i<=13) 363 { 364 brightness[0][i] =LbandValues[6]; 365 brightness[1][i] =RbandValues[6]; 366 } 367 if(i>13 && i<=15) 368 { 369 brightness[0][i] =LbandValues[7]; 370 brightness[1][i] =RbandValues[7]; 371 } 372 if(i>15 && i<=17) 373 { 374 brightness[0][i] =LbandValues[8]; 375 brightness[1][i] =RbandValues[8]; 376 } 377 if(i>17 && i<=19) 378 { 379 brightness[0][i] =LbandValues[9]; 380 brightness[1][i] =RbandValues[9]; 381 } 382 if(i>19 && i<=21) 383 { 384 brightness[0][i] =LbandValues[10]; 385 brightness[1][i] =RbandValues[10]; 386 } 387 if(i>21 && i<=23) 388 { 389 brightness[0][i] =LbandValues[11]; 390 brightness[1][i] =RbandValues[11]; 391 } 392 if(i>23 && i<=25) 393 { 394 brightness[0][i] =LbandValues[12]; 395 brightness[1][i] =RbandValues[12]; 396 } 397 if(i>25 && i<=27) 398 { 399 brightness[0][i] =LbandValues[13]; 400 brightness[1][i] =RbandValues[13]; 401 } 402 if(i>27 && i<=29) 403 { 404 brightness[0][i] =LbandValues[14]; 405 brightness[1][i] =RbandValues[14]; 406 } 407 408 } 409 410 switch (mode_num) //choose modes 411 { 412 case 0: 413 if(palette_flag ==true) 414 { 415 EEPROM.put(1,mode_num); 416 EEPROM.commit(); 417 band_flag =false; 418 } 419 palette_flag = false; 420 default_rainbow(); 421 break; 422 case 1: 423 if(palette_flag==true) 424 { 425 EEPROM.put(1,mode_num); 426 EEPROM.commit(); 427 band_flag =false; 428 } 429 palette_flag =false; 430 TWICE(); 431 break; 432 case 2: 433 if(palette_flag==true) 434 { 435 EEPROM.put(1,mode_num); 436 EEPROM.commit(); 437 band_flag =false; 438 } 439 palette_flag =false; 440 Ocean(); 441 break; 442 case 3: 443 if(palette_flag==true) 444 { 445 EEPROM.put(1,mode_num); 446 EEPROM.commit(); 447 band_flag =false; 448 } 449 palette_flag =false; 450 Poison(); 451 break; 452 case 4: 453 if(palette_flag==true) 454 { 455 EEPROM.put(1,mode_num); 456 EEPROM.commit(); 457 band_flag =true; 458 } 459 palette_flag =false; 460 Temp(); 461 break; 462 case 5: 463 if(palette_flag==true) 464 { 465 EEPROM.put(1,mode_num); 466 EEPROM.commit(); 467 band_flag =true; 468 } 469 palette_flag =false; 470 Temp_amp(); 471 break; 472 case 6: 473 if(palette_flag==true) 474 { 475 EEPROM.put(1,mode_num); 476 EEPROM.commit(); 477 band_flag =true; 478 } 479 palette_flag =false; 480 Rainbow_amp(); 481 break; 482 break; 483 } 484 485} 486 487void default_rainbow () // the functions that are used to generate the patterns 488{ 489 for(int i=0; i< NUM_LEDS; i++) 490 { 491 leds[1][i] =ColorFromPalette(Rainbow_pal, hue+i*8,brightness[1][i],LINEARBLEND); 492 leds[0][i] =ColorFromPalette(Rainbow_pal, hue+i*8,brightness[0][i],LINEARBLEND); 493 hue = inoise8(15*beatsin8(5,10,50),15*beatsin8(10,20,40),millis()/10); 494 } 495 hue++; 496 FastLED.show(); 497} 498 499void TWICE() 500{ 501 for(int i=0; i<NUM_LEDS; i++) 502 { 503 leds[1][i] =ColorFromPalette(TWICE_pal, hue+i*8,brightness[1][i],LINEARBLEND); 504 leds[0][i] =ColorFromPalette(TWICE_pal, hue+i*8,brightness[0][i],LINEARBLEND); 505 hue = inoise8(i*beatsin8(5,10,50),i*beatsin8(10,20,40),millis()/7); 506 } 507 hue++; 508 FastLED.show(); 509} 510 511void Ocean() 512{ 513 for(int i=0; i<NUM_LEDS; i++) 514 { 515 leds[1][i] =ColorFromPalette(Ocean_pal, hue,brightness[1][i],NOBLEND); 516 leds[0][i] =ColorFromPalette(Ocean_pal, hue,brightness[0][i],NOBLEND); 517 hue = inoise8(i*beatsin8(5,10,50),i*beatsin8(10,20,40),millis()/7); 518 } 519 hue++; 520 FastLED.show(); 521} 522 523void Poison() 524{ 525 for(int i=0; i<NUM_LEDS; i++) 526 { 527 leds[1][i] =ColorFromPalette(Poison_pal, hue,brightness[1][i],NOBLEND); 528 leds[0][i] =ColorFromPalette(Poison_pal, hue,brightness[0][i],NOBLEND); 529 hue = inoise8(i*beatsin8(5,10,50),i*beatsin8(10,20,40),millis()/7); 530 } 531 hue++; 532 FastLED.show(); 533} 534 535void Temp () 536{ 537 for(int i=0; i<NUM_LEDS; i++) 538 { 539 leds[1][i] =ColorFromPalette(Temp_pal, 0+brightness[1][i]-basebrightness,brightness[1][i]/4,LINEARBLEND); 540 leds[0][i] =ColorFromPalette(Temp_pal, 0+brightness[0][i]-basebrightness,brightness[0][i]/4,LINEARBLEND); 541 } 542 FastLED.show(); 543} 544 545void Temp_amp () 546{ 547 for(int i=0; i<11; i++) 548 { 549 average[0] += (LbandValues[i]-basebrightness); 550 average[1] += (RbandValues[i]-basebrightness); 551 } 552 average[0] =average[0]/50-6; 553 average[1] =average[1]/50-6; 554 555 average[0] =(2*average[0]+old_average[0])/3; 556 average[1] =(2*average[1]+old_average[1])/3; 557 558 if (average[0] >=29) 559 { 560 average[0] =29; 561 } 562 if(average[1] >=29) 563 { 564 average[1] =29; 565 } 566 fill_palette(leds[0],NUM_LEDS, hue,8,Temp_pal,10,LINEARBLEND); 567 fill_palette(leds[1],NUM_LEDS, hue,8,Temp_pal,10,LINEARBLEND); 568 fill_palette(leds[0],average[0], hue,8,Temp_pal,50,LINEARBLEND); 569 fill_palette(leds[1],average[1], hue,8,Temp_pal,50,LINEARBLEND); 570 571 old_average[0] =average[0]; 572 old_average[1] =average[1]; 573 574 if(peak_amp[0]<= average[0]) 575 { 576 peak_amp[0] =average[0]; 577 } 578 if(peak_amp[1]<= average[1]) 579 { 580 peak_amp[1] =average[1]; 581 } 582 if(peak_amp[0]>=0) 583 { 584 leds[0][peak_amp[0]] =ColorFromPalette(Temp_pal, hue+peak_amp[0]*8,50,LINEARBLEND); 585 } 586 if(peak_amp[1]>=0) 587 { 588 leds[1][peak_amp[1]] =ColorFromPalette(Temp_pal, hue+peak_amp[0]*8,50,LINEARBLEND); 589 } 590 hue++; 591 EVERY_N_MILLISECONDS(100) 592 { 593 peak_amp[0]-=1; 594 peak_amp[1]-=1; 595 } 596 FastLED.show(); 597} 598 599void Rainbow_amp () 600{ 601 for(int i=0; i<11; i++) 602 { 603 average[0] += (LbandValues[i]-basebrightness); 604 average[1] += (RbandValues[i]-basebrightness); 605 } 606 average[0] =average[0]/50-6; 607 average[1] =average[1]/50-6; 608 609 average[0] =(2*average[0]+old_average[0])/3; 610 average[1] =(2*average[1]+old_average[1])/3; 611 612 if (average[0] >=29) 613 { 614 average[0] =29; 615 } 616 if(average[1] >=29) 617 { 618 average[1] =29; 619 } 620 fill_palette(leds[0],NUM_LEDS, hue,8,Rainbow_pal,10,LINEARBLEND); 621 fill_palette(leds[1],NUM_LEDS, hue,8,Rainbow_pal,10,LINEARBLEND); 622 fill_palette(leds[0],average[0], hue,8,Rainbow_pal,50,LINEARBLEND); 623 fill_palette(leds[1],average[1], hue,8,Rainbow_pal,50,LINEARBLEND); 624 625 626 627 old_average[0] =average[0]; 628 old_average[1] =average[1]; 629 630 if(peak_amp[0]<= average[0]) 631 { 632 peak_amp[0] =average[0]; 633 } 634 if(peak_amp[1]<= average[1]) 635 { 636 peak_amp[1] =average[1]; 637 } 638 if(peak_amp[0]>=0) 639 { 640 leds[0][peak_amp[0]] =ColorFromPalette(Rainbow_pal, hue +peak_amp[0]*8,50,LINEARBLEND); 641 } 642 if(peak_amp[1]>=0) 643 { 644 leds[1][peak_amp[1]] =ColorFromPalette(Rainbow_pal, hue +peak_amp[1]*8,50,LINEARBLEND); 645 } 646 hue++; 647 EVERY_N_MILLISECONDS(100) 648 { 649 peak_amp[0]-=1; 650 peak_amp[1]-=1; 651 } 652 FastLED.show(); 653}
Downloadable files
20210107_011052_WYRU1N7R8U.jpg
20210107_011052_WYRU1N7R8U.jpg

Comments
Only logged in users can leave comments