[LAD] Libraries for simple audio programming, libao, other options?

Stephen Cameron smcameron at yahoo.com
Thu May 3 01:51:30 UTC 2007


--- nick thomas <jesuswaffle at gmail.com> wrote:

> On 5/2/07, Stephen Cameron <smcameron at yahoo.com> wrote:
> > So, I found libao ( http://xiph.org/ao/doc/ ) which looks
> > nice and simple, and the sample program I tried
> > ( http://xiph.org/ao/doc/ao_example.c ) worked right off
> > the bat,
> >
> If you want real-time, then you'd better use a callback-based API.
> PortAudio might be a good choice for your application:
> 
> http://www.portaudio.com/

Ok, that looks cool.

> 
> > and the idea of synthesizing my own sounds by
> > constructing waveforms using sine waves is appealing for
> > a retro styled app like mine (though I have no experience
> > doing that and only a vague memory of trigonometry), but
> > I wonder about how to mix sound (add the waveforms, I guess)
> > and construct them on the fly (or trigger pre-computed
> > chunks of audio).
> >
> Since you're just doing this for fun, you might opt to synthesize your
> own sounds in real-time, but it would probably be more "sensible" to
> synthesize them ahead of time. In this case, I suppose it really comes
> down to your personal preference.

Yeah, I planned on doing it ahead of time, where possible.
The game already eats about 35% of a 2.1GHz Athlon, heh.

> 
> To answer your question about mixing: yes, you just add the waveforms.
> You have to be sure to avoid clipping, so it can be a bit more
> complicated than that, but that's the gist of it. An explanation of
> how analog-emulation synthesis works is out of the scope of this
> email, but I'm sure there's some literature you can find on the
> subject. For my own part, I just trawled Wikipedia and gradually
> assembled a picture of how it all works, but that's a rather
> time-consuming option. Maybe someone else can recommend some
> literature. :)
> 
> > So, I imagine that for a game, in order to satisfy the
> > real-time-ish requirements, I'd instead construct maybe
> > 1/10th or 1/20th second chunks, which would be queued up
> > in my program for playback, and whenever some event happens
> > which demands some sound be produced _right now_ (like the
> > user presses the "fire" button, and so needs some bleeping
> > laser gun sounds to be produced) I would then start adding
> > (arithmetic addition) laser-gun-waveform-data into whatever
> > chunks were already in the queue, and so out would come
> > the sound...
> >
> I think that if you look at the way PortAudio works, you'll see that
> this sort of "queueing" logic is taken care of for you by the library,
> so you don't need to worry about it.

Hmm, no, I don't see that.

I see it has a callback where I have to feed it audio data
X samples at a time (where I get to define X), but I don't
see anything to help with mixing various audio sources.

I guess the callback to do that would look something like
this: (based on what I see here: 
http://www.portaudio.com/trac/wiki/TutorialDir/WritingACallback )

/* I imagine sound_source_list to be a pointer to
   array of various sound sources I want to mix,
   passed to my callback in a cookie */

sound_source_list = (my_whatever *) callback_cookie;

/* "out" is ptr via which to feed portaudio interleaved
   L and R audio data for playback */

out[0] = 0;
out[1] = 0;
new_num_sound_sources = num_sound_sources;
for (i=0;i<frames_per_buffer) {
   for (j=0;j<num_sound_sources;j++) {
      int pos = sound_source[j]->pos;
      if (sound_source[j] == NULL)
         continue;
      out[0] += sound_source[j]->data[pos].left;     /* left */
      out[1] += sound_source[j]->data[pos].right;    /* right */
      sound_source[j]->pos++;
      if sound_source[j]->pos = sound_source[j].maxpos; {
         sound_source[j] = NULL;
         if (j == num_sound_sources)
            new_num_sound_sources--;
      }
   }
   out += 2;
   num_sound_sources = new_num_sound_sources;
}


Then, when the user presses some button that needs to make
noise, a new sound source just gets added to the sound_source 
array, maybe like this:

/* Set up structure to hold index and pointer to laser sound data */
new_sound->data = laser_sound_data;
new_sound->pos = 0;
new_sound->maxpos = laser_sound_data_num_samples;

/* add it to sound_source list */
found = 0;
for (i=0;i<num_sound_sources;i++) {
   if (sound_source[i] == NULL) {
      sound_source[i] = new_sound;
      found = i;
   } 
}
if (!found && num_sound_sources < MAX_SOUND_SOURCES)
   sound_source[num_sound_sources++] = new_sound;
 
Does all that seem more or less about right?

Eh, I see a race in setting num_sound_sources. Hmmm.
Am I even close?

(Hope that wasn't so sketchy that it failed to be comprehesible.)

> 
> > I might also want to playback some ogg encoded files for maybe
> > prerecorded sound effects and music to be mixed
> > in with the synthesized sound effects.  libao won't do that by itself, but
> > I think there are some other libs on xiph.org that do that, but
> > I'm not sure how well they'd accomodate mixing random bits of
> > sound in with them.
> >
> If you're going for the "retro" effect, you might actually consider
> synthesizing the music in real-time from a MIDI-style score. :) If
> you'd rather do it pre-recorded, however, the approach that you'll
> take would be to find a decoder library, have it decode your music
> into a memory buffer (probably streaming it somehow), and then mix
> that into your own output buffer along with the sound effects.
> 
> Hope that helps!

Yes, very much.  Thanks.

-- steve


__________________________________________________
Do You Yahoo!?
Tired of spam?  Yahoo! Mail has the best spam protection around 
http://mail.yahoo.com 



More information about the Linux-audio-dev mailing list