TweetFollow Us on Twitter

Feb 99 Getting Started

Volume Number: 15 (1999)
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

Sound Resources

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.

Sound Files

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 a resource. This is because Apple recommends that a sound resource be kept to less than half a megabyte in size, while no such limit is imposed on a sound file.

Sounds can be stored in several types of files, but on the Mac you'll work primarily with sound files of the formats AIFF (Audio Interchange File Format) and AIFF-C (Audio Interchange File Format Extension for Compression). The Toolbox makes playing AIFF and AIFF-C sound files easy, but before the sound within a file can be played your application needs to find the file on disk and open it. An example of gathering file information for a sound file and then opening that file's data fork (because the sound data in an AIFF or AIFF-C file is held in that fork) is shown here:

FSSpec      theFSSpec;
OSErr      theErr;
short      fileRefNum;
   
FSMakeFSSpec( 0, 0, "\pMySoundFile", &theFSSpec );
FSpOpenDF( &theFSSpec, fsRdPerm, &fileRefNum );

A file system specification, represented by a variable of the data structure type FSSpec, holds information about the disk location, or path, of a single file. Given a file name and a pointer to an FSSpec variable, the File Manager routine FSMakeFSSpec() fills in the fields that make up the FSSpec. The first two parameters to FSMakeFSSpec() specify the volume (or disk) the file resides on and the directory (folder) the file is in. Passing a value of 0 for each of these parameters tells FSMakeFSSpec() that the named file is in the same directory as the application.

The File Manager routine FSpOpenDF() opens a file's data fork. As shown above, FSpOpenDF() requires three parameters. The first is a pointer to a previously filled-in FSSpec. The second parameter is a permission level. Using the Apple-defined constant fsRdPerm here tells the File Manager to open the file with read permission only: the file data can be read, but the application that opens the file cannot write to (alter) it. The last parameter is a pointer to a variable that is to serve as a file reference number. After opening the specified file, the File Manager creates a reference number for the file and places that value in this last parameter.

To play an opened sound file, use the Toolbox function SndStartFilePlay(). Here's an example of the use of this function:

SndStartFilePlay( nil, fileRefNum, 0, 40960, nil, nil, 
                         nil, false );

