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

Backup and Sync 3.46 - File backup and s...
Backup and Sync (was Google Drive) is a place where you can create, share, collaborate, and keep all of your stuff. Whether you're working with a friend on a joint research project, planning a... Read more
iClock 5.5 - Customizable menu bar clock...
iClock replaces the old Apple's default menu bar clock with more features, customization and increases your productivity. Features: Have your Apple or Google calendar instantly available from the... Read more
Garmin Express 6.18.0.0 - Manage your Ga...
Garmin Express is your essential tool for managing your Garmin devices. Update maps, golf courses and device software. You can even register your device. Update maps Update software Register your... Read more
MarsEdit 4.3.5 - Quick and convenient bl...
MarsEdit is a blog editor for OS X that makes editing your blog like writing email, with spell-checking, drafts, multiple windows, and even AppleScript support. It works with with most blog services... Read more
Xcode 11.0 - Integrated development envi...
Xcode includes everything developers need to create great applications for Mac, iPhone, iPad, and Apple Watch. Xcode provides developers a unified workflow for user interface design, coding, testing... Read more
DaisyDisk 4.8 - $9.99
DaisyDisk allows you to visualize your disk usage and free up disk space by quickly finding and deleting big unused files. The program scans your disk and displays its content as a sector diagram... Read more
VMware Fusion 11.5.0 - Run Windows apps...
VMware Fusion and Fusion Pro - virtualization software for running Windows, Linux, and other systems on a Mac without rebooting. The latest version includes full support for Windows 10, macOS Mojave... Read more
Apple Configurator 2.10 - Configure and...
Apple Configurator makes it easy to deploy iPad, iPhone, iPod touch, and Apple TV devices in your school or business. Use Apple Configurator to quickly configure large numbers of devices connected to... Read more
Spotify 1.1.15.448. - Stream music, crea...
Spotify is a streaming music service that gives you on-demand access to millions of songs. Whether you like driving rock, silky R&B, or grandiose classical music, Spotify's massive catalogue puts... Read more
MenuMeters 1.9.8 - CPU, memory, disk, an...
MenuMeters is a set of CPU, memory, disk, and network monitoring tools for Mac OS X. Although there are numerous other programs which do the same thing, none had quite the feature set I was looking... Read more

Latest Forum Discussions

See All

