/*===========================================================

	File: ASndPlayer   ©1990 by Robert L Mathews / L Products
	Plays asynchronous sounds when given a 'snd ' handle.

	Based upon a Pascal source example by Larry Rosenstein
	of Apple Computer, Inc.

	History:
	1.0		2/04/90		original version
	1.1		2/08/90		fixed callback bug, added code to
						allow waiting until previous sound
						is finished
	1.2		2/09/90		fixed multifinder bug - SndTask now
						adds a callBackCmd
	1.3		2/20/90		Figured out correct way to call A5 routines
						Removed callBackCmd from SndTask
	1.3.1	11/23/91	Added prototypes for compatibility with THINK C
						5.0 when "Require Prototypes" is on.
						Changed SndPlay's "FALSE" to "TRUE"
						for compatibility with System 6.0.7 and greater
						Sound Manager. Program now compiles and works
						correctly with THINK 5.0 and new Sound Manager.
		
===========================================================*/

#include <Sound.h>

/*=========================================================*/

void			AInitSnd (void);
OSErr			ASndPlay (Handle, Boolean);
void			AStopSnd (Boolean);
Boolean			SndIsPlaying (void);
void			SndTask (void);
pascal	void	CallBack (SndChannelPtr, SndCommand*);

static	SndChannelPtr	gSndChannel;
static	Boolean			gSndPlaying;
static	SndCommand		myCommand;

/*=========================================================*/

#define		TRUE   1
#define		FALSE  0
#define		NIL    0

/*=========================================================*/
/*   AInitSnd should be called as the program starts up    */

void AInitSnd (void)

{
	gSndChannel = 0;
	gSndPlaying = FALSE;
}


/*=========================================================*/
/* 	  SndIsPlaying returns TRUE if a snd is in progress    */

Boolean SndIsPlaying (void)

{
	return ( gSndPlaying);
}


/*=======================================================*/
/* 	CallBack marks the sound as done for use by SndTask  */

pascal	void	CallBack (SndChannelPtr Temp_Channel, SndCommand *Temp_Cmd)

{
	long	Original_A5;
	
	Original_A5 = SetA5 (Temp_Cmd -> param2);	/*	Setting A5 allows us to use globals
													at interrupt time, which is when callback
													routines are called	*/
											
	gSndPlaying = FALSE;						/*  CanŐt use the memory manager here!
													Instead, we set a flag that SndTask
													will examine at a time when itŐs
													safe to call SndDisposeChannel  */

	Original_A5 = SetA5 (Original_A5);			/*	Reset A5 to what it was to start with */
}


/*=========================================================*/
/* 	SndTask disposes the channel if necessary (so other    */
/* 	applications running can use the Sound Manager).       */

void	SndTask (void)

{
	if (gSndChannel != 0 && gSndPlaying == FALSE)
	{
		SndDisposeChannel (gSndChannel, TRUE);
		gSndChannel = 0;
	}	
}


/*=========================================================*/
/* ASndPlay is the async version of SndPlay; pass a handle */
/* to a 'snd ' resource.  If Stop_Previous is TRUE, it     */
/* stops any sound already playing.  Otherwise, it takes   */
/* control of the computer until the first sound is        */
/* done (aka synchronous sound playing), and then plays    */
/* the second sound asynchronously.					       */

OSErr	ASndPlay (Handle My_snd_Handle, Boolean stopPrev)

{
	OSErr	err = noErr;

	AStopSnd (stopPrev);

	err = SndNewChannel( &gSndChannel, 0, 0, (ProcPtr) CallBack);
	if (err == noErr)
	{
		err = SndPlay (gSndChannel, My_snd_Handle, TRUE);
		if (err == noErr)
		{
			gSndPlaying = TRUE;
			myCommand.cmd = callBackCmd;
			myCommand.param2 = SetCurrentA5 ();
			err = SndDoCommand (gSndChannel, &myCommand, FALSE);
		}
	}
	return (err);
}
	
/*=========================================================*/
/*   AStopSnd stops an asyncronous sound from playing.     */
/*   It also must be called at the end of the program.     */
/*   If Stop_Now is TRUE, it stops the current sound immed- */
/*   iately.  Otherwise, it waits (here) until the sound   */
/*   is finished playing, then exits.                      */

void AStopSnd (Boolean Stop_Now)

{
	SndDisposeChannel (gSndChannel, Stop_Now);
	gSndChannel = 0;
	gSndPlaying = FALSE;
}