The eight parameters make the use of SndStartFilePlay() seem difficult, but in fact it's easy to use. That's because most of the parameters can be set to nil. Let's take a quick look at each parameter:

  • The first parameter to SndStartFilePlay() is a pointer to a sound channel. As with SndPlay(), pass a nil pointer to let the Sound Manager allocate the sound channel.
  • The second parameter is a reference number to an already open AIFF or AIFF-C File. This is the reference number returned by the prior call to FSpOpenDF().
  • The third parameter specifies whether SndStartFilePlay() will be playing a sound file or a sound resource. SndStartFilePlay() can be used to play sound resources, though Apple recommends you use SndPlay() instead. A value of 0 specifies that a sound file is to be used.
  • The fourth parameter designates the size of an input buffer (a block of free bytes of memory) that the Sound Manager can use in the playing of the sound file. SndStartFilePlay() works by reading in some of the sound data from a sound file, playing the sound defined by that data, and then reading in additional sound file data. For successful sound play Apple recommends a buffer size of at least 20,480 (20 K) bytes. The above snippet doubles that minimum recommended value to 40,960 (40 K) bytes.
  • The fifth parameter allocates the input buffer (the fourth parameter only established this buffer's size). Pass a nil pointer here to let the Sound Manager handle the buffer allocation.
  • The sixth parameter specifies whether SndStartFilePlay() should play a part, or all, of a sound file's sound data. Pass a nil pointer here to play the entire sound.
  • The seventh parameter is a pointer to a completion routine - a function used for asynchronous sound playing (performing other actions while a sound plays). For synchronous play (playing a sound without other actions, as described in this article), pass a nil pointer.
  • The eighth parameter indicates whether the sound is to be played asynchronously (true) or synchronously (false).

The SndStartFilePlay() function will be supported in the upcoming Carbon API, but Apple will be encouraging developers to start relying on QuickTime for the handling of a variety of multimedia files. Look to future issues of MacTech Magazine for QuickTime coverage. See last month's Getting Started column for an introduction to Carbon.

Obtaining Sounds

If your program is to play sounds, you'll of course need to obtain those sounds from somewhere. Sounds can be obtained from a number of sources. If you subscribe to an online service such as America Online or CompuServe, check their own software libraries for free sound files. If you need a greater variety of sounds, invest a small amount (about 30 bucks will do it) for a commercial product - a CD-ROM that holds hundreds, or more likely, thousands, of sounds in a number of formats. If the sound you seek is unique, consider creating it yourself using your Mac's built-in microphone or by plugging a sound digitizer into the back of your Macintosh.

Mac users often find sounds distributed as Finder sound files - also referred to as System 7 sound files. You'll recognize such a sound file by its icon - it looks like a document with a speaker on it. A Finder sound file is so named because it can be played from the Finder - just double-click on its icon on the desktop to hear the sound. A Finder sound file stores a sound as a snd resource, so if your program plays sound resources, you can make use of a Finder sound file's sound by opening the file from a resource editor, copying the file's snd resource, and pasting that resource into your project's resource file.

Often the same sound will be offered in a few formats, such as a Finder sound file and an AIFF file. Sometimes a sound will be distributed in just one format. If the sound of interest isn't in the format you want, use a sound-converting program to change its format. The freeware program SoundApp is an example of such a utility - you can find it on the Web at just about any archive of Mac software (such as MacShare.com at http://www.macshare.com/utility.html). With a sound-converting program you can change an AIFF to a Finder sound file and then use a resource editor to copy that converted file's snd resource to your project's resource file. Alternatively, you can convert a Finder sound file to an AIFF file and then store that file with your application. In either case, for your program to play the sound you'll of course need to include the appropriate sound-playing code in your project's source code file.

SoundPlayer

This month's program is called SoundPlayer. Running SoundPlayer results in the appearance of the menu bar shown in Figure 1. The menu of significance is the Sound menu. Choosing either of the items in this menu results in the playing of the corresponding sound. As you can surmise from the menu item names, the cat meow sound is stored in the SoundPlayer's resource fork, while the dog bark sound exists as a separate sound file that needs to be present in the same folder as the SoundPlayer application. After playing the sounds as often as desired, choose Quit from the File menu to end the program.


Figure 1. The SoundPlayer menu.

Creating the SoundPlayer Resources

To begin, open your CodeWarrior development folder and create a folder named SoundPlayer. Start up ResEdit and create a new resource file named SoundPlayer.rsrc inside the SoundPlayer folder. Figure 2 shows the five types of resources used by SoundPlayer. With the exception of the snd resource, the resource types should look familiar to you.


Figure 2. The SoundPlayer resources.

SoundPlayer uses the same ALRT resource and DITL resource that have been used in the last several Getting Started examples. These two resources are used to support the error-handling alert displayed by the program's DoError() routine. Figure 3 shows the four MENU resources the program needs. The items in the Sound menu include (resource) and (file) in their names so that you'll be able to tell which item uses which type of sound - in a real-world application there's no need to relay this information to the user. After creating the MENU resources, create an MBAR resource that references all four menus. That is, make sure it includes IDs 128, 129, 130, and 131.


Figure 3. The SoundPlayer menu resources.

The snd resource used by SoundPlayer isn't a resource you can create in ResEdit. ResEdit isn't a sound editor, so to get the sound you need you'll have to rely on a sound-producing or sound-editing software program. Or, pick up a sound resource by following one of the suggestions made earlier in this column. This month's project is available for download from MacTech's ftp site at ftp://ftp.mactech.com/src/mactech/volume15_1999/15.02.sit, and it includes a single system sound file named CatMeow. You can use ResEdit to open that file, copy its one snd resource, and then paste that resource into the SoundPlayer.rsrc file.

Figure 4 shows how the CatMeow file looks when opened in ResEdit. Here you see what happens when you double-click on the snd icon and then double-click on a particular snd resource. ResEdit is composed of a number of editors, but there is no sound editor. So ResEdit opens the sound resource in a hex editor window that does nothing but show the raw data that makes up the digital sound. After satisfying your curiosity, close the hex editor. Then click on the CatMeow resource in the list of snd resources, copy it, and paste it into the SoundPlayer.rsrc file.


Figure 4. The sound resource in a system sound file.

That's it for the SoundPlayer.rsrc file. Save the file and quit ResEdit - it's time to get started on the project file.

Creating the SoundPlayer Project

Launch CodeWarrior and choose New Project from the File menu to create a new project based on the MacOS:C_C++:MacOS Toolbox:MacOS Toolbox Multi-Target stationary. Uncheck the Create Folder check box before clicking the OK button. Name the project SoundPlayer.mcp and make the SoundPlayer folder the project's destination.

Add the SoundPlayer.rsrc file to the project window and remove the SillyBalls.rsrc file. The SoundPlayer project doesn't use of any of the standard ANSI libraries, so you can feel free to remove the ANSI Libraries folder.

Choose New from the File menu to create a new, empty source code window. Save it with the name SoundPlayer.c and then choose Add Window from the Project menu to add the file to the project. Remove the SillyBalls.c file from the project window if you already haven't done so. The source code listing for the SoundPlayer program appears next in the source code walk-through. You can type the code into the SoundPlayer.c file as you read the walk-through, or you can save a little effort and download the entire SoundPlayer project from MacTech's ftp site at ftp://ftp.mactech.com/src/mactech/volume15_1999/15.02.sit.

Walking Through the Source Code

Now, the SoundPlayer code. SoundPlayer starts off with the usual constant definitions. Most of the constants have appeared in previous projects, but there are a couple of additions. The constant ksnd_ResMeowID is the resource ID of the project's one snd resource - the resource used when the user chooses Meow (resource) from the Sound menu. For sound resources, Apple reserves IDs up to 8191 - so always give your own resources of this type an ID greater than 8191. The constant kBarkFileName is a Pascal-style string that holds the name of the AIFF sound file that's to be used when the user chooses Bark (file) from the Sound menu.

/********************* constants *********************/

#define   kMBARResID            128
#define   kALRTResID            128
#define   ksnd_ResMeowID        12000

#define   kBarkFileName      "\pDogBark.AIFF"

#define   kSleep                7
#define   kMoveToFront         (WindowPtr)-1L

#define   mApple                128
#define   iAbout                1

#define   mFile                 129
#define   iQuit                 1

#define   mSound                131
#define   iMeow                 1
#define   iBark                 2

SoundPlayer needs just one global variable - the now-familiar gDone. The user's quitting of the program toggles this variable's value from false to true.

/****************** global variables *****************/

Boolean      gDone;

Next come the program's function prototypes.

/********************* functions *********************/
void      ToolBoxInit( void );
void      MenuBarInit( void );
void      PlaySoundResource( void );
void      PlaySoundFile( void );
void      EventLoop( void );
void      DoEvent( EventRecord *eventPtr );
void      HandleMouseDown( EventRecord *eventPtr );
void      HandleMenuChoice( long menuChoice );
void      HandleAppleChoice( short item );
void      HandleFileChoice( short item );
void      HandleSoundChoice( short item );
void      DoError( Str255 errorString );

The main() function begins by initializing the Toolbox. After that a check is made to ensure that the user has version 3.0 or later of the Sound Manager. If that isn't the case, the application-defined routine DoError() posts a message and exits the program.

/************************ main ***********************/

void      main( void )
{
   NumVersion theSndMgrVers;

   ToolBoxInit();
 
   theSndMgrVers = SndSoundManagerVersion(); 
   if ( theSndMgrVers.majorRev < 3 )
       DoError( "\pSound Manager is outdated" );
   
   MenuBarInit();
   
   EventLoop();
}

The ToolBoxInit() and MenuBarInit() functions are the same as prior versions.

/******************** ToolBoxInit ********************/

void      ToolBoxInit( void )
{
   InitGraf( &qd.thePort );
   InitFonts();
   InitWindows();
   InitMenus();
   TEInit();
   InitDialogs( nil );
   InitCursor();
}

/******************** MenuBarInit ********************/

void      MenuBarInit( void )
{
   Handle            menuBar;
   MenuHandle      menu;
   
   menuBar = GetNewMBar( kMBARResID );
   SetMenuBar( menuBar );

   menu = GetMenuHandle( mApple );
   AppendResMenu( menu, 'DRVR' );
   
   DrawMenuBar();
}

When the user chooses Meow (resource) from the Sound menu, it is the application-defined function PlaySoundResource() that handles the task of loading a sound resource into memory and playing the sound.

/****************** PlaySoundResource ****************/

void PlaySoundResource( void )
{
   Handle theHandle;
   OSErr theErr;
 
   theHandle = GetResource( 'snd ', ksnd_ResMeowID );
 
   if ( theHandle == nil )
      DoError( "\pAttempt to load sound resource failed" );

   HLock( theHandle );
   theErr = SndPlay( nil, (SndListHandle)theHandle, 
                               false );
   HUnlock( theHandle );

   if ( theErr != noErr )
      DoError( "\pPlaying of sound failed" );
 
   ReleaseResource( theHandle );
}

If the call to GetResource() successfully loads the sound resource, PlaySoundResource() then plays the sound. The calls to the Toolbox functions HLock() and HUnlock() force the system to leave the sound data untouched in memory. That is, during the duration of the execution of SndPlay(), the system can't move the memory referenced by the variable theHandle. That's important - you don't want the system moving the sound data in the middle of sound playing. In the SndPlay() snippet presented earlier in this article we didn't save the OSErr value returned by SndPlay(). Here we do. If SndPlay() fails to play the sound, an error will be returned and that fact can be relayed to the user. When sound playing is complete, the memory that's holding the sound resource data is released for future use by the program.

When the user chooses Bark (file) from the Sound menu, the application-defined function PlaySoundFile() gets called to open a sound file and play its sound. PlaySoundFile() begins by creating a file system specification for a file named DogBark.AIFF. Here we've set the volume and directory values of 0, so FSMakeFSSpec() expects the file named DogBark.AIFF to be in the same directory as the SoundPlayer application. If you want to keep sound files in a different directory, you'll need to study up on the FSSpec data structure in the Files volume of Inside Macintosh.

/******************** PlaySoundFile ******************/

void PlaySoundFile( void )
{
   FSSpec      barkFSSpec;
   OSErr      theErr;
   short      sndFileRefNum;
   
   theErr = FSMakeFSSpec( 0, 0, kBarkFileName, 
                                    &barkFSSpec );

If the creation of the FSSpec fails, the program ends. If the file system specification succeeds, it's time to open the file with a call to FSpOpenDF() and play its contents with a call to SndStartFilePlay().

   if ( theErr != noErr)
      DoError( "\pSound file not found" );

   theErr = FSpOpenDF( &barkFSSpec, fsRdPerm, 
                                  &sndFileRefNum );
   if ( theErr != noErr )
      DoError( "\pSound file opening error" );

   theErr = SndStartFilePlay( nil, sndFileRefNum, 0, 40960, 
                                          nil, nil, nil, false );
   if ( theErr != noErr )
      DoError( "\pSound file playing error" );
}

PlaySoundFile() includes plenty of error-handling code. Working with files on disk subjects the program to a number of potential problems, and we want to be ready for them. For instance, if the specified file is corrupt, the call to FSpOpenDF() may fail. If the file isn't a sound file, the call to SndStartFilePlay() would fail.

Now we're in the clear. The remaining SoundPlayer code is standard stuff that's necessary to keep our event-handling program running. The only additions exist to support a menu selection from the Sound menu.

/********************** EventLoop ********************/

void      EventLoop( void )
{      
   EventRecord      event;
   
   gDone = false;
   while ( gDone == false )
   {
      if ( WaitNextEvent( everyEvent, &event, kSleep, nil ) )
         DoEvent( &event );
   }
}

/*********************** DoEvent *********************/

void      DoEvent( EventRecord *eventPtr )
{
   char      theChar;
   
   switch ( eventPtr->what )
   {
      case mouseDown: 
         HandleMouseDown( eventPtr );
         break;
      case keyDown:
      case autoKey:
         theChar = eventPtr->message & charCodeMask;
         if ( (eventPtr->modifiers & cmdKey) != 0 ) 
            HandleMenuChoice( MenuKey( theChar ) );
         break;
      case updateEvt:
         BeginUpdate( (WindowPtr)(eventPtr->message) );
         EndUpdate( (WindowPtr)(eventPtr->message) );
         break;
   }
}

/******************* HandleMouseDown *****************/

void      HandleMouseDown( EventRecord *eventPtr )
{
   WindowPtr   window;
   short         thePart;
   long            menuChoice;
   
   thePart = FindWindow( eventPtr->where, &window );
   
   switch ( thePart )
   {
      case inMenuBar:
         menuChoice = MenuSelect( eventPtr->where );
         HandleMenuChoice( menuChoice );
         break;
      case inSysWindow : 
         SystemClick( eventPtr, window );
         break;
   }
}

Here in HandleMenuChoice() we've added a switch case section for the handling of a selection from the Sound menu.

/******************* HandleMenuChoice ****************/

void      HandleMenuChoice( long menuChoice )
{
   short   menu;
   short   item;
   
   if ( menuChoice != 0 )
   {
      menu = HiWord( menuChoice );
      item = LoWord( menuChoice );
      
      switch ( menu )
      {
         case mApple:
            HandleAppleChoice( item );
            break;
         case mFile:
            HandleFileChoice( item );
            break;
         case mSound:
            HandleSoundChoice( item );
            break;
      }
      HiliteMenu( 0 );
   }
}

/****************** HandleAppleChoice ****************/

void      HandleAppleChoice( short item )
{
   MenuHandle      appleMenu;
   Str255            accName;
   short            accNumber;
   
   switch ( item )
   {
      case iAbout:
         SysBeep( 10 );
         break;
      default:
         appleMenu = GetMenuHandle( mApple );
         GetMenuItemText( appleMenu, item, accName );
         accNumber = OpenDeskAcc( accName );
         break;
   }
}

/******************* HandleFileChoice ****************/

void      HandleFileChoice( short item )
{
   switch ( item )
   {
      case iQuit:
         gDone = true;
         break;
   }
}

The HandleSoundChoice() routine is new to SoundPlayer. It's code should be intuitive - a Meow (resource) menu selection invokes PlaySoundResource() to play the sound resource, while a Bark (file) menu selection invokes PlaySoundFile() to play the DogBark.AIFF sound file.

/****************** HandleSoundChoice ****************/

void      HandleSoundChoice( short item )
{
   switch ( item )
   {
      case iMeow:
         PlaySoundResource();
         break;
      case iBark:
         PlaySoundFile();
         break;
   }
}

/*********************** DoError *********************/

void      DoError( Str255 errorString )
{
   ParamText( errorString, "\p", "\p", "\p" );
   
   StopAlert( kALRTResID, nil );
   
   ExitToShell();
}

Running SoundPlayer

Run SoundPlayer by selecting Run from the Project menu. Once your code compiles, the menu bar shown in Figure 1 appears. Choose one Sound menu item, then the other, to verify that the sounds play. Make sure your Mac's speaker volume is set above zero! Choose Quit from the File menu to end the animation and the program.

Till Next Month...

If your program will be playing more than one sound, you'll want to adapt either or both of the sound-playing routines to make them more flexible. In the case of PlaySoundResource(), you'll want to pass in the resource ID of the snd resource to play. For PlaySoundFile() you'll pass in the name of the sound file to play, or perhaps predetermine the file's FSSpec and pass in that data structure. Try adapting SoundPlayer so that the playing of a sound is contingent on something other than a menu selection. For instance, allow the user to click a button in a window to play a sound.

You can learn more about playing sounds by reading the Sound volume of Inside Macintosh. You can also wait until next month, when we look at how a Mac program plays asynchronous sound - sound that plays as other action takes place in the program. Asynchronous sound is an important way of playing sound because it doesn't tie up your program and force it to wait for sound-completion before carrying out other actions. This is especially important in games, where sound plays in the background, or accompanies some event (such as the sound of a gun firing, or a bomb exploding, or a rocket launching). Until next month's look at asynchronous sound, examine, modify, and play with the SoundPlayer code so that you're familiar with the basics of sound.

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

BetterTouchTool 2.332 - Customize multi-...
BetterTouchTool adds many new, fully customizable gestures to the Magic Mouse, Multi-Touch MacBook trackpad, and Magic Trackpad. These gestures are customizable: Magic Mouse: Pinch in / out (zoom... Read more
Capture One 11.0.1.40 - RAW workflow sof...
Capture One is a professional RAW converter offering you ultimate image quality with accurate colors and incredible detail from more than 400 high-end cameras -- straight out of the box. It offers... Read more
Capture One 11.0.1.40 - RAW workflow sof...
Capture One is a professional RAW converter offering you ultimate image quality with accurate colors and incredible detail from more than 400 high-end cameras -- straight out of the box. It offers... Read more
GraphicConverter 10.5.4 - $39.95
GraphicConverter is an all-purpose image-editing program that can import 200 different graphic-based formats, edit the image, and export it to any of 80 available file formats. The high-end editing... Read more
Dash 4.1.3 - Instant search and offline...
Dash is an API documentation browser and code snippet manager. Dash helps you store snippets of code, as well as instantly search and browse documentation for almost any API you might use (for a full... Read more
Microsoft OneNote 16.9 - Free digital no...
OneNote is your very own digital notebook. With OneNote, you can capture that flash of genius, that moment of inspiration, or that list of errands that's too important to forget. Whether you're at... Read more
DEVONthink Pro 2.9.17 - Knowledge base,...
Save 10% with our exclusive coupon code: MACUPDATE10 DEVONthink Pro is your essential assistant for today's world, where almost everything is digital. From shopping receipts to important research... Read more
OmniGraffle 7.6 - Create diagrams, flow...
OmniGraffle helps you draw beautiful diagrams, family trees, flow charts, org charts, layouts, and (mathematically speaking) any other directed or non-directed graphs. We've had people use Graffle to... Read more
iFinance 4.3.7 - Comprehensively manage...
iFinance allows you to keep track of your income and spending -- from your lunchbreak coffee to your new car -- in the most convenient and fastest way. Clearly arranged transaction lists of all your... Read more
Opera 50.0.2762.58 - High-performance We...
Opera is a fast and secure browser trusted by millions of users. With the intuitive interface, Speed Dial and visual bookmarks for organizing favorite sites, news feature with fresh, relevant content... Read more

Latest Forum Discussions

See All

Around the Empire: What have you missed...
Around this time every week we're going to have a look at the comings and goings on the other sites in Steel Media's pocket-gaming empire. We'll round up the very best content you might have missed, so you're always going to be up to date with the... | Read more »
Everything about Hero Academy 2: Part 4...
In this part of our Hero Academy 2 guide, we're going to have a look at some of the tactics you're going to need to learn if you want to rise up the ranks. We're going to start off slow, then get more advanced in the next section. [Read more] | Read more »
All the best games on sale for iPhone an...
Another week has flown by. Sometimes it feels like the only truly unstoppable thing is time. Time will make dust of us all. But before it does, we should probably play as many awesome mobile videogames as we can. Am I right, or am I right? [Read... | Read more »
The 7 best games that came out for iPhon...
Well, it's that time of the week. You know what I mean. You know exactly what I mean. It's the time of the week when we take a look at the best games that have landed on the App Store over the past seven days. And there are some real doozies here... | Read more »
Popular MMO Strategy game Lords Mobile i...
Delve into the crowded halls of the Play Store and you’ll find mobile fantasy strategy MMOs-a-plenty. One that’s kicking off the new year in style however is IGG’s Lords Mobile, which has beaten out the fierce competition to receive Google Play’s... | Read more »
Blocky Racing is a funky and fresh new k...
Blocky Racing has zoomed onto the App Store and Google Play this week, bringing with it plenty of classic kart racing shenanigans that will take you straight back to your childhood. If you’ve found yourself hooked on games like Mario Kart or Crash... | Read more »
Cytus II (Games)
Cytus II 1.0.1 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0.1 (iTunes) Description: "Cytus II" is a music rhythm game created by Rayark Games. It's our fourth rhythm game title, following the footsteps of three... | Read more »
JYDGE (Games)
JYDGE 1.0.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0.0 (iTunes) Description: Build your JYDGE. Enter Edenbyrg. Get out alive. JYDGE is a lawful but awful roguehate top-down shooter where you get to build your... | Read more »
Tako Bubble guide - Tips and Tricks to S...
Tako Bubble is a pretty simple and fun puzzler, but the game can get downright devious with its puzzle design. If you insist on not paying for the game and want to manage your lives appropriately, check out these tips so you can avoid getting... | Read more »
Everything about Hero Academy 2 - The co...
It's fair to say we've spent a good deal of time on Hero Academy 2. So much so, that we think we're probably in a really good place to give you some advice about how to get the most out of the game. And in this guide, that's exactly what you're... | Read more »

Price Scanner via MacPrices.net

Deals on clearance 15″ Apple MacBook Pros wit...
B&H Photo has clearance 2016 15″ MacBook Pros available for up to $800 off original MSRP. Shipping is free, and B&H charges NY & NJ sales tax only: – 15″ 2.7GHz Touch Bar MacBook Pro... Read more
Apple restocked Certified Refurbished 13″ Mac...
Apple has restocked a full line of Certified Refurbished 2017 13″ MacBook Airs starting at $849. An Apple one-year warranty is included with each MacBook, and shipping is free: – 13″ 1.8GHz/8GB/128GB... Read more
How to find the lowest prices on 2017 Apple M...
Apple has Certified Refurbished 13″ and 15″ 2017 MacBook Pros available for $200 to $420 off the cost of new models. Apple’s refurbished prices are the lowest available for each model from any... Read more
The lowest prices anywhere on Apple 12″ MacBo...
Apple has Certified Refurbished 2017 12″ Retina MacBooks available for $200-$240 off the cost of new models. Apple will include a standard one-year warranty with each MacBook, and shipping is free.... Read more
Apple now offering a full line of Certified R...
Apple is now offering Certified Refurbished 2017 10″ and 12″ iPad Pros for $100-$190 off MSRP, depending on the model. An Apple one-year warranty is included with each model, and shipping is free: –... Read more
27″ iMacs on sale for $100-$130 off MSRP, pay...
B&H Photo has 27″ iMacs on sale for $100-$130 off MSRP. Shipping is free, and B&H charges sales tax for NY & NJ residents only: – 27″ 3.8GHz iMac (MNED2LL/A): $2199 $100 off MSRP – 27″ 3.... Read more
2.8GHz Mac mini on sale for $899, $100 off MS...
B&H Photo has the 2.8GHz Mac mini (model number MGEQ2LL/A) on sale for $899 including free shipping plus NY & NJ sales tax only. Their price is $100 off MSRP. Read more
Apple offers Certified Refurbished iPad minis...
Apple has Certified Refurbished 128GB iPad minis available today for $339 including free shipping. Apple’s standard one-year warranty is included. Their price is $60 off MSRP. Read more
Amazon offers 13″ 256GB MacBook Air for $1049...
Amazon has the 13″ 1.8GHz/256B #Apple #MacBook Air on sale today for $150 off MSRP including free shipping: – 13″ 1.8GHz/256GB MacBook Air (MQD42LL/A): $1049.99, $150 off MSRP Read more
9.7-inch 2017 WiFi iPads on sale starting at...
B&H Photo has 9.7″ 2017 WiFi #Apple #iPads on sale for $30 off MSRP for a limited time. Shipping is free, and pay sales tax in NY & NJ only: – 32GB iPad WiFi: $299, $30 off – 128GB iPad WiFi... Read more

Jobs Board

AppleCare Support Engineer for *Apple* Medi...
# AppleCare Support Engineer for Apple Media Products Job Number: 113222855 Santa Clara Valley, California, United States Posted: 14-Nov-2017 Weekly Hours: 40.00 Read more
QA Automation Engineer, *Apple* Pay - Apple...
# QA Automation Engineer, Apple Pay Job Number: 113202642 Santa Clara Valley, California, United States Posted: 11-Dec-2017 Weekly Hours: 40.00 **Job Summary** At Read more
*Apple* Video Partnerships - Apple (United S...
# Apple Video Partnerships Job Number: 113059126 Santa Clara Valley, California, United States Posted: 15-Nov-2017 Weekly Hours: 40.00 **Job Summary** Partnerships Read more
Sr. Engineering Manager- *Apple* Media Produ...
# Sr. Engineering Manager- Apple Media Products Job Number: 113335268 Santa Clara Valley, California, United States Posted: 17-Jan-2018 Weekly Hours: 40.00 **Job Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description:SalesSpecialist - Retail Customer Service and SalesTransform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.