Marvel Strike Force is adding Agent Coul...
Marvel Strike Force, the popular squad-based RPG, is set to receive a bunch of new content over the next few weeks. [Read more] | Read more »
Lots of premium games are going free (so...
You may have seen over the past couple weeks a that a bunch of premium games have suddenly become free. This isn’t a mistake, nor is it some last hurrah before Apple Arcade hits, and it’s important to know that these games aren’t actually becoming... | Read more »
Yoozoo Games launches Saint Seiya Awaken...
If you’re into your anime, you’ve probably seen or heard of Saint Seiya. Based on a shonen manga by Masami Kurumada, the series was massively popular in the 1980s – especially in its native Japan. Since then, it’s grown into a franchise of all... | Read more »
Five Nights at Freddy's AR: Special...
Five Nights at Freddy's AR: Special Delivery is a terrifying new nightmare from developer Illumix. Last week, FNAF fans were sent into a frenzy by a short teaser for what we now know to be Special Delivery. Those in the comments were quick to... | Read more »
Rush Rally 3's new live events are...
Last week, Rush Rally 3 got updated with live events, and it’s one of the best things to happen to racing games on mobile. Prior to this update, the game already had multiplayer, but live events are more convenient in the sense that it’s somewhat... | Read more »
Why your free-to-play racer sucks
It’s been this way for a while now, but playing Hot Wheels Infinite Loop really highlights a big issue with free-to-play mobile racing games: They suck. It doesn’t matter if you’re trying going for realism, cart racing, or arcade nonsense, they’re... | Read more »
Steam Link Spotlight - The Banner Saga 3
Steam Link Spotlight is a new feature where we take a look at PC games that play exceptionally well using the Steam Link app. Our last entry talked about Terry Cavanaugh’s incredible Dicey Dungeons. Read about how it’s a great mobile experience... | Read more »
Combo Quest (Games)
Combo Quest 1.0 Device: iOS Universal Category: Games Price: $.99, Version: 1.0 (iTunes) Description: Combo Quest is an epic, time tap role-playing adventure. In this unique masterpiece, you are a knight on a heroic quest to retrieve... | Read more »
Hero Emblems (Games)
Hero Emblems 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: ** 25% OFF for a limited time to celebrate the release ** ** Note for iPhone 6 user: If it doesn't run fullscreen on your device... | Read more »
Puzzle Blitz (Games)
Puzzle Blitz 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: Puzzle Blitz is a frantic puzzle solving race against the clock! Solve as many puzzles as you can, before time runs out! You have... | Read more »

Price Scanner via MacPrices.net

11″ WiFi iPad Pros on sale today for up to $2...
Amazon has new 2018 Apple 11″ WiFi iPad Pros in stock today and on sale for up to $200 off Apple’s MSRP. These are the same iPad Pros sold by Apple in its retail and online stores. Be sure to select... Read more
Select 12″ iPad Pros on sale for $200 off App...
Amazon has select 2018 Apple 12″ iPad Pros in stock today and on sale for $200 off Apple’s MSRP. These are the same iPad Pros sold by Apple in its retail and online stores. Be sure to select Amazon... Read more
Get one of Apple’s new 2019 iPhone 11 models...
Boost Mobile is offering the new 2019 Apple iPhone 11, iPhone 11 Pro, and 11 Pro Max for $100 off MSRP. Their discount reduces the cost of an iPhone 11 to $599 for the 64GB models, $899 for the 64GB... Read more
13″ 1.4GHz Silver MacBook Pros on sale for $1...
B&H Photo has new 2019 13″ 1.4GHz 4-Core Touch Bar Silver MacBook Pros on sale for $100 off Apple’s MSRP. Overnight shipping is free to many addresses in the US. These are the same MacBook Pros... Read more
4-core and 6-core 2018 Mac minis available at...
Apple has Certified Refurbished 2018 Mac minis available on their online store for $120-$170 off the cost of new models. Each mini comes with a new outer case plus a standard Apple one-year warranty... Read more
$250 prepaid Visa card with any Apple iPhone,...
Xfinity Mobile will include a free $250 prepaid Visa card with the purchase of any new iPhone, new line activation, and transfer of phone number to Xfinity Mobile. Offer is valid through October 27,... Read more
Sprint is offering the 64GB Apple iPhone 11 P...
Sprint has the new 64GB iPhone 11 Pro available for $12.50 per month for new customers with an eligible trade-in in of iPhone 7 or newer. That’s down from their standard monthly lease of $41.67. The... Read more
Final week: Apple’s 2019 Back to School Promo...
Purchase a new Mac using Apple’s Education discount, and take up to $400 off MSRP. All teachers, students, and staff of any educational institution with a .edu email address qualify for the discount... Read more
Save $30 on Apple’s AirPods at these reseller...
Amazon is offering discounts on new 2019 Apple AirPods ranging up to $30 off MSRP as part of their Labor Day sale. Shipping is free: – AirPods with Charging Case: $144.95 $15 off MSRP – AirPods with... Read more
Preorder your Apple Watch Series 5 today at A...
Amazon has Apple Watch Series 5 GPS models available for preorder and on sale today for $15 off Apple’s MSRP. Shipping is free and starts on September 20th: – 40mm Apple Watch Series 5 GPS: $384.99 $... Read more

Jobs Board

Systems Analyst ( *Apple* & Android) (Jo...
Systems Analyst ( Apple & Android) (Job ID: 572513) + 11751 Meadowville Ln, Chester, VA 23836, USA + Full-time Company Description Computer Consultants International, Read more
*Apple* Mobile App Developer - eiWorkflow So...
…eiWorkflow Solutions, LLC is currently looking for a consultant for the following role. Apple Mobile App Developer Tasks the role will be performing: ? Mobile App Read more
Essbase Developer - *Apple* - Theorem, LLC...
Job Summary Apple is seeking an experienced, detail-minded Essbase developer to join our worldwide business development and strategy team. If you are someone who Read more
Student Employment (Blue *Apple* Cafe) Spri...
Student Employment (Blue Apple Cafe) Spring 2019 Penn State University Campus/Location: Penn State Brandywine Campus City: Media, PA Date Announced: 12/20/2018 Date Read more
Best Buy *Apple* Computing Master - Best Bu...
**732093BR** **Job Title:** Best Buy Apple Computing Master **Job Category:** Store Associates **Location Number:** 001441-Beaumont-Store **Job Description:** The Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.