*******************************************************************************
*
* Math -- Version 3.0
*
* (C)  Copyright Apple Computer, Inc. 1988-1990
* All rights reserved.
*
* Developer Technical Support Apple II Sample Code
*
* by Jim Mensch
*
* Sample to show how to use the Integer math and SANE tools. This program shows
* 2 basic operations performed both with the integer math tools and SANE. The
* first is the calculation and display of a simple SINE curve. The second is
* a more complex Fast Fourier Transform.
*
*******************************************************************************
	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  NOHDR,NOGEN
	STRING AsIS

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

*******************************************************************************
*
* Math Macros
*
* Description:	The following macros are given to take care of some common
*	operations used when you are using SANE or IntMath.
*
*
*
*******************************************************************************

;------------------------------------------------------------------------------
;
; Copy and extended value from one variable to another
;
; ExtendEq SrcLoc,DestLoc - Copies 10 bytes from srcloc to DestLoc
;
;------------------------------------------------------------------------------
	MACRO
	ExtendEq &SrcLoc,&DestLoc
	lda &SrcLoc
	sta &DestLoc
	lda &SrcLoc+2
	sta &DestLoc+2
	lda &SrcLoc+4
	sta &DestLoc+4
	lda &SrcLoc+6
	sta &DestLoc+6
	lda &SrcLoc+8
	sta &DestLoc+8
	MEND
	
;-----------------------------------------------------------------------------
;
; Push a long space on the stack for fuction results
;
; LongResult
;
;-----------------------------------------------------------------------------
	MACRO
	LongResult
	pha
	pha
	mend
	
;-----------------------------------------------------------------------------
;
; Store 0's into an Extended number
;
; STZEXT Dest - Stores 10 bytes of 0 into Dest
;
;------------------------------------------------------------------------------
	MACRO
	STZEXT &Dest
	stz &Dest
	stz &Dest+2
	stz &Dest+4
	stz &Dest+6
	stz &Dest+8
	mend
	
;------------------------------------------------------------------------------
;
; Store 0's into a longword
;
; STZL Dest - stores 4 bytes of 0 into Dest
;
;------------------------------------------------------------------------------
	MACRO
	STZL &Dest
	stz &Dest
	stz &Dest+2
	mend

*******************************************************************************

	PRINT POP

DPHandle	equ 0
DPPointer	equ DPHandle+4
DeRef	equ DPPointer+4

ScreenWidth	equ 640
ScreenMode	equ $80

	EJECT
*******************************************************************************
*
Math	PROC
*
* Description:	This main routine calls the other major routines in the 
*	correct order.
*
*
* Inputs:	None
*
* Outputs:	None
*
* External Refs:
	Import QuitParms
	Import InitTools
	Import InitApp
	Import EventLoop
	Import CloseTools
	Import CloseApp
*
* Entry Points:	None
*
*******************************************************************************

	jsr InitTools
	jsr InitApp

	_ShowCursor

	jsr EventLoop
	jsr CloseApp
	jsr CloseTools

	_Quit QuitParms

	EndP

	EJECT
*******************************************************************************
*
Globals	RECORD
*
* Description:	Global data for use in all routines of this demo. This area
*	also contains the data used by StandardLib.aii	
*
*
* Inputs:	None
*
* Outputs:	None
*
* External Refs:
	import displayCache
*
* Entry Points:
	export QuitParms	; used by Main
*
*******************************************************************************
*
* Standard global data
*
*******************************************************************************

TitleString	str 'Apple IIgs Integer Math/Sane demo'
AutString	str 'By Jim 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

EventRecord
EventWhat	ds.B 2
EventMessage	ds.B 4
EventWhen	ds.B 4
EventWhere	ds.B 4
EventModifiers	ds.B 2
TaskData	ds.B 4
TaskMask	dC.L $0000FFFF

portCacheInfo	ds.b 4
	ds.b 4
	ds.b 4
	ds.b 4
	dc.w $C000
	dc.w 0,0,175,599
	dc.w 0,0,175,599

	EJECT
*******************************************************************************
*
* Application specific global data
*
*******************************************************************************

