;------------------------------------------------------------------------------
; YM2612 sound driver
;	Written by: Phil Summers (b1ackmailer) difficultylevelhigh@gmail.com
;
;------------------------------------------------------------------------------
; References:
;	https://hiddenpalace.org/News/Sega_of_Japan_Sound_Documents_and_Source_Code
;	https://www.smspower.org/maxim/Documents/YM2612
;	https://plutiedev.com/blog/20200103
;	https://www.plutiedev.com/ym2612-registers
;	https://www.plutiedev.com/ym2612-operations
;	https://en.wikipedia.org/wiki/Scientific_pitch_notation
;	https://gendev.spritesmind.net/forum/viewtopic.php?t=2915 (1)
;	http://nemesis.hacking-cult.org/MegaDrive/Documentation/YM2608J.PDF
;
;------------------------------------------------------------------------------
; Octave range is A#0-B7+3/4 HBIOS note 0..343
;------------------------------------------------------------------------------
;
YMSEL		.EQU	VGMBASE+00H		; Primary YM2162 11000000 a1=0 a0=0
YMDAT		.EQU	VGMBASE+01H		; Primary YM2162 11000001 a1=0 a0=1
YM2SEL		.EQU	VGMBASE+02H		; Secondary YM2162 11000010 a1=1 a0=0
YM2DAT		.EQU	VGMBASE+03H		; Secondary YM2162 11000011 a1=1 a0=1

;------------------------------------------------------------------------------
; Device capabilities and configuration
;------------------------------------------------------------------------------
;
YM_TONECNT	.EQU	6			; Count number of tone channels
YM_NOISECNT	.EQU	0			; Count number of noise channels
;
YM_PENDING_PERIOD	.DW	0	; PENDING PERIOD (12 BITS)
YM_PENDING_VOLUME	.DB	0	; PENDING VOL (8 BITS)	
YM_PENDING_DURATION	.DW	0	; PENDING DURATION (16 BITS)
YM_READY		.DB	0	; BIT 0 -> NZ DRIVER IS READY TO RECEIVE PLAY COMMAND
					; BIT 1 -> NZ EXECUTING WITHIN TIMER HANDLER = DO NOT DIS/ENABLE INT
YM_RDY_RST		.DB	0	; FLAG INDICATES IF DEVICE IS IN READY (NZ) OR RESET STATE (Z)
YM_DEBUG		.EQU	0	; CHANGE TO 1 TO ENABLE DEBUGGING
YM_RSTCFG		.EQU	0	; SET TO 1 FOR FULL REGISTER CLEAR
YM_FAST3438		.EQU	0	; FAST CPU'S WITH A YM3438 MAY REQUIRE A DELAY
;
		DEVECHO	"YM: IO="
		DEVECHO	YMSEL
		DEVECHO	"\n"
;
;------------------------------------------------------------------------------
; Driver function table and instance data
;------------------------------------------------------------------------------
;
YM_FNTBL:	.DW	YM_RESET
		.DW	ym_volume
		.DW	YM_PERIOD
		.DW	YM_NOTE
		.DW	YM_PLAY
		.DW	YM_QUERY
		.DW	YM_DURATION
		.DW	YM_DEVICE
		.DW	YM_BEEP
;
#IF (($ - YM_FNTBL) != (SND_FNCNT * 2))
	.ECHO	"*** INVALID SND FUNCTION TABLE ***\n"
	!!!!!
#ENDIF
;
YM_IDAT	.EQU	0				; NO INSTANCE DATA FOR THIS DEVICE
;
;------------------------------------------------------------------------------
; YM2162 Initialization
;	Announce device on console. 
;	Setup function tables. Setup the device.
;	Set volume off.
;	Return initialization status
;------------------------------------------------------------------------------
;
YM2612_INIT:	CALL	NEWLINE			; ANNOUNCE
		PRTS("YM:$")
;
		PRTS(" IO=0x$")
		LD	A,YMSEL
		CALL	PRTHEXBYTE
;
		LD	IY, YM_IDAT		; SETUP FUNCTION TABLE
		LD	BC, YM_FNTBL		; POINTER TO INSTANCE DATA
		LD	DE, YM_IDAT		; BC := FUNCTION TABLE ADDRESS
		CALL	SND_ADDENT		; DE := INSTANCE DATA PTR
