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. */
audio.cpp@2:9429f84ea165, 2014-03-27 (annotated)
- Committer:
- bw
- Date:
- Thu Mar 27 21:43:41 2014 +0000
- Revision:
- 2:9429f84ea165
- Parent:
- 0:bbf6cf0eab95
Clean up comments.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
bw | 0:bbf6cf0eab95 | 1 | /******************************************************************************* |
bw | 0:bbf6cf0eab95 | 2 | * Manages all aspects of audio playback with sound effects. |
bw | 0:bbf6cf0eab95 | 3 | * Bryan Wade |
bw | 0:bbf6cf0eab95 | 4 | * 27 MAR 2014 |
bw | 0:bbf6cf0eab95 | 5 | ******************************************************************************/ |
bw | 0:bbf6cf0eab95 | 6 | #include "mbed.h" |
bw | 0:bbf6cf0eab95 | 7 | #include "USBAudio.h" |
bw | 0:bbf6cf0eab95 | 8 | #include "buffer.h" |
bw | 0:bbf6cf0eab95 | 9 | #include "effects.h" |
bw | 0:bbf6cf0eab95 | 10 | |
bw | 0:bbf6cf0eab95 | 11 | static const int SAMPLE_FREQ = 50000; |
bw | 0:bbf6cf0eab95 | 12 | static const int NUM_CHANNELS = 1; |
bw | 0:bbf6cf0eab95 | 13 | static const int PACKET_FREQ = 1000; |
bw | 0:bbf6cf0eab95 | 14 | static const int PACKET_LENGTH = SAMPLE_FREQ / PACKET_FREQ; |
bw | 0:bbf6cf0eab95 | 15 | static const int PLAYBACK_BUFFER_SIZE = 8 * 1024; |
bw | 0:bbf6cf0eab95 | 16 | |
bw | 0:bbf6cf0eab95 | 17 | static int16_t packetBuffer[PACKET_LENGTH]; |
bw | 0:bbf6cf0eab95 | 18 | static char playbackBufferRAM[PLAYBACK_BUFFER_SIZE]; |
bw | 0:bbf6cf0eab95 | 19 | static buffer_t *playbackBuffer; |
bw | 0:bbf6cf0eab95 | 20 | static bool playbackReady = false; |
bw | 0:bbf6cf0eab95 | 21 | |
bw | 0:bbf6cf0eab95 | 22 | AnalogOut speaker(p18); |
bw | 0:bbf6cf0eab95 | 23 | USBAudio audio(SAMPLE_FREQ, NUM_CHANNELS, 8000, 1, 0x7180, 0x7500); |
bw | 0:bbf6cf0eab95 | 24 | Ticker playbackTic; |
bw | 0:bbf6cf0eab95 | 25 | DigitalOut bufferLED(LED1); // On when buffer is ready for playback. |
bw | 0:bbf6cf0eab95 | 26 | DigitalOut playbackLED(LED2); // On when playing audio. |
bw | 0:bbf6cf0eab95 | 27 | DigitalOut sampleLED(LED3); // Toggles on each audio sample played. |
bw | 0:bbf6cf0eab95 | 28 | DigitalOut packetLED(LED4); // Toggles on each audio packet received. |
bw | 0:bbf6cf0eab95 | 29 | |
bw | 0:bbf6cf0eab95 | 30 | /* |
bw | 0:bbf6cf0eab95 | 31 | * Transfers packet to the playback buffer each time a packet is received. |
bw | 0:bbf6cf0eab95 | 32 | */ |
bw | 0:bbf6cf0eab95 | 33 | void handlePacket(void) { |
bw | 0:bbf6cf0eab95 | 34 | Buffer_WriteBlock(playbackBuffer, packetBuffer, PACKET_LENGTH); |
bw | 0:bbf6cf0eab95 | 35 | packetLED = !packetLED; |
bw | 0:bbf6cf0eab95 | 36 | } |
bw | 0:bbf6cf0eab95 | 37 | |
bw | 0:bbf6cf0eab95 | 38 | /* |
bw | 0:bbf6cf0eab95 | 39 | * Pulls a sample from the playback buffer, adds effects and sends to speaker. |
bw | 0:bbf6cf0eab95 | 40 | */ |
bw | 0:bbf6cf0eab95 | 41 | void handlePlayback() |
bw | 0:bbf6cf0eab95 | 42 | { |
bw | 0:bbf6cf0eab95 | 43 | int16_t sample; |
bw | 0:bbf6cf0eab95 | 44 | |
bw | 0:bbf6cf0eab95 | 45 | // Get a sample from playback buffer |
bw | 0:bbf6cf0eab95 | 46 | if (playbackReady) { |
bw | 0:bbf6cf0eab95 | 47 | if (Buffer_Read(playbackBuffer, &sample)) |
bw | 0:bbf6cf0eab95 | 48 | { |
bw | 0:bbf6cf0eab95 | 49 | playbackLED = 1; // Playing |
bw | 0:bbf6cf0eab95 | 50 | } else { |
bw | 0:bbf6cf0eab95 | 51 | sample = 0; // Shouldn't get hear if buffer limits set properly. |
bw | 0:bbf6cf0eab95 | 52 | playbackLED = 0; |
bw | 0:bbf6cf0eab95 | 53 | } |
bw | 0:bbf6cf0eab95 | 54 | } else { |
bw | 0:bbf6cf0eab95 | 55 | sample = 0; // Nothing to play |
bw | 0:bbf6cf0eab95 | 56 | playbackLED = 0; |
bw | 0:bbf6cf0eab95 | 57 | } |
bw | 0:bbf6cf0eab95 | 58 | |
bw | 0:bbf6cf0eab95 | 59 | // Add sound effects |
bw | 0:bbf6cf0eab95 | 60 | int32_t out = Effects_ProcessSample(sample); |
bw | 0:bbf6cf0eab95 | 61 | |
bw | 0:bbf6cf0eab95 | 62 | // Write the sample to the uni-polar A/D, which requires offseting the signed 16-bit sample. |
bw | 0:bbf6cf0eab95 | 63 | speaker.write_u16(out + 32767); |
bw | 0:bbf6cf0eab95 | 64 | |
bw | 0:bbf6cf0eab95 | 65 | sampleLED = !sampleLED; |
bw | 0:bbf6cf0eab95 | 66 | } |
bw | 0:bbf6cf0eab95 | 67 | |
bw | 0:bbf6cf0eab95 | 68 | /* |
bw | 0:bbf6cf0eab95 | 69 | * Initialize audio module. |
bw | 0:bbf6cf0eab95 | 70 | */ |
bw | 0:bbf6cf0eab95 | 71 | void Audio_Initialize(void) |
bw | 0:bbf6cf0eab95 | 72 | { |
bw | 0:bbf6cf0eab95 | 73 | Effects_Initialize(); |
bw | 0:bbf6cf0eab95 | 74 | |
bw | 0:bbf6cf0eab95 | 75 | // Create a buffer that will incomming audio packets and provide a consistent supply |
bw | 0:bbf6cf0eab95 | 76 | // for playback at the desired sample rate. |
bw | 0:bbf6cf0eab95 | 77 | playbackBuffer = Buffer_Create(playbackBufferRAM, sizeof(playbackBufferRAM)); |
bw | 0:bbf6cf0eab95 | 78 | |
bw | 0:bbf6cf0eab95 | 79 | // Start the playback timer interrupt that will call the playback handler at the desired |
bw | 0:bbf6cf0eab95 | 80 | // sample rate. |
bw | 0:bbf6cf0eab95 | 81 | playbackTic.attach_us(handlePlayback, 1000000.0/(float)(SAMPLE_FREQ)); |
bw | 0:bbf6cf0eab95 | 82 | |
bw | 0:bbf6cf0eab95 | 83 | // Attach the handler that will buffer packets from incomming USB audio. |
bw | 0:bbf6cf0eab95 | 84 | // Perform the first read to set the buffer location, then all subsequent packets |
bw | 0:bbf6cf0eab95 | 85 | // will go to this buffer, and the handler pulls them from this small buffer |
bw | 0:bbf6cf0eab95 | 86 | // and places them in the large playback buffer. |
bw | 0:bbf6cf0eab95 | 87 | audio.attachReadCallback(handlePacket); |
bw | 0:bbf6cf0eab95 | 88 | audio.readNB((uint8_t *)packetBuffer); |
bw | 0:bbf6cf0eab95 | 89 | |
bw | 0:bbf6cf0eab95 | 90 | // Reduce USB IRQ priority so that audio playback is not interrupted by USB activity. |
bw | 0:bbf6cf0eab95 | 91 | static const int LOW_PRIORITY = 255; // Larger number is lower priority. |
bw | 0:bbf6cf0eab95 | 92 | NVIC_SetPriority(USB_IRQn, LOW_PRIORITY); |
bw | 0:bbf6cf0eab95 | 93 | } |
bw | 0:bbf6cf0eab95 | 94 | |
bw | 0:bbf6cf0eab95 | 95 | /* |
bw | 0:bbf6cf0eab95 | 96 | * Checks buffer level and updates playbackReady flag. |
bw | 0:bbf6cf0eab95 | 97 | * @return Buffer level. |
bw | 0:bbf6cf0eab95 | 98 | */ |
bw | 0:bbf6cf0eab95 | 99 | int32_t Audio_CheckPlaybackBufferLevel(void) |
bw | 0:bbf6cf0eab95 | 100 | { |
bw | 0:bbf6cf0eab95 | 101 | static int32_t PLAYBACK_START_LEVEL = 4 * PACKET_LENGTH; |
bw | 0:bbf6cf0eab95 | 102 | static int32_t PLAYBACK_STOP_LEVEL = 2 * PACKET_LENGTH; |
bw | 0:bbf6cf0eab95 | 103 | |
bw | 0:bbf6cf0eab95 | 104 | int32_t level = Buffer_GetLevel(playbackBuffer); |
bw | 0:bbf6cf0eab95 | 105 | if (level > PLAYBACK_START_LEVEL) { |
bw | 0:bbf6cf0eab95 | 106 | playbackReady = true; |
bw | 0:bbf6cf0eab95 | 107 | } else if (level < PLAYBACK_STOP_LEVEL) { |
bw | 0:bbf6cf0eab95 | 108 | playbackReady = false; |
bw | 0:bbf6cf0eab95 | 109 | } |
bw | 0:bbf6cf0eab95 | 110 | |
bw | 0:bbf6cf0eab95 | 111 | bufferLED = playbackReady; |
bw | 0:bbf6cf0eab95 | 112 | |
bw | 0:bbf6cf0eab95 | 113 | return level; |
bw | 0:bbf6cf0eab95 | 114 | } |
bw | 0:bbf6cf0eab95 | 115 | |
bw | 0:bbf6cf0eab95 | 116 |