; This is a list of pointers to the text that is used to create our menus. It
; is used by InitApp to find all of the menu templates and use them to create
; our menubar. This loop loads MenuPtrLen-4 into an index, gets the
; corresponding menu template pointer in this table, and uses that in a
; NewMenu call. It then decrements the index by 4, and repeats the procees
; until the index is negative.

MenuPtr	dc.l AppMenu
	dc.l FileMenu
MenuPtrLen	equ *-MenuPtr


; Menu list: menu items should be numbered consecutivly starting from 250.
; As a convention, use 256 as about and 257 as Quit.



AppMenu	dc.B '$$@\XN1',$0D
	dc.B '--About Math...\N256V',$00
	dc.B '.'
FileMenu	dc.B '$$ File \N2',$0D
	dc.B '--SANE Fast Fourier transform\N260',$00
	dc.B '--Integer Fast Fourier transform\N261',0
	dc.B '--Integer Sine wave\N258*Ii',$00
	dc.B '--SANE Sine wave\N259*SsV',$00
	dc.B '--Quit\N257*Qq',$00
	dc.B '.'

; Paramater block used to create the main window for display. All the
; graphing routines will use this window to draw into.

MyWindow	dc.W WindEnd-*	; size of paramBlock
	dc.W %0010000000100000 ; frame bits : alert, vis
	dc.L 0	; no title bar, no title...
	dc.L 0	; ref con 0
	dc.W 0,0,0,0	; zoomed rect
	dc.L 0	; color table = default
	dc.W 0,0	; scroll bar XY origin
	dc.W 0,0	; no scroll no max...
	dc.W 0,0	; No zooming...
	dc.W 0,0	; no scrolling
	dc.W 0,0	; no paging....
	dc.L 0	; no info bar, no ref con
	dc.W 0	; info bar height (	none...)
	dc.L 0	; Frame defproc, NIL=standard
	dc.L 0	; no info bar def proc
	dc.L displayCache	; update procedure to display cache
	dc.W 20,20,195,619	; bounds rect...
	dc.L $FFFFFFFF	; plane= on top...
	dc.L 0	; NIL storage pointer
WindEnd	equ *
ContRect	dc.W 0,0,180,599	; content rectangle

WindPointer	ds.B 4

; Constants used thru the program both represent PI*2

TwoPi	dc.b $1D,$72,$33,$DC,$80,$CF,$0F,$C9,$01,$40
TwoPiFix	dc.W $487E,$0006

; Titles for the bottom of the window

IntSineTitle	str 'Integer Math Demo: plotting Y=SIN(X)'
SANESineTitle	str 'SANE Demo: plotting Y=SIN(X)'
IntHarmTitle	str 'Integer Math Demo: plotting complex waveform'
SANEHarmTitle	str 'SANE Demo: plotting complex waveform'
	EndR
	
	EJECT
*******************************************************************************
*
InitApp	PROC
*
* Description:	This routine creates our window and zeros out the quitflag
*
*
* Inputs:	None
*
* Outputs:	None
*
* External Refs:
	Import newPort
*
* Entry Points:	None
*
*******************************************************************************
	With Globals

	Stz QuitFlag	; zero out quit flag

	PushLong #0
	PushLong #MyWindow
	_NewWindow	; create a window to graph in
	PullLong WindPointer

	PushLong WindPointer
	_SetPort	; make the new window the current port

	pha
	pha
	pea portCacheInfo>>16
	pea portCacheInfo
	jsl newPort
	pla	; The result is also stored in portCacheInfo.
	pla

	rts
	EndP

	EJECT
*******************************************************************************
*
CloseApp	PROC
*
* Description:	This routine will be called at program end to dispose of
*	the window.
*
*
* Inputs:	None
*
* Outputs:	None
*
* External Refs:
	Import killPort
*
* Entry Points:	None
*
*******************************************************************************
	With Globals

	PushLong WindPointer
	_CloseWindow

	pea portCacheInfo>>16
	pea portCacheInfo
	jsl killPort

	rts
	EndP

	EJECT
*******************************************************************************
*
EventLoop	PROC
*
* Description:	Main loop. Handles events until the user selects quit
*
*
* Inputs:	None
*
* Outputs:	None
*
* External Refs:
	Import Ignore
	Import MenuSelect
*
* Entry Points:
*
*******************************************************************************
	With Globals


	pha	; Push on space for TaskMaster result
	PushWord #$FFFF	; GetNextEvent mask
	PushLong #EventRecord ; Pointer to Event Record
	_TaskMaster

	pla	; Get TaskMaster result
	beq EventLoop	; Remove if you want to use null events
	asl A	; Turn it into an index
	tax
	jsr (TaskTable,x)	; Call appropriate event handler

	lda QuitFlag	; Quit selected?
	beq EventLoop	; no - keep looping

	rts	; yes- leave the program


TaskTable	dc.W Ignore	; 0 Null
	dc.W Ignore	; 1 MouseDown
	dc.W Ignore	; 2 Mouse Up
	dc.W Ignore	; 3 KeyDown
	dc.W Ignore	; 4 Undefined
	dc.W Ignore	; 5 AutoKey
	dc.W Ignore	; 6 Update
	dc.W Ignore	; 7 undefined
	dc.W Ignore	; 8 activate
	dc.W Ignore	; 9 Switch
	dc.W Ignore	; 10 desk acc
	dc.W Ignore	; 11 device driver
	dc.W Ignore	; 12 ap
	dc.W Ignore	; 13 ap
	dc.W Ignore	; 14 ap
	dc.W Ignore	; 15 ap
	dc.W Ignore	; TASK 0 indesk
	dc.W MenuSelect	; TASK 1 in menuBar
	dc.W Ignore	; TASK 2 in system window
	dc.W Ignore	; TASK 3 in content
	dc.W Ignore	; TASK 4 in Drag
	dc.W Ignore	; TASK 5 in grow
	dc.W Ignore	; TASK 6 in goaway
	dc.W Ignore	; TASK 7 in zoom
	dc.W Ignore	; TASK 8 in info bar
	dc.W Ignore	; TASK 9 in special	menu
	dc.W Ignore	; TASK 10 in NDA
	dc.W Ignore	; TASK 11 in frame
	dc.W Ignore	; TASK 12 in drop	        

	EndP
	
	EJECT
*******************************************************************************
*
MenuSelect	PROC
*
* Description:	This routine is called when taskmaster returns a code
*	indicating that the user selected one of our menu options.
*	This routine will call whatever routine is indicated for
*	each menu action
*
*
* Inputs:	TaskData - menu selected by the user
*
* Outputs:	None
*
* External Refs:
	Import Ignore
	Import doAbout
	Import doQuit
	Import IntSineCurve
	Import SANESineCurve
	Import IntHarmWave
	Import SANEHarmWave
*
* Entry Points:
*
*******************************************************************************
	With Globals

	lda TaskData	; get the ID of the menu item selected
	sec	; adjust it to be between 0 and 5
	sbc #256
	asl a	; multiply it by 2
	tax	; and use it as an index into our jump
	jsr (MenuTable,x)	; table.

MSDone
	PushWord #0	; menu action complete, unhilite the
	PushWord TaskData+2	; selected menu to show we are done
	_HiliteMenu

	rts	; and quit

MenuTable	dc.W doAbout	; about shell...
	dc.W doQuit	; quit selected
	dc.W IntSineCurve	; draw integer math	sine wave
	dc.W SANESineCurve	; draw sane sine wave
	dc.W SANEHarmWave
	dc.W IntHarmWave
	EndP

	EJECT
*******************************************************************************
*
doQuit	PROC
*
* Description:	Sets the quit flag to inform the event loop that the user
*	wants to stop the program
*
*
* Inputs:	None
*
* Outputs:	None
*
* External Refs:	None
*
* Entry Points:	None
*
*******************************************************************************
	With Globals

	lda #$FFFF
	sta QuitFlag
	rts
	EndP

*******************************************************************************
*
Ignore	PROC
*
* Description:	Called when the program gets an event or menu selection that
*	it does not want to handle
*
*
* Inputs:	None
*
* Outputs:	None
*
* External Refs:	None
*
* Entry Points:	None
*
*******************************************************************************
	rts
	EndP

	EJECT
*******************************************************************************
*
setCachePort	PROC
	export setViewPort, displayCache
	with   Globals

	plx	;Clone enough of the stack.
	tsc
	sta keepStackPtr
	ldy #10