;
YM_INIT:	ld	hl,ym_cfg
;		call	ym_prog
;		ret
;
;------------------------------------------------------------------------------
; Program ym2612 with a list of register entries
;------------------------------------------------------------------------------
;
ym_prog:	ld	c,(hl)			; get port address
		inc	hl
		ld	d,(hl)			; count of pairs
		inc	hl
;
#IF (YM_DEBUG)		
	push	af
	ld	a,c				; port
	call PRTHEXBYTE
	pop	af
#ENDIF
;
t_loop:		ld	a,(hl)			; get register to write
		out	(c),a			; write reg to RSEL port
;
#IF (YM_DEBUG)
	call PRTHEXBYTE				; register
#ENDIF
;
		inc	hl
		inc	c			; point to RDAT port
		ld	a,(hl)			; get value to write
		out	(c),a			; write value to RDAT port
;
#IF (YM_DEBUG)
	call PRTHEXBYTE
	call PC_SPACE
#ENDIF
;
		dec	c			; point back to RSEL port
		ld	b,0			; 
nready1:	
#IF YM_FAST3438==1) \ cp (ix) \ #ENDIF	\	; ym3438 delay (1)
		in	a,(c)           	; check device 
		rlca                    	; ready with timeout
		jr	nc,ready1       		; bits 7 = busy
		djnz	nready1
;
;		timed out
;
ready1:		inc	hl			;
		dec	d			; decrease # left to do
		jr	nz,t_loop
;
#IF (YM_DEBUG)
	call NEWLINE
#ENDIF
;
		ld	a,(hl)			; end flag?
		or	a
		jr	nz,ym_prog		; no? restart
		ret
;
;------------------------------------------------------------------------------
; Sound driver function - QUERY and subfunctions
;------------------------------------------------------------------------------
;
YM_QUERY:	LD	A, E
		CP	BF_SNDQ_CHCNT		; SUB FUNCTION 01
		JR	Z, YM_QUERY_CHCNT
;
		CP	BF_SNDQ_VOLUME		; SUB FUNCTION 02
		JR	Z, YM_QUERY_VOLUME
;
		CP	BF_SNDQ_PERIOD		; SUB FUNCTION 03
		JR	Z, YM_QUERY_PERIOD
;
		CP	BF_SNDQ_DEV		; SUB FUNCTION 04
		JR	Z, YM_QUERY_DEV
;
		OR	$FF			; SIGNAL FAILURE
		RET
;
YM_QUERY_CHCNT:	LD	BC,(YM_TONECNT*256)+YM_NOISECNT	
		XOR	A			; RETURN NUMBER OF TONE AND NOISE
		RET				; NOISE CHANNELS IN BC
;
YM_QUERY_PERIOD:LD	HL, (YM_PENDING_PERIOD)	; RETURN 16-BIT PERIOD
		XOR	A			; IN HL REGISTER
		RET
;
YM_QUERY_VOLUME:LD	A, (YM_PENDING_VOLUME)	; RETURN 8-BIT VOLUME
		LD	L, A			; IN L REGISTER
		XOR	A
;		LD	H, A
		RET
;
YM_QUERY_DEV:	LD	B, SNDDEV_YM2612	; RETURN DEVICE IDENTIFIER
		LD	DE, +(YMSEL*256)+YMDAT	; AND ADDRESS AND DATA PORT
		LD	HL, +(YM2SEL*256)+YM2DAT	
		XOR	A
		RET
;
;------------------------------------------------------------------------------
; Sound driver function - DEVICE
;------------------------------------------------------------------------------
;
YM_DEVICE:	LD	D,SNDDEV_YM2612		; D := DEVICE TYPE
		LD	E,0			; E := PHYSICAL UNIT
		LD	C,$00			; C := DEVICE TYPE
		LD	H,0			; H := MODE
		LD	L,YMSEL			; L := BASE I/O ADDRESS
		XOR	A
		RET
;
;------------------------------------------------------------------------------
; Sound driver function - BEEP
;------------------------------------------------------------------------------
;
YM_BEEP:
	JP	SND_BEEP		; DEFER TO GENERIC CODE IN HBIOS
;
;------------------------------------------------------------------------------
; Sound driver function - RESET
; Initialize device. Set volume off. Reset volume and tone variables.
;------------------------------------------------------------------------------
;
YM_RESET:	;CALL	AY_CHKREDY		; RETURNS TO OUR CALLER IF NOT READY
;
		PUSH	DE
		PUSH	HL
		CALL	YM_INIT			; SET DEFAULT CHIP CONFIGURATION
