Re: [stella] Scan lines, FotR....

Subject: Re: [stella] Scan lines, FotR....
From: Paul Slocum <paul-stella@xxxxxxxxxxxxxx>
Date: Wed, 24 Apr 2002 00:46:16 -0500

Turns out Dark Mage *also* has 271 scan lines.  So it's not anything my
code, in particular, is doing, but rather something in Greg's engine.

I noticed that too.


Where would I look to figure out whether that's something I can reduce
to a more NTSC-friendly value (I assume 262 or 263 would be ideal...) ?

I use a few Stellar Track functions and a some of Greg's code/comments on the Synthcart, and it runs 11 lines of text at 262 scan lines. So it is possible. But it's been a while and I have no idea how I shaved off those extra lines. Although it's a mess, you're welcome to take a look at my source. There are two kernals -- you want to look at the one called "Picture".


-Paul
;---------------------------------------------------------------------------
;
; Synthcart by Paul Slocum
;
; Text macros from Dark Mage (Greg Troutman) 
; Text code from Stellar Track (Atari)
;	
;---------------------------------------------------------------------------

	processor 6502	
	include vcs.h	


;---------------------------------------------------------------------------
; Constants
;---------------------------------------------------------------------------
SETUPDELAY equ #255

; Amount of balance attenuation
BALATT equ 5


;---------------------------------------------------------------------------
; RAM Variables 
;---------------------------------------------------------------------------
frame equ $80

temp equ frame + 1

; 16 bit temp
temp16L equ temp + 1
temp16H equ temp16L + 1

; Initialize Flag
init equ temp16H + 1

visualBuffer equ init + 1; 46 bytes (overlaps with gfxBuffer and textPointer)

; Text engine variables
grfxBuffer equ init + 1 ; 24 bytes

; Array of text pointers to be displayed
textPointer equ grfxBuffer + 24	; 22 bytes

visualPointer equ textPointer + 22 ; (overlap)
scanSec equ textPointer + 22

EOTflag equ scanSec + 1

backColor equ EOTflag + 1

; Variable for reading Keyboards
keyRead equ backColor + 1

note1 equ keyRead + 1
note2 equ note1 + 1

vol1 equ note2 + 1
vol2 equ vol1 + 1

soundTypeL equ vol2 + 1
soundTypeR equ soundTypeL + 1

sound1 equ soundTypeR + 1
sound2 equ sound1 + 1

soundEffect equ sound2 + 1

arpOn equ soundEffect + 1
arpPattern equ arpOn + 1

scale equ arpPattern + 1

beatBox1 equ scale + 1
beatBox2 equ beatBox1 + 1
beatLock equ beatBox2 + 1
beatBank equ beatLock + 1

beatResetCount equ beatBank + 1

adsrcount equ beatResetCount + 1
adsrSetting equ adsrcount + 1

; Attack/Decay/Sustain/Release variables
adsrLevel1 equ adsrSetting + 1
adsrLevel2 equ adsrLevel1 + 1
adsrEnable1 equ adsrLevel2 + 1
adsrEnable2 equ adsrEnable1 + 1
lastNote1 equ adsrEnable2 + 1
lastNote2 equ lastNote1 + 1
lastSound1 equ lastNote2 + 1
lastSound2 equ lastSound1 + 1

; Attenuation
atten1 equ lastSound2 + 1
atten2 equ atten1 + 1
balAttLeft equ atten2 + 1
balAttRight equ balAttLeft + 1

; Metrenome stuff
beat equ balAttRight + 1
tempoCount equ beat + 1

; Color cycle counter
colorCycle equ tempoCount + 1

arpShort equ colorCycle + 1 ;***

visualMode equ arpShort + 1
easterPointer equ visualMode + 1
visualModeCount equ easterPointer + 1

setupMode equ visualModeCount + 1
setupCount equ setupMode + 1
lastSetupKey equ setupCount + 1

tempo equ lastSetupKey + 1

; Keyboard key buffers
keys1 equ tempo + 1
keypad1 equ keys1 + 1	; 4 bytes
keys2 equ keypad1 + 4
keypad2 equ keys2 + 1	; 4 bytes
tempKeys1 equ keypad2 + 4
tempKeypad1 equ tempKeys1 + 1 ; 4 bytes
tempKeys2 equ tempKeypad1 + 4
tempKeypad2 equ tempKeys2 + 1 ; 4 bytes

; 111 bytes 1-25-02


;---------------------------------------------------------------------------
; Text Macros
;---------------------------------------------------------------------------
; a few macros for storing text in a reasonably easy to read format
;---------------------------------------------------------------------------

	mac off
	dc.b <#{0}
	endm

	mac wordOff
	dc.b #<{1}
	dc.b #>{1}
	endm
	
	mac mapRow
	wordOff {1}
	wordOff {2}	
	wordOff {3}
	wordOff {4}
	wordOff {5}
	endm

	mac EOL
	dc.b #$FF
	endm

	mac EOT
	dc.b #$FE
	endm

	mac line
	;must supply 12 characters, though 0's will not be assembled
	;------------------------------------------------------------
	if {1} != 0
	 off {1}
	endif
	if {2} != 0
	 off {2}
	endif
	if {3} != 0
	 off {3}
	endif
	if {4} != 0
	 off {4}
	endif
	if {5} != 0
	 off {5}
	endif
	if {6} != 0
	 off {6}
	endif
	if {7} != 0
	 off {7}
	endif
	if {8} != 0
	 off {8}
	endif
	if {9} != 0
	 off {9}
	endif
	if {10} != 0
	 off {10}
	endif
	if {11} != 0
	 off {11}
	endif
	if {12} != 0
	 off {12}
	endif
	EOL
	endm
	
	mac blank
	 line #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
	endm



;---------------------------------------------------------------------------
;---------------------------------------------------------------------------
	org $1000
;---------------------------------------------------------------------------
;---------------------------------------------------------------------------



;---------------------------------------------------------------------------
; Font Data
;---------------------------------------------------------------------------
; Include the font data here so it is aligned on a page
; boundary without wasting any space
;---------------------------------------------------------------------------
	include snthfont.h		;just change the filename to use a different font...


;--------------------------------------------------------------------------
; Println
;--------------------------------------------------------------------------
; Most of this subroutine is ripped from Stellar Trak.  Feel free to add
; your own comments--it's pretty straightforward ;)  and very touchy.  Won't
; work if a page boundary appears at certain places, due to excruciating
; cycle dependency, so if modifying the source, you might need an ALIGN
; pseudo-op to correct flubbery text displays.  ALIGN 256 will always work,
; but maybe ALIGN 128, ALIGN 64, etc. will also work, and not waste as many
; bytes.
;--------------------------------------------------------------------------
	align 256
println
	ldx #4
	sta WSYNC
pause
	nop
	dex	
	bne pause
	lda temp
	lda temp	
		
	sta HMCLR
	ldx #$90
	ldy #6	;FONTHEIGHT
	lda frame
	and #$01
	beq oddFrame
	jmp evenFrame