aa	lda 10*2-1,s
	pha
	dey
	bne aa
	phx

	lda portCacheInfo+2	;Switch to cache port.
	pha
	lda portCacheInfo
	pha
	_SetPort

	rts

setViewPort	plx	;Set the stack back to before cloning.
	lda keepStackPtr
	tcs
	phx

	lda WindPointer+2
	pha
	lda WindPointer
	pha
	_SetPort

	rts

keepStackPtr	dc.w 0

displayCache	pha
	pha
	_GetPort

	lda portCacheInfo+2
	pha
	lda portCacheInfo
	pha
	_SetPort

	pea cacheLocInfo>>16
	pea cacheLocInfo
	_GetPortLoc

	pea cachePortRect>>16
	pea cachePortRect
	_GetPortRect

	_SetPort

	pea cacheLocInfo>>16
	pea cacheLocInfo
	pea cacheBoundsRect>>16
	pea cacheBoundsRect
	lda #0
	pha
	pha
	pha
	_PPToPort
	rtl

cacheLocInfo	ds.b 8
cacheBoundsRect	ds.b 8
cachePortRect	ds.b 8

	endp
*
*******************************************************************************



*******************************************************************************
*
IntSineCurve	PROC
*
* Description:	This routine will calculate a simple Sine curve and display
*	it graphically on the screen.	
*
*
* Inputs:	None
*
* Outputs:	None
*
* External Refs:	None
*
* Entry Points:	None
*
*******************************************************************************
	With Globals

	_WaitCursor

	PushLong #ContRect	; first, start with a clean screen
	jsr setCachePort	; by erasing the old screen
	_EraseRect
	jsr setViewPort
	_EraseRect

	PushWord #10	; label the bottom of the window
	PushWord #170	; to show what we are doing
	jsr setCachePort
	_MoveTo
	jsr setViewPort
	_MoveTo

	PushLong #IntSineTitle
	jsr setCachePort
	_DrawString
	jsr setViewPort
	_DrawString

	stzL LoopCount	; zero the counter to start this thing

	PushWord #0	; start this drawing off
	PushWord #80
	jsr setCachePort
	_MoveTo
	jsr setViewPort
	_MoveTo


DIMLoop
	LongResult	; space for results	here for all the
	LongResult	; following calculations. by pushing
	LongResult	; the space here, we do not need to 
	LongResult	; adjust the stack between int math calls
	LongResult	; and we save time and space
	
	PushLong LoopCount	; Calc: LoopCount/180
	PushLong One80	; 
	_FixDiv	; leave result on stack for next calc
		
	PushLong RFixPi	; Calc (LoopCount/180)*PI
	_FixMul	; to convert LoopCount to radians
	
	_FracSin	; take the sine of the counter
	
	_Frac2Fix	; convert it back to fixed #
	
	PushLong Eighty	; multiply it by 80 to scale
	_FixMul	; we have our number!
	PullLong YCord	; and its the y coordinate

	PushWord LoopCount+2 ; X coordinate (HiWord of Fixed)
	lda YCord+2	; Y coordinate + 80
	clc	; to scale the number between
	adc #80	; 0 and 160
	pha
	jsr setCachePort
	_LineTo	; draw the linesegment for this point
	jsr setViewPort
	_LineTo

	inc LoopCount+2	; bump the loopcounter
	lda LoopCount+2	; and see if we have reached 360
	cmp #360	; for a full SINE curve
	bge DIMDone	; if so, then finish the loop
	brl DIMLoop	; if not do the next iteration

DIMDone	_InitCursor
	rts	; finish the routine

LoopCount	ds.B 4	; Fixed number to store degrees
One80	dc.W 0,180	; a fixed number representing 180
Eighty	dc.W 0,80	; a FIxed number represenging 80
YCord	ds.B 4	; temp storage for the y coordinate
RFixPi	dc.L $0003243F	; 3.14159 (PI in fixed format)
	EndP

	EJECT