;
		XOR	A			; SIGNAL SUCCESS
		LD	(YM_RDY_RST),A		; IN RESET STATE
		LD	(YM_PENDING_VOLUME),A	; SET VOLUME TO ZERO
		LD	H,A
		LD	L,A
		LD	(YM_PENDING_PERIOD),HL	; SET TONE PERIOD TO ZERO
;
		POP	HL
		POP	DE
		RET
;
;------------------------------------------------------------------------------
; Sound driver function - VOLUME
;------------------------------------------------------------------------------
;
ym_volume:	LD	A,L			; SAVE VOLUME
		LD	(YM_PENDING_VOLUME),A
		XOR	A			; SIGNAL SUCCESS
		RET
;
;------------------------------------------------------------------------------
; Sound driver function - NOTE 
;------------------------------------------------------------------------------
;
YM_NOTE:	;CALL	PRTHEXWORDHL
		;CALL	PC_COLON

		LD	DE,40			; Calculate the ym2612 block (octave)
		ADD	HL,DE			; This will go into b13-b11
		LD	DE,48			; HL / DE
		CALL	DIV16			; BC = block (octave) HL = quarter semitone note
;				
		ADD	HL,HL
		LD	DE,ym_notetable		; point HL to frequency entry
		ADD	HL,DE			; for the quarter semitone note

		;CALL	PRTHEXWORDHL
		;CALL	PC_COLON
		;CALL	PRTHEXWORD
		;CALL	PC_COLON
;		
		LD	A,C			; SHIFT OCTAVE INTO RIGHT POSITION
		ADD	A,A			; X2
		ADD	A,A			; X4
		ADD	A,A			; X8 -NEEDS TO BE OR'ED WITH HIGH BYTE
;
		LD	E,(HL)			; COMBINE FREQUENCY ENTRY
		INC	HL			; AND BLOCK (OCTAVE) IN HL
		OR	(HL)
		LD	H,A
		LD	L,E

		;CALL	PRTHEXWORDHL
;
;------------------------------------------------------------------------------
; Sound driver function - PERIOD
;	The format for setting frequency on the ym2612 is 00xxxyyy-yyyyyyyy
;	Where xxx us the octave and yyy-yyyyyyyy is the frequency
;------------------------------------------------------------------------------
;
YM_PERIOD:	LD	A, H			; IF ZERO - ERROR
		OR	L
		JR	Z, YM_PERIOD1
;
		LD	A, H			; MAXIMUM TONE PERIOD IS 11-BITS
		AND	11000000B		; ALLOWED RANGE IS 0001-07FF (2047)
		JR	NZ,YM_PERIOD1		; AND 3 BITS FOR OCTAVE (7)
		LD	(YM_PENDING_PERIOD),HL	; RETURN NZ IF NUMBER TOO LARGE
		RET				; SAVE AND RETURN SUCCESSFUL
;
YM_PERIOD1:	LD	A, $FF			; REQUESTED PERIOD IS LARGER
		LD	(YM_PENDING_PERIOD),A	; THAN THE DEVICE CAN SUPPORT
		LD	(YM_PENDING_PERIOD+1),A	; SO SET PERIOD TO FFFF
		RET				; AND RETURN FAILURE
;
;------------------------------------------------------------------------------
; Sound driver function - DURATION
;------------------------------------------------------------------------------
;
YM_DURATION:	LD	(YM_PENDING_DURATION),HL ; SET TONE DURATION
		XOR	A
		RET
;
;------------------------------------------------------------------------------
; Sound driver function - PLAY
;	D = CHANNEL
;------------------------------------------------------------------------------
;
YM_PLAY:	ld	a,d
		cp	YM_TONECNT		; error if bad channel
		ret	nc
						
		cp	3			; 000 > 000, 011 > 100
		ld	e,part1			; 001 > 001, 100 > 101
		jr	c,ch012                 ; 010 > 010, 101 > 110
		sub	3
		ld	d,a			; d = 0..2
		add	a,4			; a = 4..6
		jr	ch345