print1	
	sta GRP1
	lda (grfxBuffer + $8),y
	sta GRP0
	lda (grfxBuffer + $C),y
	stx HMP0
	stx HMP1
	sta GRP1
	lda (grfxBuffer + $10),y
	sta GRP0
	lda (grfxBuffer + $14),y
	sta GRP1
	sta GRP0
evenFrame	
	dey
	bmi wrapEven
	lda (grfxBuffer + $2),y
	lsr
	sta GRP0
	lda (grfxBuffer +6),y
	lsr
	sta.w $001C
	sta HMOVE
	lda (grfxBuffer + $A),y
	lsr
	sta GRP0
	lda (grfxBuffer + $12),y
	lsr
	sta temp
	lda (grfxBuffer + $E),y
	lsr
	sta GRP1
	lda temp
	sta GRP0
	lda (grfxBuffer + $16),y
	lsr
	sta GRP1

oddFrame
	sta GRP0
	lda #$70
	sta HMP0
	sta HMP1
	dey
	bmi wrapOdd
	lda (grfxBuffer),y
	sta GRP0
	lda (grfxBuffer + $4),y
	sta HMOVE
	jmp print1

wrapEven
	stx HMP0
	stx HMP1
	sta WSYNC
	sta HMOVE
	jmp print2

wrapOdd
	sta WSYNC
	sta temp
	sta temp

print2
	lda #$00
	sta GRP0
	sta GRP1
	sta GRP0

	rts ; println


				
;---------------------------------------------------------------------------
; Start of Program
;---------------------------------------------------------------------------
; Clear memory, locate character graphics positions and such,
; initialize key memory values, start GameLoop.
;-------------------------------------------------------------
Start
	sei  	
	cld  		
	ldx #$FF
	txs  		
	lda #0
clear   
	sta 0,x
	dex
	bne clear	




;---------------------------------------------------------------------------
; Initialize variables
;---------------------------------------------------------------------------
	jsr fontSetup

	; debug - start in setup mode
	;lda #2
	;sta setupMode
	;lda #255
	;sta setupCount
	;lda #255
	;sta visualMode

	lda #11
	sta beatBox1
	sta beatBox2

	lda #2
	sta tempo

	sta soundTypeL
	sta soundTypeR

	; clear keypad buffers
	jsr clearKeys

	; Set initialization flag.
	; This stays set until the first frame is drawn.
	lda #255
	sta init
	sta lastSetupKey

	lda #startupSoundEffect
	sta soundEffect

	; Set up the text pointers for the status screen
	jsr printStatus	

	sta lastNote1
	sta lastNote2

	lda #$0f	;set text color to white
	sta COLUP0
	sta COLUP1	

	jsr graphicsSetup

;--------------------------------------------------------------------------
; GameLoop
;--------------------------------------------------------------------------
GameLoop
	jsr VSync 	;start vertical retrace

	inc frame	;we count frames for alternating graphics displays

	jsr VBlank    	; spare time during screen blank
	jsr Picture		; draw one screen
	jsr overscan	; do overscan

	; Clear init flag
	lda #0
	sta init

	jmp GameLoop    ;back to top



;---------------------------------------------------------------------------
; Font Setup
;---------------------------------------------------------------------------
;the entire font is limited to one page, so we can hard code that page
;value into the MSB position of our graphics buffer
;-----------------------------------------------------
fontSetup
	ldx #23		;graphics buffer is 24 bytes
	lda #>_space	;load up the page value for the font
grOff
	sta grfxBuffer,x	;stuff it, won't ever change
	dex		;back up two bytes
	dex
	bpl grOff	;and loop

	rts



;---------------------------------------------------------------------------
; Text Engine Graphics Setup
;---------------------------------------------------------------------------
; use cycle counting to get the GRP registers configured and located
; in exactly the right spot
;---------------------------------------------------------------------------
graphicsSetup
	sta WSYNC	;newline
	lda #54		;triple copy sprites, spaced wide
	sta NUSIZ0	;for both player graphic registers
	sta NUSIZ1	
	lda #$31	;draw leftmost and rightmost 2 playfield bits: reflect
	sta PF0		;this turns left/right edges black
	sta CTRLPF	;this makes playfield reflective
	nop		;wait 2 cycles, we need them get our RESP0/1 right
	sta VDELP0	;turn on vertical delay for both players
	sta VDELP1
	sta RESP0	;mark our left margin here in P0
	lda #$D0	;setup to shift over 3 pixels to the right
	sta RESP1	;set P1
	sta HMP0	;prep P0 for his HMOVE
	lda #$C0	;setup to shift P1 4 pixels to the right
	sta HMP1	;prep P1 for his HMOVE

	sta WSYNC	;newline
	sta HMOVE	;anchor them down

	rts



;--------------------------------------------------------------------------
; VSync
;--------------------------------------------------------------------------
VSync
	lda #2		;bit 1 needs to be 1 to start retrace
	sta VSYNC	;start retrace
	sta WSYNC 	;wait a few lines
	sta WSYNC 
	lda #44		;prepare timer to exit blank period (44)
	sta TIM64T	;turn it on
	sta WSYNC 	;wait one more
	sta VSYNC 	;done with retrace, write 0 to bit 1

	rts ; VSync




;--------------------------------------------------------------------------
; Easter Check
;--------------------------------------------------------------------------
; Checks to see if the user has activated
; an easter egg (by playing a special melody)
;--------------------------------------------------------------------------
easterCheck

	lda note1
	cmp #255
	beq stay

	lda sound1
	cmp #7
	beq contEaster
	cmp #1
	beq contEaster
	
	jmp resetPointer


contEaster

	ldx easterPointer

	lda note1
	cmp easterArray,x
	beq stay

	inx
	
	cmp easterArray,x
	bne resetPointer

	cpx #6
	beq activateEaster

	stx easterPointer
	rts

activateEaster
	lda visualMode
	beq setupVisualMode

	lda #0
	sta visualMode
	sta easterPointer

	; Disable missles
	sta ENAM0
	sta ENAM1

	; Have to re-setup text graphics since everything's
	; messed up in visual mode.

	jsr fontSetup
	jsr graphicsSetup

	; Set up the text pointers for the status screen
	jsr printStatus	

	;set text color to white
	lda #$0f	
	sta COLUP0
	sta COLUP1		
	
	rts


setupVisualMode

	lda #100
	sta visualModeCount
	
resetPointer
	lda #0
	sta easterPointer
	rts	

stay
	rts ; easterCheck



;--------------------------------------------------------------------------
; Clear temp Keypad Buffers
;--------------------------------------------------------------------------
; This function is copied in the upper 4k as clearKeys8k
;--------------------------------------------------------------------------
clearKeys
	lda #255
	sta tempKeypad1;
	sta tempKeypad1+1;
	sta tempKeypad1+2;
	sta tempKeypad1+3;
	sta tempKeypad2;
	sta tempKeypad2+1;
	sta tempKeypad2+2;
	sta tempKeypad2+3;
	lda #0
	sta tempKeys1
	sta tempKeys2	
	rts ; clearKeys



;--------------------------------------------------------------------------
; Background Color Cycling
;--------------------------------------------------------------------------
colorCycling

	; Decrement the beat reset counter here.
	; This makes it so the measure/beat will
	; reset when a beat and arp are off for a while.

	lda beatResetCount
	beq noDecResetCount
	dec beatResetCount
noDecResetCount



	lda visualMode
	bne colorModeA

	; Use special bkgd colors for setup mode
	lda setupCount
	beq goAhead

	lda setupMode
	cmp #1
	beq colorModeA

	lda #62
	sta colorCycle
	
	rts

colorModeA
	lda #51
	sta colorCycle

	rts

goAhead
	; Every other frame
	lda frame
	and #%00000001
	beq skipCycle

	lda colorCycle
	cmp #39
	bmi skipColorReset
	lda #0	
skipColorReset
	tax
	inx
	stx colorCycle

skipCycle

	rts ; colorCycling


;--------------------------------------------------------------------------
; Set Sound Text
;--------------------------------------------------------------------------
; Stores a pointer to sound type text
; in the text pointer array using a lookup
; table.
; - ACC must contain the sound type (255 = beat)
; - X must contain the offset in the text pointer array
;	where the text is to be stored.
;--------------------------------------------------------------------------
setSoundText
	cmp #255
	bne notBeat

	lda #2

notBeat

	asl ; x2
	tay

	dey	; back off one word.  The array's just 
	dey	; set up like this.

	; ERRCHECK
	; (the Atari will crash if an odd value
	; occurs here)

;	cpy #22
;	bpl err
;	jmp noErr
;err
;	ldy #22
;noErr

	; Set sound text
	lda soundTextArray,y
	sta textPointer,x
	inx
	iny
	lda soundTextArray,y
	sta textPointer,x

	rts ; setSoundText




;--------------------------------------------------------------------------
; Set Arp Text
;--------------------------------------------------------------------------
; Stores a pointer to arpeggiator text
; in the text pointer array based on arp settings.
;
; - X must contain the offset in the text pointer array
;	where the text is to be stored.
;--------------------------------------------------------------------------
setArpText

	; set up arp text from arp settings
	lda arpShort
	and #8
	sta temp
	lda arpOn
	asl
	adc temp
	tay

	lda arpTextArray,y 
	sta textPointer,x
	iny
	inx
	lda arpTextArray,y
	sta textPointer,x

	rts ; setArpText

;--------------------------------------------------------------------------
; Set Tempo Text
;--------------------------------------------------------------------------
; Stores a pointer to tempo text
; in the text pointer array based on tempo settings.
;
; - X must contain the offset in the text pointer array
;	where the text is to be stored.
;--------------------------------------------------------------------------
setTempoText

	
	; set up tempo text from tempo delay
	lda tempo
	asl
	tay

	lda tempoTextArray,y
	sta textPointer,x
	inx
	iny
	lda tempoTextArray,y 
	sta textPointer,x

	rts ; setTempoText



;--------------------------------------------------------------------------
; Set ADSR Text
;--------------------------------------------------------------------------
; Stores a pointer to ADSR text
; in the text pointer array based on tempo settings.
;
; - X must contain the offset in the text pointer array
;	where the text is to be stored.
;--------------------------------------------------------------------------
setADSRText

	lda adsrSetting

	cmp #8 ; tremelo
	bne notTremText

	lda #5

notTremText
	asl
	tay

	;DEBUG
	;ldy #2

	lda adsrTextArray,y 
	sta textPointer,x
	inx
	iny
	lda adsrTextArray,y 
	sta textPointer,x
	
	rts ; setADSRText



;--------------------------------------------------------------------------
; Set Title Text
;--------------------------------------------------------------------------
; Stores a pointer to title text.
; Fuji logo flashes with tempo.
;
; - X must contain the offset in the text pointer array
;	where the text is to be stored.
;--------------------------------------------------------------------------
setTitleText

	; If the beatResetCount is zero, then
	; the beat will reset next time it's started,
	; so don't flash the tempo
	ldy #0
	lda beatResetCount
	beq alwaysOn

	lda beat
	and #%00001100
	lsr
	tay

alwaysOn

	lda titleTextArray,y 
	sta textPointer,x
	inx
	iny
	lda titleTextArray,y 
	sta textPointer,x
	
	rts ; setTitleText


;--------------------------------------------------------------------------
; Set Arp Pattren
;--------------------------------------------------------------------------
; Stores a pointer to arp pattern text.
;
; - X must contain the offset in the text pointer array
;	where the text is to be stored.
;--------------------------------------------------------------------------
setArpPatternText

	lda arpPattern
	asl
	tay

	lda arpPatternTextArray,y 
	sta textPointer,x
	inx
	iny
	lda arpPatternTextArray,y 
	sta textPointer,x
	
	rts ; setArpPatternText




;--------------------------------------------------------------------------
; Set Balance and Bank Text
;--------------------------------------------------------------------------
; Stores a pointer to balance and bank text.
; (Balance and Beat Bank are on the same line)
; 
; - X must contain the offset in the text pointer array
;	where the text is to be stored.
;--------------------------------------------------------------------------
setBalBankText
	
	lda beatBank
	asl

	ldy balAttLeft
	beq checkRightBal

	ora #8

checkRightBal

	ldy balAttRight
	beq copyBalPointer

	ora #16

copyBalPointer
	tay

	lda balBeatTextArray,y 
	sta textPointer,x
	inx
	iny
	lda balBeatTextArray,y 
	sta textPointer,x
	
	rts ; setBalText




;--------------------------------------------------------------------------
; Set Scale Text
;--------------------------------------------------------------------------
; Stores a pointer to scale text.
; 
; - X must contain the offset in the text pointer array
;	where the text is to be stored.
;--------------------------------------------------------------------------
setScaleText
	
	lda scale
	asl
	tay

	lda scaleTextArray,y 
	sta textPointer,x
	inx
	iny
	lda scaleTextArray,y 
	sta textPointer,x
	
	rts ; setScaleText




;--------------------------------------------------------------------------
; Set Text
;--------------------------------------------------------------------------
; Stores text pointer in text pointer array.
;
; - ACC must be low byte
; - X must be high byte
; - Y must by text pointer array offset
;--------------------------------------------------------------------------
setText

	sta textPointer,y
	txa
	iny
	sta textPointer,y

	rts ; setText



;--------------------------------------------------------------------------
; Print Status Screen
;--------------------------------------------------------------------------
; This sets the text pointers to display the 
; status screen (the information shown while
; playing the synthcart
;--------------------------------------------------------------------------
printStatus
	ldx #0
	jsr setTitleText

	ldx #2
	jsr setADSRText

	ldx #4
	jsr setTempoText

	ldx #6
	jsr setArpText

	ldx #8
	jsr setArpPatternText

	ldx #10
	jsr setScaleText

	ldx #12
	jsr setBalBankText

	lda #<tx_leftsound
	ldx #>tx_leftsound
	ldy #14
	jsr setText

	ldx #16
	lda soundTypeL
	jsr setSoundText

	lda #<tx_rightsound
	ldx #>tx_rightsound
	ldy #18
	jsr setText

	ldx #20
	lda soundTypeR
	jsr setSoundText

	rts ; setupStatus


;--------------------------------------------------------------------------
; Print Setup Screen B
;--------------------------------------------------------------------------
; This sets the text pointers to display the 
; setup screen B, where the user changes
; synthesizer settings
;--------------------------------------------------------------------------
printSetupB

	lda #<tx_setupB1
	sta textPointer + 0
	lda #>tx_setupB1
	sta textPointer + 1

	lda #<tx_setupB2
	sta textPointer + 2
	lda #>tx_setupB2
	sta textPointer + 3

	lda #<tx_setupB3
	sta textPointer + 4
	lda #>tx_setupB3
	sta textPointer + 5

	lda #<tx_setupB4
	sta textPointer + 6
	lda #>tx_setupB4
	sta textPointer + 7

	lda #<tx_setupB5
	sta textPointer + 8
	lda #>tx_setupB5
	sta textPointer + 9

	lda #<tx_setupB6
	sta textPointer + 10
	lda #>tx_setupB6
	sta textPointer + 11

	lda #<tx_setupB7
	sta textPointer + 12
	lda #>tx_setupB7
	sta textPointer + 13

	lda #<tx_setupB8
	sta textPointer + 14
	lda #>tx_setupB8
	sta textPointer + 15

	ldx #16
	jsr setADSRText

	ldx #18
	jsr setTempoText

	ldx #20
	jsr setArpText

	rts ; printSetupB


;--------------------------------------------------------------------------
; Print Setup Screen A
;--------------------------------------------------------------------------
; This sets the text pointers to display the 
; setup screen A, where the user changes
; synthesizer settings
;--------------------------------------------------------------------------
printSetupA

	lda #<tx_setupA1
	sta textPointer + 0
	lda #>tx_setupA1
	sta textPointer + 1

	lda #<tx_setupA2
	sta textPointer + 2
	lda #>tx_setupA2
	sta textPointer + 3

	lda #<tx_setupA3
	sta textPointer + 4
	lda #>tx_setupA3
	sta textPointer + 5

	lda #<tx_setupA4
	sta textPointer + 6
	lda #>tx_setupA4
	sta textPointer + 7

	lda #<tx_setupA5
	sta textPointer + 8
	lda #>tx_setupA5
	sta textPointer + 9

	lda #<tx_setupA6
	sta textPointer + 10
	lda #>tx_setupA6
	sta textPointer + 11

	lda #<tx_setupA7
	sta textPointer + 12
	lda #>tx_setupA7
	sta textPointer + 13

	lda #<tx_setupA8
	sta textPointer + 14
	lda #>tx_setupA8
	sta textPointer + 15

	ldx #16
	jsr setArpPatternText

	ldx #18
	jsr setScaleText

	ldx #20
	jsr setBalBankText

	rts ; printSetupA



;--------------------------------------------------------------------------
; Print Visual Mode
;--------------------------------------------------------------------------
; Displays a message that visual mode is being activated
;--------------------------------------------------------------------------
printVisualMode

	lda #<tx_blank
	sta textPointer + 0
	sta textPointer + 2
	sta textPointer + 4
	sta textPointer + 6
	sta textPointer + 8
	sta textPointer + 10
	sta textPointer + 12
	sta textPointer + 14
	sta textPointer + 16
	lda #>tx_blank
	sta textPointer + 1
	sta textPointer + 3
	sta textPointer + 5
	sta textPointer + 7
	sta textPointer + 9
	sta textPointer + 11
	sta textPointer + 13
	sta textPointer + 15
	sta textPointer + 17

	lda #<tx_visual1
	ldx #>tx_visual1
	ldy #18
	jsr setText

	lda #<tx_visual2
	ldx #>tx_visual2
	ldy #20
	jsr setText

	rts ; printVisualMode


;--------------------------------------------------------------------------
; Handle Setup Mode Keys
;--------------------------------------------------------------------------
; If in setup mode, deal with setup keys
; pressed.  Must be called after readKeyboards.
;--------------------------------------------------------------------------
handleSetupKeys

	lda setupCount
	beq noSetup

	ldx setupMode
	dex
	beq setup1
	
	dex
	bne noSetup

	jsr handleSetup2
	rts

setup1
	jsr handleSetup1
	rts

noSetup

	rts ; handleSetupKeys



;--------------------------------------------------------------------------
; Handle Switches
;--------------------------------------------------------------------------
; Read and respond to console switches.  
; Set up sound types.
; Display sound information on screen.
;--------------------------------------------------------------------------
handleSwitches

; *** Choose Sound from B&W, DF1, and DF2 switches ***

	lda SWCHB
	and #%00001000
	lsr
	sta temp

	lda SWCHB
	and #%11000000
	clc
	rol
	rol
	rol
	ora temp

	; Now ACC = 
	;
	;      BRL
	;      W
	; 00000111

	; Get the two sounds from the sound pair arrays
	tax
	lda soundPairArrayL,x
	sta soundTypeL
	lda soundPairArrayR,x
	sta soundTypeR

	; Clear the selected beats if
	; beatbox is de-selected
	cmp #255
	beq noBeatReset

	lda #11
	sta beatBox1
	sta beatBox2
noBeatReset

; Game Select Switch (activates Advanced Setup Mode for a few seconds)
;--------------------------------------------------------------------------

	lda SWCHB
	and #%000000010
	bne noSel

	lda setupCount
	bne noSoundB

	lda #setupActEffect
	sta soundEffect

noSoundB

	lda #255
	sta setupCount
	lda #2
	sta setupMode

noSel

; Game Reset Switch (activates Setup Mode for a few seconds)
;--------------------------------------------------------------------------

	lda SWCHB
	and #%000000001
	bne noRes

	lda setupCount
	bne noSoundA

	lda #setupActEffect
	sta soundEffect

noSoundA

	lda #255
	sta setupCount
	lda #1
	sta setupMode

noRes


; Update display
;--------------------------------------------------------------------------
updateDisplay

	; check setup mode timer to see if setup mode is active
	lda setupCount
	beq statusScreen
	
	; Count down
	dec setupCount

	bne noSetupDeactivateSound

	lda #setupDeaEffect
	sta soundEffect

noSetupDeactivateSound


	; Figure out which setup mode is enabled
	lda setupMode
	cmp #1
	beq goPrintSetupB

	; Don't print test if visual mode is active
	lda visualMode
	bne handleVisualMode

	jsr printSetupA

	jmp handleVisualMode

goPrintSetupB
	; Don't print test if visual mode is active
	lda visualMode
	bne handleVisualMode

	jsr printSetupB

	jmp handleVisualMode

	; Setup mode is not active, so print the status screen
statusScreen

	; Don't print test if visual mode is active
	lda visualMode
	bne handleVisualMode

	jsr printStatus

; Handle Visual Mode
;--------------------------------------------------------------------------
handleVisualMode

	; If visualModeCount is >0 then 
	; display "light show mode" message.
	ldx visualModeCount
	bne goVisualMode

	jmp endHandleSwitches

goVisualMode
	dex
	stx visualModeCount
	beq activateVisualMode

	jsr printVisualMode
	jmp endHandleSwitches

	; Time has expired so switch to visual mode
activateVisualMode
	lda #255
	sta visualMode

	; The visual color buffer shares space with the
	; text buffers, so clear them out before
	; visual mode starts.

	lda #0
	ldx #45
clearVisual
	sta visualBuffer,x
	dex
	bne clearVisual 
	sta visualBuffer,x

endHandleSwitches
	rts ; handleSwitches



;--------------------------------------------------------------------------
; Handle Setup 1
;--------------------------------------------------------------------------
; Deal with keys pressed in setup mode.
; Changes synth settings.
; Don't call this unless the synth is in setup mode
; since it will clear the keyboard buffers.
;--------------------------------------------------------------------------
handleSetup1

	lda keypad1
	cmp #255
	bne handleKeys

	lda keypad2
	cmp #255
	bne handleKeys

	; Only unmark on odd frames (long story...)
	lda keyRead
	and #%00000001
	beq noLastKeyReset

	; Unmark the "last key" indicating that the key was released
	lda lastSetupKey
	and #%01111111
	sta lastSetupKey

noLastKeyReset
	; No keys pressed -- quit
	jmp quitHandleSetup

endSetup
	; If a key is pressed twice in a row, quit setup mode
	lda #0
	sta setupCount
	lda #255
	sta lastSetupKey

	; Setup mode de-activate sound effect
	lda #setupDeaEffect
	sta soundEffect

	jmp quitHandleSetup

handleKeys


	; reset setup mode delay
	ldx #255
	stx setupCount

	; Handle the tempo keys first since they're the
	; only ones that won't close setup if pressed twice

	cmp #0
	bne notTempUp

	ora #%10000000
	cmp lastSetupKey
	beq noDecTempo

	sta lastSetupKey

	lda tempo
	beq noDecTempo

	; Key press sound effect
	ldx #setupSelectEffect
	stx soundEffect
	dec tempo

	lda #0
	sta tempoCount

noDecTempo
	jmp quitHandleSetup

notTempUp

	cmp #3
	bne notTempDown

	ora #%10000000
	cmp lastSetupKey
	beq noIncTempo

	sta lastSetupKey

	lda tempo
	cmp #9
	beq noIncTempo

	; Key press sound effect
	ldx #setupSelectEffect
	stx soundEffect

	inc tempo

noIncTempo
	jmp quitHandleSetup

notTempDown

	bit lastSetupKey
	bmi noKeyHitSound	

	; Key press sound effect
	ldx #setupSelectEffect
	stx soundEffect

noKeyHitSound

	; Check to see if the same key was pressed twice in a row
	cmp lastSetupKey
	beq endSetup


	; Mark the new "last key"
	ora #%10000000
	sta lastSetupKey
	and #%01111111


	cmp #4
	bne notArp32

	lda #3
	sta arpOn

	jmp quitHandleSetup

notArp32
		
	cmp #1
	bne notArp16

	lda #2
	sta arpOn
	jmp quitHandleSetup

notArp16

	cmp #2
	bne notArp8

	lda #1
	sta arpOn
	jmp quitHandleSetup

notArp8

	cmp #5
	bne notArpOff

	lda #0
	sta arpOn
	jmp quitHandleSetup

notArpOff

	cmp #9
	bne notTremA

	lda #4
	sta adsrSetting

	jmp quitHandleSetup

notTremA

	cmp #7
	bne notLongRelease

	lda #2
	sta adsrSetting

	lda #0
	sta adsrLevel1
	sta adsrLevel2

	jmp quitHandleSetup

notLongRelease

	cmp #6
	bne notTremS

	lda #8
	sta adsrSetting

	jmp quitHandleSetup

notTremS

	cmp #8
	bne notSlowAtk

	lda #1
	sta adsrSetting

	jmp quitHandleSetup

notSlowAtk

	cmp #10
	bne notSlowAtkRel

	lda #3
	sta adsrSetting

	lda #0
	sta adsrLevel1
	sta adsrLevel2

	jmp quitHandleSetup

notSlowAtkRel

	cmp #11
	bne notNormAtk

	lda #0
	sta adsrSetting

	jmp quitHandleSetup

notNormAtk


quitHandleSetup

	; Clear keypad buffers
	ldx #255
	stx keypad1
	stx keypad1+1
	stx keypad1+2
	stx keypad1+3
	stx keypad2
	stx keypad2+1
	stx keypad2+2
	stx keypad2+3

	rts ; handleSetup



;--------------------------------------------------------------------------
; Handle Setup 2
;--------------------------------------------------------------------------
; Deal with keys pressed in setup mode.
; Changes synth settings.
; Don't call this unless the synth is in setup mode
; since it will clear the keyboard buffers.
;--------------------------------------------------------------------------
handleSetup2

	lda keypad1
	cmp #255
	bne handleKeys2

	lda keypad2
	cmp #255
	bne handleKeys2

	; Only unmark on odd frames (long story...)
	lda keyRead
	and #%00000001
	beq noLastKeyReset2

	; Unmark the "last key" indicating that the key was released
	lda lastSetupKey
	and #%01111111
	sta lastSetupKey

noLastKeyReset2
	; No keys pressed -- quit
	jmp quitHandleSetup2

endSetup2
	; If a key is pressed twice in a row, quit setup mode
	lda #0
	sta setupCount
	lda #255
	sta lastSetupKey

	; Setup mode de-activate sound effect
	lda #setupDeaEffect
	sta soundEffect

	jmp quitHandleSetup2

handleKeys2


	; reset setup mode delay
	ldx #255
	stx setupCount

	bit lastSetupKey
	bmi noKeyHitSound2

	; Key press sound effect
	ldx #setupSelectEffect
	stx soundEffect

noKeyHitSound2

	; Check to see if the same key was pressed twice in a row
	cmp lastSetupKey
	beq endSetup2

	; Mark the new "last key"
	ora #%10000000
	sta lastSetupKey
	and #%01111111


	; Check keys/set settings...

	cmp #0
	bne notArpUp

	lda #0
	sta arpPattern

	jmp quitHandleSetup2

notArpUp
		
	cmp #1
	bne notArpDown

	lda #1
	sta arpPattern
	jmp quitHandleSetup2

notArpDown

	cmp #2
	bne notArpMix

	lda #2
	sta arpPattern
	jmp quitHandleSetup2

notArpMix

	cmp #6
	bne notBeatBank1

	lda #0
	sta beatBank
	jmp quitHandleSetup2

notBeatBank1

	cmp #7
	bne notBeatBank2

	lda #1
	sta beatBank
	jmp quitHandleSetup2

notBeatBank2

	cmp #8
	bne notBeatBank3

	lda #2
	sta beatBank
	jmp quitHandleSetup2

notBeatBank3

	cmp #3
	bne notMajorScale

	lda #0
	sta scale
	jmp quitHandleSetup2

notMajorScale

	cmp #4
	bne notMinorScale

	lda #1
	sta scale
	jmp quitHandleSetup2

notMinorScale

	cmp #5
	bne notAtonalScale

	lda #2
	sta scale
	jmp quitHandleSetup2

notAtonalScale

	cmp #9
	bne notLeftBal

	lda #0
	sta balAttLeft 
	lda #BALATT
	sta balAttRight
	jmp quitHandleSetup2

notLeftBal

	cmp #10
	bne notCentBal

	lda #0
	sta balAttLeft
	sta balAttRight
	jmp quitHandleSetup2

notCentBal

	cmp #11
	bne notRightBal

	lda #BALATT
	sta balAttLeft
	lda #0
	sta balAttRight
	jmp quitHandleSetup2

notRightBal


quitHandleSetup2

	; Clear keypad buffers
	ldx #255
	stx keypad1
	stx keypad1+1
	stx keypad1+2
	stx keypad1+3
	stx keypad2
	stx keypad2+1
	stx keypad2+2
	stx keypad2+3

	rts ; handleSetup2




;--------------------------------------------------------------------------
; Sound Effect Player
;--------------------------------------------------------------------------
; This function plays sound effects to indicate the status
; of the machine.  Sound effects are selected by setting
; soundEffect to the start of a sound in the
; sound effect array.
;--------------------------------------------------------------------------
soundEffectPlayer

	ldx soundEffect
	lda soundEffectArray,x
	cmp #255
	beq noSoundEffects

	sta note1

	inx
	stx soundEffect

	lda #5
	sta sound1

	lda #7
	sta vol1
	
noSoundEffects
	rts ; soundEffectPlayer










;--------------------------------------------------------------------------
; Voice Manager
;--------------------------------------------------------------------------
; This funtion calls the standard player, argpeggiator, and beat box
; based on which setup is selected.  It also designates voices
; to the players based on some rules:
;
; 1) If keys are pressed on both keyboards, then each sound
;    generator gets one voice.
; 2) If multiple keys are pressed on a keyboard and none on the other,
;    the sound generator can have both voices.
; 3) The arpeggiator gets at most one voice.
;
; Note that the BeatBox is only allowed on soundR
;--------------------------------------------------------------------------
voiceManager

	lda soundTypeR
	cmp #255
	beq beatBoxPlay
	lda arpOn
	bne arpPlay

