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
/* 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. */
Diff: effects.cpp
- Revision:
- 0:bbf6cf0eab95
diff -r 000000000000 -r bbf6cf0eab95 effects.cpp --- /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