ch012:		ld	e,part0
ch345:
;
#IF (YM_DEBUG)		
		call	PC_COLON
		call	PRTHEXBYTE		; a = 0..2 4..6
		push	af
		ld	a,d
		call	PRTHEXBYTE		; d = 00..05
		ld	a,e
		call	PRTHEXBYTE		; e = part0/part1 (c0/c2) 
		pop	af
		call	NEWLINE
#ENDIF
;
		ld	hl,ym_playcmd01
		ld	(hl),e			; set the part
;		
		ld	hl,ym_playcmd00		; setup keyoff channel
		ld	(hl),a
		ld	hl,ym_playcmd09		; setup keyon channel
		or	%10000000		; operator 4 only
		ld	(hl),a

		ld	a,$a4			; setup frequency register msb
		add	a,d			; $a4-$a6
		ld	hl,ym_playcmd02
		ld	(hl),a

		ld	a,$a0			; setup frequency register lsb
		add	a,d			; $a0-$a2
		ld	hl,ym_playcmd04
		ld	(hl),a

		ld	a,$4c			; setup volume register
		add	a,d			; $4c-$4e
		ld	hl,ym_playcmd06
		ld	(hl),a

		LD	A,(YM_RDY_RST)		; IF STILL IN RESET
		OR	A			; STATE GO SETUP FOR
		CALL	Z,YM_MAKE_RDY		; PLAYING
;
		ld	hl,(YM_PENDING_PERIOD)	; GET THE PREVIOUSLY SETUP
		ld 	de,ym_playcmd03		; TONE DATA AND
		ld	a,h
		ld	(de),a			; PATCH IT INTO THE
		ld 	de,ym_playcmd05		; YM2612 PLAY COMMAND
		ld	a,l
		ld	(de),a
;
		ld	de,ym_playcmd07
		ld	A,(YM_PENDING_VOLUME)	; GET VOLUME
		srl	a
		cpl
		and	%01111111		; PATCH IT INTO THE
		ld	(de),a   		; YM2612 PLAY COMMAND
#IF (YM_DEBUG)	
		ld	b,16			; debug
		call	NEWLINE			; dump
		ld	de,ym_playnote		; the 
ym_dbgcmd:	ld	a,(de)			; command
		call	PRTHEXBYTE		; stream
		call	PC_SPACE
		inc	de
		djnz	ym_dbgcmd
		call	NEWLINE
#ENDIF
		ld	hl,ym_playnote		; NOW PLAY IT
		jp	ym_prog
;
;------------------------------------------------------------------------------
; Make ready for hbios play
;------------------------------------------------------------------------------
;
YM_MAKE_RDY:	CPL
		LD	(YM_RDY_RST),A		; Invert the ready flag
		ld	hl,ym_cfg_ready		; Program ym2612 for playing
		jp	ym_prog
;
;------------------------------------------------------------------------------
; Command sequence to play a note
;------------------------------------------------------------------------------
;
ym_playnote:	.db	part0, 2/2
		.db	$28
ym_playcmd00:	.db	$00			; [0] KEY OFF		
;
ym_playcmd01:	.db	part0,6/2
ym_playcmd02:	.db	$A4
ym_playcmd03:	.db	$3F			; [X] Frequency MSB	
ym_playcmd04:	.db	$A0
ym_playcmd05:	.db	$FF			; [X] Frequency LSB	
ym_playcmd06:	.db	$4C
ym_playcmd07:	.db	$00			; [X] Volume	       
;
		.db	part0, 2/2
ym_playcmd08:	.db	$28
ym_playcmd09:	.db	$F0			; [0] KEY ON		

		.db	$00			; End flag
;
;------------------------------------------------------------------------------
; Quarter semitone F-Number values for frequency 
;------------------------------------------------------------------------------
;
ym_notetable:	.dw	644			; C	; 152
		.dw	653			;  approx
		.dw	663			;  approx
		.dw	672			;  approx	
		.dw	681			; C#	; 156
		.dw	691			;  approx
		.dw	702			;  approx
		.dw	712			;  approx
		.dw	722			; D	; 160
		.dw	733			;  approx
		.dw	744			;  approx
		.dw	754			;  approx
		.dw	765			; D#	; 164
		.dw	776			;  approx
		.dw	788			;  approx
		.dw	799			;  approx
		.dw	810			; E	; 168
		.dw	822			;  approx
		.dw	834			;  approx
		.dw	846			;  approx
		.dw	858			; F	; 172
		.dw	871			;  approx
		.dw	884			;  approx
		.dw	897			;  approx
		.dw	910			; F#	; 176
		.dw	924			;  approx
		.dw	937			;  approx
		.dw	951			;  approx
		.dw	964			; G 	; 180
		.dw	978			;  approx
		.dw	993			;  approx
		.dw	1007			;  approx
		.dw	1021			; G#	; 184
		.dw	1036			;  approx
		.dw	1051			;  approx
		.dw	1066			;  approx
		.dw	1081			; A 	; 188
		.dw	1097			;  approx
		.dw	1114			;  approx
		.dw	1130			;  approx
		.dw	1146			; A#	; 192
		.dw	1163			;  approx
		.dw	1180			;  approx
		.dw	1197			;  approx
		.dw	1214			; B	; 196
		.dw	1232			;  approx
		.dw	1250			;  approx
		.dw	1268			;  approx
