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.
Devices & Components
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
Hardware & Tools
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
Software & Tools
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