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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers effects.cpp Source File

effects.cpp

00001 /*******************************************************************************
00002  * Module processes 16-bit audio samples to produces delay-based sound effects.
00003  * Bryan Wade
00004  * 27 MAR 2014
00005  ******************************************************************************/
00006 #include "mbed.h"
00007 #include "effects.h"
00008 #include "delay.h"
00009 
00010 // Delay based effects require significant RAM, so we must
00011 // scavange two banks of RAM that mbed has reserved for ethernet:
00012 //   AHBSRAM0: 0x2007C000 - 0x2007FFFF (16KB)
00013 //   AHBSRAM1: 0x20080000 - 0x20083FFF (16KB)                            
00014 // To keep the linker happy we allocate the RAM with a 16KB array in each bank, 
00015 // but since they are contiguous, we can treat them as one 32KB block.
00016 static const int RAM_BANK0_SIZE = 16 * 1024;
00017 static const int RAM_BANK1_SIZE = 16 * 1024; 
00018 __attribute((section("AHBSRAM0"),aligned)) char ramBank0[RAM_BANK0_SIZE];
00019 __attribute((section("AHBSRAM1"),aligned)) char ramBank1[RAM_BANK1_SIZE];
00020 
00021 static effect_mode_t effectMode;
00022 static uint16_t effectGain;
00023 static const int MAX_DELAYS = 7;
00024 static delay_t *delay[MAX_DELAYS];
00025 
00026 static void initializeEcho(void);
00027 static void initializeReverb(void);
00028 
00029 /*
00030  * Initialize module.
00031  */
00032 void Effects_Initialize(void) 
00033 {
00034     effectGain = 0;
00035     
00036     // Create all the delay objects. They will be initialized and
00037     // re-initialized as needed each time the mode changes, but the
00038     // total number of delay objects is fixed.
00039     for (int i = 0; i < MAX_DELAYS; i++) 
00040     {
00041         delay[i] = Delay_Create();  
00042     }
00043     Effects_SetMode(EFFECT_STRAIGHT);
00044 }
00045 
00046 /*
00047  * Apply current effect to sample stream.
00048  * @return Processed sample.
00049  */
00050 int16_t Effects_ProcessSample(int16_t dataIn)
00051 {
00052     int16_t dataOut;
00053     
00054     switch (effectMode) 
00055     {
00056     case EFFECT_ECHO:
00057         dataOut = Delay_WriteWithFeedback(delay[0], dataIn, effectGain);
00058         break;
00059     
00060     case EFFECT_REVERB:
00061         dataOut = (Delay_WriteWithFeedback(delay[0], dataIn, effectGain) + 
00062                    Delay_WriteWithFeedback(delay[1], dataIn, effectGain) +
00063                    Delay_WriteWithFeedback(delay[2], dataIn, effectGain) +
00064                    Delay_WriteWithFeedback(delay[3], dataIn, effectGain) +
00065                    Delay_WriteWithFeedback(delay[4], dataIn, effectGain) +
00066                    Delay_WriteWithFeedback(delay[5], dataIn, effectGain) +
00067                    Delay_WriteWithFeedback(delay[6], dataIn, effectGain)) / 7;    
00068         break;
00069     
00070     case EFFECT_STRAIGHT:
00071     default:
00072         dataOut = dataIn;
00073     }
00074     
00075     return dataOut;
00076 }
00077 
00078 /*
00079  * Getter/setters.
00080  */
00081 void Effects_SetMode(effect_mode_t mode)
00082 {
00083     // Ignore if already in desired mode.
00084     if (effectMode == mode) return;
00085         
00086     // Effects_Process() will continue to be called by an ISR while
00087     // changing modes, so first change to straight mode since this 
00088     // can safely play at any time. Then change to the desired mode
00089     // once it is fully configured.
00090     effectMode = EFFECT_STRAIGHT;
00091     
00092     switch (mode)
00093     {
00094     case EFFECT_ECHO:
00095         initializeEcho();
00096         effectMode = mode;
00097         break;
00098     
00099     case EFFECT_REVERB:
00100         initializeReverb();  
00101         effectMode = mode;
00102         break;
00103     
00104     case EFFECT_STRAIGHT:
00105     default:
00106         effectMode = mode;
00107     }
00108 }
00109 
00110 void Effects_SetGain(uint16_t gain) { effectGain = gain; }
00111 
00112 /*
00113  * Configure one large delay for echo.
00114  */
00115 void initializeEcho(void)
00116 {
00117     // The maximum echo delay is 16K samples since each sample is 2 bytes
00118     // and we have 32KB available. 
00119     static const int ECHO_DELAY_SAMPLES = 12000; 
00120     Delay_Configure(delay[0], (void *)ramBank0, ECHO_DELAY_SAMPLES * sizeof(int16_t));  
00121 }
00122 
00123 /*
00124  * Configure all delays for reverb.
00125  */
00126 void initializeReverb(void)
00127 {
00128     // Delay lengths are chosen as a base length times prime numbers to prevent 
00129     // interfernce patterns. Total size of all delay lines must fit within 32KB.
00130     static const int REVERB_BASE_DELAY_SAMPLES = 256;
00131     static const int PRIMES[MAX_DELAYS] = {2, 3, 5, 7, 11, 13, 17};   
00132     
00133     char *ram = ramBank0; // Location for first buffer.
00134     
00135     for (int i = 0; i < MAX_DELAYS; i++) 
00136     {
00137         // Configure each delay with proper buffer size and location
00138         int size = PRIMES[i] * REVERB_BASE_DELAY_SAMPLES * sizeof(int16_t);              
00139         Delay_Configure(delay[i], (void *)ram, size);      
00140         
00141         // The next buffer location immediately follows this one.
00142         ram += size; 
00143     }  
00144 }
00145 
00146 
00147