home *** CD-ROM | disk | FTP | other *** search
- /*
- SndPlay1.c
-
- SndPlay1(snd) plays a sound, asynchronously, i.e. it returns immediately, while the
- sound is still playing. The argument is a handle to a snd resource. If a sound is
- still playing from a previous call to SndPlay1, it is allowed to finish before
- SndPlay1 closes and reopens the channel and begins the new sound.
- SndPlay1(NULL) waits for any previously SndPlay1-initiated sound to end and then closes the channel.
- SndStop1() closes the channel immediately.
- SndDone1() returns true if the last sound initiated by SndPlay1() has finished.
-
- Apple advises against leaving the channel open for extended periods, because the open
- channel blocks SysBeep. To minimize this, make sure to call SndPlay1(NULL) or SndStop1()
- to close the channel when you no longer need it.
-
- The easiest way to get a sound that you can play is to call GetNamedResource().
- Here's a complete program to get a sound and play it.
- Handle snd;
- snd=GetNamedResource('snd ',"\pSimple Beep");
- SndPlay1(snd); // start snd playing, and return immediately, while it's playing
- // do something useful here
- SndPlay1(NULL); // wait till snd is done, then close and dispose of sound channel
- ReleaseResource(snd);
- It's also easy to create your own snd in memory, as a series of commands,
- following the instructions in Inside Mac:Sound. Use VideoToolbox CreateTrialsSnds.c as an example.
-
- As of 1994, the Apple Sound Manager has the annoying characteristic of insisting on loading
- any synth that's mentioned in a snd resource, even if that synth is already loaded,
- which causes an error. This makes it necessary to dispose of and recreate the
- snd channel before each new sound, which these routines do.
-
- NOTE: The snd is not locked while being played. I don't know whether that's necessary.
- It seems to work ok as is, on both 68k and ppc machines, but I haven't stressed it. In
- particular, I don't move memory while the sound is playing. I probably ought to lock it
- down and HoldMemory on the snd while it's playing. However, that would complicate the
- program slightly, since the locking and unlocking would have to happen in different
- routines, below, and the address of the snd would have to be communicated between them,
- presumably by a variable global to this file.
-
- HISTORY:
- 3/30/92 dgp wrote it.
- 4/1/92 dgp renamed it and commented out the printf's.
- 7/9/93 dgp Test MATLAB in if() instead of #if.
- 5/28/94 dgp Made compatible with Apple's Universal Headers. Thanks to Bob Dougherty
- (wolfgang@cats.ucsc.edu) for reporting the incompatibility.
- 9/5/94 dgp removed assumption in printf's that int==short.
- 9/10/94 dgp cosmetic
- 10/5/94 dgp simplified SndCallBack1 until it stopped crashing when I run native on ppc.
- 10/27/94 dgp It is very annoying for the machine to crash anytime you try to quit your
- application by escaping via MacsBugs escape to shell. The problem is that CodeWarrior
- doesn't attach the atexit() tasks to _EscapeToShell. So I do it here.
- 7/1/95 dgp just call AtExitToShell(), without any conditionals. Special cases, e.g. MATLAB,
- are handled in AtExitToShell.c.
- */
- #include "VideoToolbox.h"
- //#include <Sound.h>
- static pascal void SndCallBack1(SndChannelPtr channelPtr,SndCommand command);
- static SndChannel *channelPtr=NULL,channel;
- static SndCommand callBack;
- #if !UNIVERSAL_HEADERS
- #define NewSndCallBackProc (SndCallBackUPP)
- typedef ProcPtr SndCallBackUPP;
- #endif
- #if UNIVERSAL_HEADERS<2
- #define SndListHandle Handle
- #endif
-
- OSErr SndPlay1(Handle snd)
- {
- int error=0;
- static Boolean firstTime=1;
- static SndCallBackUPP sndCallBackProc;
-
- if(snd!=NULL)HNoPurge(snd); // make sure snd is not purged while we're allocating memory
- if(firstTime){
- sndCallBackProc=NewSndCallBackProc(SndCallBack1);
- AtExitToShell(SndStop1);
- firstTime=0;
- }
- if(channelPtr!=NULL)error=SndDisposeChannel(channelPtr,FALSE); // wait till done
- channelPtr=NULL;
- if(error)return error;
- if(snd==NULL)return 0;
- if(1)error=SndNewChannel(&channelPtr,0,0L,sndCallBackProc); // allocates space for 128 snds.
- else{
- channelPtr=&channel;
- channelPtr->qLength=10; // how many snd commands to allow space for. CreateTrialSnds.c snds use 4.
- error=SndNewChannel(&channelPtr,0,0L,sndCallBackProc);
- if(error)channelPtr=NULL;
- }
- if(error){
- printf("%s %d:SndNewChannel failed with error %d\007\n",__FILE__,__LINE__,error);
- return error;
- }
- error=SndPlay(channelPtr,(SndListHandle)snd,TRUE);
- if(error){
- printf("%s %d:SndPlay failed with error %d\007\n",__FILE__,__LINE__,error);
- return error;
- }
- callBack.cmd=callBackCmd;
- callBack.param1=0;
- error=SndDoCommand(channelPtr,&callBack,FALSE);
- if(error)printf("%s %d:SndDoCommand failed with error %d\007\n",__FILE__,__LINE__,error);
- return error;
- }
-
- void SndStop1(void)
- {
- if(channelPtr!=NULL)SndDisposeChannel(channelPtr,TRUE); // immediately
- channelPtr=NULL;
- }
-
- short SndDone1(void)
- // Returns 1 if the last sound initiated by SndPlay1 has finished. Otherwise 0.
- {
- return callBack.param1;
- }
-
- #if (THINK_C || THINK_CPLUS || SYMANTEC_C)
- #pragma options(!profile) // Disable profiling because A5 may be invalid.
- #endif
- #if __MWERKS__ && __profile__
- #pragma profile off // on 68k it would be dangerous to call the profiler from here
- #endif
-
- static pascal void SndCallBack1(SndChannelPtr channelPtr,SndCommand command)
- // Load a short int.
- // Called back by sound manager. Lets us know when sound is done.
- {
- channelPtr; // prevent "unused argument" warning
- command.param1=1;
- }
-
-