#include <FastLED.h>
#include <arduinoFFT.h>
#include <EasyButton.h>
#include <EEPROM.h>
#define samples 512
#define sampling_freq 40000
#define Noise_filter 1300 // change this value as needed
#define Left_AudioIn 36 // you can use different pins for the ADC but make sure that they do not conflict
#define Right_AudioIn 35
#define max_brightness 200 // define the max brightness of all the leds DOES NOT APPLY TO ALL MODES
#define basebrightness 15 // used to set the minimum brightness
#define NUM_LEDS 30
#define LEFT_LED_PINOUT 22
#define RIGHT_LED_PINOUT 23
#define peak 255 //define the peak of fft results
#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
#define EEPROM_size 512 // define the number of bytes that will be used for eeprom storage
const float Lamp =1.7; // extra amp for channel tuning may change these values depending on your situation to balance the audio channels
const float Ramp =1.3;
#define amp_0 200 // used to control the amplification to divide the value of the bands after fft
#define amp_1 200
#define amp_2 200 // you can chnage these values to adjust the output of the FFT
#define amp_3 150
#define amp_4 150
#define amp_5 120
#define amp_6 120
#define amp_7 120
#define amp_8 120
#define amp_9 100
#define amp_10 80
#define amp_11 80
#define amp_12 50
#define amp_13 40
#define amp_14 40
unsigned 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
amp_8, amp_9, amp_10, amp_11, amp_12, amp_13, amp_14,};
unsigned int sampling_period_us; // create a 16bit unsigned integer value to store the sampling period
int 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
int RbandValues[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int LoldbandValues[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; //store the previous band values
int RoldbandValues[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
double LvReal [samples]; // the arrays that will store the initial data created from fft
double LvImag [samples];
double RvReal [samples];
double RvImag [samples];
unsigned long newTime, oldTime; // used to time the sampling for of signals
uint8_t hue =0; //the hue integer number that will range from 0-255
int average[2]; // average will be used for the _amp modes
int old_average[2];
int peak_amp[2];
arduinoFFT FFTL =arduinoFFT(LvReal,LvImag, samples, sampling_freq); // FFT magic starts here
arduinoFFT FFTR =arduinoFFT(RvReal,RvImag, samples, sampling_freq);
EasyButton mode_button(button_1); // set button to be used to change modes
bool mode_switch_call = false;
bool palette_flag =true;
bool band_flag =false;
uint8_t mode_num =0;
CRGB leds[2][NUM_LEDS]; // FastLED magic
int brightness[2][NUM_LEDS];
CRGBPalette16 TWICE_pal =CRGBPalette16( //TWICE Colors (PS: its a Kpop girl group with a color theme dedicated to them)
CHSV(32,205,200), CHSV(16,210,200),
CHSV(245,210,200), CHSV(237,255,200)
);
CRGBPalette16 Rainbow_pal =CRGBPalette16( //Rainbow colors
CHSV(0,255,255), CHSV(85,255,255),
CHSV(171,255,255), CHSV(255,255,255)
);
CRGBPalette16 Ocean_pal =CRGBPalette16( //Ocean colors
CRGB(0,0,255), CRGB(0,128,255),
CRGB(200,200,200)
);
CRGBPalette16 Temp_pal =CRGBPalette16( //Temp colors
CRGB(0,0,255), CRGB(255,0,0), CRGB(255,255,0)
);
CRGBPalette16 Poison_pal =CRGBPalette16( //Poison colors
CRGB(0,255,0), CRGB(0,0,255), CRGB(255,0,80)
);
void mode_switch() // this function is called when a button press is detected
{
mode_num = (mode_num + 1)%7; // the mod numbers needs to be altered based on the number of modes currently available
palette_flag = true;
}
void setup() {
pinMode(Right_AudioIn, INPUT);
pinMode(Left_AudioIn, INPUT);
EEPROM.begin(EEPROM_size);
delay(3000);
mode_num =EEPROM.read(1); // Reads the current mode saved in EEPROM address 1 to choose mode before running.
mode_button.begin();
FastLED.addLeds <WS2812B, LEFT_LED_PINOUT, GRB> (leds[0], NUM_LEDS);
FastLED.addLeds <WS2812B, RIGHT_LED_PINOUT, GRB> (leds[1], NUM_LEDS);
FastLED.setCorrection(TypicalSMD5050);
sampling_period_us = round (1000000*(1/sampling_freq));
}
void loop() {
mode_button.read();
if(mode_button.wasPressed()==true)
{
mode_switch();
mode_switch_call =false;
}
for (int i=0; i<samples;i++)
{
newTime =micros();
LvReal[i]=analogRead(Left_AudioIn);
LvImag[i]= 0;
RvReal[i] =analogRead(Right_AudioIn);
RvImag[i]=0;
while ((micros()-newTime) < sampling_period_us) // used to time the sampling rate
{
}
}
FFTL.DCRemoval(); //removes the DC offset
FFTL.Windowing(FFT_WIN_TYP_HAMMING, FFT_FORWARD); //FFT magic happening!!
FFTL.Compute(FFT_FORWARD);
FFTL.ComplexToMagnitude();
FFTR.DCRemoval();
FFTR.Windowing(FFT_WIN_TYP_HAMMING, FFT_FORWARD);
FFTR.Compute(FFT_FORWARD);
FFTR.ComplexToMagnitude();
//Analyse FFT results
for(int i=1; i < (samples/2); i++)
{
if (RvReal[i]> Noise_filter ) //crude noise filter
{
if (i<=1)
{
RbandValues[0] = (int)RvReal[i];
}
if (i>1 && i<=2 )
{
RbandValues[1] = (int)RvReal[i];
}
if (i>2 && i<=3 )
{
RbandValues[2] = (int)RvReal[i];
}
if (i>3 && i<=4 )
{
RbandValues[3] = (int)RvReal[i];
}
if (i>4 && i<=5 )
{
RbandValues[4] = (int)RvReal[i];
}
if (i>5 && i<=7 )
{
RbandValues[5] = (int)RvReal[i];
}
if (i>7 && i<=10 )
{
RbandValues[6] = (int)RvReal[i];
}
if (i>10 && i<=15 )
{
RbandValues[7] = (int)RvReal[i];
}
if (i>15 && i<=21 )
{
RbandValues[8] = (int)RvReal[i];
}
if (i>21 && i<=29 )
{
RbandValues[9] = (int)RvReal[i];
}
if (i>29 && i<=42 )
{
RbandValues[10] = (int)RvReal[i];
}
if (i>42 && i<=59 )
{
RbandValues[11] = (int)RvReal[i];
}
if (i>59 && i<=84 )
{
RbandValues[12] = (int)RvReal[i];
}
if (i>84 && i<=120 )
{
RbandValues[13] = (int)RvReal[i];
}
if (i>120 && i<=170 )
{
RbandValues[14] = (int)RvReal[i];
}
}
if(LvReal[i] > Noise_filter)
{
if (i<=1)
{
LbandValues[0] = (int)LvReal[i];
}
if (i>1 && i<=2 )
{
LbandValues[1] = (int)LvReal[i];
}
if (i>2 && i<=3 )
{
LbandValues[2] = (int)LvReal[i];
}
if (i>3 && i<=4 )
{
LbandValues[3] = (int)LvReal[i];
}
if (i>4 && i<=5 )
{
LbandValues[4] = (int)LvReal[i];
}
if (i>5 && i<=7 )
{
LbandValues[5] = (int)LvReal[i];
}
if (i>7 && i<=10 )
{
LbandValues[6] = (int)LvReal[i];
}
if (i>10 && i<=15 )
{
LbandValues[7] = (int)LvReal[i];
}
if (i>15 && i<=21 )
{
LbandValues[8] = (int)LvReal[i];
}
if (i>21 && i<=29 )
{
LbandValues[9] = (int)LvReal[i];
}
if (i>29 && i<=42 )
{
LbandValues[10] = (int)LvReal[i];
}
if (i>42 && i<=59 )
{
LbandValues[11] = (int)LvReal[i];
}
if (i>59 && i<=84 )
{
LbandValues[12] = (int)LvReal[i];
}
if (i>84 && i<=120 )
{
LbandValues[13] = (int)LvReal[i];
}
if (i>120 && i<=170 )
{
LbandValues[14] = (int)LvReal[i];
}
}
}
for( int i =0; i <=14; i++) //adjust the values of the output.
{
LbandValues[i] =LbandValues[i]*Lamp/amp[i];
RbandValues[i] =RbandValues[i]*Ramp/amp[i];
if(LbandValues[i]>= peak)
{
LbandValues[i] =peak;
}
if(RbandValues[i]>= peak)
{
RbandValues[i] =peak;
}
LbandValues[i] =map(LbandValues[i],0, peak,0,max_brightness); // adjusted band values
RbandValues[i] =map(RbandValues[i],0, peak,0,max_brightness);
if (LoldbandValues[i] >= LbandValues[i])
{
LbandValues[i] =(LoldbandValues[i]*2+LbandValues[i])/3; //weighted average to slow down decay
}
if (RoldbandValues[i] >= RbandValues[i])
{
RbandValues[i] =(RoldbandValues[i]*2+RbandValues[i])/3;
}
if(band_flag ==true) // some modes will use these to make the lights move smoother
{
if (LoldbandValues[i] <= LbandValues[i])
{
LbandValues[i] =(LoldbandValues[i]*1+LbandValues[i])/2; //weighted average to slow down increment
}
if (RoldbandValues[i] <= RbandValues[i])
{
RbandValues[i] =(RoldbandValues[i]*1+RbandValues[i])/2;
}
}
LbandValues[i] += basebrightness;
RbandValues[i] += basebrightness;
LoldbandValues[i] =LbandValues[i]; //save the current band value to be used in future band averaging
RoldbandValues[i] =RbandValues[i];
}
for(int i=0; i<NUM_LEDS; i++)
{
if (i<=1) // the brightness array values will determine the brightness of each leds.
{
brightness[0][i] =LbandValues[0];
brightness[1][i] =RbandValues[0];
}
if (i>1 && i<=3)
{
brightness[0][i] =LbandValues[1];
brightness[1][i] =RbandValues[1];
}
if(i>3 && i<=5)
{
brightness[0][i] =LbandValues[2];
brightness[1][i] =RbandValues[2];
}
if(i>5 && i<=7)
{
brightness[0][i] =LbandValues[3];
brightness[1][i] =RbandValues[3];
}
if(i>7 && i<=9)
{
brightness[0][i] =LbandValues[4];
brightness[1][i] =RbandValues[4];
}
if(i>9 && i<=11)
{
brightness[0][i] =LbandValues[5];
brightness[1][i] =RbandValues[5];
}
if(i>11 && i<=13)
{
brightness[0][i] =LbandValues[6];
brightness[1][i] =RbandValues[6];
}
if(i>13 && i<=15)
{
brightness[0][i] =LbandValues[7];
brightness[1][i] =RbandValues[7];
}
if(i>15 && i<=17)
{
brightness[0][i] =LbandValues[8];
brightness[1][i] =RbandValues[8];
}
if(i>17 && i<=19)
{
brightness[0][i] =LbandValues[9];
brightness[1][i] =RbandValues[9];
}
if(i>19 && i<=21)
{
brightness[0][i] =LbandValues[10];
brightness[1][i] =RbandValues[10];
}
if(i>21 && i<=23)
{
brightness[0][i] =LbandValues[11];
brightness[1][i] =RbandValues[11];
}
if(i>23 && i<=25)
{
brightness[0][i] =LbandValues[12];
brightness[1][i] =RbandValues[12];
}
if(i>25 && i<=27)
{
brightness[0][i] =LbandValues[13];
brightness[1][i] =RbandValues[13];
}
if(i>27 && i<=29)
{
brightness[0][i] =LbandValues[14];
brightness[1][i] =RbandValues[14];
}
}
switch (mode_num) //choose modes
{
case 0:
if(palette_flag ==true)
{
EEPROM.put(1,mode_num);
EEPROM.commit();
band_flag =false;
}
palette_flag = false;
default_rainbow();
break;
case 1:
if(palette_flag==true)
{
EEPROM.put(1,mode_num);
EEPROM.commit();
band_flag =false;
}
palette_flag =false;
TWICE();
break;
case 2:
if(palette_flag==true)
{
EEPROM.put(1,mode_num);
EEPROM.commit();
band_flag =false;
}
palette_flag =false;
Ocean();
break;
case 3:
if(palette_flag==true)
{
EEPROM.put(1,mode_num);
EEPROM.commit();
band_flag =false;
}
palette_flag =false;
Poison();
break;
case 4:
if(palette_flag==true)
{
EEPROM.put(1,mode_num);
EEPROM.commit();
band_flag =true;
}
palette_flag =false;
Temp();
break;
case 5:
if(palette_flag==true)
{
EEPROM.put(1,mode_num);
EEPROM.commit();
band_flag =true;
}
palette_flag =false;
Temp_amp();
break;
case 6:
if(palette_flag==true)
{
EEPROM.put(1,mode_num);
EEPROM.commit();
band_flag =true;
}
palette_flag =false;
Rainbow_amp();
break;
break;
}
}
void default_rainbow () // the functions that are used to generate the patterns
{
for(int i=0; i< NUM_LEDS; i++)
{
leds[1][i] =ColorFromPalette(Rainbow_pal, hue+i*8,brightness[1][i],LINEARBLEND);
leds[0][i] =ColorFromPalette(Rainbow_pal, hue+i*8,brightness[0][i],LINEARBLEND);
hue = inoise8(15*beatsin8(5,10,50),15*beatsin8(10,20,40),millis()/10);
}
hue++;
FastLED.show();
}
void TWICE()
{
for(int i=0; i<NUM_LEDS; i++)
{
leds[1][i] =ColorFromPalette(TWICE_pal, hue+i*8,brightness[1][i],LINEARBLEND);
leds[0][i] =ColorFromPalette(TWICE_pal, hue+i*8,brightness[0][i],LINEARBLEND);
hue = inoise8(i*beatsin8(5,10,50),i*beatsin8(10,20,40),millis()/7);
}
hue++;
FastLED.show();
}
void Ocean()
{
for(int i=0; i<NUM_LEDS; i++)
{
leds[1][i] =ColorFromPalette(Ocean_pal, hue,brightness[1][i],NOBLEND);
leds[0][i] =ColorFromPalette(Ocean_pal, hue,brightness[0][i],NOBLEND);
hue = inoise8(i*beatsin8(5,10,50),i*beatsin8(10,20,40),millis()/7);
}
hue++;
FastLED.show();
}
void Poison()
{
for(int i=0; i<NUM_LEDS; i++)
{
leds[1][i] =ColorFromPalette(Poison_pal, hue,brightness[1][i],NOBLEND);
leds[0][i] =ColorFromPalette(Poison_pal, hue,brightness[0][i],NOBLEND);
hue = inoise8(i*beatsin8(5,10,50),i*beatsin8(10,20,40),millis()/7);
}
hue++;
FastLED.show();
}
void Temp ()
{
for(int i=0; i<NUM_LEDS; i++)
{
leds[1][i] =ColorFromPalette(Temp_pal, 0+brightness[1][i]-basebrightness,brightness[1][i]/4,LINEARBLEND);
leds[0][i] =ColorFromPalette(Temp_pal, 0+brightness[0][i]-basebrightness,brightness[0][i]/4,LINEARBLEND);
}
FastLED.show();
}
void Temp_amp ()
{
for(int i=0; i<11; i++)
{
average[0] += (LbandValues[i]-basebrightness);
average[1] += (RbandValues[i]-basebrightness);
}
average[0] =average[0]/50-6;
average[1] =average[1]/50-6;
average[0] =(2*average[0]+old_average[0])/3;
average[1] =(2*average[1]+old_average[1])/3;
if (average[0] >=29)
{
average[0] =29;
}
if(average[1] >=29)
{
average[1] =29;
}
fill_palette(leds[0],NUM_LEDS, hue,8,Temp_pal,10,LINEARBLEND);
fill_palette(leds[1],NUM_LEDS, hue,8,Temp_pal,10,LINEARBLEND);
fill_palette(leds[0],average[0], hue,8,Temp_pal,50,LINEARBLEND);
fill_palette(leds[1],average[1], hue,8,Temp_pal,50,LINEARBLEND);
old_average[0] =average[0];
old_average[1] =average[1];
if(peak_amp[0]<= average[0])
{
peak_amp[0] =average[0];
}
if(peak_amp[1]<= average[1])
{
peak_amp[1] =average[1];
}
if(peak_amp[0]>=0)
{
leds[0][peak_amp[0]] =ColorFromPalette(Temp_pal, hue+peak_amp[0]*8,50,LINEARBLEND);
}
if(peak_amp[1]>=0)
{
leds[1][peak_amp[1]] =ColorFromPalette(Temp_pal, hue+peak_amp[0]*8,50,LINEARBLEND);
}
hue++;
EVERY_N_MILLISECONDS(100)
{
peak_amp[0]-=1;
peak_amp[1]-=1;
}
FastLED.show();
}
void Rainbow_amp ()
{
for(int i=0; i<11; i++)
{
average[0] += (LbandValues[i]-basebrightness);
average[1] += (RbandValues[i]-basebrightness);
}
average[0] =average[0]/50-6;
average[1] =average[1]/50-6;
average[0] =(2*average[0]+old_average[0])/3;
average[1] =(2*average[1]+old_average[1])/3;
if (average[0] >=29)
{
average[0] =29;
}
if(average[1] >=29)
{
average[1] =29;
}
fill_palette(leds[0],NUM_LEDS, hue,8,Rainbow_pal,10,LINEARBLEND);
fill_palette(leds[1],NUM_LEDS, hue,8,Rainbow_pal,10,LINEARBLEND);
fill_palette(leds[0],average[0], hue,8,Rainbow_pal,50,LINEARBLEND);
fill_palette(leds[1],average[1], hue,8,Rainbow_pal,50,LINEARBLEND);
old_average[0] =average[0];
old_average[1] =average[1];
if(peak_amp[0]<= average[0])
{
peak_amp[0] =average[0];
}
if(peak_amp[1]<= average[1])
{
peak_amp[1] =average[1];
}
if(peak_amp[0]>=0)
{
leds[0][peak_amp[0]] =ColorFromPalette(Rainbow_pal, hue +peak_amp[0]*8,50,LINEARBLEND);
}
if(peak_amp[1]>=0)
{
leds[1][peak_amp[1]] =ColorFromPalette(Rainbow_pal, hue +peak_amp[1]*8,50,LINEARBLEND);
}
hue++;
EVERY_N_MILLISECONDS(100)
{
peak_amp[0]-=1;
peak_amp[1]-=1;
}
FastLED.show();
}
Comments