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
- closing and reopening the channel and beginning the new sound.
- SndPlay1(NULL) waits for the sound to end and then closes the channel.
- SndStop1() closes the channel immediately.
- SndDone1() returns true once the last sound initiated by SndPlay1() has
- finished.
-
- GENERAL NOTE:
- 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. Apple advises against
- this approach because it leaves the channel open a lot of the time,
- which blocks SysBeep.
-
- To avoid this, make sure to call SndPlay1(NULL) or SndStop1() to close the channel after
- you start a sound going.
-
- The easiest way to get a sound to play is to call GetNamedResource().
- Handle snd;
- snd=GetNamedResource('snd ',"\pSimple Beep");
- However, it's also easy to create your own snd in memory, as a series of commands,
- following the instructions in Inside Mac VI.
-
- 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
- 4.5 doesn't attach the atexit() tasks to _EscapeToShell. So I do it here.
- */
- #include "VideoToolbox.h"
- #include <Sound.h>
- static pascal void SndCallBack1(SndChannelPtr channel,SndCommand command);
- static SndChannelPtr channel=NULL;
- static SndCommand callBack;
- #if !defined(NewSndCallBackProc)
- #define NewSndCallBackProc (SndCallBackUPP)
- typedef ProcPtr SndCallBackUPP;
- #endif
- static void PatchExitToShell(void);
-
- OSErr SndPlay1(Handle snd)
- {
- int error=0;
-
- static firstTime=1;
- static SndCallBackUPP sndCallBackProc;
-
- if(firstTime){
- sndCallBackProc=NewSndCallBackProc(SndCallBack1);
- if(!MATLAB){
- #if __MWERKS__
- // In CW _atexit() only gets called if you quit via abort() or exit().
- PatchExitToShell();
- #else
- _atexit(SndStop1);
- #endif
- }
- firstTime=0;
- }
- if(channel!=NULL)error=SndDisposeChannel(channel,FALSE); // wait till done
- channel=NULL;
- if(error)return error;
- if(snd==NULL)return 0;
- error=SndNewChannel(&channel,0,0L,sndCallBackProc);
- if(error){
- printf("%s line %d:SndNewChannel failed with error %d\n",__FILE__,__LINE__,error);
- return error;
- }
- #if UNIVERSAL_HEADERS<2
- error=SndPlay(channel,snd,TRUE);
- #else
- error=SndPlay(channel,(SndListHandle)snd,TRUE);
- #endif
- if(error){
- printf("%s line %d:SndPlay failed with error %d\n",__FILE__,__LINE__,error);
- return error;
- }
- callBack.cmd=callBackCmd;
- callBack.param1=0;
- error=SndDoCommand(channel,&callBack,FALSE);
- if(error)printf("%s line %d:SndDoCommand failed with error %d\n",__FILE__,__LINE__,error);
- return error;
- }
-
- void SndStop1(void)
- {
- if(channel!=NULL)SndDisposeChannel(channel,TRUE); // immediately
- channel=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)
- #pragma options(!profile) // Disable profiling because A5 may be invalid.
- #endif
-
- static pascal void SndCallBack1(SndChannelPtr channel,SndCommand command)
- // Load a short int.
- // Called back by sound manager. Lets us know when sound is done.
- {
- channel; // prevent "unused argument" warning
- command.param1=1;
- }
-
- /*
- The following code, which seems to work on 68k and ppc,
- is based on examples that appeared in UseNet csmp-digest-v3-046
- by Kevin Bell (kbell@cs.utexas.edu) and Bill Hofmann (wdh@netcom.com)
- in response to a query by Steve Coy (stevec@jolt.mpx.com.au)
- */
-
- #if UNIVERSAL_HEADERS
- #if UNIVERSAL_HEADERS>1
- extern pascal void ExitToShell(void) ONEWORDINLINE(0xA9F4);
- #endif
- typedef UniversalProcPtr TrapAddressType;
- #else
- #define UniversalProcPtr ProcPtr
- #define NewRoutineDescriptor(a,b,c) a
- typedef long TrapAddressType;
- #endif
- static UniversalProcPtr oldExitToShellTrapAddress=NULL;
- static void PatchExitToShell(void);
- static pascal void MyExitToShell(void);
- #include <Traps.h> // _ExitToShell
-
- static void PatchExitToShell(void)
- {
- UniversalProcPtr myExitToShellUPP;
- if(oldExitToShellTrapAddress==NULL){
- myExitToShellUPP=NewRoutineDescriptor((ProcPtr)MyExitToShell,kPascalStackBased,GetCurrentISA());
- oldExitToShellTrapAddress=(UniversalProcPtr)GetToolTrapAddress(_ExitToShell);
- SetToolTrapAddress((TrapAddressType)myExitToShellUPP,_ExitToShell);
- }
- }
-
- static pascal void MyExitToShell(void)
- {
- SetCurrentA5();
- SetToolTrapAddress((TrapAddressType)oldExitToShellTrapAddress,_ExitToShell);
- SndStop1();
- ExitToShell();
- }
-