; Standard Play on both keypads
;--------------------------------------------------------------------------
standard
	lda keypad1
	cmp #255
	beq twoOnTwo
	lda keypad2
	cmp #255
	beq twoOnOne

oneOnEach
	lda #<keypad1	; Use keypad 1
	sta temp16L
	lda #0
	sta temp16H
	ldy #1			; One voice available
	ldx #0			; Osc 1
	jsr standardPlayer

	lda #<keypad2	; Use keypad 2
	sta temp16L
	lda #0
	sta temp16H
	ldy #1			; One voice available
	ldx #1			; Osc 2
	jsr standardPlayer

	rts

twoOnOne
	lda #<keypad1	; Use keypad 1
	sta temp16L
	lda #0
	sta temp16H
	ldy #2			; Two voices available
	ldx #0			; Osc1 primary
	jsr standardPlayer

	rts

twoOnTwo
	lda #<keypad2	; Use keypad 2
	sta temp16L
	lda #0
	sta temp16H
	ldy #2			; Two voices available
	ldx #1			; Osc2 primary
	jsr standardPlayer

	rts


; Arp on both keypads
;--------------------------------------------------------------------------
arpPlay
	lda #<keypad2	; Use keypad 1
	sta temp16L
	lda #0
	sta temp16H
	lda #1			; Osc1
	jsr arp

	lda #<keypad1	; Use keypad 2
	sta temp16L
	lda #0
	sta temp16H
	lda #0			; Osc2
	jsr arp

	rts

