Feb 99 Getting Started
Volume Number: 15
Issue Number: 2
Column Tag: Getting Started
Sound Basics
by Dan Parks Sydow
How a Mac program plays sounds stored in
resources and files
In October and December of this past year, Getting Started covered animation. The
movement of objects in a window is one very important aspect of bringing multimedia
effects into your Mac program. Another key element to making multimedia a reality is
the playing of sounds. This month we'll take a look at how to easily add sound-playing
capabilities to any of your own Macintosh applications. To give you a choice of
techniques, we'll cover the playing of sounds that are stored in an application's
resource fork, and the playing of sounds that are kept in separate sound files.
The Sound Manager
The standard audio hardware on Macintosh computers includes one or more internal
speakers. A Mac program includes the code that specifies what sound to play, and the
hardware generates the sound itself. The Sound Manager holds the code that translates
your wishes to information the hardware can use. The Sound Manager 3.0 software is
built into the system of every PowerPC-based Mac, came as an extension included with
many pre-Mac OS 8 versions of the Macintosh operating system, and is available as a
system extension for older Macs or Macs running an older version of the system
software.
The Mac has always been able to generate sound, but it hasn't always had the Sound
Manager to serve as the programmer's link to the Mac's speakers. Prior to System
6.0, the sound routines were a part of the Toolbox but weren't specifically organized
into what we now know as the Sound Manager. Version 2.0, or the enhanced Sound
Manager, was introduced along with System 6.0.7. Version 3.0 became a part of
System 7.5. A Macintosh owner who hasn't upgraded to System 7.5 or beyond can gain
the capabilities of Sound Manager 3.0 by adding the Sound Manager system software
extension to his System Folder.
Sound Manager 3.0 improves upon how the Mac works with sound, and adds new
sound-playing capabilities to the Macintosh - so your sound-playing program will
want to make use of it. Most Mac owners now have Sound Manager 3.0 as a part of their
system software - but a few users may not. You'll want to save the user of an older Mac
(or older system software) the aggravation of crashing their computer by checking for
the presence of version 3.0 (or later) of the Sound Manager before your application
calls Sound Manager Toolbox routines.
The check for a particular version of the Sound Manager involves the use of a variable
of type NumVersion. Here's the definition of the NumVersion data type:
struct NumVersion
UInt8 majorRev;
UInt8 minorAndBugRev;
UInt8 stage;
UInt8 nonRelRev;
Apple defines the Byte type to be an unsigned char, so it's range is 0 to 255. Simply as
a convenience, Apple defines the UInt8 type to be the same as the Byte type. By the type
name it should be readily apparent that a UInt8 variable is an unsigned integer
occupying eight bits, or one byte. When a Toolbox routine returns a NumVersion, you
can check the majorRev field to see if the version is appropriate to meet your
program's requirements. In the case of the check for Sound Manager 3.0, call the
Toolbox routine SndSoundManagerVersion() and then see if the majorRev field of the
returned NumVersion has a value of at least 3:
NumVersion theSndMgrVersion;
theSndMgrVersion = SndSoundManagerVersion();
if ( theSndMgrVersion.majorRev < 3 )
// user has an outdated version of the Sound Manager
Apple has created the snd resource type to hold the data for a sound. It's very important
to note that all resource types must be four characters, and that the sound resource
type is somewhat unusual in that it ends with a space. If your code includes a reference
to the sound resource type and you omit the trailing space character, the code won't
compile. A sound can exist as a sound resource or as a sound file (we look at sound files
a bit later). Storing a sound as a resource in your application's resource fork is a good
way to ensure that the sound will always be available for your application's use.
The Toolbox function SndPlay() is used to play a sound resource. SndPlay() expects a
sound resource to already be loaded into memory, so you'll want to call GetResource()
before calling SndPlay(). Pass GetResource() the type of resource you're interested in
(here, a snd resource) and the ID of the resource, and GetResource() loads the
specified resource and returns a handle to the memory location of the loaded data.
Assuming your program has a snd resource with an ID of 12000, here's how the call to
GetResource() looks:
Handle theHandle;
theHandle = GetResource( 'snd ', 12000 );
Once you have a handle to a sound resource, call SndPlay() to play the sound. Here's a
typical call to this routine:
SndPlay( nil, (SndListHandle)theHandle, false );
The first of the three SndPlay() parameters is a pointer to a sound channel. The Sound
Manager always uses a sound channel to store information about how a sound is to be
played. If you pass a value of nil as this first parameter, the Sound Manager takes care
of the allocation of a sound channel. The second parameter is a handle to the sound
resource to play. GetResource() returned a generic handle, while SndPlay() requires
a specific type of handle - a SndListHandle. Typecasting the generic handle is all that's
necessary. The last parameter to SndPlay() is a Boolean value that indicates whether
the sound should be played asynchronously (true) or synchronously (false).
With asynchronous sound-playing, other actions can take place at the same time as the
playing of the sound. With synchronous sound playing, no other actions take place until
the sound has finished playing. The above call to SndPlay() plays the sound
synchronously. To play a sound asynchronously, you need to allocate your own sound
channel and you need to know about a special type of routine called a callback
procedure. Both these topics are beyond the scope of this article - but watch for them
next month.
If you'd rather your program play a sound from a separate file, the Toolbox makes that
possible. Sound resources are handy because the sounds are kept within the application
that plays them, but there are situations when you'll want to instead store sounds in
separate files. A sound used by more than one application would be a good candidate to
be stored in a file. A large sound is also a good nominee to be stored in a file rather than