Channels ▼

Al Williams

Dr. Dobb's Bloggers

The Sounds of Raspberry

July 12, 2013

I've been talking about using Linux-based systems for embedded use lately. One very popular system has been the Raspberry Pi. I wanted to do a small project with the Pi, but was disappointed to see that it only has audio out and no audio in capabilities.

On the other hand, it does have USB ports. I rummaged a bit and found an old Labtec USB mic based on an AK5370 A/D converter. As expected, the Pi found it and suddenly had audio input capabilities.

There are many ways to work with audio hardware under Linux, but one of the best is the PortAudio library. One of the great things about this library is that is very portable to different platforms and it is also easy to use. The portability means you could easily develop your code on a desktop Linux machine and then move it. You could even do some development on a Windows machine or a Mac, although porting the rest of the code might not be as easy.

I have longer term plans, but for now I just wanted to get something working, so I dug through some old code I'd used before with PortAudio to refresh my memory. The library is easy to use. You open each input or output device you want to use as a stream. When you open the stream, you provide a callback function. When PortAudio needs more data for an output device, or has a block of data from an input device, it calls your callback function.

You can find the entire program in the online listings. However, here's the callback function:

// Audio data comes in through this callback
static int paCallback(const void *in, void *out, unsigned long framesPerBuffer,
		      const PaStreamCallbackTimeInfo *timeinfo,
		      PaStreamCallbackFlags statusFlags,
		      void *userdata)
{
  unsigned i;
  uint32_t *buf=(uint32_t *)in;
  audiostats *stats=(audiostats *)userdata;
  for (i=0;i<framesPerBuffer;i++)
    {
      // update stats
      if (stats->minin>buf[i]) stats->minin=buf[i];
      if (stats->maxin<buf[i]) stats->maxin=buf[i];
      stats->total+=buf[i];
    }
  stats->count+=framesPerBuffer;
  return 0;
}

In this case, the callback just gathers some statistics that the main program will print out. However, eventually you'll want to do something more interesting (perhaps a fast Fourier transform or a Goertzel on the incoming data). Keep in mind that the callback (at least on some systems) will be time critical, so you don't want to do too much here. I'm planning on just copying the buffer over and letting another part of the code do the processing.

If you dig into the online listing, you'll see the setup is pretty much what you'd expect:

  • Initialize the PortAudio library (Pa_Initialize)
  • Query the library about the default input stream (Pa_GetDefaultInputDevice, Pa_GetDeviceInfo)
  • Open the default input stream (Pa_OpenDefaultStream)
  • Start the stream (Pa_StartStream)
  • Wait (Pa_Sleep; although there were other ways to do this)
  • Stop the stream (Pa_StopStream)
  • Close the stream (Pa_CloseStream)
  • Shut the library down (Pa_Terminate)

You can find the documentation for the calls on the PortAudio website.

This is a great example of how using Linux gives you a lot of leverage. I have no idea how the microphone delivers audio data over USB. I don't have to deal with raw audio data from a device file. The code is even fairly portable to other operating systems. What's not to like?

I'll be looking more at PortAudio and other Linux tools over the next few weeks. Although I'm using the Raspberry Pi, the techniques would apply to any Linux system like a Beagle Bone, or even a small form factor PC running Linux.

Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Comments:



Video