BSoundPlayer¶
The BSoundPlayer
class plays sound by directly filling audio
buffers with data provided by a hook function you specify. A single
BSoundPlayer
can play multiple sounds at a time.
BSoundPlayer
takes care of all the nitty-gritty details of
instantiating the necessary sound player node and managing the time source.
All you have to do is start up a BSoundPlayer
and feed it
sounds to play.
You need to implement a hook function that will be called for each audio
buffer passed through the BSoundPlayer
’s playback node.
Using BSoundPlayer¶
Once you’ve instantiated a BSoundPlayer
object, you need to
start it up before you can actually play sounds with it. This instantiates
the sound player node, attaches it to an appropriate time source, and makes
sure the time source is running. This is done by calling the
Start()
function.
When you’re done using the BSoundPlayer
, you can delete it if
you don’t plan to use it again, or, if you want to keep it around for
reuse, you can just Stop()
it. This deletes the
sound node and cleans up the sounds.
You can find out the current time of the time source to which sounds are
being synchronized by calling the CurrentTime()
function.
By default, the audio format used by a BSoundPlayer
is
BSoundPlayer::B_AUDIO_FLOAT
, which is to say
that the audio is in floating-point format, where each sample ranges from
-1.0 to 1.0. The Media Kit uses floating-point audio internally, so using
floating-point audio whenever you can will improve your application’s
performance by cutting down on format conversions. However, if you want to
use another format, you may do so by specifying a
media_raw_audio_format
when you instantiate the
BSoundPlayer
object.
Sound streams may only contain 1 or 2 channels (either mono or stereo, in other words). There’s no support yet for multichannel sound.
Note
BSoundPlayer
can only play sounds in the native byte order.
The audio mixer performs best if you don’t specify a particular buffer size.
Playing Sound¶
When you specify a play buffer handler function, either when instantiating
the BSoundPlayer
object or by calling
SetCallbacks()
or
SetBufferPlayer()
, that function will be called
once for each buffer that passes through the BSoundPlayer
’s
sound playing node. Your play buffer handler can then fill the buffer with
whatever data you wish.
The following code sets up a BSoundPlayer
that will play a
triangle wave.
typedef struct cookie_record {
float value;
float direction;
} cookie_record;
...
cookie_record cookie;
cookie.value = 0.0;
cookie.direction = 1.0;
BSoundPlayer player("wave_player", BufferProc, NULL, &cookie);
player.Start();
player.SetHasData(true);
...
player.Stop();
This code establishes a record, cookie, that contains information the play
buffer function will need to track, and creates a BSoundPlayer
named “wave_player” that will use a function called BufferProc() to play
sound, and uses the cookie we’ve created.
Then the player is started, and SetHasData()
is
called to let the sound player node know that there’s data to be played.
This will cause the play buffer function to start being called.
Once playback is over, the Stop()
function is
called to stop playback.
The BufferProc() function looks like this:
void BufferProc(void *theCookie, void *buffer, size_t size,
const media_raw_audio_format &format) {
size_t i, j;
float *buf = (float *) buffer;
size_t float_size = size/4;
uint32 channel_count = format.channel_count;
cookie_record *cookie = (cookie_record *) theCookie;
// We're going to be cheap and only work for floating-point audio
if (format.format != media_raw_audio_format::B_AUDIO_FLOAT) {
return;
}
// Now fill the buffer with sound!
for (i=0; i<float_size; i+=channel_count) {
for (j=0; j<channel_count; j++) {
buf[i+j] = cookie->value;
}
if ((cookie->direction == 1.0) && (cookie->value >= 1.0)) {
cookie->direction = -1.0;
}
else if ((cookie->direction == -1.0) && (cookie->value <= -1.0)) {
cookie->direction = 1.0;
}
cookie->value += cookie->direction*(1.0/64.0);
}
}
This example play buffer function generates a triangle wave, ramping the wave up and down from 1.0 to -1.0 and back, over and over again, 1/64th at a time. The next value to store in the buffer and the direction in which the value is changing are kept in the cookie’s fields.
Note
The buffers your play buffer function receives are empty. Do with them as you please (or do nothing at all).