;
;------------------------------------------------------------------------------
; Register configuration data for play
;------------------------------------------------------------------------------
;
ym_cfg_ready:	.db	part0, 2/2
		.db	$22, $00		; Global: LFO disable
;
		.db	part0, 6/2
		.db	$B0,$30			; Channel 1-3
		.db	$b1,$30			; Algorithm 0 S1>S2>S3>S4
		.db	$b2,$30			; Feedback pure sine wave
;
		.db	part1, 6/2
		.db	$B0,$30			; Channel 4-6
		.db	$b1,$30			; Algorithm 0 S1>S2>S3>S4
		.db	$b2,$30			; Feedback pure sine wave
;
		.db	part0, 6/2
		.db	$3c, $01		; Channel 1-3
		.db	$3d, $01		; Operator 4.MUL = 1
		.db	$3e, $01
;
		.db	part1, 6/2
		.db	$3c, $01		; Channel 4-6
		.db	$3d, $01		; Operator 4.MUL = 1
		.db	$3e, $01
;
		.db	part0, 6/2
		.db	$b4,%01000000		; Channel 1-3
		.db	$b5,%01000000		; Left Channel
		.db	$b6,%01000000
;
		.db	part1, 6/2
		.db	$b4,%10000000		; Channel 4-6
		.db	$b5,%10000000		; Right Channel
		.db	$b6,%10000000
;
		.db	part0, 6/2
		.db	$44, $7F		; Channel 1-3
		.db	$45, $7F		; Mute operator 3 <- pure sine wave
		.db	$46, $7F
;
		.db	part1, 6/2
		.db	$44, $7F		; Channel 4-6
		.db	$45, $7F		; Mute operator 3 <- pure sine wave
		.db	$46, $7F
;
		.db	part0, 6/2
		.db	$4C, $00		; Channel 1-3
		.db	$4d, $00		; Max volume for operator 4
		.db	$4e, $00
;
		.db	part1, 6/2
		.db	$4C, $00		; Channel 4-6
		.db	$4d, $00		; Max volume for operator 4
		.db	$4e, $00
;
		.db	part0, 6/2
		.db	$5C, $1F		; Channel 1-3
		.db	$5d, $1F		; Operator 4.AR = shortest
		.db	$5e, $1F
;
		.db	part1, 6/2
		.db	$5C, $1F		; Channel 4-6
		.db	$5d, $1F		; Operator 4.AR = shortest
		.db	$5e, $1F
;
		.db	part0, 6/2
		.db	$6C, $06		; Channel 1-3
		.db	$6d, $06		; Operator 4.D1R= 6
		.db	$6e, $06
;
		.db	part1, 6/2
		.db	$6C, $06		; Channel 4-6
		.db	$6d, $06		; Operator 4.D1R= 6
		.db	$6e, $06
;
		.db	part0, 6/2
		.db	$7C, $1F		; Channel 1-3
		.db	$7d, $1F		; Operator 4.D2R= 31
		.db	$7e, $1F
;
		.db	part1, 6/2
		.db	$7C, $1F		; Channel 4-6
		.db	$7d, $1F		; Operator 4.D2R= 31
		.db	$7e, $1F
;
		.db	part0, 6/2
		.db	$8C, $FF		; Channel 1-3
		.db	$8d, $FF		; Operator 4.SL = 15 / Operator4. RR=15
		.db	$8e, $FF
;
		.db	part1, 6/2
		.db	$8C, $FF		; Channel 4-6
		.db	$8d, $FF		; Operator 4.SL = 15 / Operator4. RR=15
		.db	$8e, $FF
