Streams USB audio with sound effects applied. Sound effect selected by joystick and intensity altered by tilting the mbed. Output to the mbed-application-board phono jack.

Dependencies:   C12832_lcd MMA7660 USBDevice mbed

/media/uploads/bw/img_1293.jpg

/* Uses the mbed LPC1768 and mbed-application-board to create a USB audio device
 * that streams audio from a host computer to headphones or powered speakers. 
 * A couple different sound effects can be applied to the stream in real-time,
 * and tilting the mbed alters intensity of the effect.
 *
 *                                               ECHO
 *       The joystick selects )                   |
 *       one of three effect  )       STRAIGHT -  o  - STRAIGHT
 *       modes.               )                   |
 *                                              REVERB   
 * 
 *
 *
 *                                               \\           ||    
 *       Tilting the mbed     )      ======       \\          ||
 *       determines intensity )                    \\         ||
 *       of the effect.       )
 *                                     0%         50%         100%  
 *
 * The LCD display shows the current effect mode, intesity and buffer level.
*/
Revision:
0:bbf6cf0eab95
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/effects.cpp	Thu Mar 27 21:27:04 2014 +0000
@@ -0,0 +1,147 @@
+/*******************************************************************************
+ * Module processes 16-bit audio samples to produces delay-based sound effects.
+ * Bryan Wade
+ * 27 MAR 2014
+ ******************************************************************************/
+#include "mbed.h"
+#include "effects.h"
+#include "delay.h"
+
+// Delay based effects require significant RAM, so we must
+// scavange two banks of RAM that mbed has reserved for ethernet:
+//   AHBSRAM0: 0x2007C000 - 0x2007FFFF (16KB)
+//   AHBSRAM1: 0x20080000 - 0x20083FFF (16KB)                            
+// To keep the linker happy we allocate the RAM with a 16KB array in each bank, 
+// but since they are contiguous, we can treat them as one 32KB block.
+static const int RAM_BANK0_SIZE = 16 * 1024;
+static const int RAM_BANK1_SIZE = 16 * 1024; 
+__attribute((section("AHBSRAM0"),aligned)) char ramBank0[RAM_BANK0_SIZE];
+__attribute((section("AHBSRAM1"),aligned)) char ramBank1[RAM_BANK1_SIZE];
+
+static effect_mode_t effectMode;
+static uint16_t effectGain;
+static const int MAX_DELAYS = 7;
+static delay_t *delay[MAX_DELAYS];
+
+static void initializeEcho(void);
+static void initializeReverb(void);
+
+/*
+ * Initialize module.
+ */
+void Effects_Initialize(void) 
+{
+    effectGain = 0;
+    
+    // Create all the delay objects. They will be initialized and
+    // re-initialized as needed each time the mode changes, but the
+    // total number of delay objects is fixed.
+    for (int i = 0; i < MAX_DELAYS; i++) 
+    {
+        delay[i] = Delay_Create();  
+    }
+    Effects_SetMode(EFFECT_STRAIGHT);
+}
+
+/*
+ * Apply current effect to sample stream.
+ * @return Processed sample.
+ */
+int16_t Effects_ProcessSample(int16_t dataIn)
+{
+    int16_t dataOut;
+    
+    switch (effectMode) 
+    {
+    case EFFECT_ECHO:
+        dataOut = Delay_WriteWithFeedback(delay[0], dataIn, effectGain);
+        break;
+    
+    case EFFECT_REVERB:
+        dataOut = (Delay_WriteWithFeedback(delay[0], dataIn, effectGain) + 
+                   Delay_WriteWithFeedback(delay[1], dataIn, effectGain) +
+                   Delay_WriteWithFeedback(delay[2], dataIn, effectGain) +
+                   Delay_WriteWithFeedback(delay[3], dataIn, effectGain) +
+                   Delay_WriteWithFeedback(delay[4], dataIn, effectGain) +
+                   Delay_WriteWithFeedback(delay[5], dataIn, effectGain) +
+                   Delay_WriteWithFeedback(delay[6], dataIn, effectGain)) / 7;    
+        break;
+    
+    case EFFECT_STRAIGHT:
+    default:
+        dataOut = dataIn;
+    }
+    
+    return dataOut;
+}
+
+/*
+ * Getter/setters.
+ */
+void Effects_SetMode(effect_mode_t mode)
+{
+    // Ignore if already in desired mode.
+    if (effectMode == mode) return;
+        
+    // Effects_Process() will continue to be called by an ISR while
+    // changing modes, so first change to straight mode since this 
+    // can safely play at any time. Then change to the desired mode
+    // once it is fully configured.
+    effectMode = EFFECT_STRAIGHT;
+    
+    switch (mode)
+    {
+    case EFFECT_ECHO:
+        initializeEcho();
+        effectMode = mode;
+        break;
+    
+    case EFFECT_REVERB:
+        initializeReverb();  
+        effectMode = mode;
+        break;
+    
+    case EFFECT_STRAIGHT:
+    default:
+        effectMode = mode;
+    }
+}
+
+void Effects_SetGain(uint16_t gain) { effectGain = gain; }
+
+/*
+ * Configure one large delay for echo.
+ */
+void initializeEcho(void)
+{
+    // The maximum echo delay is 16K samples since each sample is 2 bytes
+    // and we have 32KB available. 
+    static const int ECHO_DELAY_SAMPLES = 12000; 
+    Delay_Configure(delay[0], (void *)ramBank0, ECHO_DELAY_SAMPLES * sizeof(int16_t));  
+}
+
+/*
+ * Configure all delays for reverb.
+ */
+void initializeReverb(void)
+{
+    // Delay lengths are chosen as a base length times prime numbers to prevent 
+    // interfernce patterns. Total size of all delay lines must fit within 32KB.
+    static const int REVERB_BASE_DELAY_SAMPLES = 256;
+    static const int PRIMES[MAX_DELAYS] = {2, 3, 5, 7, 11, 13, 17};   
+    
+    char *ram = ramBank0; // Location for first buffer.
+    
+    for (int i = 0; i < MAX_DELAYS; i++) 
+    {
+        // Configure each delay with proper buffer size and location
+        int size = PRIMES[i] * REVERB_BASE_DELAY_SAMPLES * sizeof(int16_t);              
+        Delay_Configure(delay[i], (void *)ram, size);      
+        
+        // The next buffer location immediately follows this one.
+        ram += size; 
+    }  
+}
+
+
+    
\ No newline at end of file