; Standard play on left, Beatbox on right
;--------------------------------------------------------------------------
beatBoxPlay
	lda arpOn
	bne beatAndArpPlay

	lda keypad1
	cmp #255
	beq checkRelease

	lda beatBox1
	cmp #11
	beq twoOnPlayer

	jmp beatAndPlayer


; Before going to twoOnBeat, need to make
; sure that long release isn't on and fading
; out a release.

checkRelease
	; Check to see if a long
	; release is being held

	lda adsrSetting
	and #2
	beq twoOnBeat

	ldx adsrLevel1
	beq twoOnBeat


beatAndPlayer
	lda #<keypad1	; Use keypad 1
	sta temp16L
	lda #0
	sta temp16H
	ldy #1			; One voice available
	ldx #0			; Osc 1
	jsr standardPlayer

	lda #1	; One voice
	jsr callBeatBox

	rts

twoOnPlayer
	lda #<keypad1	; Use keypad 1
	sta temp16L
	lda #0
	sta temp16H
	ldy #2			; Two voices available
	ldx #0			; Osc 1
	jsr standardPlayer
	
	rts
	
twoOnBeat
	lda #2	; Two voices available
	jsr callBeatBox

	rts

; Arp on left, Beatbox on right
;--------------------------------------------------------------------------
beatAndArpPlay
	lda keypad1
	cmp #255
	bne beatOneArpOne

	; Check to see if a long
	; release is being held

	lda adsrSetting
	and #2
	beq twoOnBeat

	ldx adsrLevel1
	beq twoOnBeat

beatOneArpOne
	lda #<keypad1	; Use keypad 1
	sta temp16L
	lda #0			; page 1/osc1
	sta temp16H
	jsr arp

	lda #1	; One voice
	jsr callBeatBox

	rts ; voiceManager

;--------------------------------------------------------------------------
; Tempo
;--------------------------------------------------------------------------
; Generates tempo based on set tempo
;--------------------------------------------------------------------------
handleTempo


	; Now deal with the tempo

	; increment the tempo counter
	inc tempoCount
	
	; Check to see if the tempo counter
	; has reached the point where the beat counter
	; will be incremented
	lda tempo
	clc
	adc #4
	cmp tempoCount
	bne quitTempo

	; reset the tempo counter
	lda #0
	sta tempoCount

	; increment the beat
	ldx beat
	inx
	stx beat
	cpx #128
	bne quitTempo

	lda #0
	sta beat

quitTempo

	rts ; tempo


;--------------------------------------------------------------------------
; Arpeggiator
;--------------------------------------------------------------------------
; Effectively two arpeggiators -- can arpeggiate both keypads
; simultaneously.  Each supports up to 4 points.
; - temp16 should contain the address of the keypad array
; - ACC should contain the primary oscillator number (0 or 1)
;--------------------------------------------------------------------------
arp

	tax
	
	lda soundTypeL,x
	sta sound1,x

	ldy #0

	lda (temp16L),y
	cmp #255
	bne keyCount

	sta note1,x

	; enable adsr control for arp
	lda #255
	sta adsrEnable1,x

	rts

	; Get number of keys pressed
