Last active
May 7, 2016 13:49
-
-
Save dz0ny/8d6c2650ffa3609ac035803ba6969d9d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #define NumOfFreqBins 32 | |
| #define RedPin 9 | |
| #define GreenPin 10 | |
| #define BluePin 11 | |
| #define ButtonPin 8 | |
| #define LIN_OUT 1 // use linear fht output function | |
| #define FHT_N NumOfFreqBins | |
| #define ADCReset 0b11110111 // reset the adc, freq = 1000 kHz / 13 =~ 74 kHz sampling rate | |
| #define ADCFreeRun 0b11100111 // set the adc to free running mode, freq = 1000 kHz / 13.5 =~ 74 kHz sampling rate | |
| #define PeakPWMValue 255 | |
| #define RedMinLimit 1350 | |
| #define GreenMinLimit 125 | |
| #define BlueMinLimit 350 | |
| #define PopThreshold 120 // large delta in ADC samples means the reading has lots of error | |
| #include <FHT.h> // http://wiki.openmusiclabs.com/wiki/ArduinoFHT | |
| #include <Pushbutton.h> | |
| static const uint8_t PROGMEM | |
| // This is low-level noise that's subtracted from each FFT output column: | |
| noise[64] = { 8, 6, 6, 5, 3, 4, 4, 4, 3, 4, 4, 3, 2, 3, 3, 4, | |
| 2, 1, 2, 1, 3, 2, 3, 2, 1, 2, 3, 1, 2, 3, 4, 4, | |
| 3, 2, 2, 2, 2, 2, 2, 1, 3, 2, 2, 2, 2, 2, 2, 2, | |
| 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 4 | |
| }; | |
| /* Create a Pushbutton object with default settings, which | |
| enables the internal pull-up on the pin and interprets a HIGH | |
| pin value as the default (unpressed) state of the | |
| button. (Optional arguments can be passed to the constructor | |
| to specify other button types and connection methods; see the | |
| documentation for details.) */ | |
| Pushbutton button(ButtonPin); | |
| unsigned int OutputGreen = 0; | |
| unsigned int OutputRed = 0; | |
| unsigned int OutputBlue = 0; | |
| unsigned int RedPeak = 0; | |
| unsigned int GreenPeak = 0; | |
| unsigned int BluePeak = 0; | |
| unsigned int RedMin = 65535; // set to max so a new min is always found the first time | |
| unsigned int GreenMin = 65535; | |
| unsigned int BlueMin = 65535; | |
| unsigned int RedFilterStorage = 0; | |
| unsigned int GreenFilterStorage = 0; | |
| unsigned int BlueFilterStorage = 0; | |
| unsigned int MainArray[NumOfFreqBins / 2]; | |
| unsigned int PeakArray[NumOfFreqBins / 2]; | |
| unsigned int MinArray[NumOfFreqBins / 2]; | |
| byte RangeErrorRed = 0; | |
| byte RangeErrorGreen = 0; | |
| byte RangeErrorBlue = 0; | |
| byte BadSample = 0; | |
| int Delta = 0; | |
| int Mode = 0; | |
| int LastValue = 32767; | |
| void setup() | |
| { | |
| pinMode(RedPin, OUTPUT); | |
| pinMode(GreenPin, OUTPUT); | |
| pinMode(BluePin, OUTPUT); | |
| // 16MHZ/prescaller / 13(CPU cycles) > target freq range | |
| ADCSRA = ADCFreeRun; // set the adc to free running mode | |
| ADCSRB = 0; // Free run mode, no high MUX bit | |
| ADMUX = _BV(REFS1) | _BV(MUX0); | |
| DIDR0 = 0x01; // turn off the digital input for adc5 | |
| } | |
| int ReadADC() | |
| { | |
| noInterrupts(); // get lots more nasty pops/error on the measurements without doing this | |
| while (!(ADCSRA & 0x10)); // wait for adc to be ready | |
| ADCSRA = ADCReset; // reset the adc | |
| int Output = ADCW; // read the adc | |
| interrupts(); | |
| return Output; | |
| } | |
| void loop() { | |
| checkButton(); | |
| if (Mode <= 2) { | |
| Sound2RGB(); | |
| } | |
| if (Mode == 3) { | |
| fade(RedPin); | |
| fade(GreenPin); | |
| fade(BluePin); | |
| } | |
| } | |
| void checkButton() { | |
| if (button.getSingleDebouncedRelease()) | |
| { | |
| Mode++; | |
| if (Mode >= 3) { | |
| Mode = 0; | |
| } | |
| } | |
| } | |
| void ProcessSound(){ | |
| uint8_t L; | |
| BadSample = 0; | |
| for (byte i = 0 ; i < NumOfFreqBins ; i++) // save NumOfFreqBins samples for FHT | |
| { | |
| int Sample; | |
| if (LastValue != 32767) | |
| { | |
| Sample = ReadADC(); | |
| Delta = Sample - LastValue; | |
| if (abs(Delta) > 100) // looks like a pop, don't process this sample | |
| { | |
| BadSample = 1; | |
| } | |
| } | |
| else { | |
| Sample = ReadADC(); // it's the first sample, just read | |
| } | |
| LastValue = Sample; | |
| Sample <<= 6; // form into a 16b signed int | |
| fht_input[i] = Sample; // put real data into bins | |
| } | |
| fht_window(); // window the data for better frequency response | |
| fht_reorder(); // reorder the data before doing the fht | |
| fht_run(); // process the data in the fht | |
| fht_mag_lin(); // take the linear output of the fht | |
| for (byte Index = 0; Index < (NumOfFreqBins / 2); Index++) | |
| { | |
| if (fht_lin_out[Index] > MainArray[Index]) { | |
| MainArray[Index] = fht_lin_out[Index]; | |
| if (Mode == 2) { | |
| // Remove noise and apply EQ levels | |
| L = pgm_read_byte(&noise[Index]); | |
| } | |
| } | |
| if (MainArray[Index] > PeakArray[Index]) | |
| { | |
| PeakArray[Index] = MainArray[Index]; | |
| } | |
| } | |
| } | |
| void Sound2RGB() { | |
| ProcessSound(); | |
| unsigned int RedMap = ArrayRedParser(MainArray); | |
| unsigned int GreenMap = ArrayGreenParser(MainArray); | |
| unsigned int BlueMap = ArrayBlueParser(MainArray); | |
| if (RedMap > RedPeak){RedPeak = RedMap;} | |
| if (RedMap < RedMin){RedMin = RedMap;} | |
| if (GreenMap > GreenPeak){GreenPeak = GreenMap;} | |
| if (GreenMap < GreenMin){GreenMin = GreenMap;} | |
| if (BlueMap > BluePeak){BluePeak = BlueMap;} | |
| if (BlueMap < BlueMin){BlueMin = BlueMap;} | |
| if (RedPeak < RedMinLimit){RedPeak = RedMinLimit;} | |
| if (GreenPeak < GreenMinLimit){GreenPeak = GreenMinLimit;} | |
| if (BluePeak < BlueMinLimit){BluePeak = BlueMinLimit;} | |
| RedFilterStorage = map(RedMap, RedMin, RedPeak, 0, PeakPWMValue); | |
| GreenFilterStorage = map(GreenMap, GreenMin, GreenPeak, 0, PeakPWMValue); | |
| BlueFilterStorage = map(BlueMap, BlueMin, BluePeak, 0, PeakPWMValue); | |
| if (RedFilterStorage > PeakPWMValue){RedFilterStorage = PeakPWMValue; RangeErrorRed = 1;} | |
| if (GreenFilterStorage > PeakPWMValue){GreenFilterStorage = PeakPWMValue; RangeErrorGreen = 1;} | |
| if (BlueFilterStorage > PeakPWMValue){BlueFilterStorage = PeakPWMValue; RangeErrorBlue = 1;} | |
| OutputRed = RedFilterStorage; | |
| OutputGreen = GreenFilterStorage; | |
| OutputBlue = BlueFilterStorage; | |
| analogWrite(RedPin, OutputRed); | |
| analogWrite(GreenPin, OutputGreen); | |
| analogWrite(BluePin, OutputBlue); | |
| for (byte Index = 0; Index < (NumOfFreqBins / 2); Index++) { | |
| MainArray[Index] = 0; // Clean the main array | |
| } | |
| } | |
| unsigned int ArrayRedParser(unsigned int Array[]) | |
| { | |
| unsigned int RedParser = ((Array[0]) + Array[1] + (Array[2] * 0.65)); | |
| return RedParser; | |
| } | |
| unsigned int ArrayGreenParser(unsigned int Array[]) | |
| { | |
| unsigned int GreenParser = ((Array[2] * 0.95) + Array[3] + (Array[4] * 0.75) + (Array[5]) * 0.25); | |
| return GreenParser; | |
| } | |
| unsigned int ArrayBlueParser(unsigned int Array[]) | |
| { | |
| unsigned int BlueParser = ((Array[4] * 0.25) + (Array[5] * 0.75)); | |
| for (byte BlueIndex = 6; BlueIndex < (NumOfFreqBins/2); BlueIndex++){BlueParser = (BlueParser + Array[BlueIndex]);} | |
| return BlueParser; | |
| } | |
| void fade(int ledPin) { | |
| // fade in from min to max in increments of 5 points: | |
| for (int fadeValue = 0 ; fadeValue <= 255; fadeValue += 5) { | |
| // sets the value (range from 0 to 255): | |
| analogWrite(ledPin, fadeValue); | |
| delayMicroseconds(500); | |
| if (button.isPressed()) { | |
| checkButton(); | |
| } | |
| } | |
| // fade out from max to min in increments of 5 points: | |
| for (int fadeValue = 255 ; fadeValue >= 0; fadeValue -= 5) { | |
| // sets the value (range from 0 to 255): | |
| analogWrite(ledPin, fadeValue); | |
| delayMicroseconds(500); | |
| if (button.isPressed()) { | |
| checkButton(); | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment