*******************************************************************************
*
* PlaySound -- Version 3.0
*
* (C)  Copyright Apple Computer, Inc. 1988-1990
* All rights reserved.
*
* Developer Technical Support Apple II Sample Code
*
* by Jim MENSCH
*
* This program demonstrates how to use the Apple IIgs freeform sound playback
* capabilities. It allows the user to select a file containing a digitized 
* waveform and play it back at any user selected frequency. 
* 
*******************************************************************************
	eject
	
**********************************************************************
*                                                                    *
*     This program and its derivatives are licensed only for         *
*     use on Apple computers.                                        *
*                                                                    *
*     Works based on this program must contain and                   *
*     conspicuously display this notice.                             *
*                                                                    *
*     This software is provided for your evaluation and to           *
*     assist you in developing software for the Apple IIGS           *
*     computer.                                                      *
*                                                                    *
*     DISCLAIMER OF WARRANTY                                         *
*                                                                    *
*     THE SOFTWARE IS PROVIDED "AS IS" WITHOUT                       *
*     WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,               *
*     WITH RESPECT TO ITS MERCHANTABILITY OR ITS FITNESS             *
*     FOR ANY PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO             *
*     THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH            *
*     YOU.  SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU (AND            *
*     NOT APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE)               *
*     ASSUME THE ENTIRE COST OF ALL NECESSARY SERVICING,             *
*     REPAIR OR CORRECTION.                                          *
*                                                                    *
*     Apple does not warrant that the functions                      *
*     contained in the Software will meet your requirements          *
*     or that the operation of the Software will be                  *
*     uninterrupted or error free or that defects in the             *
*     Software will be corrected.                                    *
*                                                                    *
*     SOME STATES DO NOT ALLOW THE EXCLUSION                         *
*     OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY              *
*     NOT APPLY TO YOU.  THIS WARRANTY GIVES YOU SPECIFIC            *
*     LEGAL RIGHTS AND YOU MAY ALSO HAVE OTHER RIGHTS                *
*     WHICH VARY FROM STATE TO STATE.                                *
*                                                                    *
*                                                                    *
**********************************************************************
	eject
	
	case   on
	PRINT  NOGEN,NOHDR
	STRING AsIS

	PRINT PUSH,OFF
	INCLUDE 'M16.Util'
	INCLUDE 'M16.ProDOS'
	INCLUDE 'M16.QUICKDRAW'
	Include 'E16.Quickdraw'
	INCLUDE 'M16.MEMORY'
	Include 'E16.Memory'
	INCLUDE 'M16.EVENT'
	INCLUDE 'E16.Event'
	INCLUDE 'M16.LOCATOR'
	INCLUDE 'M16.MISCTOOL'
	INCLUDE 'M16.TextTOOL'
	INCLUDE 'M16.Menu'
	INCLUDE 'M16.Control'
	INCLUDE 'M16.Window'
	INCLUDE 'E16.Window'
	INCLUDE 'M16.Dialog'
	Include 'E16.Dialog'
	INCLUDE 'M16.LineEdit'
	INCLUDE 'M16.IntMath'
	INCLUDE 'M16.Scrap'
	INCLUDE 'M16.Desk'
	Include 'M16.StdFile'
	Include 'M16.Sound'
	PRINT ON

DPHandle	equ 0	; handle to Tool Direct Page area
DPPointer	equ DPHandle+4	; Pointer to Tool Direct Page area
DeRef	equ DPPointer+4	; Temprary Handle dereference area
Temp1	equ DeRef+4	; temp DPage storage for general use
ScreenMode	equ mode640	; used to set scan line SCB
ScreenWidth	equ 640	; used to set mouse	clamps 	  


;
;   Dialog Item Numbers
;

ItemPlayB	equ 1
ItemQuitB	equ 2
ItemLoadB	equ 3
ItemRad22	equ 4
ItemRad16	equ 5
ItemRad11	equ 6
ItemRad08	equ 7
ItemRadUsr	equ 8
ItemEditUsr	equ 12
ItemEditVol	equ 13


	EJECT
*******************************************************************************
*
playSounds	PROC
*
* Description:	This is the main routine of the program, it calls all
*	other major routines in the proper order.
*
*
* Inputs:	None
*
* Outputs:	None
*
* External Refs:	
	Import InitTools
	Import EventLoop
	Import CloseTools
	Import QuitParms
*
* Entry Points:
*
*******************************************************************************

	jsr InitTools

	_ShowCursor

	jsr EventLoop
	jsr CloseTools

	_Quit QuitParms

	EndP

	EJECT
