Audio Reactive Infinity Mirror
Dependencies: mbed-dsp mbed-rtos mbed
Infinity Mirror Project Page https://developer.mbed.org/users/mgolino/notebook/infinity-mirror/
Diff: fftstuff.cpp
- Revision:
- 0:85385a11b2da
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fftstuff.cpp Sat Dec 12 01:22:30 2015 +0000 @@ -0,0 +1,312 @@ +#include "fftstuff.h" +#include <iostream> + +AnalogIn mic(p15); +AnalogIn aux(p20); +bool auxControl = false; +bool micControl = false; +float redColor, greenColor, blueColor; +// Integers used to cycle LED colors +int rIdx = 0; +int gIdx = 1; +int bIdx = 2; +Serial pc2(USBTX, USBRX); +PwmOut grled(p23); +PwmOut rrled(p22); +PwmOut brled(p21); +Ticker counter; +int i = 0; +int flipCount = 0; +//////////////////////////////////////////////////////////////////////////////// +// CONFIGURATION +// These values alter the behavior of the audio reaction. +//////////////////////////////////////////////////////////////////////////////// +int SLOWDOWN = 0; // Create an optical delay in spectrumLoop - useful when only one RGB led is used. + // Only active when nonzero. + // A value >= 1000 and <= 1000 + PIXEL_COUNT fixes the output to a single frequency + // window = a single color. +int SAMPLE_RATE_HZ = 6000; // Sample rate of the audio in hertz +float SPECTRUM_MIN_DB = 30.0; // Audio intensity (in decibels) that maps to low LED brightness => sensitive to quiet +float SPECTRUM_MAX_DB = 100.0; // Audio intensity (in decibels) that maps to high LED brightness => sensitive to loud +const int FFT_SIZE = 32; // Size of the FFT +const int PIXEL_COUNT = 3; // Number of pixels (1)R, (2)G, & (3)B for LED strip +// END CONFIGURATION + +//////////////////////////////////////////////////////////////////////////////// +// INTERNAL STATE +// These shouldn't be modified unless you know what you're doing. +//////////////////////////////////////////////////////////////////////////////// +const static arm_cfft_instance_f32 *S; +Ticker samplingTimer; +float samples[FFT_SIZE*2]; +float magnitudes[FFT_SIZE]; +int sampleCounter = 0; +float frequencyWindow[PIXEL_COUNT+1]; +float hues[PIXEL_COUNT]; +// END INTERNAL STATE + +//////////////////////////////////////////////////////////////////////////////// +// SAMPLING FUNCTIONS +//////////////////////////////////////////////////////////////////////////////// +// Read from the ADC and store the sample data +void samplingCallback() +{ + i++; + if(auxControl) { // Read aux input (pin 20) + samples[sampleCounter] = (1023 * aux) - 511.0f; + } + else if(micControl) { // Read mic input (pin 15) + samples[sampleCounter] = (1023 * mic) - 511.0f; + } + // Complex FFT functions require a coefficient for the imaginary part of the input. + // Since we only have real data, set this coefficient to zero. + samples[sampleCounter+1] = 0.0; + // Update sample buffer position and stop after the buffer is filled + sampleCounter += 2; + if (sampleCounter >= FFT_SIZE*2) { + samplingTimer.detach(); + } +} // End samplingCallBack + +// Begin sampling audio +void samplingBegin() +{ + // Reset sample buffer position and start callback at necessary rate. + sampleCounter = 0; + samplingTimer.attach_us(&samplingCallback, 1000000/SAMPLE_RATE_HZ); +} + +// Check if sampling is done before performing FFT +bool samplingIsDone() +{ + return sampleCounter >= FFT_SIZE*2; +} // End samplingIsDone +// END SAMPLING FUNCTIONS + +//////////////////////////////////////////////////////////////////////////////// +// FFT FUNCTIONS +// Used for performing FFT on audio signal +///////////////////////////////////////////////////////////////////////////////// +// Initialize FFT Size +void initFFT() +{ + switch (FFT_SIZE) { // Call appropriate FFT + case 16: + S = & arm_cfft_sR_f32_len16; + break; + case 32: + S = & arm_cfft_sR_f32_len32; + break; + case 64: + S = & arm_cfft_sR_f32_len64; + break; + case 128: + S = & arm_cfft_sR_f32_len128; + break; + case 256: + S = & arm_cfft_sR_f32_len256; + break; + case 512: + S = & arm_cfft_sR_f32_len512; + break; + case 1024: + S = & arm_cfft_sR_f32_len1024; + break; + case 2048: + S = & arm_cfft_sR_f32_len2048; + break; + case 4096: + S = & arm_cfft_sR_f32_len4096; + break; + } +} // End initFFT + +// Setup the frequency windowing size given sampling rate +void spectrumSetup() +{ + // Set the frequency window values by evenly dividing the possible frequency + float windowSize = (SAMPLE_RATE_HZ / 2.0) / float(PIXEL_COUNT); + for (int i = 0; i < PIXEL_COUNT+1; ++i) { + frequencyWindow[i] = i*windowSize; + } +} // End spectrumSetup + +// Convert a frequency to the appropriate FFT bin it will fall within +int frequencyToBin(float frequency) +{ + float binFrequency = float(SAMPLE_RATE_HZ) / float(FFT_SIZE); + return int(frequency / binFrequency); +} + +// Compute the average magnitude of a target frequency window vs. all other frequencies +void windowMean(float* magnitudes, int lowBin, int highBin, float* windowMean, float* otherMean) +{ + *windowMean = 0; + *otherMean = 0; + // Notice the first magnitude bin is skipped because it represents the average power of the signal + for (int i = 1; i < FFT_SIZE/2; ++i) { + // Sum values + if (i >= lowBin && i <= highBin) { + *windowMean += magnitudes[i]; + } else { + *otherMean += magnitudes[i]; + } + } + // Average values + *windowMean /= (highBin - lowBin) + 1; + *otherMean /= (FFT_SIZE / 2 - (highBin - lowBin)); +} + +// Update LED RGB values based on intensity of frequency window +void spectrumLoop() +{ + + // Update each LED color based on the audio intensity of each frequency window + float max = 0.0f; + static int SLrpt = 0; + static int SLpixcnt = 0; + int SLpixend = 0; + float intensity, otherMean; + if(SLOWDOWN != 0) + { + if(SLOWDOWN >= 1000) + { + if(SLOWDOWN <= (1000 + PIXEL_COUNT-1)) + { + SLpixcnt = SLOWDOWN - 1000; + SLrpt = 0; + SLpixend = SLpixcnt + 1; + } + else + SLOWDOWN = 0; + } + else + { + SLrpt++; + if (SLrpt >= SLOWDOWN) + { + SLrpt = 0; + SLpixcnt = SLpixcnt < PIXEL_COUNT-1 ? ++SLpixcnt : 0; + } + SLpixend = SLpixcnt + 1; + } + } + else + { + SLpixcnt = 0; + SLrpt = 0; + SLpixend = PIXEL_COUNT; + } + + for (int i = SLpixcnt; i < SLpixend; ++i) { + windowMean(magnitudes, + frequencyToBin(frequencyWindow[i]), + frequencyToBin(frequencyWindow[i+1]), + &intensity, + &otherMean); + // Convert intensity to decibels. + intensity = 20.0*log10(intensity); + //pc2.printf("INTENSITY1: %f\n\r", intensity); + // Scale the intensity and clamp between 0 and 1.0. + intensity -= SPECTRUM_MIN_DB; + //intensity = intensity < 0.0 ? 0.0 : intensity; + intensity /= (SPECTRUM_MAX_DB-SPECTRUM_MIN_DB); + intensity = intensity > 1.0 ? 1.0 : intensity; + //pc2.printf("INTENSITY2: %f\n\r", intensity); + + + if(intensity > max){ + max = intensity; + } + + + hues[i]=intensity; + } + //cout << "AUX VALUE" << mic << "\n\r" << endl; + //cout << "/n HUES: " << hues[0] << " " << hues[1] << " " << hues[2] << "\n\r" << endl; + redColor= hues[rIdx]; + greenColor= hues[gIdx]; + blueColor= hues[bIdx]; + + //pc2.printf("writing colors\n\r"); + //pc2.printf("!!!red %f, green %f, blue %f!!!\n\n\n\r", redColor, greenColor, blueColor); + rrled = hues[rIdx]/max; + grled= hues[gIdx]/max; + brled= hues[bIdx]/max; + // possible add Threading to make this function wait rather than SLOWDOWN +} + +//////////////////////////////////////////////////////////////////////////////// +// TIMING THREADS +//////////////////////////////////////////////////////////////////////////////// +// Cycle given frequency window controlling an LED color +////***************************************** +void flip() // add input argument for FFT processing +{ + rIdx++; + gIdx++; + bIdx++; + if(rIdx > 2){ + rIdx = 0; + } + if(gIdx > 2){ + gIdx = 0; + } + if(bIdx > 2){ + bIdx = 0; + } + // 4s wait time +} +////***************************************** + +void runFFT(bool input, float colors[]) +{ + //counter.attach(&flip, 4.0); + // Initialize frequency window size + spectrumSetup(); + //pc2.printf("hi"); + if (input == true){ + micControl = true; + auxControl = false; + } + else{ + micControl = false; + auxControl = true; + } + + + // Begin sampling audio + samplingBegin(); + //pc2.printf("sampling began\n"); + // Init arm_ccft_32 + initFFT(); + + //6000 HZ = check back for readable every 1/2 second + i = 0; + while(i< 3000){ + if (samplingIsDone()) { + // Run FFT on sample data. + arm_cfft_f32(S, samples, 0, 1); + // Calculate magnitude of complex numbers output by the FFT. + arm_cmplx_mag_f32(samples, magnitudes, FFT_SIZE); + spectrumLoop(); + // Restart audio sampling. + samplingBegin(); + } + } + + colors[0] = redColor; + colors[1] = greenColor; + colors[2] = blueColor; + flipCount++; + //shift colors around every 4 seconds + if (flipCount >= 8){ + flipCount = 0; + flip(); + } + + +} +// END FFT FUNCTIONS + +