Playing audio on an embedded device

audio

Sometimes you have an embedded project that needs to play audio. Maybe you just need to make a beep, in which case a simple piezo speaker and a square wave will work, but other times you’ll need to play actual audio, like voice or music. In that case, you need to use a Digital to Analog Converter (DAC) to generate the stored waveforms. The other question is how to store these waveforms; the easiest way is to use the WAV file format. This tutorial will discuss the basics of WAV files and how to play these with the provided code, using the on-board DACs of the MCF5441X processor found on Netburner’s MOD5441X and NANO54415 modules.

What’s a WAV?

A WAV file (pronounced ‘wāv’), also referred to as a WAVE file, is an audio format which stores the waveform as raw values in an uncompressed form.
While there are many possible encodings and internal formats, there is a standard “canonical” format. This is the format our application will be expecting; it’s also the format that practically every WAV file follows.

Playing a WAV

To play a WAV file using the provided example, you’ll need to create and configure a WavPlayer. This class provides a simple interface with very little to configure. A quick configuration looks like this:

#include "wavPlayer.h"
WavPlayer::WavPlayer testPlayer;
WavPlayer::wavError ret;

ret = testPlayer.SetChannelDAC( 1, 0 ); // Play channel 1 on DAC 0
ret = testPlayer.SetChannelDAC( 0, 1 ); // Play channel 0 on DAC 1
ret = testPlayer.SetTimer( 3 );         // Use DMA timer 3 as the clock source

Now that we’ve got the WavPlayer configured for the hardware, we can load the WAV file to be played. For that, we can either load it from a preloaded buffer (for example, if had been compiled into the application) or from an offboard SD card using the FlashFileSystem:

// To open a preloaded buffer, use this 
testPlayer.OpenBuffer( preload_buffer );

// To open a file on an SD card, use this
ret = testPlayer.OpenFile( WAV_filename, buffer_to_load_into, BUFFER_SIZE );
if ( ret == WavPlayer::ERROR_FILE_SIZE ) {
    iprintf("Wav file too big. Increase BUFFER_SIZE or use smaller file.rn");
    break;
}

Once we’ve opened the file with the player, we just tell it to play:

testPlayer.Play();

If we want to wait until the file finishes playing, we can pass a semaphore and then pend on the semaphore:

testPlayer.Play( &playbackSem );
OSSemPend( &playbackSem, 0 );

Or we could poll the player’s state:

testPlayer.Play();
while (testPlayer.GetState() != WavPlayer::STATE_FINISHED);

Putting that all together a simple case would look like the following:

#include "wavPlayer.h"
WavPlayer::WavPlayer testPlayer;
WavPlayer::wavError ret;

ret = testPlayer.SetChannelDAC( 1, 0 ); // Play channel 1 on DAC 0
ret = testPlayer.SetChannelDAC( 0, 1 ); // Play channel 0 on DAC 1
ret = testPlayer.SetTimer( 3 );         // Use DMA timer 3 as the clock source

testPlayer.OpenBuffer( preload_buffer );// Open a preloaded buffer

testPlayer.Play( &playbackSem );        // Play the loaded WAV file
OSSemPend( &playbackSem, 0 );           // Wait until the file has finished playing

Hardware Considerations

To actually hear the audio being played, you’ll need to connect the DAC outputs to an amplifier and speaker. You’ll also want to connect the analog ground of the device to the ground of the amplifier, therefore you’ll want to either use the same power supply or a battery powered amplifier. If using a battery powered speaker and hearing a 50/60 Hz buzz (mains hum), you may also with to put a high value capacitor in series with the DAC output and the amplifier inputs to filter it out.

Source Code

The project, with full source code, for the application described is one of over a hundred that come with the  NetBurner development kits.

Share this post

Subscribe to our Newsletter

Get monthly updates from our Learn Blog with the latest in IoT and Embedded technology news, trends, tutorial and best practices. Or just opt in for product change notifications.

Leave a Reply
Click to access the login or register cheese