*******************************************************************************
*
Globals	RECORD
*
* Description:	Global data for use in all routines of this program
*	This area also contains data used by the init file.
*
*
* Inputs:	None
*
* Outputs:	None
*
* External Refs:	None
*
* Entry Points:
	Export QuitParms
*
*******************************************************************************
*
* Standard Global Data here
*
*******************************************************************************

TitleString	str 'Apple IIgs Freeform Sound Demo'
AutString	str 'By Mensch Apple DTS -- Version: 3.0'
VersString	str 'Copyright (c) 1988-1990 Apple Computer'

MenuHeight	ds.B 2	; Stored height of menu bar
MyID	ds.B 2	; application ID
MyDP	ds.B 2	; My direct page storage

QuitFlag	ds.B 2
QuitParms	dc.L 0	; Pathname of next app
	dc.W $00	; flags

	EJECT
*******************************************************************************
*
* Application specific data
*
*******************************************************************************
theDialog	ds.L 1	; pointer to my dialog

MyDialog
	dc.W 29,60,189,460	; bounds rect...
	dc.W $FFFF	; true visible
	dc.L 0	; refcon=0
	dc.L PlayB	; Item 1
	dc.L QuitB	; Item 2
	dc.L LoadB	; Item 3
	dc.L K22B
	dc.L K16B
	dc.L K11B
	dc.L K08B
	dc.L KUsrB
	dc.L KUsrE
	dc.L KVolE
	dc.L KVolS
	dc.L STit
	dc.L NPStat
	dc.L 0	; end of list!

PlayBTitle	dc.B 4,'Play'
PlayB
	dc.W 1
	dc.W 142,316,0,0
	dc.W buttonItem	; standard button
	dc.L PlayBTitle
	dc.W 0
	dc.W 0	; item flag
	dc.L 0	; no color table

QuitBTitle	dc.B 4,'Quit'
QuitB
	dc.W 2
	dc.W 123,316,0,0
	dc.W buttonItem	; standard button
	dc.L QuitBTitle
	dc.W 0
	dc.W 0	; item flag
	dc.L 0	; no color table

LoadBTitle	dc.B 7,'Open...'
LoadB
	dc.W 3
	dc.W 105,308,0,0
	dc.W buttonItem	; standard button
	dc.L LoadBTitle
	dc.W 0
	dc.W 0	; item flag
	dc.L 0	; no color table

K22BTitle	dc.B 6,'22 Khz'
K22B
	dc.W 4
	dc.W 30,10,40,190
	dc.W radioItem	; radio button
	dc.L K22BTitle
	dc.W 0
	dc.W 1	; item flag: Family 1
	dc.L 0	; no color table

K16BTitle	dc.B 6,'16 Khz'
K16B
	dc.W 5
	dc.W 45,10,55,190
	dc.W radioItem	; radio button
	dc.L K16BTitle
	dc.W 0
	dc.W 1	; item flag
	dc.L 0	; no color table

K11BTitle	dc.B 6,'11 Khz'
K11B
	dc.W 6
	dc.W 60,10,70,190
	dc.W radioItem	; radio button
	dc.L K11BTitle
	dc.W 0
	dc.W 1	; item flag:Family 1
	dc.L 0	; no color table

K08BTitle	dc.B 6,' 8 Khz'
K08B
	dc.W 7
	dc.W 75,10,85,190
	dc.W radioItem	; radio button
	dc.L K08BTitle
	dc.W 0
	dc.W 1	; item flag: family 1
	dc.L 0	; no color table

KUsrBTitle	dc.B 17,'User Supplied:  $'
KUsrB
	dc.W 8
	dc.W 90,10,100,154
	dc.W radioItem	; radio button
	dc.L KUsrBTitle
	dc.W 0
	dc.W 1	; item flag: family 1
	dc.L 0	; no color table


KUsrEDef	dc.B 6,'00FF'
KUsrE
	dc.W 12
	dc.W 88,154,102,196
	dc.W editLine
	dc.L KUsrEDef
	dc.W 4	; maximum length of	edit item
	dc.W 0	; item flag
	dc.L 0	; no color table

KVolEDef	dc.B 6,'00FF'
KVolE
	dc.W 13
	dc.W 28,252,42,294
	dc.W editLine+itemDisable
	dc.L KVolEDef
	dc.W 4
	dc.W 0	; item flag
	dc.L 0	; no color table

STitTitle	dc.B 50,'Digitized sound player By Jim Mensch Apple II DTS'
STit
	dc.W 9
	dc.W 1,10,11,380
	dc.W statText+itemDisable
	dc.L STitTitle
	dc.W 0
	dc.W 0
	dc.L 0