keyCount
	lda #255
	sta beatResetCount

	txa
	pha

	; Get the location of the number of keys 
	; variable (right before key array)
	ldx temp16L
	dex
	
	; Get number of keys pressed
	ldy 0,x
	
playArp
	; # of keys pressed
	dey
	tya

	asl
	asl
	asl
	sta temp

	clc
	lda beat
	and #%00011111

	; Check arp rate (8/16/32) and shift accordingly
	ldx arpOn
	cpx #3
	beq doneShifting
	lsr
	cpx #2
	beq doneShifting
	lsr
doneShifting

	and #%00000111
	clc

	; keyspressed*8 + beat = arpArray index
	adc temp
	asl
	asl
	adc arpPattern
	tax

	lda arpUpArray,x
	tay
	
	lda (temp16L),y
	asl
	asl
	clc
	adc scale
	tax

	pla
	tay

	lda soundData1,x
	
	sta note1,y

	; Handle balance setting
	lda balAttLeft,y
	adc atten1,y
	sta atten1,y

	; enable adsr control for arp
	lda #255
	sta adsrEnable1,y

endArp
	rts ; arp




;--------------------------------------------------------------------------
; Standard Player
;--------------------------------------------------------------------------
; For normal playing of notes from keyboard
; data (no arpeggiator or beat box)
; - temp16 should contain the address of the keypad array
; - Y should contain the number of voices available (1 or 2)
; - x should contain the primary oscillator number (0 or 1)
; - ACC should contain the attenuation setting
; If two oscillators are available, the other oscillator
; will be used if a second key is pressed on the keypad.
;--------------------------------------------------------------------------
standardPlayer

	lda balAttLeft,x
	sta temp

	cpy #2
	bne primaryOsc

secondOsc
	lda soundTypeL,x
	pha
	txa
	eor #%00000001
	tax
	pla
	sta sound1,x
	
	ldy #1
	lda (temp16L),y

	cmp #255
	beq noSound2

	asl
	asl
	clc
	adc scale
	tay
	lda soundData1,y
noSound2
	sta note1,x

	; Handle balance setting
	lda temp
	adc atten1,x
	sta atten1,x

	; enable adsr control for standard play
	lda #255
	sta adsrEnable1,x

	txa
	eor #%00000001
	tax

primaryOsc

	ldy #0
	lda (temp16L),y

	cmp #255
	beq noSound1

	asl
	asl
	clc
	adc scale
	tay
	lda soundData1,y
noSound1
	sta note1,x

	; Handle balance setting
	lda temp
	adc atten1,x
	sta atten1,x
	
	; enable adsr control for standard play
	lda #255
	sta adsrEnable1,x

	lda soundTypeL,x
	sta sound1,x
	
	rts ; standardPlayer


;--------------------------------------------------------------------------
; VBlank
;--------------------------------------------------------------------------
; Handle user input and display setup during the VBLANK period
;--------------------------------------------------------------------------
VBlank
	; Read keyboards here.  
	jsr readKeyboards
	jsr handleSetupKeys
	
	; If the tempo is calculated once per frame, the tempo change
	; increments are too large.  So I chose to count the tempo 
	; twice per frame.  The tempo is checked and the voices setup here,
	; but the notePlayer is called about halfway through the screen draw
	; to keep the tempo steady.
	jsr handleTempo

	jsr calcVolume
	jsr easterCheck

	jsr soundEffectPlayer

	jsr colorCycling

	rts ; VBlank

;--------------------------------------------------------------------------
; Overscan
;--------------------------------------------------------------------------
; I ran out of time in VBlank, so I'm doing some things during overscan
;--------------------------------------------------------------------------
overscan

	sta WSYNC	
	lda #33		; Use the timer to make sure overscan takes (34)
	sta TIM64T	; 30 scan lines.  29 scan lines * 76 = 2204 / 64 = 34.4

	jsr handleSwitches

	ldx #255
	stx adsrEnable1
	stx adsrEnable2
	jsr voiceManager

	jsr calcVolume

	jsr soundEffectPlayer
	jsr notePlayer

	jsr handleTempo

	ldx #255
	stx adsrEnable1
	stx adsrEnable2
	jsr voiceManager

endOS	
	lda INTIM	; We finished, but wait for timer
	bne endOS	; by looping till zero
	
	sta WSYNC	; End last scanline

	lda #$82
	sta VBLANK
	lda #$02
	sta VBLANK

	rts	; overscan


;--------------------------------------------------------------------------
; Note Player
;--------------------------------------------------------------------------
; Actually plays assigned notes using assigned voices
;--------------------------------------------------------------------------
notePlayer

	; Sound type
	ldx sound1
	ldy sound2
	stx AUDC0
	sty AUDC1

	; Frequency
	ldx note1
	ldy note2
	stx AUDF0
	sty AUDF1

	; Volume
	ldx vol1
	ldy vol2
	stx AUDV0
	sty AUDV1
	
	rts ; notePlayer



;--------------------------------------------------------------------------
; Show Visuals
;--------------------------------------------------------------------------
; Alternative draw screen function for visual mode
;--------------------------------------------------------------------------
showVisuals

pictureLoop2
	lda INTIM			;check timer for end of VBLANK period
	bne pictureLoop2	;loop until it reaches 0

	lda #0
	sta COLUBK

	lda #$80
	sta VBLANK  	;end screen blank

; Setup Color buffer pointer
;--------------------------------------------------------------------------
	ldx visualPointer
	inx
	cpx #46
	bmi notResetVis
	ldx #0
notResetVis
	stx visualPointer

	sta WSYNC

; Put current note color into buffer
;--------------------------------------------------------------------------

	; Put the next color in the scrolling buffer
	; based on the current note1.

	lda note1
	cmp #255
	bne calcColor

	lda #0
	jmp setColor

calcColor
	asl
	asl
	asl
	asl
	asl
	ora #%00000100

setColor	
	sta visualBuffer,x

	sta WSYNC

	; Set the missile colors based on the current note2.

	lda note2

	cmp #255
	bne getColor2

	lda #0
	jmp setColor2

getColor2

	asl
	asl
	asl
	asl
	asl
	ora #%00001000

setColor2

	sta WSYNC

	sta COLUP0
	sta COLUP1

	; Enable missiles
	lda #255
	sta ENAM0
	sta ENAM1

	sta WSYNC

; Draw screen loop
;--------------------------------------------------------------------------
	ldy #46
visualLoop

	sta WSYNC
	
	; Move the missles around every few scanlines
	; based on notes pressed.  This creates some
	; neat patterns.
	lda note1
	asl
	asl
	sta HMM0
	lda note2
	asl
	asl
	sta HMM1

	sta WSYNC
	sta HMOVE

	; Have to play last calculated note around middle of screen 
	; for steadiest beat.
	cpy #22
	bne noNotePlay

	; Have to save X and Y on stack
	tya
	pha
	txa
	pha
	jsr notePlayer
	pla
	tax
	pla
	tay

noNotePlay

	sta WSYNC

	; Display the scrolling note-color buffer	
	inx
	cpx #46
	bmi notResetVis2
	ldx #0