*******************************************************************************
*
SANESineCurve	PROC
*
* Description:	This routine will use the SANE toolset to calculate
*	a Sine curve. It will then plot the points on the screen.
*
*
* Inputs:	None
*
* Outputs:	None
*
* External Refs:	None
*
* Entry Points:	None
*
*******************************************************************************
	With Globals

	_WaitCursor

	PushLong #ContRect	; first, start with a clean screen
	jsr setCachePort	; by erasing the old screen
	_EraseRect
	jsr setViewPort
	_EraseRect

	PushWord #10	; label the bottom of the window
	PushWord #170	; to show what we are doing
	jsr setCachePort
	_MoveTo
	jsr setViewPort
	_MoveTo

	PushLong #SANESineTitle
	jsr setCachePort
	_DrawString
	jsr setViewPort
	_DrawString
	
	PushWord #0	; start this drawing off
	PushWord #80	; in the middle of the screen
	jsr setCachePort
	_MoveTo
	jsr setViewPort
	_MoveTo
	
	stz LoopCount

DSaneLoop
	ExtendEq SanePi,TempResult ; move pi/180 into the result

	PushLong #LoopCount	; convert LoopCount to Radians
	PushLong #TempResult
	FMULI	; by multiplying by pi/180

	PushLong #TempResult
	FSINX	; now get the SINE of it

	PushLong #Eighty	; multiply by 80
	PushLong #TempResult
	FMULI

	PushLong #TempResult
	PushLong #YCord	; convert to an Integer
	FX2I

	PushWord LoopCount	; X coordinate
	lda YCord	; Y coordinate + 80
	clc	; to get a number between 
	adc #80	; 0 and 160
	pha
	jsr setCachePort	; draw the line segement
	_LineTo
	jsr setViewPort
	_LineTo

	inc LoopCount	; bump the counter
	lda LoopCount
	cmp #360	; and see if we have done all 360 degrees
	bge DSaneDone	; if so then end
	brl DSaneLoop	; if not, get next value

DSaneDone	_InitCursor
	rts

LoopCount	ds.B 4
SanePi	dc.B $AE,$C8,$E9,$94,$12,$35,$FA,$8E,$F9,$3F ; pi/180 ...
TempResult	ds.B 10
Eighty	dc.L 80
YCord	ds.B 4
	EndP


	EJECT
*******************************************************************************
*
FFTransData	Record
*
* Description:	Data used by both FFT calculation routines
*
*
* Inputs:	None
*
* Outputs:	None
*
* External Refs:	None
*
* Entry Points:	None
*
*******************************************************************************

FixCount	dc.W 0	; fractional portsion of our
Count	ds.B 2	; fixed point counter
LoopCount	ds.B 2
FixSamp	dc.W 0	; fractional portion of the sample var
Sample	ds.B 2	; sample to figure for
FixMaxSamp	dc.W 0	; fractional portion of Max Sample
MaxSample	dc.W 256	; maximum number of	samples
MaxHarm	dc.W 6	; maximum number of harmonics
MaxValue	ds.B 10	; maximum vaule of the FFT
AmpTbl	dc.W 0,10,8,6,4,2,1	; amplitudes of each harmonic
PhaseTbl	dc.W 0,1,2,4,6,8,10	; high word of each fixed phase
PhaseTblF	dc.L 0,6554,13107,26214,39321,52428,$FFFF
TempValue	ds.B 10	; intermediate result storage
TempFactor	ds.B 10
Temp1	ds.B 10
Temp2	ds.B 10
FFTWave	ds.B 2560	; table to hold intermediate values
MyDecForm	dc.W 1
	dc.W 8	; 8 digits after the decimal place
TempI	ds.B 2
TempF	ds.B 4
Const127	dc.W 79
Const80Fix	dc.L $004F000
Const10	dc.W 10
	EndR


	EJECT
*******************************************************************************
*
SANEHarmWave	proc
*
* Description:	Create a complex harmonic wave using SANE
*
*
* Inputs:	None
*
* Outputs:	None
*
* External Refs:
	Import SaneFFTIteration
	Import doNormIter