NPTitle	dc.B 16,'Now Playing:  ^0    '
NPNoFile	dc.B 15,'No files loaded'
NPStat
	dc.W 10
	dc.W 12,10,22,300
	dc.W statText+itemDisable
	dc.L NPTitle
	dc.W 0
	dc.W 0
	dc.L 0

KVolSTit	dc.B 10,'Volume:  $'
KVolS
	dc.W 11
	dc.W 30,180,40,252
	dc.W statText+itemDisable
	dc.L KVolSTit
	dc.W 0
	dc.W 0
	dc.L 0


Rect	ds.B 8
MyRect	ds.B 8

PromptStr	dc.B 5,'Hello'	; SFGetFile record
MyReply
MyRGood	ds.b 2
MyRFType	ds.b 2
MyRAType	ds.b 2
MyRName	ds.b 16
MyRFName	ds.b 129


OPParms
OPRefNum	dc.W 0	; ProDOS 16 open call parm block
	dc.L MyRFName
	dc.L 0
GEParms
GERefNum	dc.W 0	; ProDOS 16 GetEOF Parm block
GESize	dc.L 0

RDParms		; ProDOS 16 read parm block
RDRefNum	dc.W 0
RDDataBuf	dc.L 0
RDReqCnt	dc.L 0
	dc.L 0
CLParms
CLRefNum	dc.W 0	; ProDOS 16 close parm block

; Record used for FFStartsound to describe the freeform wave

MyFFRecord	dc.L 0	; address of wave
	dc.W 0	; size of wave in pages..
Rate	dc.W $1AC	; sample rate 22Khz
	dc.W $0100	; DOC starting address
	dc.W $8000	; DOC buffer size
	dc.L 0
Vol1	dc.W $00FF	; kinda medium..

; Table of standard sampling rates 
;	     22khz,16khz,11khz, 8khz, filler
RateTable	dc.W $01ac,$0137,$00D6,$009C,$0000,$0000

	EndR

	EJECT
*******************************************************************************
*
EventLoop	PROC
*
* Description:	This is the main routine of the program. It creates a
*	Dialog box and handles all user selections that occur. When
*	the user selects quit, this routine exits and the program
*	will then end.
*
*
* Inputs:	None
*
* Outputs:	None
*
* External Refs:
	Import SFLoop
	Import PlaySound
*
* Entry Points:	None
*
*******************************************************************************
	With Globals

	PushLong #0	; create the dialog	this program
	PushLong #MyDialog	; revolves around from a template
	_GetNewModalDialog
	PullLong theDialog	; store its pointer	into theDialog

	lda #ItemRad22	; reset radio buttons to the initial
	jsr RadHit	; state of 22Khz default freq.

	PushLong #NPNoFile	; set the Paramtext ^0 item to
	PushLong #0	; the initial file name of "no file"  
	PushLong #0
	PushLong #0
	_ParamText

EL0010	PushWord #0	; now wait for a selection by the user
	PushLong #0
	_ModalDialog
	pla	; recover the item hit from the stack

	cmp #ItemPlayB	; is it the play button?
	bne EL0020	; if not test next button
	jsr PlaySound	; if it was the play button then play
	bra EL0010	; the saved sound and get another hit

EL0020
	cmp #ItemQuitB	; is it the quit button?
	bne EL0030	; if not test next button
	bra ELDone	; if it was, end the program

EL0030
	cmp #ItemLoadB	; is it the load button?
	bne EL0040	; if not test usr Rate item
	jsr SFLoop	; if so, ask user for a new sound file
	bra EL0010	; and get another hit

EL0040
	cmp #ItemEditUsr	; see if the user changed the usr rate
	bne EL0050	; if not test radio buttons
	jsr SetUsr	; if so, get the new value
	bra EL0010
EL0050
; If we get this far, the only thing we have left to test for is radio buttons
; and the radio buttons are items 4-8
	cmp #9	; test to see if 3<ItemHit<9
	bge EL0060	; if not then skip the next line
	jsr RadHit	; if so then a radio button was hit
	bra EL0010	; handle it and get another hit

EL0060
	brl EL0010	; this should not occur since no other
;		  items are enabled

; When the user selects quit the program branches here to close the dialog
; and go back and close down the program
ELDone
	PushLong theDialog	; close the dialog and dispose of all
	_CloseDialog	; memory used by it
	rts	; and return to the main loop