;
		.db	$00			; End flag
;
;
;------------------------------------------------------------------------------
; Register configuration data for soft reset state
;------------------------------------------------------------------------------
;	
part0:		.equ	YMSEL
part1:		.equ	YM2SEL
;
#IF (YM_RSTCFG==0)
ym_cfg:		.db	part0,  24/2
		.db	$22,$00			; [0] lfo off
		.db	$27,$00			; [0] Disable independant Channel 3
		.db	$28,$00			; [0] note off ch 1
		.db	$28,$01			; [0] note off ch 2
		.db	$28,$02			; [0] note off ch 3
		.db	$28,$04			; [0] note off ch 4
		.db	$28,$05			; [0] note off ch 5
		.db	$28,$06			; [0] note off ch 6
		.db	$2b,$00			; [0] dac off
		.db	$b4,$00			; [0] sound off ch 1-3
		.db	$b5,$00	
		.db	$b6,$00	
;
		.db	part1, 6/2
		.db	$b4,$00			; [1] sound off ch 4-6
		.db	$b5,$00			; [1] 
		.db	$b6,$00			; [1] 
;
		.db	part0, 24/2
		.db	$40,$7f			; [0] ch 1-3 total level minimum
		.db	$41,$7f			; [0] 
		.db	$42,$7f			; [0] 
		.db	$44,$7f			; [0] 
		.db	$45,$7f			; [0] 
		.db	$46,$7f			; [0] 
		.db	$48,$7f			; [0] 
		.db	$49,$7f			; [0] 
		.db	$4a,$7f			; [0] 
		.db	$4c,$7f			; [0] 
		.db	$4d,$7f			; [0] 
		.db	$4e,$7f			; [0] 
;
		.db	part1, 24/2
		.db	$40,$7f			; [1] ch 4-6 total level minimum
		.db	$41,$7f			; [1]
		.db	$42,$7f			; [1]
		.db	$44,$7f			; [1]
		.db	$45,$7f			; [1]
		.db	$46,$7f			; [1]
		.db	$48,$7f			; [1]
		.db	$49,$7f			; [1]
		.db	$4a,$7f			; [1]
		.db	$4c,$7f			; [1]
		.db	$4d,$7f			; [1]
		.db	$4e,$7f			; [1]
;
		.db	$00			; End flag
