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
+
+