*
* Entry Points:
*
*******************************************************************************

	With Globals
	With FFTransData

	_WaitCursor

	PushLong #ContRect	; first, start with a clean screen
	jsr setCachePort	; by erasing the old screen
	_EraseRect
	jsr setViewPort
	_EraseRect

	PushWord #10	; label the bottom of the window
	PushWord #170	; to show what we are doing
	jsr setCachePort
	_MoveTo
	jsr setViewPort
	_MoveTo
	
	PushLong #SANEHarmTitle
	jsr setCachePort
	_DrawString
	jsr setViewPort
	_DrawString
	

	PushWord #0	; start this drawing off
	PushWord #80	; at the left edge
	jsr setCachePort
	_MoveTo
	jsr setViewPort
	_MoveTo

	stz Sample	; and zero out all global values
	STZEXT MaxValue
	STZEXT Temp1
	STZEXT Temp2
	STZEXT TempFactor

DHWLoop1	jsr SaneFFTIteration ; do one iteration

	lda Sample	; now save tempValue into our array
	asl a	; multiply by 2
	sta Temp1	; and save it for a	sec
	asl a
	asl a	; multiply by 8
	clc
	adc Temp1	; x*8+x*2=x*10
	tax	; use as an index into the sample array

	lda TempValue	; now stow the current value
	sta FFTWave,x	; into our wave table. Later this
	lda TempValue+2	; table will be normalized
	sta FFTWave+2,x
	lda TempValue+4
	sta FFTWave+4,x
	lda TempValue+6
	sta FFTWave+6,x
	lda TempValue+8
	sta FFTWave+8,x

	inc Sample	; bump the sample counter
	lda #255
	cmp Sample	; test to see if we have reached the 
	bge DHWLoop1	; last sample, if not do the next one

; if the last sample was reached, it is time to go thru the wavetable and
; convert all the number so they are between 0 and 160.
	
	stz Count	; initialize the index
DHWLoop2	inc Count
	jsr doNormIter	; normalize one iteration

	PushWord Count	; X coordinate
	PushWord TempValue	; value returned by doNormIter
	jsr setCachePort	; draw the line
	_LineTo
	jsr setViewPort
	_LineTo

	lda #255	; see if the counter has reached the max
	cmp Count	; sample we recorded
	bge DHWLoop2	; if not, do another point


	_InitCursor	; if it has, then we can simply end
	rts
	EndP
	
	EJECT
*******************************************************************************
*
SaneFFTIteration	PROC
*
* Description:	This routine takes the current sample value and computes
*	all the harmonic components that make up the wave for that
*	sample.
*
*
* Inputs:	Sample - current sample to compute for
*
* Outputs:	TempValue - output sample value
*
* External Refs:
*
* Entry Points:
*
*******************************************************************************
	With Globals
	With FFTransData

	STZEXT TempValue

	PushLong #Sample
	PushLong #TempFactor
	FI2X	; convert the max sample rate to extended

	PushLong #MaxSample
	PushLong #Temp1
	FI2X

	PushLong #Temp1
	PushLong #TempFactor
	FDIVX	; TempFactor:=TempFactor/Temp1

	PushLong #TwoPi
	PushLong #TempFactor
	FMULX	; TempFactor:=6.28318*(count/maxSample)

	stz Count	; zero out the counter

FFLoop
	ExtendEq TwoPi,Temp2

	lda Count	; get the count
	asl a	; multiply by 2
	tax
	lda PhaseTbl,x
	sta TempI
	PushLong #TempI
	PushLong #Temp1
	FI2X	; Temp1:=Phase[count]

	PushLong #Const10
	PushLong #Temp1
	FDIVI	; divide by 10 to make it fractional

	PushLong #Temp1
	PushLong #Temp2
	FMulX	; Temp2:=(Temp1)/10*TwoPi

	ExtendEq TempFactor,Temp1

	PushLong #Count
	PushLong #Temp1
	FMULI	; tempi:=count*TempFactor

	PushLong #Temp2
	PushLong #Temp1
	FADDX	; Temp1:=((count*TempFactor)+(6.28318*Phase[count]))

	PushLong #Temp1
	FCOSX	; Temp1:=Cos(Temp1)

	lda Count	; get the count
	asl a	; multiply by 2
	tax
	lda AmpTbl,x
	sta TempI
	PushLong #TempI
	PushLong #Temp1
	FMULI	; Temp1:=Temp1*Amp[count]

	PushLong #Temp1
	PushLong #TempValue
	FADDX	; finally tempValue:=tempValue+Temp1

	PushLong #TempValue
	PushLong #Temp1
	FX2X	; copy tempvalue into Temp1

	PushLong #Temp1
	FABSX

	PushLong #Temp1
	PushLong #MaxValue
	FCMPX	; now update the max value if needed

	FBLE FFTL010	; if the new number	<= old max ignore next line

	ExtendEq Temp1,MaxValue

