Audio Reactive Infinity Mirror

Dependencies:   mbed-dsp mbed-rtos mbed

Infinity Mirror Project Page https://developer.mbed.org/users/mgolino/notebook/infinity-mirror/

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