notResetVis2
	sta WSYNC
	lda visualBuffer,x
	sta COLUBK

	dey
	bne visualLoop

; Done drawing screen.  Finish up.
;--------------------------------------------------------------------------
	sta WSYNC
	sta WSYNC
	sta WSYNC
	sta WSYNC
	sta WSYNC
	sta WSYNC
	
	
	lda #$82
	sta VBLANK	; Finished a screen, blank the beam.

	rts ; showVisuals




;--------------------------------------------------------------------------
; Draw TV Pictures
;--------------------------------------------------------------------------
; Here is where we step down the screen drawing everything.
;
; Note that temp16 is used in here as a text pointer, so don't use
; it for anything else during the loop.
;--------------------------------------------------------------------------
Picture
	ldx visualMode
	beq regularPicture

	jmp showVisuals

regularPicture
	lda #0
	sta COLUBK

	lda #11		;setup counter for rows of text
	sta scanSec	;store in zero page memory variable

	ldy #0		;Y is used to track progress through this screen's text
	sty EOTflag

pictureLoop
	lda INTIM	;check timer for end of VBLANK period
	bne pictureLoop	;loop until it reaches 0

	;sta WSYNC	;newline (1)
	lda #$80
	sta VBLANK  	;end screen blank


ScanLoop	
;---------------------------------------------------------------------------
	; This allows a different pointer to each line of text
	lda #12
	clc
	sbc scanSec		; Get the current row of chars
	pha
	asl				; multiply x2
	tax

	; Get the pointer to the next text.
	lda textPointer,x	
	sta temp16L
	inx
	lda textPointer,x
	sta temp16H


	; *** Set the BG Colors ***
	pla
	tay
	adc colorCycle
	tax
	lda bgColorCycles,x
	sta backColor

	lda setupCount
	beq loadSetupArray

	lda dividerArray1,y
	jmp drawDividers

loadSetupArray
	lda dividerArray2,y

drawDividers

	beq skipWhiteLine
	sta WSYNC

	; Draw a white line
	lda #$0D
	sta COLUBK	

	lda setupCount
	beq skipWhiteLine
	
	cpy #8
	beq skipWhiteLine

	; This makes some of the divider lines
	; in setup mode shorter to make the keyboard
	; grid look better 	

	; Waste some cycles:
	lda (temp16L,y)
	lda (temp16L,y)
	lda (temp16L,y)
	lda (temp16L,y)
	lda (temp16L,y)
	lda (temp16L,y)
	lda (temp16L,y)
	lda (temp16L,y)
	nop
	nop
	lda temp16L

	lda backColor
	sta COLUBK	

	
skipWhiteLine

	; Around the middle of the screen, the notePlayer is called.
	; This must occur on a line where the white divider line
	; is not drawn (on the Status or Setup screen)
	cpy #5
	bne skipNotePlayer
	jsr notePlayer

skipNotePlayer

	lda #64		; A variable amount of text will be processed, so stay....

	ldx backColor

	sta WSYNC
	jmp timer


; Timer
;--------------------------------------------------------------------------

;	align 256
timer

	sta  TIM8T	;....in sync by timing out after finished (7 scanlines)

	stx COLUBK

	ldx #22		;write 12 spaces to text buffer to wipe out what's there
	lda #<_space	; from previous row/frame/etc.
blankLine
	sta grfxBuffer,x	;grfxBuffer is our 24 byte, 16 bit list of chars
	dex	
	dex
	bpl blankLine	;fill it
	lda EOTflag
	bne eol
	

	ldx #0		; Will load from left to right.
	ldy #0		; Each line is referenced individually.
nextCol

	lda (temp16L),y	; Indirect/indexed - pointer to a section of text

	iny			; next char
	cmp #$FF	; FF is EOL
	beq eol		; done with a line?
	cmp #$FE
	bne noEOT
	lda #1
	sta EOTflag
	jmp eol
noEOT	
    sta grfxBuffer,x	; No, stuff this char into the buffer
	inx	
	inx
	jmp nextCol	; Just keep going--a screen w/o 10 $FF's will screw this up

eol	
	lda INTIM	; We finished, but wait for timer
	bne eol		; by looping till zero
	sta WSYNC	; end current line

	tya			; Need to save Y by putting into accumulator
	pha			; then onto stack.
	jsr println	; Print this row via subroutine. (6 scanlines)
	pla			; Pull Y off stack
	tay			; and put back.

	dec scanSec	; next row to print
	beq quitScanLoop; loop until all 11 rows of text have been displayed

	jmp ScanLoop

quitScanLoop

	sta WSYNC

	; Skip one line if in setup mode to make it exactly 262 lines
	lda setupCount
	bne skipLastLine
	sta WSYNC
skipLastLine

	; Draw the white line at the bottom.
	lda #$0D
	sta COLUBK
	sta WSYNC

	lda #$82
	sta VBLANK	; Finished a screen, blank the beam.
endScreen

	rts	; Picture




;---------------------------------------------------------------------------
; Text and Note Data
;---------------------------------------------------------------------------
	include snthdata.h



;--------------------------------------------------------------------------
; Call Keyboard Reader
;--------------------------------------------------------------------------
; Bankswitching code to call keyboard reader subroutine
; and then switch back to bank 1.
;--------------------------------------------------------------------------

	org $1FC0

readKeyboards
	ldx $1FF9	; (switch to bank 2)	
	nop         ; 1FE3 jsr readKeyboards8k
	nop         ; .
	nop         ; .
	nop         ; 1FE6 lda $1FF8  (Switch back to bank 1)        
	nop         ; .
	nop         ; .
	rts


;--------------------------------------------------------------------------
; Call Calculate Volume
;--------------------------------------------------------------------------
; Bankswitching code to call beat player subroutine
; and then switch back to bank 1.
;--------------------------------------------------------------------------

	org $1FD0

calcVolume
	ldx $1FF9	; (switch to bank 2)	
	nop         ; 1FE3 jsr calcVolume8k
	nop         ; .
	nop         ; .
	nop         ; 1FE6 lda $1FF8  (Switch back to bank 1)        
	nop         ; .
	nop         ; .
	rts

;--------------------------------------------------------------------------
; Call Beat Box
;--------------------------------------------------------------------------
; Bankswitching code to call beat player subroutine
; and then switch back to bank 1.
;
; Can't use ACC here since it is set to the number
; of oscillators for the beat box player.
;--------------------------------------------------------------------------

	org $1FE0

callBeatBox
	ldx $1FF9	; (switch to bank 2)	
	nop         ; 1FE3 jsr beat box
	nop         ; .
	nop         ; .
	nop         ; 1FE6 lda $1FF8  (Switch back to bank 1)        
	nop         ; .
	nop         ; .
	rts

;---------------------------------------------------------------------------
; Program Startup Vector
;---------------------------------------------------------------------------
	org $1FF3  	; The cart will start in bank 2, then a bankswitch
				; will occur and land here...

	jmp Start   ; Start program

	org $1FFC	; Program startup vector (not used)
	.word Start
	.word Start

	include snthup4k.h	; Upper 4k
Current Thread