FFTL010
	inc Count
	lda Count
	cmp MaxHarm	; are we done yet???
	bge FFTDone
	brl FFLoop
FFTDone	rts
	EndP

	EJECT
*******************************************************************************
*
doNormIter	Proc
*
* Description:	Normalize one iteration of the wavetable. This routine
*	takes the current sample value and converts it to 
*
*
* Inputs:	Count - current sample number
*
* Outputs:	TempValue - the normalized value
*
* External Refs:	None
*
* Entry Points:	None
*
*******************************************************************************
	With Globals
	With FFTransData

	lda Count
	asl a	; multiply by 2
	sta Temp1	; and save it for a	sec
	asl a
	asl a	; multiply by 8
	clc
	adc Temp1	; x*8+x*2=x*10
	tax

	lda FFTWave,x	; now load the current value
	sta TempValue
	lda FFTWave+2,x
	sta TempValue+2
	lda FFTWave+4,x
	sta TempValue+4
	lda FFTWave+6,x
	sta TempValue+6
	lda FFTWave+8,x
	sta TempValue+8

	ExtendEq MaxValue,Temp2

	PushLong #Temp2
	PushLong #TempValue	; divide the two
	FDIVX

	PushLong #Const127	; now scale it
	PushLong #TempValue
	FMULI

	PushLong #Const127
	PushLong #TempValue
	FADDI

	PushLong #TempValue	; now, convert ot to an integer
	PushLong #TempI
	FX2I

	lda TempI
	sta TempValue
	rts
	EndP



	EJECT
*******************************************************************************
*
IntHarmWave	PROC
*
* Description:	This routine will create a complex waveformusing the 
*	integer math tools
*
*
* Inputs:	None
*
* Outputs:	None
*
* External Refs:
	Import IntFFTIteration
	Import IntHarmI
*
* Entry Points:
*
*******************************************************************************
	With Globals
	With FFTransData

	_WaitCursor

	PushLong #ContRect	; first, start with a clean screen
	jsr setCachePort	; by erasing the old screen
	_EraseRect
	jsr setViewPort
	_EraseRect

	PushWord #10	; label the bottom of the window
	PushWord #170	; to show what we are doing
	jsr setCachePort
	_MoveTo
	jsr setViewPort
	_MoveTo
	
	PushLong #IntHarmTitle
	jsr setCachePort
	_DrawString
	jsr setViewPort
	_DrawString
	
	PushWord #0	; start this drawing off
	PushWord #80
	jsr setCachePort
	_MoveTo
	jsr setViewPort
	_MoveTo

	stz Sample	; zero out some starting values
	STZL MaxValue
	STZL Temp1
	STZL Temp2
	STZL TempFactor


DIWLoop1	jsr IntFFTIteration	; do one iteration of the wave

	lda Sample	; now save tempValue into our array
	asl a	; multiply by 2
	asl a
	tax

	lda TempValue	; now stow the temp	value
	sta FFTWave,x	; into an array for later use
	lda TempValue+2
	sta FFTWave+2,x

	inc Sample	; bump the sample counter
	lda #255	
	cmp Sample	; see if we are done
	bge DIWLoop1	; if not, get another sample

; Now that the array of values has been created. Go thru and scale
; each value so that it fits in our wave and is between 0 and 160

	stz Count	; zero the sample counter
DIWLoop2	inc Count
	jsr IntHarmI	; normalize one iteration

	PushWord Count	; X coordinate
	PushWord TempValue
	jsr setCachePort	; draw the line
	_LineTo
	jsr setViewPort
	_LineTo

	lda #255
	cmp Count
	bge DIWLoop2

	_InitCursor
	rts
	EndP

	EJECT