;
;------------------------------------------------------------------------------
; Register configuration data for hard reset state
;------------------------------------------------------------------------------
;
#ELSE
ym_cfg:		.db	part0, 24/2
		.db	$22,$00			; [0] lfo off
		.db	$27,$00			; [0] Disable independant Channel 3
		.db	$28,$00			; [0] note off ch 1
		.db	$28,$01			; [0] note off ch 2
		.db	$28,$02			; [0] note off ch 3
		.db	$28,$04			; [0] note off ch 4
		.db	$28,$05			; [0] note off ch 5
		.db	$28,$06			; [0] note off ch 6
		.db	$2b,$00			; [0] dac off
		.db	$b4,$00			; [0] sound off ch 1-3
		.db	$b5,$00			; [0] 
		.db	$b6,$00			; [0] 

		.db	part1, 6/2
		.db	$b4,$00			; [1] sound off ch 4-6
		.db	$b5,$00			; [1] 
		.db	$b6,$00			; [1] 

		.db	part0, 24/2
		.db	$40,$7f			; [0] ch 1-3 total level minimum
		.db	$41,$7f			; [0] 
		.db	$42,$7f			; [0] 
		.db	$44,$7f			; [0] 
		.db	$45,$7f			; [0] 
		.db	$46,$7f			; [0] 
		.db	$48,$7f			; [0] 
		.db	$49,$7f			; [0] 
		.db	$4a,$7f			; [0] 
		.db	$4c,$7f			; [0] 
		.db	$4d,$7f			; [0] 
		.db	$4e,$7f			; [0] 

		.db	part1, 24/2
		.db	$40,$7f			; [1] ch 4-6 total level minimum
		.db	$41,$7f			; [1]
		.db	$42,$7f			; [1]
		.db	$44,$7f			; [1]
		.db	$45,$7f			; [1]
		.db	$46,$7f			; [1]
		.db	$48,$7f			; [1]
		.db	$49,$7f			; [1]
		.db	$4a,$7f			; [1]
		.db	$4c,$7f			; [1]
		.db	$4d,$7f			; [1]
		.db	$4e,$7f			; [1]

		.db	part0, 32/2
		.db	$2a,$00			; [0]	; dac value
 		.db	$24,$00			; [0]	; timer A frequency
		.db	$25,$00			; [0]	; timer A frequency
		.db	$26,$00			; [0]	; time B frequency
		.db	$30,$00			; [0]	; ch 1-3 multiply & detune
		.db	$31,$00	                ; [0]
		.db	$32,$00	                ; [0]
		.db	$34,$00	                ; [0]
		.db	$35,$00	                ; [0]
		.db	$36,$00	                ; [0]
		.db	$38,$00	                ; [0]
		.db	$39,$00	                ; [0]
		.db	$3a,$00	                ; [0]
		.db	$3c,$00	                ; [0]
		.db	$3d,$00	                ; [0]
		.db	$3e,$00	                ; [0]

		.db	part1, 24/2
		.db	$30,$00			; [1] ch 4-6 multiply & detune
		.db	$31,$00			; [1]
		.db	$32,$00			; [1]
		.db	$34,$00			; [1]
		.db	$35,$00			; [1]
		.db	$36,$00			; [1]
		.db	$38,$00			; [1]
		.db	$39,$00			; [1]
		.db	$3a,$00			; [1]
		.db	$3c,$00			; [1]
		.db	$3d,$00			; [1]
		.db	$3e,$00			; [1]
                             			
		.db	part0, 24/2
		.db	$50,$00	                ; [0] ch 1-3 attack rate and scaling
		.db	$51,$00	                ; [0]
		.db	$52,$00	                ; [0]
		.db	$54,$00	                ; [0]
		.db	$55,$00	                ; [0]
		.db	$56,$00	                ; [0]
		.db	$58,$00	                ; [0]
		.db	$59,$00	                ; [0]
		.db	$5a,$00	                ; [0]
		.db	$5c,$00	                ; [0]
		.db	$5d,$00	                ; [0]
		.db	$5e,$00	                ; [0]

		.db	part1, 24/2
		.db	$50,$00			; [1] ch 4-6 attack rate and scaling
		.db	$51,$00			; [1]
		.db	$52,$00			; [1]
		.db	$54,$00			; [1]
		.db	$55,$00			; [1]
		.db	$56,$00			; [1]
		.db	$58,$00			; [1]
		.db	$59,$00			; [1]
		.db	$5a,$00			; [1]
		.db	$5c,$00			; [1]
		.db	$5d,$00			; [1]
		.db	$5e,$00			; [1]

		.db	part0, 24/2
		.db	$60,$00	                ; [0] ch 1-3 decay rate and am enable
		.db	$61,$00	                ; [0]
		.db	$62,$00	                ; [0]
		.db	$64,$00	                ; [0]
		.db	$65,$00	                ; [0]
		.db	$66,$00	                ; [0]
		.db	$68,$00	                ; [0]
		.db	$69,$00	                ; [0]
		.db	$6a,$00	                ; [0]
		.db	$6c,$00	                ; [0]
		.db	$6d,$00	                ; [0]
		.db	$6e,$00	                ; [0]

		.db	part1, 24/2
		.db	$60,$00			; [1] ch 4-6 decay rate and am enable
		.db	$61,$00			; [1]
		.db	$62,$00			; [1]
		.db	$64,$00			; [1]
		.db	$65,$00			; [1]
		.db	$66,$00			; [1]
		.db	$68,$00			; [1]
		.db	$69,$00			; [1]
		.db	$6a,$00			; [1]
		.db	$6c,$00			; [1]
		.db	$6d,$00			; [1]
		.db	$6e,$00			; [1]

		.db	part0, 24/2
		.db	$70,$00	                ; [0] ch 1-3 sustain rate
		.db	$71,$00	                ; [0]
		.db	$72,$00	                ; [0]
		.db	$74,$00	                ; [0]
		.db	$75,$00	                ; [0]
		.db	$76,$00	                ; [0]
		.db	$78,$00	                ; [0]
		.db	$79,$00	                ; [0]
		.db	$7a,$00	                ; [0]
		.db	$7c,$00	                ; [0]
		.db	$7d,$00	                ; [0]
		.db	$7e,$00	                ; [0]

		.db	part1, 24/2
		.db	$70,$00			; [1] ch 4-6 sustain rate
		.db	$71,$00			; [1]
		.db	$72,$00			; [1]
		.db	$74,$00			; [1]
		.db	$75,$00			; [1]
		.db	$76,$00			; [1]
		.db	$78,$00			; [1]
		.db	$79,$00			; [1]
		.db	$7a,$00			; [1]
		.db	$7c,$00			; [1]
		.db	$7d,$00			; [1]
		.db	$7e,$00			; [1]

		.db	part0, 24/2
		.db	$80,$00	                ; [0] ch 1-3 release rate and sustain level
		.db	$81,$00	                ; [0]
		.db	$82,$00	                ; [0]
		.db	$84,$00	                ; [0]
		.db	$85,$00	                ; [0]
		.db	$86,$00	                ; [0]
		.db	$88,$00	                ; [0]
		.db	$89,$00	                ; [0]
		.db	$8a,$00	                ; [0]
		.db	$8c,$00	                ; [0]
		.db	$8d,$00	                ; [0]
		.db	$8e,$00	                ; [0]

		.db	part1, 24/2
		.db	$80,$00			; [1] ch 4-6 release rate and sustain level
		.db	$81,$00			; [1]
		.db	$82,$00			; [1]
		.db	$84,$00			; [1]
		.db	$85,$00			; [1]
		.db	$86,$00			; [1]
		.db	$88,$00			; [1]
		.db	$89,$00			; [1]
		.db	$8a,$00			; [1]
		.db	$8c,$00			; [1]
		.db	$8d,$00			; [1]
		.db	$8e,$00			; [1]

		.db	part0, 24/2
		.db	$90,$00	                ; [0] ch 1-3 ssg-eg
		.db	$91,$00	                ; [0]
		.db	$92,$00	                ; [0]
		.db	$94,$00	                ; [0]
		.db	$95,$00	                ; [0]
		.db	$96,$00	                ; [0]
		.db	$98,$00	                ; [0]
		.db	$99,$00	                ; [0]
		.db	$9a,$00	                ; [0]
		.db	$9c,$00	                ; [0]
		.db	$9d,$00	                ; [0]
		.db	$9e,$00	                ; [0]

		.db	part1, 24/2
		.db	$90,$00			; [1] ch 4-6 ssg-eg
		.db	$91,$00			; [1]
		.db	$92,$00			; [1]
		.db	$94,$00			; [1]
		.db	$95,$00			; [1]
		.db	$96,$00			; [1]
		.db	$98,$00			; [1]
		.db	$99,$00			; [1]
		.db	$9a,$00			; [1]
		.db	$9c,$00			; [1]
		.db	$9d,$00			; [1]
		.db	$9e,$00			; [1]

		.db	part0, 12/2
		.db	$a0,$00	                ; [0] ch 1-3 frequency
		.db	$a1,$00	                ; [0]
		.db	$a2,$00	                ; [0]
		.db	$a4,$00	                ; [0]
		.db	$a5,$00	                ; [0]
		.db	$a6,$00	                ; [0]
