^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
BE ENGINEERING INSIGHTS:
Do You Have 24 Ears?
By Jon Watte -- <hplus@be.com>
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

I don't, but I have at least 11 friends who can play
instruments and sing. With the coming of Maui, we can all
jam together and record the results using BeOS and an
appropriate third-party software package. That's because
we've introduced support for multichannel audio devices and
file formats out-of-the-box. This means some additions to
the Media Kit API that I'll go over in this article.

First out, the media_raw_audio_format struct needed to be
enhanced to convey information about things like how many
bits of an int32 sample are actually valid data, and which
channels are assigned to which logical speaker positions or
matrix channels. Unfortunately, media_raw_audio_format had
no padding to take, so we invented media_multi_audio_format
which is the same thing, plus the extra fields, plus
padding. media_format.u.raw_audio is now a
media_multi_audio_format, as is
media_raw_audio_format::wildcard. Because of the wonders of
C++ inheritance, most of your code will compile unchanged,
but you'd do well to string-replace all occurrences of
"media_raw_audio_format" with "media_multi_audio_format".

The new fields in media_multi_audio_format are:

* channel_mask : contains a bit mask of the logical channel
  assignments present in the format. If there are more
  channels in the format than bits in this bit mask, the
  rest of the channels are undefined. Channel assignments
  include   B_CHANNEL_LEFT, B_CHANNEL_RIGHT,
  B_CHANNEL_CENTER,  B_CHANNEL_SUB, B_CHANNEL_REARLEFT,
  B_CHANNEL_REARRIGHT, and about 10 more that you can
  find in MediaDefs.h or the next version of the BeBook.

* valid_bits : contains a count of how many bits of an
  int32 sample actually contain valid data. The rest of the
  bits may contain out-of-band data, zeros, or noise. If
  this value is 0, assume the entire value is valid.

* matrix_mask : contains a bit mask for which matrix
  encoding format was used, if any, for the data. These
  include B_MATRIX_PROLOGIC_LR and B_MATRIX_AMBISONIC_WXYZ.
  Currently, the Be System Mixer does nothing with this
  information, but I think an Ambisonic "renderer" Node
  would be an excellent and fun application using the Be
  Media Kit.

Unfortunately, struct media_encoded_audio_format contained a
media_raw_audio_format with no extra padding, so the extra
fields have been split out into a "multi_info" field of type
media_multi_audio_info. media_multi_audio_format actually
multiplies inherits from media_raw_audio_format and
media_multi_audio_info for this reason. Something to be
aware of when you're coding away.

There were some other places in the Media Kit which used a
naked media_raw_audio_format without padding; most notably
the constructor for BSoundPlayer. BSoundPlayer has thus
gotten a new constructor which takes not only a
media_multi_audio_format argument, but also a media_node and
media_input, so that you can point it at the Node/input of
your choice. This is a good way to send data directly at one
of what may be many installed sound devices, without
involving the Be System Mixer (which does stereo-only output
in Maui).

Judging from questions I've received, I feel it is worth
reiterating: BSoundPlayer is NOT being retired, but the
helper class BSound IS being retired. Any bugs filed against
BSound will go unfixed. The header may disappear at any
moment. There may be secret code in the media server that
deletes the header file Sound.h from your hard disk at some
random date in the future. If you can't just use a
BSoundPlayer directly (either by overriding PlayBuffer() or
by using the hooks) then I suggest you look into BGameSound
and its most-derived classes BSimpleGameSound,
BFileGameSound and BPushGameSound. Indeed, while most of the
high-end Media Kit is gone in our separate "Stinger" product
for Internet appliances, BSoundPlayer and BGameSound are
still part of that product. BSound is not.

As far as file formats go, we've added support for the new
WAV_FORMAT_EXTENSIBLE flavor of WAV files that was recently
defined. Our WAV file writer and extractor will
transparently read/write this flavor when dealing with
formats that are not unambiguously describable using the old
style of WAV header. Thus, if you use our WAV writer to
write a 16-bit stereo file, that file will play fine on a
friend's system running some other operating system product,
whereas a 4-channel or 24-bit file may not, as his OS may
not yet be prepared to deal with those files.

What about recording? This article comes with sample
code for two utilities, one that plays a sound file back at
the named sound device of your choice (from the command
line) and one which records a multichannel file from the
device of your choice. I've tried these with the Layla from
Echo, a 10-in 12-out 20-bit device, and it works there; your
system may vary. Feel free to snarf the parts of the sample
code that you need into your own application, as long as you
don't use that code for a non-BeOS product.

Sample Code:
<ftp://ftp.be.com/pub/samples/media_kit/multiaudio.zip>

While debugging the new format negotiation in BSoundPlayer,
we found some more ill-behaved applications which pass bad
format descriptions to the BSoundPlayer constructor, and/or
don't actually check which format is being used but assume
some format which happened to be chosen on their system when
they wrote the program. We've inserted code to stay
compatible with these programs, but I suggest that you make
sure to look at the format used by a BSoundPlayer and
conform to that; don't just blithely assume some specific
format, even if that's what you ask of it or what it has
used in the past.

One humorous e-mail exchange started with, "I'm fixing bugs
in app-name-deleted and it can't play audio anymore; it
comes out as noise." It seems the developer had assumed
floating-point samples, but changed the code to actually
check and use whatever the BSoundPlayer wanted (in this
case, int16). Our workaround for the old version of the
program assumed he was still giving us floats, and thus
noise came out. The solution for him was to change his
application's MIME signature, which is the information we
use in BSoundPlayer to activate possible application bug
workarounds.

That said, you cannot assume that we'll cushion bugs in your
code as we update the system. Some bugs are deemed too hard
to work around or too egregious in nature to support, and a
user upgrading the OS will see those applications stop
working. Sometimes, we don't even have a copy of the
application to test with, so we can't find the bug in the
first place. Writing code that follows the rules is always
your best defense. Check error codes, check modified
non-const arguments, and don't assume any parameters (buffer
size, sample format, etc.) will stay fixed just because
they're on your machine.

One simple test is to run your program with "Real-Time
Audio" enabled and disabled (restart media services in
between) as enabling this option will make audio buffers
smaller (how much depends on your sound card and CPU) and
disabling it will make them bigger.

Are you one of the developers who reported sound glitch bugs
with the MediaPlayer application? You're not alone. It turns
out that the MediaPlayer was violating the "one clock" rule,
and dropping/doubling buffers of audio when the audio stream
played at a slightly different speed than system_time().
B_DONT_DO_THAT. It also had a knack for tickling a bug in
the mixer which resulted in faint "sparkles" in the sound.
Both problems have been fixed as I write this article.

Go out, seize the day, and write awesome media applications
for BeOS. You'll find that BeOS gets in your way much less
than other platforms (at least the ones I've tried). It's a
very satisfying development experience. Good luck!