*******************************************************************************
*
IntFFTIteration	PROC
*
* Description:	This routine will calculate one single iteration of the 
*	wave. It will add a the Cosine*amp of each desired
*	harmonic to create a single sample
*
*
* Inputs:	None
*
* Outputs:	None
*
* External Refs:
*
* Entry Points:
*
*******************************************************************************
	With Globals
	With FFTransData

	stzL TempValue

	LongResult	 ; push room on the stack
	LongResult	 ; push room on the stack
	PushLong FixSamp	; sample fixed number format
	PushLong FixMaxSamp	; max sample fixed point number
	_FixDiv

	PushLong TwoPiFix
	_FixMul	; now multiply the two to get theFactor
	PullLong TempFactor


	stz Count	; zero out the counter

FFLoop

	lda Count	; get the count
	asl a	; multiply by 2
	asl a
	tax
	lda PhaseTblF,x
	sta TempF
	lda PhaseTblF+2,X
	sta TempF+2

	LongResult	 ; push room on the stack
	PushLong TwoPiFix
	PushLong TempF
	_FixMul	; Temp2:=Phase(Count)*TwoPi
	PullLong Temp2

	LongResult	 ; push room on the stack
	PushLong FixCount
	PushLong TempFactor
	_FixMul	; Temp1:=count*TempFactor
	PullLong Temp1

	lda Temp1	; Temp2:=Temp1+Temp2
	clc
	adc Temp2
	sta Temp2
	lda Temp1+2
	adc Temp2+2
	sta Temp2+2

	LongResult	 ; push room on the stack
	LongResult	 ; push room on the stack
	LongResult	 ; push room on the stack
	PushLong Temp2
	_FracCos	; Temp2:=Cos(Temp2)
	_Frac2Fix	; convert back to fixed!
	PullLong Temp2

	PushLong Temp2
	lda Count	; get the count
	asl a	; multiply by 2
	tax
	lda AmpTbl,x
	pha
	pea $0	; Low word of fixed	count
	_FixMul	; Temp1:=Temp1*Amp[count]
	PullLong Temp2

	lda TempValue	; now add it to tempValue
	clc
	adc Temp2
	sta TempValue
	sta Temp2
	lda TempValue+2
	adc Temp2+2
	sta TempValue+2	; Now test for max value
	sta Temp2+2
	bpl TestHigh	; number is positive, test for high
	lda #0	; Negate this number to get absolute value
	sec
	sbc Temp2	; negate this number
	sta Temp2
	lda #0
	sbc Temp2+2
	sta Temp2+2
TestHigh	lda Temp2+2
	cmp MaxValue+2	; is it bigger than	max value+2?
	beq FFTTestLow	; if equal test the	low byte
	bge FFTStoreMax	; if greater move it to high
	bra FFTL010
FFTTestLow	lda Temp2
	cmp MaxValue	; is it bigger?
	blt FFTL010
FFTStoreMax	lda Temp2+2
	sta MaxValue+2
	lda Temp2
	sta MaxValue

FFTL010
	inc Count
	lda Count
	cmp MaxHarm	; are we done yet???
	bge FFTDone
	brl FFLoop
FFTDone	rts
	EndP

	EJECT
*******************************************************************************
*
IntHarmI	PROC
*
* Description:	Takes an iteration of the wave divides it by the max value
*	and multiplies it by 160 to create a valid screen location
*
*
* Inputs:	None
*
* Outputs:	None
*
* External Refs:
*
* Entry Points:
*
*******************************************************************************
	With Globals
	With FFTransData

	lda Count
	asl a	; multiply by 4
	asl a
	tax
	lda FFTWave+2,x	; push current value on stack
	sta Temp1+2
	lda FFTWave,x	; 
	sta Temp1

	LongResult	 ; push room on the stack
	LongResult	 ; push room on the stack
	PushLong Temp1
	PushLong MaxValue	; divide it by maxvalue
	_FixDiv
	PullLong Temp2

	PushLong Temp2
	PushWord #$4F
	PushWord #0	; now scale it
	_FixMul
	PullLong Temp1

	lda Temp1+2
	clc
	adc #79
	sta TempValue
	rts
	EndP

	Include 'Math.Init.aii'

	END