;		.db	$a8,$00	                ; [0] ch 3 special mode
;		.db	$a9,$00	                ; [0]
;		.db	$aa,$00	                ; [0]
;		.db	$ac,$00	                ; [0]
;		.db	$ad,$00	                ; [0]
;		.db	$ae,$00	                ; [0]

		.db	part1, 12/2
		.db	$a0,$00			; [1] ch 4-6 frequency
		.db	$a1,$00			; [1]
		.db	$a2,$00			; [1]
		.db	$a4,$00			; [1]
		.db	$a5,$00			; [1]
		.db	$a6,$00			; [1]
;		.db	$a8,$00			; [1] ch 3 special mode
;		.db	$a9,$00			; [1]
;		.db	$aa,$00			; [1]
;		.db	$ac,$00			; [1]
;		.db	$ad,$00			; [1]
;		.db	$ae,$00			; [1]

		.db	part0, 6/2
		.db	$b0,$00	                ; [0] ch 1-3 algorith + feedback
		.db	$b1,$00	                ; [0]
		.db	$b2,$00	                ; [0]

		.db	part1, 6/2
		.db	$b0,$00			; [1] ch 4-6 algorith + feedback
		.db	$b1,$00			; [1]
		.db	$b2,$00			; [1]
;
		.db	$00			; End flag
#ENDIF
