^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
BE ENGINEERING INSIGHTS: Farewell BSound and BSoundFile
(All Hail BGameSound and BMediaFile)
By Jon Watte -- <hplus@be.com>
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Among other important improvements in BeOS Release 4.5 is the
BMediaFile, which gives access to various kinds of media file
formats, and BGameSound (with subclasses), which allows simple
but efficient playback of sound effects and background sounds.
The BSoundFile class has been with us for a long time, and was
starting to show its age. Many older programs that still run
on PowerPC depend on idiosyncrasies of this class, so rather
than make it use the same mechanism as BMediaFile to access
data, which would break the previous semantic of the file (we
tried this), we decided to stay compatible, and suggest that
all newer applications use BMediaFile for all their media
reading/writing needs.

However, if you have an application which uses BSoundFile,
you may need some features that BMediaFile and BMediaTrack
don't provide. Most notably, BMediaTrack reads audio frames
in blocks of a predetermined size, whereas BSoundFile lets
you read any number of frames at any time. BMediaTrack also
may not be precise in seeking to a specified frame location
(because of compression algorithm constraints). I present here
a simple wrapper for BMediaTrack, known as ATrackReader. It
lets you treat a generic media file, accessed internally
through a BMediaFile object, much like a BSoundFile. It's also
a good introduction to using BMediaFile/BMediaTrack to read
data in general.

If you use a BSoundPlayer with a number of BSounds to play
sound effects, you'll probably want to change over to the
new BGameSound system the next time you overhaul your code.
BGameSound is designed to allow for hardware acceleration in
a future version of BeOS (when this will happen is TBD), and
it's also designed to be really simple to use! If you used
BSound with a chunk of data in memory as your data, you now
create a BSimpleGameSound object. If you use BSound with a
large-ish sound file on disk for background music or other
something similar, you now create a BFileGameSound.

BSimpleGameSound can be created either with a pointer to
data and a description of the data pointed to (it should be
uncompressed PCM sample data), or with an entry_ref, in
which case it will load the sound file from disk (uncompressing,
if necessary) into memory so it's always readily available to
be played. The BGameSound system makes a copy of the data you
provide it, so you can free that memory as soon as the object
is created. If you need more than one copy of the same sound
running, you can call Clone() to get a second BSimpleGameSound
which references the same data as the first. When you make a
Clone(), that clone references the same internal copy with a
reference count, so no extra memory is wasted. The Be Book
accidentally documents an earlier behaviour where data was
copied inside Clone().

To play the sound, just call StartPlaying() on it.

BFileGameSound is created with an entry_ref as argument,
and can optionally be set to looping or non-looping mode.
When you call StartPlaying(), it will start playing, and
keep going until you stop it with StopPlaying(), or, if
it's not looping, until it reaches the end of the file.

It's important to note that the first BGameSound instance
you create determines the format of the connection
between BGameSound and the Audio Mixer. In our sample
program, we create a dummy 44 kHz stereo sound and
immediately delete it to establish the connection in a
known format, since otherwise the first file the user drags
into the program will determine the format that all files
will be played back as.

All BGameSound instances that are playing are mixed into
one connection to the Audio Mixer; this connection is
currently named after your application with no way of
changing it. In some future version of the API, we may let
you create more than one connection, and name these
connections. That's what the BGameSoundDevice argument is
for in the constructors for these classes; however, we
currently only support the default (NULL) device, so you
can leave it to the default value without worrying about
it.

If you want to set the pan position or gain (volume) of a
BGameSound, you do that by calling SetPan() and SetGain().
The "duration" parameter (which is optional) allows you to
specify that the change should take place over some amount
of time, if the sound is currently playing. Thus, if a file
was playing, and you wanted to fade it out over the course of
two seconds for a soft ending, you could call
SetGain(0.0, 2000000LL).

You can also change the effective sampling rate of a
BGameSound. This changes both the pitch and duration of the
sound. The BGameSound system contains a built-in software
resampler which uses a fast, reasonable quality 0-th order
resampler. There is no additional overhead of playing a sound
at some other sampling frequency than the one you initially
specify. However, there is no SetSamplingRate() function;
instead, you have to use the low-level SetAttributes() function
to change the B_GS_SAMPLING_RATE attribute. Again, you can
specify a duration during which the change ramps in. Thus, if
you're playing a sound at a 22000 Hz sampling rate, and ramp
it to 12000 Hz with a duration of 500000, it will take
approximately half a second for the full change to take
effect. The resulting sound effect is similar to a tape
deck or record slowing down. Specific details are found in
the gameplay.cpp file in the source code that goes with
this article:

<ftp://ftp.be.com/pub/samples/game_kit/gameplay.zip>.

To build the sample code, just "cd" to the directory where
you unpacked it in Terminal, and type "make". Run it with
obj.x86/gameplay (or obj.ppc/gameplay) from the command
line, or double-click it. You can drag a sound file into
the lower half of the window, and the program will load it
as a BSimpleGameSound or a BFileGameSound. You can then
start playing with the "Start" button, and play with
volume/sampling rate with the sliders in the window. Note
that the pop-up menu for sound kind (SimpleGameSound or
FileGameSound) only decides what kind of object to create
the next time you drag a file to the window; it does not
change the type of the current sound.