; RadHit is called when the user selects any radio button. This routine
; turns off all radio buttons and turns on the one that the user hit.
; It then finds the correct value for the selected rate in RateTable
; and inserts  it into the waveform data.
; If the user selects the "User Supplied" sampling rate option, This
; routine will call SetUsr to obtain the users rate value.
RadHit
	sta Temp1	; save the item hit	number

;	PushWord #0	; and turn off all radio buttons
;	PushLong theDialog
;	PushWord #ItemRad22
;	_SetDItemValue;;
;
;	PushWord #0
;	PushLong theDialog
;	PushWord #ItemRad16
;	_SetDItemValue;
;
;	PushWord #0
;	PushLong theDialog
;	PushWord #ItemRad11
;	_SetDItemValue
;
;	PushWord #0
;	PushLong theDialog
;	PushWord #ItemRad08
;	_SetDItemValue
;
;	PushWord #0
;	PushLong theDialog
;	PushWord #ItemRadUsr
;	_SetDItemValue

	PushWord #1	; now turn on the radio button that 
	PushLong theDialog	; was hit
	PushWord Temp1
	_SetDItemValue

	lda Temp1	; Check to see if the user button was hit
	cmp #ItemRadUsr
	beq SetUsr1	; if so, get the user rate
	sec	; if not, get the new sampling rate
	sbc #4	; subtract 4 from choice
	asl a	; multiply it by 2
	tax	; use it as an index
	lda RateTable,x
	sta Rate
	rts

; This routine gets the users input value from the "User Supplied" edit line item
; converts it to an integer and stores it as the current sampling rate
SetUsr
	PushWord #1
	PushLong theDialog
	PushWord #ItemRadUsr
	_SetDItemValue
SetUsr1
	PushLong theDialog	; get the text from	the user sampleing
	Pushword #ItemEditUsr ; rate item
	PushLong #tempAns
	_GetIText

	PushWord #0	; and convert it to	an integer
	PushLong #tempAns+1	; Skip the length byte
	lda tempAns	; push the length byte seperately
	and #$00FF	; after stripping off extra data
	pha
	_Hex2Int

	pla	; store this number	as the new rate
	sta Rate
	rts
tempAns	ds.B 8

	EndP


	EJECT
*******************************************************************************
*
LoadSound	PROC
*
* Description:	Procedure that loads a selected file from disk and stores
*	it in RDDataBuf.
*
*
* Inputs:	MyRFName should contain the full pathname of the file to load
*
* Outputs:	Data in the handle RDDataBuf
*
* External Refs:
	Import PDosError
	Import ToolError
*
* Entry Points:	None
*
*******************************************************************************
	With Globals

	lda RDDataBuf	; check handle to see if its already 
	ora RDDataBuf+2	; allocated by seeing if its 0
	beq LS0010	; if it is, skip next line

	PushLong RDDataBuf	; if non-zero then de-allocate
	_DisposeHandle	; the memory

LS0010
	_Open OPParms	; open the file chosen by user
	bcc LS0015	; no error, branch around next line
	jsr PDosError	; got error, report to user
	brl LoadDone	; and end this routine

LS0015
	lda OPRefNum	; save the file ref	number into all
	sta RDRefNum	; the other parm blocks 
	sta GERefNum
	sta CLRefNum
 
; Now that the file is opened we ask ProDOS for the length of the file.
; Once recieved we create a handle to read the data into and update the FFRecord
; to reflect the size and location of the data.

	_Get_EOF GEParms	; Find out how big the file is
	bcc LS0020	; so we can create the right sized buffer
	jsr PDosError	; we got an error, so report it and...
	brl LoadCDone	; file open was succesfull, so close it
LS0020
	lda GESize	; first, update the read request count so
	sta RDReqCnt	; read call knows how much to load
	lda GESize+2	; Now get the high word of the file size
	sta RDReqCnt+2	; and finish updating the read parms
	lda RDReqCnt+1	; get the number of 256 byte pages
	sta MyFFRecord+4	; and update the FFRecord

	PushLong #0	; reserve memory for the waveform
	PushLong GESize
	PushWord MyID
	PushWord #%1100000000001100
	PushLong #0
	_NewHandle
	bcc LS0025
	jsr ToolError
	brl LoadCDone

LS0025
	pla	; dereference the handle to get the
	sta DeRef	; pointer
	pla
	sta DeRef+2

	lda [DeRef]
	sta RDDataBuf	; store the pointer into the read parms 
	sta MyFFRecord	; and the FFRecord

	ldy #2
	lda [DeRef],y
	sta RDDataBuf+2
	sta MyFFRecord+2

	_Read RDParms	; Read the data from the file
	bcc LS0030
	jsr PDosError
	brl LoadCDone
