lsr@Apple.COM (Larry Rosenstein) (05/10/89)
[Asynchronous Sound Code] Enclosed is the source for an MPW Pascal unit that shows how to play asynchronous sounds with the Sound Manager. I have tried this unit only on System 6.0.2; supposdly there are bugs in earlier versions of the Sound Manager. This unit also doesn't check for the existence of the Sound Manager, I assume that you do this at a higher level. I used this in a simple MacApp program that will open any file and allow you to play any snd resource in the file ansynchronously. (I started this with the idea of allowing copy & paste, but haven't gotten that far yet. If there is interest, I can post that program.) Larry Rosenstein, Object Specialist Apple Computer, Inc. 20525 Mariani Ave, MS 46-B Cupertino, CA 95014 AppleLink:Rosenstein1 domain:lsr@Apple.COM UUCP:{sun,voder,nsc,decwrl}!apple!lsr --- (* A simple unit that demonstrates how to produce asynchronous sound with the Macintosh Sound Manager. Although I am pretty confident about this code, I don't guarantee that this code demonstrates the correct way to do things. It does seem to work reliably. This unit doesn't solve any of the tricky issues about using the Sound Manager. Primarily, sound channels should be disposed of as soon as they are no longer needed. This code does just that, but it doesn't prevent your program or a background program from trying to make sound. Changes: 2/16/89 Lock the sound resource; state restored in call back gSoundPlaying is the actual handle. Larry Rosenstein Apple Computer, Inc. lsr@Apple.COM Copyright 1988-1989 Apple Computer Inc. All Rights Reserved. *) UNIT UAsynchSnd; INTERFACE USES MemTypes, Quickdraw, OSIntf, ToolIntf; { call this before any other routine } PROCEDURE InitUAsynchSnd; { returns TRUE if an asynchronous sound is playing } FUNCTION IsSoundPlaying: BOOLEAN; { equivalent to SndPlay, but does it asynchronously; if you call this while another sound is playing, the first one will be stopped } FUNCTION ASynchSndPlay(sndHandle: Handle): OSErr; { stop the sound from playing; may be called even if no sound is currently playing } PROCEDURE StopAsynchSound; { should be called when your program exits } PROCEDURE TerminateUAsynchSnd; IMPLEMENTATION VAR gSoundPlaying: Handle; gSoundState: SignedByte; gSndChannel: SndChannelPtr; PROCEDURE ChanCallBack(chan: SndChannelPtr; cmd: SndCommand); FORWARD; FUNCTION GetA5: LONGINT; INLINE $2E8D; {MOVE.L A5,(A7)} FUNCTION LoadA5(newA5: LONGINT): LONGINT; INLINE $2F4D,$0004,$2A5F; (********************) PROCEDURE InitUAsynchSnd; BEGIN gSndChannel := NIL; gSoundPlaying := NIL; END; FUNCTION ASynchSndPlay(sndHandle: Handle): OSErr; VAR err: OSErr; aCommand: SndCommand; BEGIN StopAsynchSound; { kill the current sound & channel } err := noErr; { default value } { gSndChannel should be NIL now } err := SndNewChannel(gSndChannel, 0, 0, @ChanCallBack); { We don't specify a synthesizer, since we are assuming that the snd resource specifies one. For example, the standard Clink-Klank snd resource doesn't use the sampled synthesizer. } gSoundState := HGetState(sndHandle); MoveHHi(sndHandle); HLock(sndHandle); gSoundPlaying := sndHandle; IF err = noErr THEN err := SndPlay(gSndChannel, sndHandle, TRUE); WITH aCommand DO BEGIN cmd := callBackCmd; param1 := 0; param2 := GetA5; END; IF err = noErr THEN err := SndDoCommand(gSndChannel, aCommand, FALSE); IF err <> noErr THEN StopAsynchSound; { flush channel; unlock sound } AsynchSndPlay := err; END; PROCEDURE ChanCallBack(chan: SndChannelPtr; cmd: SndCommand); VAR oldA5: LONGINT; BEGIN oldA5 := LoadA5(cmd.param2); { get the application's A5 and set it } HSetState(gSoundPlaying, gSoundState); gSoundPlaying := NIL; oldA5 := LoadA5(oldA5); { restore old A5 } END; FUNCTION IsSoundPlaying: BOOLEAN; BEGIN IsSoundPlaying := gSoundPlaying <> NIL; END; PROCEDURE StopAsynchSound; BEGIN IF gSndChannel <> NIL THEN BEGIN IF SndDisposeChannel(gSndChannel, TRUE) = noErr THEN { nothing }; gSndChannel := NIL; END; IF gSoundPlaying <> NIL THEN BEGIN HSetState(gSoundPlaying, gSoundState); gSoundPlaying := NIL; END; END; PROCEDURE TerminateUAsynchSnd; BEGIN StopAsynchSound; END; END. ---