world leader in high performance signal processing
Trace: » recorder

ADSP-BF548 EZ-KIT Quick Start: Peripheral Demos: recorder

www.analog.com_static_imported-files_images_product_descriptions_680755565image1a.jpg

What is recorder

An application that uses the alsa api to record audio coming in from the microphone port. It then writes this data out to a wav file as cd quality. This program will do so until it is terminated.

Note that the kernel option 'Device Drivers > Sound card Support > Alsa for SoC audio support > SoC AC97 Audio for the ADI BF5xx chip' must be enabled for this to work. The suboptions of that should have 'BOARD has COLD Reset GPIO' enabled with port 19 set for gpio cold reset and also have suboption 'SoC AD1980/1 Audio support for BF5xx (Obsolete)' enabled.

Download recorder

The demo comes with the customised Ubuntu ISO and can be found in the folder /home/Blackfin/demos. Alternatively it is already installed on the demo uClinux image (demo-uclinux.img) that you can get on ADSP-BF548 EZ-KIT Quick Start: Booting uClinux.

If you just want to download the demos on their own and get their source code you can download the compressed archive (demos-R1.tar.gz) here bf548-quick-start .

How to run the recorder program

  • Change directory to /demos/audio

    root:/> cd /demos/audio
  • Make sure headphones or speakers are plugged into the correct port

  • Make sure microphone is plugged into the correct port

  • Run recorder

    root:/> ./recorder
    Playing. Interrupt to exit
  • Make some noise to record
  • Stop recording & Exit (Ctrl + C)
  • Playback recording

    root:/> aplay -f cd ./recording.wav
  • Listen to recording from your headphones / speakers

How the recorder demo works

Required header files

#include <stdio.h>
#include <stdlib.h>
#include <alsa/asoundlib.h>

These alsa/asoundlib header is to access the alsa api. This is required for developing an alsa application.

Main function

int main() 
{
  atexit(cleanup);

Just the standard main function like any other C program. You can also see that a clean up function is binded to exiting the program so it should clean up after itself.

void cleanup(void)
{
  fclose(fp);
  snd_pcm_drain(recording_handle);
  snd_pcm_close(recording_handle);
  free(buffer);
}

Opening output file

// Open file to write to
fp = fopen("./recording.wav", "w");

This section is just the standard IO to open a file for writing out into.

Opening capture device

// Open capture device
rc = snd_pcm_open(&recording_handle, "default", SND_PCM_STREAM_CAPTURE, 0);
if (rc < 0) 
{
  fprintf(stderr, "unable to device: %s\n", snd_strerror(rc));
  exit(1);
}

This section opens up the audio card for capturing, it will get the handle to operate with.

Setting capture parameters

// Allocate hardware parameters object
snd_pcm_hw_params_alloca(&hwparams);

// Set default values
snd_pcm_hw_params_any(recording_handle, hwparams);

// Set for CD quality (Interleaved mode, S16 LE, 44100Hz, 2 channels, period=32frames)
val = 44100;
frames = 32;
channels = 2;
snd_pcm_hw_params_set_access(recording_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
snd_pcm_hw_params_set_format(recording_handle, hwparams, SND_PCM_FORMAT_S16_LE);
snd_pcm_hw_params_set_channels(recording_handle, hwparams, channels);
snd_pcm_hw_params_set_rate_near(recording_handle, hwparams, &val, &dir);
snd_pcm_hw_params_set_period_size_near(recording_handle, hwparams, &frames, &dir);

// Write parameters out
rc = snd_pcm_hw_params(recording_handle, hwparams);
if (rc < 0) 
{
  fprintf(stderr, "unable to set parameters: %s\n", snd_strerror(rc));
  exit(1);
}

This section configures the settings and parameters for the capture device. As you can see it first gets the parameters object, sets it to default values for anything that is unnecessary to configure, and then applies the programmed parameters. The settings above are for CD stereo quality.

When configuration is done, it must be written back to the capture device to set it. This is done by snd_pcm_hw_params.

Setting aside buffer space

// Use a buffer large enough to hold one period
snd_pcm_hw_params_get_period_size(hwparams, &frames, &dir);
size = frames * 4; /* 2 bytes/sample * 2 channels */
buffer = (char *) malloc(size);

This is just a small section allocating a buffer so that as data is read in from the capture device, it can be temporarily held.

Main Loop

while (1) 
{
  rc = snd_pcm_readi(recording_handle, buffer, frames);
  if (rc == -EPIPE) 
  {
    fprintf(stderr, "overrun occurred\n");
    snd_pcm_prepare(recording_handle);
  } 
  else if (rc < 0) 
  {
    fprintf(stderr, "error from read: %s\n", snd_strerror(rc));
  } 
  else if (rc != (int)frames) 
  {
    fprintf(stderr, "short read, read %d frames\n", rc);
  }

  // Write buffer out to file
  rc = fwrite(buffer, size, 1, fp);
}

This loop just empties the capture device buffer using snd_pcm_readi into the buffer. If there are any errors, it deals with it. It then writes the buffer contents out to the output file and loops back to get more content. If you're building an audio handling program, for example digital signal processing of this audio, you would be able to at this point build in your processing functions.

Compiling recorder

First make sure that your kernel has the library Alsa enabled.

Secondly, make sure your vendor staging install is complete (ADSP-BF548 EZ-KIT Quick Start: Compiling uClinux).

root:/> make vendor_staging_install

Run the following compile command in the same directory as the source code:

root:/> bfin-linux-uclibc-gcc -O2 -lasound recorder.c -o recorder

What this compile command is doing is it is calling the uclibc cross compiler that is set up from the Blackfin toolchains to compile our application.

The parameters prefixed with -l are to indicate we need to load that library, so in this case the alsa library is loaded. Without this, our program would not have access to the required audio functions.

The final parameters match up to standard gcc compiling, “recorder.c” is the source file while ”-o recorder” indicates the output file is “recorder”.

A standard make file is accompanies this demo and you can run that by simply calling

root:/> make recorder

Further Reading

Alsa Utils is expected to be installed for the aplay command to work. You can actually record and play audio using aplay and arecord from alsa utils if you want to have a simpler time. To enable alsa utils when compiling uClinux enable Blackfin app programs > ALSA utils.

You can read up on the alsa library at its official documentation http://www.alsa-project.org

If you cannot find your audio device on the BF548 with a fresh copy of the uClinux2011R1-RC3 release that is because in that release the audio drivers had a slight error. You can fix this by downloading the latest kernel updates from the Blackfin uClinux git repository or getting the upgrade.patch file from the custom Ubuntu ISO in the “Blackfin/blackfin-linux-dist/linux-2.6.x” folder and applying it to your distribution to run the updates automatically (patch -p1 < upgrade.patch).

To check that the alsa audio driver is running, check the dev directory for /dev/dsp. If it exists, the driver should be ready to go. If not, you'll need to determine whether the audio drivers are enabled or not.

root:/> ls /dev/dsp