LS0030
LoadCDone
	_Close CLParms	; and finally close the file
	bcc LoadDone
	jsr PDosError
LoadDone
	rts	; and leave

	EndP

	EJECT
*******************************************************************************
*
PlaySound	PROC
*
* Description:	Tell the sound managerto start the digitized sound
*	descripbed by myFFRecord
*
*
* Inputs:	None
*
* Outputs:	None
*
* External Refs:	
	Import ToolError
*
* Entry Points:	None
*
*******************************************************************************
	With Globals

	PushLong theDialog	; get the volume from the Dialog
	Pushword #ItemEditVol ; box. 
	PushLong #tempAns	; 
	_GetIText

	PushWord #0	; convert the ASCII	hexidecimal value to
	PushLong #tempAns+1	; an integer.
	lda tempAns	; load length of the string
	and #$00FF	; strip off the high byte
	pha	; and push it onto the stack as out length
	_Hex2Int

	pla
	sta Vol1	; store this value into our volume


	PushWord #$0001	; stop gen 0
	_FFStopSound

	PushWord #$0001	; and start the sound at gen 0
	PushLong #MyFFRecord
	_FFStartSound
	bcc PS0010	; if no error then just end
	jsr ToolError	; However, if an error occured report it
PS0010
	rts

tempAns	ds.B 8	; temporary storage for the str convert

	EndP

**********************************************************************************
*
*   SFLoop -    Throw up a sfGetFile dialog and let the user select file of
*               their choice.
*
	EJECT
*******************************************************************************
*
SFLoop	PROC
*
* Description:	Call SFGetFile to obtain the users choice of sound file
*	to playback. If the user selects a valid file, load it and
*	play it. If the user selects cancel, do nothing.
*
*
* Inputs:	None
*
* Outputs:	None
*
* External Refs:	
	Import LoadSound
	Import PlaySound
*
* Entry Points:
*
*******************************************************************************
	With Globals

	PushWord #30	; Location of dialog on screen
	PushWord #30

	PushLong #PromptStr	; promtp for within	the dialog
	PushLong #0	; no filter proc
	PushLong #0	; no type list
	PushLong #MyReply	; record to put user selection
	_SFGetFile

	lda MyRGood	; test if cancel hit...
	sta QuitFlag	; save it in quitflag
	beq SFQuit	; and just quit

	jsr LoadSound	; Now load the file	into the buffer
	jsr PlaySound	; and play the loaded file


	PushLong #MyRName	; set Param ^0 as the name of the
	PushLong #0	; file for display in the didlog box
	PushLong #0
	PushLong #0
	_ParamText

SFQuit	rts
	EndP

	EJECT
*******************************************************************************
*
PDosError	PROC
*
* Description:	Reports an error to the user and calls it a ProDos error.
*
*
* Inputs:	<A> - error code to report
*
* Outputs:	None
*
* External Refs:	None
*
* Entry Points:	None
*
*******************************************************************************
	With Globals

	pha	; and convert the error to a string
	PushLong #ErrorNum
	PushWord #4
	_Int2Hex
	
; Use the window manager AlertWindow call to report the error message
	pha	; space for result
	PushWord #0	; we are using P-Strings
	PushLong #SubStringA
	PushLong #AlertStr
	ldx #$590E	; _AlertWindow
	jsl $E10000
	pla	; pull off button hit


	rts
tempError	ds.B 2
SubStringA	DC.L ErrorNum	; substitution string array
ErrorNum	dc.B 'xxxx',0
AlertStr	dc.B '24/ProDOS Error Loading File #*0/^#6'
	dc.B 0

	EndP

	EJECT
*******************************************************************************
*
ToolError	PROC
*
* Description:	Report an error to the user and say it was a tool error.
*
*
* Inputs:	<A> error number to report
*
* Outputs:	None
*
* External Refs:	None
*
* Entry Points:	None
*
*******************************************************************************
	With Globals

	pha
	PushLong #ErrorNum
	PushWord #4
	_Int2Hex

	pha	; space for result
	PushWord #0	; we are using P-Strings
	PushLong #SubStringA
	PushLong #AlertStr
	ldx #$590E	; _AlertWindow
	jsl $E10000
	pla	; pull off button hit


	rts
SubStringA	DC.L ErrorNum	; substitution string array
ErrorNum	dc.B 'xxxx',0
AlertStr	dc.B '24/Tool Error #*0/^#6'
	dc.B 0

	EndP

	Include 'PlaySound.init.aii'

	END

