; NSPC engine, as documented by MathOnNapkins
; Version 4
; 
; Song 		-> Pattern 		-> Track -> Data (from DJBouche)
; $D000[variable] -> $0016[0x10] 	-> $[16] -> 
; Example: The first song at $D000 has a pointer to $D036.
; This gets stored to SPC location $0040. basically, $0040 = #$D036
; Indirectly, the value at $D036 is #$D03C. This is the start of the pattern table.
; It is as follows: $D04C, $D0A3, $D0C1, $D0E0, $D0EE, $0000, $0000, $0000
; The pattern table has 8 word length track pointers, as shown above.
; This table gets copied to the 16 byte array at $0030.
;

;Memory map:

; $00 = input song value
; $01 = input sfx value 1
; $02 = input sfx value 2
; $03 = input sfx value 3

; $04 = current song" value. e.g. the Dark World theme would be 9.
; $05 = current sfx value 1
; $06 = current sfx value 2
; $07 = current sfx value 3

; $08 = reference song value (used when the S-CPU tries to change the song to see if the value written to $04 is different.)
; $09 = reference sfx value 1
; $0A = reference sfx value 2
; $0B = reference sfx value 3

; $0C = delay counter used when a new song is loaded. starts at 2 and ticks down each frame. 
; gives the system enough time to get all the data for the new song running

; $0D = unused as far as I can tell

; $0E = another place to keep track of muted voices 
; $0F = related to pitch modulation somehow. causes a vibrato effect for each channel it's set for

; $10 = ????
; $11 = index into the Pitch Jump table
; $12 = sometimes used to write to DSP Registers.
; $13 = seems to be some kind of thing telling us not to interrupt some process.

; $14[0x02] = used as a scratch / temporary variable

; $16 = pointers in the track/song system are loaded off here sometimes.
; Let's call it part

; $17 = mirror for $80+X in one routine (still investigating)

; $18 = seems to be totally unused (though written to, along with $19)
; $19 = seems to be totally unused (though written to, along with $18)

; $1A = mirrors muted voices?
; $1B = flag, basically if set, means that the SPC is still processing song data, but it's not outputting new data to the DSP

; $1C[0x04] = unused

; $20 = related to sound effects (sfx3?)

; $21[0x0A] = unused

; $2C[0x02] - word pointer to the current byte of sound effect data

; $2E[0x02] - unused

; $30[0x10] = track pointers, each being two bytes. Each track pointer is associated with a voice, from left to right
; e.g. track 0's pointer is at $30 and goes with voice 0.

; $40 = Master song pointer
; $42 = ???
; $43 = Sound Effect Delay Timer
; $44 = probably just a temporary place to store X's value
;		though in the case of tracks, it seems to store the current track number (times two of course)
; $45 = indicates which voices are keyed
; $46 = indicates which voices are muted
; $47 = probably some sort of bitwise "voice" indicator when going through loops.
; $48 = VOXCON register. 
; $49 = noise enabled voices
; $4A = echo enabled voices
; $4B = pitch modulated voices, but never seems to get used.
; $4C = related to $4D, I'm guessing it's sometimes a bit inversion of $4D
; $4D = echo delay enabled voices.
; $4E = buffer for echo feedback volume register (EFB)
; $4F = unused?
; $50 = Master Pitch Control
; $51 = Music Delay Timer
; $52 = Lower byte of master speed control ($53). Probably not used
; $53 = Master speed control for music (AKA tempo)
; $54 = ???

; $58[0x02] = Global Volume. Usually only the high byte is used
; $5A	= countdown timer for a volume change. Once it reaches zero the global volume ($59) will be set to the value at $5B
; $5B = target global volume value
; $5C[0x02] = in a global volume ramp situation, this is the rate per "frame" that $58[0x02] is adjusted by

; $5E = ???? maybe this indicates global volume ramp on a per voice basis?

; $5F = For one byte instrument commands (0xCA to 0xDF), 
; this is a base offset into the instrument table that is applied in addition.

; $60[2] = echo volume left
; $62[2] = echo volume right
; $64[2] = echo volume left pan step counter
; $66[2] = echo volume right pan step counter
; $68 = number of frames to perform echo pan
; $69 = echo volume left target pan value
; $6A = echo volume right target pan value 

; $70+X = flag of sorts...
; $71+X = ???? related to the multiplication of $0200+X and $0201+X
; $80+X = iteration counter for the CallLoop command. When the command is invoked,
; it sets this memory location to the number of times the routine will loop.

; $90+X = number of "frames" it takes for the volume setting ($0301+X) to reach its target value ($0320+X (I think))
; $91+X = number of "frames" it takes for the pan setting ($0331+X) to reach its target value ($0350+X)

; $A0+X = Number of frames to perform pitch slide for
; $A1+X = Countdown timer until pitch slide can start (blocks pitch slide from occurring for this many frames)

; $B0+X = Starts at zero and counts up to the vibrato set point $02B0+X (when vibrato is enabled). Rests to zero on voice
; key off.
; $B1+X = Vibrato intensity value. Has a multiplicative effect on the oscillation of the pitch.

; $C0+X = Up counter for tremelo. Once a voice is keyed on, this counts up to the set point ($02E0+X), when that happens
; tremelo begins occurring for that voice. Resets to zero when a voice keys off or is rekeyed on.
; $C1+X = Tremelo intensity value. Has a multiplicative effect on the oscillation that tremelo causes.

; $D0[0x20] = Not used?

; $F0 - $F1 = register
; $F2 = DSP Register Latch
; $F3 = DSP Register Write
; $F4 - $FF registers (see spc documentation)

; $0100+X = ???? vibrato related

; $0200+X = note sustain time (when a voice is keyed on, this is how long it takes to reach release state)
; $0201+X = note level pitch modulation? (I think?) 

; $0210+X = note level volume modulation
; $0211+X = contains the instrument value for each voice.

; $0220+X = last two bytes of the instrument table for this voice
; $0221+X = same as $0220+X. Usage isn't clear for these two bytes yet.

; $0230+X = in a call loop, this is the return address to the caller
; $0231+X = high byte of $0230+X

; $0240+X = in a call loop, this is the destination address
; $0241+X = high byte of $0240+X

; $0250[0x30] = unused... presumably

; $0280+X = Used to set the value of $A0+X in PSlideTo and PSlideFr. See $0281+X for explanation.
; $0281+X = Used to set the value of $A1+X in PSlideTo and PSlideFr. This is because those commands make
; use of code that the more general PSlide command has

; $0290+X = If nonzero, a pitch slide is performed every frame
; $0291+X = The pitch slide value is how much pitch is adjusted by

; $02A0+X = Vibrato additive accumulator. See $02A1+X
; $02A1+X = Amount to add to $02A0+X each frame (used for Vibrato)

; $02B0+X = Vibrato set point value. This is how many frames must pass before vibrato on a keyed voice is enabled
; $02B1+X = Vibrato value that $100+X must meet before

; $02C0+X = Vibrato step variable (gets added to $B1+X whenever $0100+X is not equal to $02B0+X)
; $02C1+X = When a certain condition is met, this is used to set $B1+X (vibrato intensity) to a new value.

; $02D0+X = Tremelo additive accumulator. See $02D1+X
; $02D1+X = Tremelo Rate value. This value gets added to $02D0+X each frame when tremelo is in affect.

; $02E0+X = Tremelo Setpoint. $C0+X has to count up to this value inorder for tremelo to go into affect.
; $02E1+X = Unused?

; $02F0+X = channel pitch control (additive)
; $02F1+X = ?????

; $0300+X = low byte of actual volume level
; $0301+X = actual volume level (fractional)

; $0310+X = low byte of volume ramp increment value
; $0311+X = volume ramp increment value

; $0320+X = volume ramp target value
; $0321+X = fully adjusted volume level (after all multiplication is done in a routine or two)

; $0330+X = lower byte of pan value (likely not used)
; $0331+X = pan setting. Valid values range from 0 (full left) to 0x0A (fully balanced) to 0x14 (fully right)
; other values can be used, but certainly the output isn't going to work as expected

; $0340+X = lower byte of pan sweep increment value
; $0341+X = pan sweep increment value

; $0350+X = Target pan value in a pan sweep
; $0351+X = Pan amount. 0x0A means no pan

; $0360+X = low byte of a temporary pitch scaler variable
; $0361+X = high byte of a temporary pitch scaler variable

; $0370+X = low byte of a hexadecimal fraction (this is right of the "hexadecimal point")
; $0371+X = high byte of a hexadecimal fraction (this is left of the "hexadecimal point")

; $0380+X = holds the pitch value of the current note (clamped to 7 bits)
; $0381+X = "fine tune" pitch control. basically the low byte of pitch modulation, for very minor variations

; $0390+X = low byte of data pointer for sfx (mirrors $2C when sfx is not in use)
; $0391+X = high byte of data pointer for sfx (mirrors $2D when sfx is not in use)

; $03A0+X = ????
; $03A1+X = ????

; $03B0+X = countdown timer for sound effects
; $03B1+X = mirrors $03B0+X

; $03C0 = multiple of 2, frequently stored to X during sfx code

; $03C1 = related to echo enable

; $03C2 = ???

; $03C3 = related to command F5, which does something like echo

; $03CA = if nonzero, it will cause the current song to stop silent 
; after it has counted down to zero.
; if already at zero, it causes no harm.

; $03CB = associated with sfx2
; $03CC = associated with sfx2

; $03CD = associated with sfx3
; $03CE = associated with sfx3

; $03CF = associated with sfx1

; $03E0 = associated with sfx1

; $03E1 = used with half volume command (and the restoring to full volume)

; $03E2 = used with sfx 3
; $03E4 = Seems to be a delay timer that happens before SFX can actually be played
; don't confuse with $43
; $03E5 = Is half of $03E4. This value gets fed to voice 7 volume when loading sound effects.
; $03FF+X = for each channel, if nonzero it will mute the channel (though not sure if mute is the exact word)

; $3C00 = the sample table
; $3D00 = the instrument table, which carries some DSP settings, and the sample number for the instrument
; $3E00 = sound effects table used to write to VxVOLL through VxGAIN (registers x0 through x7) the 9th value is stored to
; a RAM location ($0221+X)

; $17BE[0x40] = Table of 2 byte pointers to each sfx1's main data

; $17FF[0x20] = Table of 1 byte values that... don't seem to be formatted to be even used properly
;			jury's out on this one

; $181E[0x80] = Table of 2 byte pointers to each sfx2's main data
; $189D[0x40] = Replaces the value at $02 when sfx2 starts playing
; $18DC[0x40] = ???? gets written to $03E2

; $191A[0x80] = Table of 2 byte pointers to each sfx3's main data
; $1999[0x40] = Replaces the value at $03 when sfx3 starts playing
; $19D8[0x40] = ???? gets written to $03E2
 
; *********************************************************************
; *********************************************************************
; NSPC Initialization ------------------------------------------
; This code gets jumped to after Zelda 3 finishes loading up all the sound data.
; So this is in effect, the beginning of the engine.

	0800: 20        CLRP	; sets direct page to $00
	0801: CD CF     MOV   X,#$CF
	0803: BD        MOV   SP,X
	0804: E8 00     MOV   A,#$00  ; A = 0
	0806: 5D        MOV   X,A	; X = 0

ZeroLoop1:

	0807: AF        MOV   (X)+,A
	0808: C8 E0     CMP   X, #$E0 ; ZERO OUT THE FIRST 0xE0 BYTES OF MEM.

	080A: D0 FB     BNE   ZeroLoop1

	080C: CD 00     MOV   X,#$00

ZeroLoop2:

	080E: D5 00 02  MOV   $0200+X, A
	0811: 3D        INC   X
	0812: D0 FA     BNE   ZeroLoop2 ; ZERO OUT $200-$2FF

ZeroLoop3:

	0814: D5 00 03  MOV   $0300+X,A
	0817: 3D        INC   X
	0818: D0 FA     BNE   ZeroLoop3 ; ZERO OUT $300-$3FF

	081A: BC        INC   A ; A = 1

	081B: 3F 22 0E  CALL  $0E22 ; Handle Echo Delay

	081E: A2 48     SET5  $48 ; Turn off echo.

	0820: E8 60     MOV   A,#$60
	0822: 8D 0C     MOV   Y,#$0C ; SET MASTVOLL TO #$60

	0824: 3F F7 09  CALL  WriteToDsp(A,Y)

	0827: 8D 1C     MOV   Y,#$1C ; SET MASTVOLR TO #$60

	0829: 3F F7 09  CALL  WriteToDsp(A,Y)

	082C: E8 3C     MOV   A,#$3C
	082E: 8D 5D     MOV   Y,#$5D ; SAMPLE DIRECTORY TABLE IS AT $3CXX

	0830: 3F F7 09  CALL  WriteToDsp(A,Y)

	0833: E8 F0     MOV   A,#$F0
	0835: C5 F1 00  MOV   $00F1,A   ; Clear all the IO ports ($2140-3 aka $F4-7?) Not well documented.

	0838: E8 10     MOV   A,#$10    ; Start a timer at $00FA. Needs to count up to 0x10
	083A: C5 FA 00  MOV   $00FA,A
	083D: C4 53     MOV   $53,A     ; Store the value it needs to hit at $0053

	083F: E8 01     MOV   A,#$01    ; Enables the first timer ($00FA, presumably :/ )
	0841: C5 F1 00  MOV   $00F1,A 

ExecutionLoop:

	0844: 8D 0A     MOV   Y,#$0A	  ; Y = 0x0A

NextRegister:

	0846: AD 05     CMP   Y,#$05

	0848: F0 07     BEQ   $0851 	  	; if(Y == 0x05)

	084A: B0 08     BCS   $0854     	; if(Y >= 0x05)

	084C: 69 4D 4C  CMP   $4C,$4D   	; else (Y < 0x05)

	084F: D0 11     BNE   $0862	  	; if($4C != $4D)

$0851:

	0851: E3 4C 0E  BBS7  $4C,$0862	; branch if the value at $4C is negative.

$0854:

	0854: F6 AC 11  MOV   A, RegisterList - 1 + Y ; DEAL WITH A BUNCH OF REGISTERS.
	0857: C5 F2 00  MOV   $00F2, A ;

	085A: F6 B6 11  MOV   A, LoadValueFrom - 1 + Y ; ASSIGN THEM VALUES FROM SPECIFIED MEMORY LOCATIONS
	085D: 5D        MOV   X, A

	085E: E6        MOV   A, (X) 		; load indirectly from the address stored in X
	085F: C5 F3 00  MOV   $00F3, A 	; mess with pitch modulation, key off bits, noise enable bits, etc.

$0862:

	0862: FE E2     DBNZ  Y, NextRegister

	0864: CB 45     MOV   $45, Y		; Unkey all voices
	0866: CB 46     MOV   $46, Y		; Unmute all voices.

	0868: E4 18     MOV   A, $18
	086A: 44 19     EOR   A, $19		; A = $18 | $19;
	086C: 5C        LSR   A
	086D: 5C        LSR   A			; A >>= 2;
	086E: ED        NOTC			; invert carry flag
	086F: 6B 18     ROR   $18		; rotate $18 to the right, possibly taking in a carry flag bit up top.
	0871: 6B 19     ROR   $19		; rotate $19 to the rigth, possibly taking $18's old lsb up top.

TimerWaitLoop:

	0873: EC FD 00  MOV   Y,$00FD ; WAIT FOR THIS TIMER TO COUNT DOWN?

	0876: F0 FB     BEQ   TimerWaitLoop

	0878: 6D        PUSH  Y
	0879: E8 38     MOV   A,#$38 ; #$38 = 56 (decimal)
	087B: CF        MUL   YA    ; A = 56 * CN0 (timer count 0)
	087C: 60        CLRC
	087D: 84 43     ADC   A,$43  ; A += value at $0043;
	087F: C4 43     MOV   $43,A

	0881: 90 31     BCC   WaitForSFX	; branch if not enough ticks have counted down.

; otherwise handle sound effects

	0883: 3F 45 14  CALL  $1445	; Seems to play the existing sfx1
	0886: 3F 6D 13  CALL  $136D	; Checks for a negative value of sfx1 input, if so,
					; causes existing sfx1 to fade out over 78 main loops.

	0889: CD 01     MOV   X,#$01 ; HANDLE VALUES WRITTEN TO $2141 (SFX)

	088B: 3F E3 08  CALL  $08E3	; Synchronizes with the CPU and determines if this is a different sound effect from the last one.

	088E: 3F AD 14  CALL  $14AD	; handles sound effects on input port 1 ($F5)
	0891: 3F B7 13  CALL  $13B7	;

	0894: CD 02     MOV   X,#$02 ; HANDLE VALUES WRITTEN TO $2142 (SFX)

	0896: 3F E3 08  CALL  $08E3
	0899: 3F 0B 15  CALL  $150B	; handles sound effects on input port 2 ($F6)
	089C: 3F BC 13  CALL  $13BC	; ????

	089F: CD 03     MOV   X,#$03	; HANDLE VALUES WRITTEN TO $2143 (SFX)

	08A1: 3F E3 08  CALL  $08E3

	08A4: 69 4D 4C  CMP   $4C,$4D	; ???

	08A7: F0 0B     BEQ   $08B4	; if($4C == $4D) branch (skip handling of these sound effects)

	08A9: AC C7 03  INC   $03C7	; $03C7++;
	08AC: E5 C7 03  MOV   A,$03C7
	08AF: 5C        LSR   A		; A = ($03C7) / 2

	08B0: B0 02     BCS   $08B4	; if($03C7 is odd)

	08B2: AB 4C     INC   $4C	; else $4C++

WaitForSFX:

	08B4: E4 53     MOV   A,$53	; The value that the $FA timer needs to increment to. In this case #$10 ticks.
	08B6: EE        POP   Y		; The number of times that CN0 has incremented
	08B7: CF        MUL   YA	; YA = timer length * num times timer has hit.
	08B8: 60        CLRC
	08B9: 84 51     ADC   A,$51
	08BB: C4 51     MOV   $51,A	; $51 apparently accumulates this amount "aggregate time" or whatever.

	08BD: 90 0B     BCC   WaitForSong	; If this amount of time has not crossed the threshhold, i.e. $51 has not rolled over past #$FF so far.

	08BF: 3F F9 0A  CALL  $0AF9	; Handle song input values.

	08C2: CD 00     MOV   X,#$00 ; HANDLE VALUES WRITTEN TO $2140 (SONG)

	08C4: 3F E3 08  CALL  $08E3	; Synchronize with the CPU.

	08C7: 5F 44 08  JMP   ExecutionLoop

WaitForSong:

; I think this is the meat of playing the songs... this is what handles the progression

	08CA: E4 04     MOV   A,$04		; What song are we playing?

	08CC: F0 12     BEQ   no_song		; if no song is playing

	08CE: CD 00     MOV   X,#$00		; else
	08D0: 8F 01 47  MOV   $47,#$01	; current voice = 0; $47 = 1;

NextTrackMain:

	08D3: F4 31     MOV   A,$31+X		; Examine the high byte of the first pointer of the track table.

	08D5: F0 03     BEQ   skip_voice	; If it's not a valid pointer

	08D7: 3F D5 10  CALL  $10D5		; else // execute the next part of the track

skip_voice:

	08DA: 3D        INC   X
	08DB: 3D        INC   X
	08DC: 0B 47     ASL   $47		; look at the next voice. (voice++ if you will)

	08DE: D0 F3     BNE   NextTrackMain

no_song:

	08E0: 5F 44 08  JMP   ExecutionLoop	; return to the start of the execution loop

; End of the main execution loop

; Subroutine $08E3
; Handles sound effects

	08E3: F4 04     MOV   A,$04+X    ; Send what we're currently playing to a port on the SNES.
	08E5: D5 F4 00  MOV   $00F4+X,A  ; CURRENT SPC SOUND -> $2140, X 

SynchronizeSound:

	08E8: F5 F4 00  MOV   A,$00F4+X  ; CURRENT CPU SOUND -> $F4 -> A 
	08EB: 75 F4 00  CMP   A,$00F4+X  ; See if the register value changed in the time we just read it.

	08EE: D0 F8     BNE   SynchronizeSound ; SYNCHRONIZE THE SOUND.

	08F0: FD        MOV   Y,A   ; Y = A

	08F1: D0 00     BNE   $08F3 			; Not a particularly useful branch. DOES NOTHING OBVIOUSLY!
					    			; Perhaps it's a code remnant or just an unimplemented idea.
	
	08F3: F4 08     MOV   A,$08+X			; A = $08+X; // $08+X is a 4 byte array of current sounds for each port.
	08F5: DB 08     MOV   $08+X,Y			; $08+X = Y;
	08F7: DE 08 05  CBNE  $08+X, ChangeSound	; If it wasn't the same sound as before...
	08FA: 8D 00     MOV   Y,#$00			; Else it was the same sound and therefore no action is necessary.
	08FC: DB 00     MOV   $00+X,Y			; Hence the reason $00+X = 0.
	
	08FE: 6F        RET				; return;
	
ChangeSound:

	08FF: DB 00     MOV   $00+X,Y			; $00+X = Y;

$0901:

	0901: 6F        RET				; return;

; **********************************************************
; Subroutine $0902
; Inputs: Y = track_byte
; Handles notes and rests 

	0902: AD CA     CMP   Y,#$CA

	0904: 90 05     BCC   $090B		; if(Y < 0xCA) goto $090B;

	0906: 3F 66 0C  CALL  $0C66		; sets the instrument for this voice using an alternate method
							; doesn't seem to see much use.
							; you can use 0xCA through 0xDF to set the instrument index to
							; 0x00 through 0x15, respectively.

	0909: 8D A4     MOV   Y,#$A4		; Set it to a note... uh????

$090B:

	090B: AD C8     CMP   Y,#$C8

	090D: B0 F2     BCS   $0901		; if(Y >= 0xC8) return;

	090F: E4 1A     MOV   A,$1A		; case for Y < 0xC8 (seems like a typical case)
	0911: 24 47     AND   A,$47

	0913: D0 EC     BNE   $0901		; if this voice is deactivated, return;

	0915: DD        MOV   A,Y		; A = track_byte;
	0916: 28 7F     AND   A,#$7F
	0918: 60        CLRC
	0919: 84 50     ADC   A,$50		; $50 is the overall pitch modulation
	091B: 60        CLRC
	091C: 95 F0 02  ADC   A,$02F0+X	; $02F0+X is an additional channel level pitch modulation
	091F: D5 61 03  MOV   $0361+X,A	; $0361+X = $50 + $2F0+X + (track_byte & 0x7F);

	0922: F5 81 03  MOV   A,$0381+X
	0925: D5 60 03  MOV   $0360+X,A	; $0360+X = $0381+X;

	0928: F5 B1 02  MOV   A,$02B1+X
	092B: 5C        LSR   A			; A = $02B1 >> 1;

	092C: E8 00     MOV   A,#$00
	092E: 7C        ROR   A
	092F: D5 A0 02  MOV   $02A0+X,A	; $02A0+X = (carry ? 0x80 : 0x00);

	0932: E8 00     MOV   A,#$00
	0934: D4 B0     MOV   $B0+X,A	
	0936: D5 00 01  MOV   $0100+X,A
	0939: D5 D0 02  MOV   $02D0+X,A
	093C: D4 C0     MOV   $C0+X,A			; $C0+X = $02D0+X = $0100+X = $B0+X = 0;

	093E: 09 47 5E  OR    $5E,$47
	0941: 09 47 45  OR    $45,$47			; in keyed voices, included the current voice...

	0944: F5 80 02  MOV   A,$0280+X
	0947: D4 A0     MOV   $A0+X,A			; $A0+X = $0280+X;

	0949: F0 1E     BEQ   no_pitch_slide	; if($0280+X == 0) goto no_pitch_slide;

	094B: F5 81 02  MOV   A,$0281+X
	094E: D4 A1     MOV   $A1+X,A			; $A1+X = $0281+X

	0950: F5 90 02  MOV   A,$0290+X

	0953: D0 0A     BNE   do_pitch_slide	; if($0290+X) goto do_pitch_slide;

	0955: F5 61 03  MOV   A,$0361+X
	0958: 80        SETC
	0959: B5 91 02  SBC   A,$0291+X		; subtract off pitch_slide
	095C: D5 61 03  MOV   $0361+X,A		; this sction pre-emptively subtracts off $0291+X which will later be added back in
								; (assuming pitch_slide is nonzero)
do_pitch_slide:

	095F: F5 91 02  MOV   A,$0291+X
	0962: 60        CLRC
	0963: 95 61 03  ADC   A,$0361+X		; A = input pitch value (so far for this channel)

	0966: 3F AB 0E  CALL  $0EAB			; sets $0370+X and $0371+X to a fraction... see the actual routine

no_pitch_slide:

	0969: 3F C3 0E  CALL  $0EC3			; Uses $0361+X and $0360+X to set $11 and $10, respectively

; alternate entry point

$096C:

	096C: 8D 00     MOV   Y,#$00
	096E: E4 11     MOV   A,$11	; YA = ($11 & 0x00FF);
	0970: 80        SETC		;
	0971: A8 34     SBC   A,#$34	;

	0973: B0 09     BCS   $097E	; if(A >= 0x34);

	0975: E4 11     MOV   A,$11	; A = $11;
	0977: 80        SETC		;
	0978: A8 13     SBC   A,#$13	;

	097A: B0 06     BCS   $0982	; if(A >= 0x13);

	097C: DC        DEC   Y		; Y = #$FF
	097D: 1C        ASL   A		; A <<= 1;
	
	097E: 7A 10     ADDW  YA,$10
	0980: DA 10     MOVW  $10,YA	; $10 += YA

	0982: 4D        PUSH  X		; Push the track index.
	0983: E4 11     MOV   A,$11	;
	0985: 1C        ASL   A		; A = $11 << 1;
	0986: 8D 00     MOV   Y,#$00	; Y = 0
	0988: CD 18     MOV   X,#$18	; X = 0x18; // (24 in decimal)
	098A: 9E        DIV   YA,X	; Since A is even, Y will contain the remainder of this division, it would appear that
						; The remainder will always be a multiple of 2 (remember 0 is a multiple of 0)
	098B: 5D        MOV   X,A	; X = A;

	098C: F6 C2 11  MOV   A,$11C2+Y
	098F: C4 15     MOV   $15,A

	0991: F6 C1 11  MOV   A,$11C1+Y
	0994: C4 14     MOV   $14,A

	0996: F6 C4 11  MOV   A,$11C4+Y
	0999: 2D        PUSH  A

	099A: F6 C3 11  MOV   A,$11C3+Y
	099D: EE        POP   Y
	099E: 9A 14     SUBW  YA,$14		; YA = ($11C3+Y - $11C1+Y); (first octave frequency?)

	; results of $11C3+Y - $11C1+Y for all Y values in decimal:
	; 127, 135, 143, 152, 160, 170, 181, 191, 202, 214, 227, 241 

	09A0: EB 10     MOV   Y,$10		
	09A2: CF        MUL   YA		; YA = (fine_tune * frequency) // iffy interpretation

	09A3: DD        MOV   A,Y
	09A4: 8D 00     MOV   Y,#$00		; Y = 0;
	09A6: 7A 14     ADDW  YA,$14		; YA += $14
	09A8: CB 15     MOV   $15,Y		; $15 = Y
	09AA: 1C        ASL   A			; 
	09AB: 2B 15     ROL   $15		; $15 = ($15 << 1) | (A & 0x80 ? 1 : 0); A <<= 1; 
	09AD: C4 14     MOV   $14,A		; $14 = A;

	09AF: 2F 04     BRA   $09B5

pitch_loop:

	09B1: 4B 15     LSR   $15
	09B3: 7C        ROR   A			; A = (A >> 1) | ($15 & 0x01 ? 0x80 : 0); $15 >>= 1;
	09B4: 3D        INC   X			; X++;

	09B5: C8 06     CMP   X,#$06

	09B7: D0 F8     BNE   pitch_loop	; if(X != 6) goto pitch_loop:

	09B9: C4 14     MOV   $14,A		; $14 = A;
	09BB: CE        POP   X			; X is restored to being the track index.

	09BC: F5 20 02  MOV   A,$0220+X
	09BF: EB 15     MOV   Y,$15	;
	09C1: CF        MUL   YA	; 
	09C2: DA 16     MOVW  $16,YA	; $16 = ($15 * $0220+X)

	09C4: F5 20 02  MOV   A,$0220+X
	09C7: EB 14     MOV   Y,$14	;
	09C9: CF        MUL   YA	; YA = ($14 * $0220+X)
	09CA: 6D        PUSH  Y		; Save Y for later.

	09CB: F5 21 02  MOV   A,$0221+X
	09CE: EB 14     MOV   Y,$14	;
	09D0: CF        MUL   YA	; 
	09D1: 7A 16     ADDW  YA,$16	;
	09D3: DA 16     MOVW  $16,YA	; $16 += ($14 * $0221+X)

	09D5: F5 21 02  MOV   A,$0221+X
	09D8: EB 15     MOV   Y,$15
	09DA: CF        MUL   YA	; YA = ($15 * $0221+X)
	09DB: FD        MOV   Y,A	; Y = A

	09DC: AE        POP   A		; A = the old Y above.
	09DD: 7A 16     ADDW  YA,$16
	09DF: DA 16     MOVW  $16,YA	; $16 += YA

	09E1: 7D        MOV   A,X	; A = X
	09E2: 9F        XCN   A		
	09E3: 5C        LSR   A
	09E4: 08 02     OR    A,#$02	; 0,2,4,6, ... -> 0x02, 0x12, 0x22, 0x32, ...
	09E6: FD        MOV   Y,A	; Y = A;

	09E7: E4 16     MOV   A,$16	; A = $16

	09E9: 3F EF 09  CALL  $09EF	; first do the lower byte of the per-voice pitch

	09EC: FC        INC   Y		; then redo the same routine but with the high byte
	09ED: E4 17     MOV   A,$17

; Subroutine $09EF (alt entry point)

	09EF: 2D        PUSH  A
	09F0: E4 47     MOV   A,$47
	09F2: 24 1A     AND   A,$1A
	09F4: AE        POP   A

	09F5: D0 06     BNE   $09FD	; If this voice is deactivated, return and do nothing.

WriteToDsp(A,Y):

; A = value to write
; Y = address of the DSP register to write to.

	09F7: CC F2 00  MOV   $00F2,Y
	09FA: C5 F3 00  MOV   $00F3,A

	09FD: 6F        RET

; End OF WriteToDsp();

; $9FE SUBROUTINE ********************************************
; Halts the SPC's playback while it loads more data.
; (special song command FF)

	09FE: E8 00     MOV   A,#$00
	0A00: 8D 2C     MOV   Y,#$2C	; Kill Echo Volume Left

	0A02: 3F F7 09  CALL  WriteToDsp(A,Y)

	0A05: E8 00     MOV   A,#$00
	0A07: 8D 3C     MOV   Y,#$3C  ; Kill Echo Volume Right

	0A09: 3F F7 09  CALL  WriteToDsp(A,Y)

	0A0C: E8 FF     MOV   A,#$FF
	0A0E: 8D 5C     MOV   Y,#$5C	; Mute all voices

	0A10: 3F F7 09  CALL  WriteToDsp(A,Y)

	0A13: 3F E6 11  CALL  $11E6	;

	0A16: E8 00     MOV   A,#$00
	0A18: C5 CA 03  MOV   $03CA,A	; $03CA = #$00
	0A1B: C4 04     MOV   $04,A	; $0004 = #$00
	0A1D: C5 CF 03  MOV   $03CF,A ; $03CF = #$00
	0A20: C5 CB 03  MOV   $03CB,A ; $03CB = #$00
	0A23: C5 CD 03  MOV   $03CD,A ; $03CD = #$00
	0A26: C4 1A     MOV   $1A,A   ; $001A = #$00

	0A28: 6F        RET		; return;

; Fade out volume
; (special song command F1) ******************************************

	0A29: CD 80     MOV   X,#$80
	0A2B: D8 5A     MOV   $5A,X		; $005A = #$80
	0A2D: C9 CA 03  MOV   $03CA,X		; $03CA = #$80

	0A30: E8 00     MOV   A,#$00
	0A32: C4 5B     MOV   $5B,A		; $005B = #$00
	0A34: 80        SETC
	0A35: A4 59     SBC   A,$59		; A -= $59;

	0A37: 3F CE 0E  CALL  $0ECE		; $14 = hexadecimal fraction of A / X

	0A3A: DA 5C     MOVW  $5C,YA		; $5C.w = YA;

	0A3C: 5F 00 0B  JMP   $0B00		; goto $0B00;

; Sets volume to half of normal volume.
; (special song command F2) ***************************************

	0A3F: E5 E1 03  MOV   A,$03E1

	0A42: D0 1E     BNE   $0A62		; if($03E1 != 0) goto $0A62; // return;

	0A44: E4 59     MOV   A,$59
	0A46: C5 E1 03  MOV   $03E1,A		; $03E1 = $59

	0A49: E8 70     MOV   A,#$70
	0A4B: C4 59     MOV   $59,A		; $0059 = #$70

	0A4D: 5F 00 0B  JMP   $0B00		; goto $0B00;

; Sets volume to normal.
; (special song command F3) *****************************************

	0A50: E5 E1 03  MOV   A,$03E1		; reload the saved volume level (before it was modified)

	0A53: F0 0D     BEQ   $0A62		; if($03E1 == 0) goto $0A62; // return;

	0A55: E5 E1 03  MOV   A,$03E1
	0A58: C4 59     MOV   $59,A	  	; $0059 = $03E1

	0A5A: E8 00     MOV   A,#$00
	0A5C: C5 E1 03  MOV   $03E1,A	   	; $03E1 = #$00

	0A5F: 5F 00 0B  JMP   $0B00		; goto $0B00;

$0A62:

	0A62: 6F        RET			; return;

; I have confirmed that this section handles the infamous F0, F1, F2, F3, and FF codes seen on the CPU side. 
; ******************************************************************

	0A63: 68 FF     CMP   A,#$FF	; if(A == #$FF)

	0A65: F0 97     BEQ   $09FE	; Load new set of Data.

	0A67: 68 F1     CMP   A,#$F1  ; if(A == #$F1)

	0A69: F0 BE     BEQ   $0A29	; Fade out value

	0A6B: 68 F2     CMP   A,#$F2  ; if(A == #$F2)

	0A6D: F0 D0     BEQ   $0A3F   ; Put volume at half.

	0A6F: 68 F3     CMP   A,#$F3  ; if(A == #$F3)

	0A71: F0 DD     BEQ   $0A50	; Puts volume up to Full.

	0A73: 68 F0     CMP   A,#$F0  ; if(A == #$F0)

	0A75: F0 0A     BEQ   $0A81	; Silences the machine?

	;Otherwise it's a song (so goto $0A9D)

	0A77: 2F 24     BRA   $0A9D	; goto $0A9D;

	; Related to the #$F1 volume fade out command.
;*******************************************************************

	0A79: 8C CA 03  DEC   $03CA

	0A7C: F0 03     BEQ   $0A81	; if($03CA == 0)

	0A7E: 5F 0C 0B  JMP   $0B0C

; Silence the machine until further song input is received
; (special song command F0)

	0A81: E4 1A     MOV   A,$1A
	0A83: 48 FF     EOR   A,#$FF		; invert all voices that are silenced
	0A85: 0E 46 00  TSET1 $0046		; and silence them somewhere else
	0A88: 8F 00 04  MOV   $04,#$00	; make it so no song is playing internally
	0A8B: 8F 00 47  MOV   $47,#$00	; disable all voices for the echo buffer

	0A8E: 6F        RET

; Pulls off a pointer from the songlist.
GetNextPart:

	0A8F: 8D 00     MOV   Y,#$00
	0A91: F7 40     MOV   A,($40)+Y	; A = lower portion of the pattern pointer
	0A93: 3A 40     INCW  $40
	0A95: 2D        PUSH  A			; push A onto the stack

	0A96: F7 40     MOV   A,($40)+Y	; A = upper byte of the pointer
	0A98: 3A 40     INCW  $40		

	0A9A: FD        MOV   Y,A		; Y = A
	0A9B: AE        POP   A			; pop A off the stack

	0A9C: 6F        RET			; in essence, A is the lower byte, and Y is the upper

; Handles just a normal call for a song.

	0A9D: 60        CLRC
	0A9E: CD 00     MOV   X,#$00	; X = 0;
	0AA0: C9 CA 03  MOV   $03CA,X ; $03CA = #$00
	0AA3: C9 E1 03  MOV   $03E1,X	; $03E1 = #$00
	0AA6: C4 04     MOV   $04,A	; Song value gets stored here.
	0AA8: 1C        ASL   A		; multiply song index by 2.
	0AA9: 5D        MOV   X,A	; X = A.

	0AAA: F5 FF CF  MOV   A,$CFFF+X	; uhhh... data was written to $D000 in the init routine on the CPU side...
	0AAD: FD        MOV   Y,A

	0AAE: F5 FE CF  MOV   A,$CFFE+X
	0AB1: DA 40     MOVW  $40,YA		; So yeah, we're probably loading a pointer from the array of word length data at $D000
	0AB3: 8F 02 0C  MOV   $0C,#$02	; Uh... pretty much delays the processing of the song data for one 'frame'

	0AB6: E4 1A     MOV   A,$1A		; I don't have a clear concept of 'frame' in terms of SPC, yet.
	0AB8: 48 FF     EOR   A,#$FF
	0ABA: 0E 46 00  TSET1 $0046

	0ABD: 6F        RET

; *********************************************************
; Looks like some kind of delay until $0C counts down.

$0ABE:a

	0ABE: CD 0E     MOV   X,#$0E	 	; X = 0x0E
	0AC0: 8F 80 47  MOV   $47,#$80	; $47 = 0x80

$0AC3:

	0AC3: E8 FF     MOV   A,#$FF
	0AC5: D5 01 03  MOV   $0301+X,A	; $0301+X = 0xFF

	0AC8: E8 0A     MOV   A,#$0A		; 0x0A is a value used for a neutral pan state

	0ACA: 3F BF 0C  CALL  $0CBF	  	; Set pan to normal (i.e. no panning in progress)

; zero out all the following addresses

	0ACD: D5 11 02  MOV   $0211+X,A	; It should be noted that at this point A = 0
	0AD0: D5 81 03  MOV   $0381+X,A
	0AD3: D5 F0 02  MOV   $02F0+X,A
	0AD6: D5 80 02  MOV   $0280+X,A
	0AD9: D5 FF 03  MOV   $03FF+X,A
	0ADC: D4 B1     MOV   $B1+X,A
	0ADE: D4 C1     MOV   $C1+X,A		; $0211+X = 0; $0381+X = 0; $02F0+X = 0; $0280+X = 0; $03FF+X = 0; $B1+X = 0; $C1+X = 0;
	0AE0: 1D        DEC   X
	0AE1: 1D        DEC   X			; X -= 2
	0AE2: 4B 47     LSR   $47		; $47 >>= 1;

	0AE4: D0 DD     BNE   $0AC3		

	0AE6: C4 5A     MOV   $5A,A		; Zero out these locations as well.
	0AE8: C4 68     MOV   $68,A
	0AEA: C4 54     MOV   $54,A
	0AEC: C4 50     MOV   $50,A
	0AEE: C4 42     MOV   $42,A
	0AF0: C4 5F     MOV   $5F,A
	0AF2: 8F C0 59  MOV   $59,#$C0	; Set the global volume to a fairly high level.
	0AF5: 8F 20 53  MOV   $53,#$20	; $53 = 0x20

	0AF8: 6F        RET			; return;

; ***************************************************************
; Subroutine $0AF9 ----- Handles song input commands from the CPU side.

	0AF9: E4 00     MOV   A,$00

	0AFB: F0 03     BEQ   $0B00	; if there is no new input, continue with the current song.

	0AFD: 5F 63 0A  JMP   $0A63	; handles a new input song value

$0B00:

	0B00: E4 04     MOV   A,$04	; look at the current song

	0B02: F0 F4     BEQ   $0AF8	; looks reminiscent of other Zelda3 programming, with its backwards branches to RTSs.

	0B04: E5 CA 03  MOV   A,$03CA ; if a volume fade out is in progress, the song will shut down.

	0B07: F0 03     BEQ   dont_fade_out	; if($03CA == 0) dont_fade_out;

	0B09: 5F 79 0A  JMP   $0A79	; fades out the volume

dont_fade_out:

	0B0C: E4 0C     MOV   A,$0C

	0B0E: F0 5D     BEQ   no_delay	; if($0C == 0) goto $0B6D;

	0B10: 6E 0C AB  DBNZ  $0C,$0ABE	; $0C--; if($0C != 0) goto $0ABE;

$0B13:

	0B13: 3F 8F 0A  CALL  $0A8F	; Pull a pointer off of the pattern table (pointer stored at $0040) to YA.

	0B16: D0 25     BNE   $0B3D	; if( highbyte != 0) goto $0B3D

	0B18: FD        MOV   Y,A	; Y = lowbyte;

	0B19: D0 03     BNE   $0B1E	; if( lowbyte != 0) no loop at all

	0B1B: 5F 81 0A  JMP   $0A81

$0B1E:

	0B1E: 68 80     CMP   A,#$80	; this will cause all the music to fade out

	0B20: F0 06     BEQ   $0B28	; if(lowbyte == 0x80) goto $0B28;

	0B22: 68 81     CMP   A,#$81	; 

	0B24: D0 06     BNE   $0B2C	; if(lowbyte != 0x81) goto $0B2C;

	0B26: E8 00     MOV   A,#$00	; going to set $1B back to 0, thus turning sound output back on

$0B28:

	0B28: C4 1B     MOV   $1B,A	; set this flag to 0x80 (used in subroutine $0FFC. silences the DSP, but sounds may linger for a few seconds)

	0B2A: 2F E7     BRA   $0B13

$0B2C:

	0B2C: 8B 42     DEC   $42	; $42--;

	0B2E: 10 02     BPL   $0B32	; if($42 >= 0) goto $0B32;

	0B30: C4 42     MOV   $42,A	; $42 = A;

$0B32:

	0B32: 3F 8F 0A  CALL  $0A8F	; Pull of a pointer to the next pattern (sort of a recursive operation)

	0B35: F8 42     MOV   X,$42	; X = $42

	0B37: F0 DA     BEQ   $0B13	; if($42 == 0) goto $0B13;

	0B39: DA 40     MOVW  $40,YA;	; $40 = YA;

	0B3B: 2F D6     BRA   $0B13	; goto $0B13;

; The high byte of pattern table offset is nonzero.
$0B3D:

	0B3D: DA 16     MOVW  $16,YA	; Load pattern table offset into $0016
	0B3F: 8D 0F     MOV   Y,#$0F	; 

; Small loop to load up the pointer table into an array.

LoadPatternTableLoop:

	0B41: F7 16     MOV   A,($16)+Y ; Load the pattern table into a 0x10 byte array
	0B43: D6 30 00  MOV   $0030+Y,A ; At $0030
	0B46: DC        DEC   Y

	0B47: 10 F8     BPL   LoadPatternTableLoop

	0B49: CD 00     MOV   X,#$00
	0B4B: 8F 01 47  MOV   $47,#$01

; Start of the first main loop.

NextTrackPointer:

	0B4E: F4 31     MOV   A,$31+X ; We're only analyzing the high byte of each pattern pointer.

	0B50: F0 0A     BEQ   $0B5C	; if (highbyte == 0), move on to the next track pointer

	0B52: F5 11 02  MOV   A,$0211+X

	0B55: D0 05     BNE   $0B5C	; If $0211+X has been loaded up with a nonzero value, skip to the next track.

	0B57: E8 00     MOV   A,#$00

	0B59: 3F 66 0C  CALL  $0C66

; highbyte of trackpointer = 0
$0B5C:

	0B5C: E8 00     MOV   A,#$00	; zero out a number of related locations.
	0B5E: D4 80     MOV   $80+X,A
	0B60: D4 90     MOV   $90+X,A
	0B62: D4 91     MOV   $91+X,A
	0B64: BC        INC   A
	0B65: D4 70     MOV   $70+X,A	; This array gets set to 1's.
	0B67: 3D        INC   X
	0B68: 3D        INC   X
	0B69: 0B 47     ASL   $47	; X += 2; $47 <<= 1;

	0B6B: D0 E1     BNE   NextTrackPointer	; Until we run out of voices to work with, goto the next track.

; End of first main loop

; The setup for the next loop ;)
no_delay:

	0B6D: CD 00     MOV   X,#$00
	0B6F: D8 5E     MOV   $5E,X		; $5E = 0x00;
	0B71: 8F 01 47  MOV   $47,#$01	; $47 = 0x01;

; Start of the second main loop

	0B74: D8 44     MOV   $44,X
	0B76: F4 31     MOV   A,$31+X

	0B78: F0 7A     BEQ   $0BF4		; If this track's pointer's high byte is zero, move on to the next track
							; note tracks only range from 0 to 7

	0B7A: 9B 70     DEC   $70+X		; $70+X--;

	0B7C: D0 6C     BNE   EmptyTrack	;

; Loop back point
$0B7E:

	0B7E: 3F 5C 0C  CALL  get_track_byte	; Grab a byte from the track data.

	0B81: D0 17     BNE   $0B9A		; if(track_byte != 0) goto $0B9A;

	0B83: F4 80     MOV   A,$80+X 	; else see if we're in a call loop.

	0B85: F0 8C     BEQ   $0B13		; if ($80+X == 0) load the next pattern; 

	0B87: 3F B7 0D  CALL  $0DB7 		; since $80+X is the number of iteration counts for the call loop, this reloads the
							; call loop's address for the next iteration

	0B8A: 9B 80     DEC   $80+X		; $80+X--; // call iteration counter

	0B8C: D0 F0     BNE   $0B7E		; if($80+X != 0) goto $0B7E;

	0B8E: F5 30 02  MOV   A,$0230+X
	0B91: D4 30     MOV   $30+X,A		; This restores the track address from before the call loop

	0B93: F5 31 02  MOV   A,$0231+X
	0B96: D4 31     MOV   $31+X,A 	; ditto, but for high byte

	0B98: 2F E4     BRA   $0B7E

; The first byte was not zero.
$0B9A:

	0B9A: 30 20     BMI   $0BBC		; if(track_byte & 0x80) goto $0BBC;

	0B9C: D5 00 02  MOV   $0200+X,A	; else store the byte to $0200+X

	0B9F: 3F 5C 0C  CALL  get_track_byte	; grab the next byte.

	0BA2: 30 18     BMI   $0BBC		; if(track_byte < 0)

	0BA4: 2D        PUSH  A		
	0BA5: 9F        XCN   A		
	0BA6: 28 07     AND   A,#$07	 
	0BA8: FD        MOV   Y,A		; Y = (XCN(A) & 0x07)

	0BA9: F6 96 3D  MOV   A,$3D96+Y	; A = one of {50,101,127,152,178,203,229,252} 
	0BAC: D5 01 02  MOV   $0201+X,A	; $0201+X = that result. (note level pitch modulator?)

	0BAF: AE        POP   A			; 
	0BB0: 28 0F     AND   A,#$0F		; 
	0BB2: FD        MOV   Y,A		;
	0BB3: F6 9E 3D  MOV   A,$3D9E+Y	; A = one of {25, 50, 76, 101, 114, 127, 140, 152, 165, 178, 191, 203, 216, 229, 242, 252}
	0BB6: D5 10 02  MOV   $0210+X,A	; $0210+X is a note level volume modulator 

	0BB9: 3F 5C 0C  CALL  get_track_byte	; retrieves a byte from the track data.

; A negative track_byte was pulled
$0BBC:

	0BBC: 68 E0     CMP   A,#$E0

	0BBE: 90 05     BCC   note_or_rest	; if(data_byte < 0xE0) goto note_or_rest; (it's a note or rest)

	0BC0: 3F 4A 0C  CALL  $0C4A		; else, track byte >= 0xE0 (it's a command)

	0BC3: 2F B9     BRA   $0B7E

; track_byte < 0xE0 (this is a note or a rest)
note_or_rest:

	0BC5: F5 FF 03  MOV   A,$03FF+X
	0BC8: 04 1B     OR    A,$1B

	0BCA: D0 0C     BNE   $0BD8		; if($03FF+X || $1B) goto $0BD8;

	0BCC: DD        MOV   A,Y		; A = track_byte (i.e. restore A with the track_byte value)
	0BCD: 2D        PUSH  A			; push track_byte to the stack

	0BCE: E4 47     MOV   A,$47
	0BD0: 24 1A     AND   A,$1A
	0BD2: AE        POP   A			; pull track_byte off the stack

	0BD3: D0 03     BNE   $0BD8		; if this voice is muted, skip the next instruction

	0BD5: 3F 02 09  CALL  $0902		; processes the note for this voice

$0BD8:

	0BD8: F5 00 02  MOV   A,$0200+X
	0BDB: D4 70     MOV   $70+X,A		; $70+X = $0200+X (apparently sets up a countdown timer)
	0BDD: FD        MOV   Y,A		; Y = $0200+X;

	0BDE: F5 01 02  MOV   A,$0201+X 	; A = $0201+X
	0BE1: CF        MUL   YA		; YA = $0201+X * $0200+X
	0BE2: DD        MOV   A,Y		; A = upper byte of that result.

	0BE3: D0 01     BNE   $0BE6		; if(($0200+X * $0201+X) == 0) goto $0BE6;

	0BE5: BC        INC   A

$0BE6:

	0BE6: D4 71     MOV   $71+X,A		; flag indicating the multiplication result had highbyte = 0

	0BE8: 2F 07     BRA   $0BF1

EmptyTrack:

	0BEA: E4 1B     MOV   A,$1B

	0BEC: D0 06     BNE   NextTrack	; if($1B != 0) goto $0BF4

	0BEE: 3F F6 0F  CALL  $0FF6		; everything is go... start tracking

$0BF1:

	0BF1: 3F 7A 0E  CALL  $0E7A		; peeks at the track data to see if the next command is a pitch slide. If so, it executes it.
							; however, if the voice is muted, it will skip over the pitch slide command.

NextTrack:

	0BF4: 3D        INC   X
	0BF5: 3D        INC   X
	0BF6: 0B 47     ASL   $47		; X += 2; $47 <<= 1;

	0BF8: F0 03     BEQ   $0BFD		; if(!$47) goto $0BFD;

	0BFA: 5F 74 0B  JMP   $0B74 ; jump back to the second main loop point and load a new track number

; End of second main loop.
$0BFD:
	
	; this section handles speed ramp (tempo ramp in other words)

	0BFD: E4 54     MOV   A,$54

	0BFF: F0 0B     BEQ   $0C0C		; if($54 == 0) goto $0C0C;

	0C01: BA 56     MOVW  YA,$56
	0C03: 7A 52     ADDW  YA,$52		; move the tempo closer to the target tempo

	0C05: 6E 54 02  DBNZ  $54,$0C0A	; $54--; if($54 != 0) goto $0C0A;

	0C08: BA 54     MOVW  YA,$54		; tempo = target tempo

$0C0A:

	0C0A: DA 52     MOVW  $52,YA		

$0C0C:
; this section handles echo pan ramp (i.e. echo volume changing from side to side gradually)

	0C0C: E4 68     MOV   A,$68

	0C0E: F0 15     BEQ   $0C25		; if($68 == 0) goto $0C25;

	0C10: BA 64     MOVW  YA,$64
	0C12: 7A 60     ADDW  YA,$60
	0C14: DA 60     MOVW  $60,YA		; $60 += $64; // echo volume left += $64

	0C16: BA 66     MOVW  YA,$66
	0C18: 7A 62     ADDW  YA,$62		; YA = $66 + $62; // echo volume right + $66

	0C1A: 6E 68 06  DBNZ  $68,$0C23	; $68--; if($68 != 0) goto $0C23;

	0C1D: BA 68     MOVW  YA,$68
	0C1F: DA 60     MOVW  $60,YA		; $60 = $68; // echo volume left = $68
	0C21: EB 6A     MOV   Y,$6A

$0C23:

	0C23: DA 62     MOVW  $62,YA		; $62 = YA;  // echo volume right = $6A (basically)

$0C25:
; this section handles global volume ramping

	0C25: E4 5A     MOV   A,$5A		

	0C27: F0 0E     BEQ   $0C37		; if($5A == 0) goto $0C37;

	0C29: BA 5C     MOVW  YA,$5C
	0C2B: 7A 58     ADDW  YA,$58		; YA = $58 + $5C;

	0C2D: 6E 5A 02  DBNZ  $5A,$0C32	; $5A--; if($5A != 0) goto $0C32;

	0C30: BA 5A     MOVW  YA,$5A		; set global volume to the target volume

$0C32:

	0C32: DA 58     MOVW  $58,YA		; adjust the global volume by $5C normally (and in one case set it to the target volume)
	0C34: 8F FF 5E  MOV   $5E,#$FF	; $5E = 0xFF; // ... not sure

$0C37:

	0C37: CD 00     MOV   X,#$00		; Set the track index back to zero. Yay!
	0C39: 8F 01 47  MOV   $47,#$01 	; Set the voice index back to the first one. Yay!

$0C3C:

	0C3C: F4 31     MOV   A,$31+X		; Check the high byte of the track pointer

	0C3E: F0 03     BEQ   $0C43		; if($31+X) goto $0C43;

	0C40: 3F 3F 0F  CALL  $0F3F		; Handles volume settings for each track

$0C43:

	0C43: 3D        INC   X
	0C44: 3D        INC   X
	0C45: 0B 47     ASL   $47		; X += 2; $47 <<= 1;

	0C47: D0 F3     BNE   $0C3C		; if($47 != 0) goto $0C3C;

	0C49: 6F        RET			; return;

; ***************************************************************
; Subroutine $0C4A
; Uses A as an input into a stack based jump table.
; This routine handles commands, which are track_byte values being greater than or equal to 0xE0

	0C4A: 1C        ASL   A		
	0C4B: FD        MOV   Y,A
	0C4C: F6 2B 0E  MOV   A,$0E2B+Y	; Command_Jump_Table (if you don't believe me, look more closely)
	0C4F: 2D        PUSH  A

	0C50: F6 2A 0E  MOV   A,$0E2A+Y
	0C53: 2D        PUSH  A

	0C54: DD        MOV   A,Y
	0C55: 5C        LSR   A
	0C56: FD        MOV   Y,A

	0C57: F6 C0 0E  MOV   A,$0EC0+Y	; Grab the parameters for the call

	0C5A: F0 08     BEQ   no_parameters	; if the command requires no parameters, Y and A will both be 0.

; Subroutine $0C5C
; Grabs a byte from the current trackpointer, then increments the 16 bit pointer accordingly.
get_track_byte: ; reads the current track_byte and increments the track pointer.

	0C5C: E7 30     MOV   A,($30+X)

skip_track_byte:	 				; alternate entry point (doesn't read the value, only increments the track pointer)

	0C5E: BB 30     INC   $30+X

	0C60: D0 02     BNE   no_parameters	; if($30+X != 0) goto $0C64;

	0C62: BB 31     INC   $31+X

no_parameters:

	0C64: FD        MOV   Y,A		; Parameter is stored in Y and A.

	0C65: 6F        RET			; This call return then jumps to the pushed value (if entered from $0C4A)

; End of Subroutine $0C5C

; ******************************************************
; Subroutine $0C66
; Inputs: A 
; Command E0, known as "Instrument" in HM.

	0C66: D5 11 02  MOV   $0211+X,A
	0C69: FD        MOV   Y,A		; Y = $0211+X = A;

	0C6A: 10 06     BPL   no_relative_offset

	0C6C: 80        SETC
	0C6D: A8 CA     SBC   A,#$CA
	0C6F: 60        CLRC
	0C70: 84 5F     ADC   A,$5F	; $5F is used as a relative offset into the instrument table
						; this means the argument passed in has to be 0xCA or higher

no_relative_offset:

	0C72: 8D 06     MOV   Y,#$06
	0C74: CF        MUL   YA
	0C75: DA 14     MOVW  $14,YA	; Determines an offset into the instrument table ($3D00)
	0C77: 60        CLRC
	0C78: 98 00 14  ADC   $14,#$00
	0C7B: 98 3D 15  ADC   $15,#$3D ; $14 = #$3D00 + (input * 6)

	0C7E: E4 1A     MOV   A,$1A	; List of muted voices
	0C80: 24 47     AND   A,$47	; Check against current voice.

	0C82: D0 3A     BNE   $0CBE	; if this voice is off, return;

	0C84: 4D        PUSH  X		; Look at the track number we're on.
	0C85: 7D        MOV   A,X
	0C86: 9F        XCN   A
	0C87: 5C        LSR   A
	0C88: 08 04     OR    A,#$04	; Make it into a ((multiple of 0x10) + #$04)
	0C8A: 5D        MOV   X,A
	0C8B: 8D 00     MOV   Y,#$00
	0C8D: F7 14     MOV   A,($14)+Y

	0C8F: 10 0E     BPL   $0C9F

	0C91: 28 1F     AND   A,#$1F
	0C93: 38 20 48  AND   $48,#$20
	0C96: 0E 48 00  TSET1 $0048
	0C99: 09 47 49  OR    ($49),($47)
	0C9C: DD        MOV   A,Y

	0C9D: 2F 07     BRA   $0CA6

$0C9F:

	0C9F: E4 47     MOV   A,$47

	0CA1: 4E 49 00  TCLR1 $0049

	0CA4: F7 14     MOV   A,($14)+Y

$0CA6:

	0CA6: C9 F2 00  MOV   $00F2,X		; Take the first four bytes of the instrument block and write them to
	0CA9: C5 F3 00  MOV   $00F3,A		; Dsp registers $00v4 through $00v7. See SPC docs for more info.
	0CAC: 3D        INC   X			; The loop writes to the SRCN, ADSR1 and ADSR2, and Gain.
	0CAD: FC        INC   Y
	0CAE: AD 04     CMP   Y,#$04

	0CB0: D0 F2     BNE   $0CA4

	0CB2: CE        POP   X
	0CB3: F7 14     MOV   A,($14)+Y
	0CB5: D5 21 02  MOV   $0221+X,A	; This is a big endian encoding. The last 2 bytes of the six byte instrument block
	0CB8: FC        INC   Y			; Are stored to [$0220-1]+X

	0CB9: F7 14     MOV   A,($14)+Y
	0CBB: D5 20 02  MOV   $0220+X,A

$0CBE:

	0CBE: 6F        RET

; **************************************************
; Subroutine $0CBF - command E1
; "Pan" command in Hyrule Magic
; takes one argument
 
	0CBF: D5 51 03  MOV   $0351+X,A	; $0351+X = A

	0CC2: 28 1F     AND   A,#$1F		
	0CC4: D5 31 03  MOV   $0331+X,A	; $0331+X = (A & #$1F)

	0CC7: E8 00     MOV   A,#$00
	0CC9: D5 30 03  MOV   $0330+X,A	; $0330+X = #$00

	0CCC: 6F        RET

; **************************************************
; Subroutine $0CCD - command E2
; "Pansweep" according to Hyrule Magic
; takes two arguments

	0CCD: D4 91     MOV   $91+X,A		; $91+X = byte 1
	0CCF: 2D        PUSH  A

	0CD0: 3F 5C 0C  CALL  get_track_byte		; grab byte 2

	0CD3: D5 50 03  MOV   $0350+X,A  	; $0350+X = A;
	0CD6: 80        SETC
	0CD7: B5 31 03  SBC   A,$0331+X
	0CDA: CE        POP   X

	0CDB: 3F CE 0E  CALL  $0ECE		; YA = ($0350+X - $0331+X)/ $91+X; (hexadecimal fraction representation)

	0CDE: D5 40 03  MOV   $0340+X,A	; $0340+X = fractional portion

	0CE1: DD        MOV   A,Y
	0CE2: D5 41 03  MOV   $0341+X,A	; $0341+X = whole number portion

	0CE5: 6F        RET

; ******************************************************
; Subroutine $0CE6 - command E3
; "Vibrato" according to Hyrule Magic

	0CE6: D5 B0 02  MOV   $02B0+X,A	; $02B0+X = byte 1 (set point)

	0CE9: 3F 5C 0C  CALL  get_track_byte

	0CEC: D5 A1 02  MOV   $02A1+X,A	; $02A1+X = byte 2

	0CEF: 3F 5C 0C  CALL  get_track_byte	; grab byte 3

; $0CF2 Alternate entry point - command E4
; takes one argument. "Vib. Off" in Hyrule Magic. (assumedly means Vibrato Off)

	0CF2: D4 B1     MOV   $B1+X,A	
	0CF4: D5 C1 02  MOV   $02C1+X,A	; $B1+X and $02C1+X = third argument

	0CF7: E8 00     MOV   A,#$00
	0CF9: D5 B1 02  MOV   $02B1+X,A	; $02B1+X = 0

	0CFC: 6F        RET

; *********************************************************
; Subroutine $0CFD - command F0
; also related to vibrato.. but how?
; Has no HM name, I suggest "VibratoStep"

	0CFD: D5 B1 02  MOV   $02B1+X,A	; $02B1+X = byte 1
	0D00: 2D        PUSH  A
	0D01: 8D 00     MOV   Y,#$00		; Y = 0;

	0D03: F4 B1     MOV   A,$B1+X
	0D05: CE        POP   X			; X = byte 1
	0D06: 9E        DIV   YA,X		;

	0D07: F8 44     MOV   X,$44 		; restore the track index to X
	0D09: D5 C0 02  MOV   $02C0+X,A	; $02C0+X = $B1+X / $02B1+X;

	0D0C: 6F        RET

; *********************************************************
; Subroutine $0D0D - command E5
; sets global volume

	0D0D: E5 CA 03  MOV   A,$03CA		; Check to see if volume is being faded

	0D10: D0 09     BNE   $0D1B		; if($03CA) goto $0D1B; //volume is in a fading process, don't interrupt the fade

	0D12: E5 E1 03  MOV   A,$03E1		; is half volume enabled?

	0D15: D0 04     BNE   $0D1B		; if($03E1) goto $0D1B; //don't all us to set global volume if we're in half volume mode.

	0D17: E8 00     MOV   A,#$00
	0D19: DA 58     MOVW  $58,YA		; $58.w = YA; // set global volume to byte 1. (value actually goes to $59 if you look closely)

$0D1B:

	0D1B: 6F        RET

; *********************************************************
; Subroutine $0D1C - command E6
; global volume ramp (gradual change)

	0D1C: C4 5A     MOV   $5A,A		; $5A = byte 1 (sets the time it takes to reach the target volume in frames)

	0D1E: 3F 5C 0C  CALL  get_track_byte		; grab next byte

	0D21: C4 5B     MOV   $5B,A		; $5B = byte 2 (sets the target volume)
	0D23: 80        SETC
	0D24: A4 59     SBC   A,$59		; A = $5B - $59; (the difference between current volume and the target volume)
	0D26: F8 5A     MOV   X,$5A		; X = byte 1

	0D28: 3F CE 0E  CALL  $0ECE		; YA = hexadecimal fraction of A / X

	0D2B: DA 5C     MOVW  $5C,YA		; $5C = a step value to add to the global each frame to achieve the target value.

	0D2D: 6F        RET			; return;

; *********************************************************
; Subroutine $0DE2 - command E7
; Speed control, according to HM

	0D2E: E8 00     MOV   A,#$00
	0D30: DA 52     MOVW  $52,YA		; $52 = YA; // this sets the tempo

	0D32: 6F        RET			; return;

; *********************************************************
; Subroutine $0D33 - command E8
; "Spd Ramp" in Hyrule Magic (speed ramp of course)

	0D33: C4 54     MOV   $54,A		; $54 = byte 1 (countdown timer for the speed ramp)

	0D35: 3F 5C 0C  CALL  get_track_byte		; grab byte 2

	0D38: C4 55     MOV   $55,A		; $55 = byte 2 (target tempo)
	0D3A: 80        SETC
	0D3B: A4 53     SBC   A,$53		; A = $55 - $53
	0D3D: F8 54     MOV   X,$54		; X = $54;

	0D3F: 3F CE 0E  CALL  $0ECE		; YA = hexadecimal fraction representing A / X

	0D42: DA 56     MOVW  $56,YA		; $56 = ($55-$53)/$54

	0D44: 6F        RET			; return;

; *****************************************************
; Subroutine $0D45 - command E9
; Hyrule Magic calls this "G. Transpose" (global transpose)
; basically it sets the pitch higher or lower than normal

	0D45: C4 50     MOV   $50,A		; $50 = A; // sets global pitch adjustment

	0D47: 6F        RET			; return;

; *****************************************************
; Subroutine $0D48 - command EA
; "Transpose" according to Hyrule Magic
; Takes only one argument

	0D48: D5 F0 02  MOV   $02F0+X,A 	; modifies pitch for this channel
	
	0D4B: 6F        RET			; return;

; *****************************************************
; Subroutine $0D4C - command EB
; "Tremelo" according to Hyrule Magic
; takes three arguments
; since vibrato takes care of rapid pitch change, my only guess is that this
; causes a rapid (or slow?) volume change

	0D4C: D5 E0 02  MOV   $02E0+X,A ; byte 1 goes here

	0D4F: 3F 5C 0C  CALL  get_track_byte	  ; grab byte 2

	0D52: D5 D1 02  MOV   $02D1+X,A ; store it here

	0D55: 3F 5C 0C  CALL  get_track_byte     ; grab a third argument and...

; $0D58 Alternate entry point - Command EC
; "Trm. Off" according to Hyrule Magic (meaning Tremelo off, I assume)
; whether it really does this or not is not exactly clear

	0D58: D4 C1     MOV   $C1+X,A	  ; store it here

	0D5A: 6F        RET

; *******************************************************
; Subroutine $0D5B - command F1
; Hyrule Magic calls this "PSlideTo" (pitch slide to)

	0D5B: E8 01     MOV   A,#$01

	0D5D: 2F 02     BRA   pitch_slide_to:

; Subroutine $0D5F - command F2
; Hyrule Magic calls this "PSlideFr" (pitch slide from?)

	0D5F: E8 00     MOV   A,#$00

pitch_slide_to:

	0D61: D5 90 02  MOV   $0290+X,A		; $0290+X = byte 1 (indicates pitch slide direction)

	0D64: DD        MOV   A,Y			; A = byte 1;
	0D65: D5 81 02  MOV   $0281+X,A		; $0281+X = A;

	0D68: 3F 5C 0C  CALL  get_track_byte	; grab byte 2

	0D6B: D5 80 02  MOV   $0280+X,A		; $0280+X = byte 2 

	0D6E: 3F 5C 0C  CALL  get_track_byte	; grab byte 3

	0D71: D5 91 02  MOV   $0291+X,A 		; $0291+X = byte 3

	0D74: 6F        RET

; ******************************************************
; Subroutine $0D75 - command F3
; Hyrule Magic has no name for this.
; But I might suggest PSlideStop (pitch slide stop)

	0D75: D5 80 02  MOV   $0280+X,A		; $0280+X = byte 1

	0D78: 6F        RET

; ******************************************************
; Subroutine $0D79 - command ED
; Known as "Volume" in HM
; controls a particular channel's volume

	0D79: D5 01 03  MOV   $0301+X,A	; $0301+X = byte 1

	0D7C: E8 00     MOV   A,#$00
	0D7E: D5 00 03  MOV   $0300+X,A	; $0300+X = 0;

	0D81: 6F        RET

; ******************************************************
; $0D82 Alternate entry point command EE
; "Volume Ramp" according to Hyrule Magic
; takes two arguments

	0D82: D4 90     MOV   $90+X,A 	; store byte 1 to $90+X
	0D84: 2D        PUSH  A

	0D85: 3F 5C 0C  CALL  get_track_byte		; grab byte 2

	0D88: D5 20 03  MOV   $0320+X,A	; set target volume for the channel at the end of the ramp
	0D8B: 80        SETC
	0D8C: B5 01 03  SBC   A,$0301+X	; subtract off the channel's volume modulation setting
	0D8F: CE        POP   X			

	0D90: 3F CE 0E  CALL  $0ECE		; YA = ($0320+X - $0301+X) / $90+X; // hexadecimal fraction

	0D93: D5 10 03  MOV   $0310+X,A	; $0310+X = fractional portion

	0D96: DD        MOV   A,Y
	0D97: D5 11 03  MOV   $0311+X,A	; $0311+X = whole number portion
	
	0D9A: 6F        RET

; *******************************************************
; Subroutine $0D9B - command F4
; HM calls it "Fine tune"

	0D9B: D5 81 03  MOV   $0381+X,A	; this is a fractional modifier for the voice's pitch
	0D9E: 6F        RET

; *******************************************************
; Subroutine $0D9F - command EF
; HM calls it "Call Loop"

	0D9F: D5 40 02  MOV   $0240+X,A	; $0240+X = byte 1

	0DA2: 3F 5C 0C  CALL  get_track_byte	; grab byte 2

	0DA5: D5 41 02  MOV   $0241+X,A	; $0241+X = byte 2

	0DA8: 3F 5C 0C  CALL  get_track_byte	; grab byte 3

	0DAB: D4 80     MOV   $80+X,A		; $80+X = byte 3

	0DAD: F4 30     MOV   A,$30+X
	0DAF: D5 30 02  MOV   $0230+X,A	; $0230+X = $30+X; (saves our current position so the call loop can return)

	0DB2: F4 31     MOV   A,$31+X
	0DB4: D5 31 02  MOV   $0231+X,A	; $0231+X = $31+X; (ditto but for the high byte)

; Subroutine $0DB7 (alt entry point)

	0DB7: F5 40 02  MOV   A,$0240+X
	0DBA: D4 30     MOV   $30+X,A		; $30+X = $0240+X;

	0DBC: F5 41 02  MOV   A,$0241+X
	0DBF: D4 31     MOV   $31+X,A		; $31+X = $0241+X;

	0DC1: 6F        RET

; ******************************************************
; Subroutine $0DC2 - command F5
; has no name in Hyrule Magic. I suggest "EchoControl"
; takes three arguments

	0DC2: C5 C3 03  MOV   $03C3,A			; $03C3 = byte 1
	0DC5: C4 4A     MOV   $4A,A			; ECHOEN = A

	0DC7: 3F 5C 0C  CALL  get_track_byte	; grab byte 2

	0DCA: E8 00     MOV   A,#$00
	0DCC: DA 60     MOVW  $60,YA			; $60 = (second parameter << 8);

	0DCE: 3F 5C 0C  CALL  get_track_byte	; grab byte 3

	0DD1: E8 00     MOV   A,#$00			; Pull the third parameter
	0DD3: DA 62     MOVW  $62,YA
	0DD5: B2 48     CLR5  $48			; Enable Echo

	0DD7: 6F        RET				; return;

; ********************************************************
; Subroutine $0DD8 - command F8
; "Echo" in Hyrule Magic

	0DD8: C4 68     MOV   $68,A	; $68 = byte 1;

	0DDA: 3F 5C 0C  CALL  get_track_byte	; grab byte 2

	0DDD: C4 69     MOV   $69,A	; $69 = byte 2;
	0DDF: 80        SETC
	0DE0: A4 61     SBC   A,$61	; $61 is ECHOVOLL
	0DE2: F8 68     MOV   X,$68	; X = $68

	0DE4: 3F CE 0E  CALL  $0ECE	; YA = ($69 - $61) / $68;

	0DE7: DA 64     MOVW  $64,YA 	; $64 = hexadecimal fraction represented by YA

	0DE9: 3F 5C 0C  CALL  get_track_byte	; grab byte 3

	0DEC: C4 6A     MOV   $6A,A	; $6A = byte 3;
	0DEE: 80        SETC
	0DEF: A4 63     SBC   A,$63	; $63 is ECHOVOLR
	0DF1: F8 68     MOV   X,$68

	0DF3: 3F CE 0E  CALL  $0ECE	; YA = ($6A - $63) / $68;

	0DF6: DA 66     MOVW  $66,YA	; $66 = hexadecimal fraction represented by YA

	0DF8: 6F        RET		; return;

; *****************************************************
; Subroutine $0DF9 - command F6
; Has no name in Hyrule Magic, I suggest "Echo Silence"
; Based on a special case, this sets echo volume to zero
; The caller sets Y and A to zero in that special case before it calls this

	0DF9: DA 60     MOVW  $60,YA
	0DFB: DA 62     MOVW  $62,YA
	0DFD: A2 48     SET5  $48	; Disable Echo
	
	0DFF: 6F        RET

; *****************************************************
; Subroutine $0E00 - command F7
; Has no name in Hyrule Magic, I suggest "EchoFilter"
; Handles Echo Delay, Echo feedback, and applies a filter from a set list.

	0E00: 3F 22 0E  CALL  $0E22			; Handle Echo Delay with byte 1

	0E03: 3F 5C 0C  CALL  get_track_byte	; grab byte 2

	0E06: C4 4E     MOV   $4E,A			; echo feedback volume (EFB) = byte 2

	0E08: 3F 5C 0C  CALL  get_track_byte	; grab byte 3

	0E0B: 8D 08     MOV   Y,#$08
	0E0D: CF        MUL   YA			; YA = (8 * byte 3) (one of 4 preset settings, seems like)
	0E0E: 5D        MOV   X,A
	0E0F: 8D 0F     MOV   Y,#$0F			; writing to DSP register $xF (FIRx)

Set_Next_Voice_Filter:

	0E11: F5 8D 11  MOV   A,$118D+X		; 4 8-byte echo coefficient lists

	0E14: 3F F7 09  CALL  WriteToDsp(A,Y)	; Set the filter designation for this voice.

	0E17: 3D        INC   X

	0E18: DD        MOV   A,Y
	0E19: 60        CLRC
	0E1A: 88 10     ADC   A,#$10			; Move on to the next voice
	0E1C: FD        MOV   Y,A			; Y += 0x10;

	0E1D: 10 F2     BPL   Set_Next_Voice_Filter

	0E1F: F8 44     MOV   X,$44			; Restore X's old value (track number?)

	0E21: 6F        RET				;return

; *************************************************************
; $0E22 SUBROUTINE
; Handles the Echo Delay register and some related echo registers.
; input: A. It's the value to put into the Echo delay register eventually.

	0E22: C4 4D     MOV   $4D,A 		; STORE TO $004D
	0E24: 8D 7D     MOV   Y,#$7D
	0E26: CC F2 00  MOV   $00F2,Y 	; latch on the EDL register (echo delay)
	0E29: E5 F3 00  MOV   A,$00F3 	; read out dsp register $7D
	0E2C: 64 4D     CMP   A,$4D		; Compare it to the input value.

	0E2E: F0 2B     BEQ   edl_same	; branch if they have the same value

	0E30: 28 0F     AND   A,#$0F		
	0E32: 48 FF     EOR   A,#$FF		; A = (A & 0x0F) ^ 0xFF;

	0E34: F3 4C 03  BBC7  $4C,$0E3A 	; branch if $004C is non negative.

	0E37: 60        CLRC		  	; clear carry so we can do a pure add.
	0E38: 84 4C     ADC   A,$4C	  	; Add $004C's value to A.

	0E3A: C4 4C     MOV   $4C,A 	  	; Store A back to $004C.
	0E3C: 8D 04     MOV   Y, #$04

	0E3E: F6 AC 11  MOV   A, RegisterList - 1 + Y ; pick a register
	0E41: C5 F2 00  MOV   $00F2,A

	0E44: E8 00     MOV   A,#$00
	0E46: C5 F3 00  MOV   $00F3,A 	; DISABLE THE ECHO EFFECT, ECHO FEEDBACK, ECHO VOLUME RIGHT, ECHO VOLUME LEFT, ETC

	0E49: FE F3     DBNZ  Y,$0E3E 	; Y--; if(Y != 0) goto $0E3E;

	0E4B: E4 48     MOV   A,$48	; A = VOXCON
	0E4D: 08 20     OR    A,#$20	; Disable the echo feature
	0E4F: 8D 6C     MOV   Y,#$6C ; USE A VERY BASIC SUBROUTINE TO DISABLE THE ECHO VOICE CONTROL IN REGISTER $6C

	0E51: 3F F7 09  CALL  WriteToDsp(A,Y)

	0E54: E4 4D     MOV   A,$4D
	0E56: 8D 7D     MOV   Y,#$7D ; Store the input value to ECHODLY

	0E58: 3F F7 09  CALL  WriteToDsp(A,Y)

edl_same:

	0E5B: 1C        ASL   A
	0E5C: 1C        ASL   A
	0E5D: 1C        ASL   A 	; AFTER THIS A = 0x08 or A = 0x00
	0E5E: 48 FF     EOR   A,#$FF  ; A = 0xF7 or A = 0xFF
	0E60: 80        SETC 		; set the carry flag. (basically we're multiplying by -1 then adding 0xD0)

	0E61: 88 D0     ADC   A,#$D0 ; ECHO LOCATION TABLE IS AT $C8 OR $D0? (NOT SURE HERE)
	0E63: 8D 6D     MOV   Y,#$6D ; Upper byte of the echo location table is about to get written.

	0E65: 5F F7 09  JMP   WriteToDsp(A,Y)

; END OF $0E22 SUBROUTINE 

; ***********************************************************
; Subroutine $0E68 - command FA
; Takes one parameter. Has no HM name, but I suggest "InstrumentOffset"

	0E68: C4 5F     MOV   $5F, A

	0E6A: 6F        RET

; ***********************************************************

	; this routine apparently isn't called... not hard to see why

	0E6B: 3F 5E 0C  CALL  skip_track_byte

	0E6E: 6F        RET

; ***********************************************************

	; Neither is this one...?

	0E6F: BC        INC   A
	0E70: D5 FF 03  MOV   $03FF+X,A

	0E73: 6F        RET

; ***********************************************************

	; Nor this one...

	0E74: BC        INC   A

	0E75: C4 1B     MOV   $1B,A

	0E77: 5F B6 0A  JMP   $0AB6

; ***********************************************************
; Subroutine $0E7A
; um... what does this do?
; I think it ignores pitch slide commands if the voice is silenced. Can't think of any other purpose...

	0E7A: F4 A0     MOV   A,$A0+X

	0E7C: D0 44     BNE   $0EC2		; if($A0+X != 0) return;

	0E7E: E7 30     MOV   A,($30+X)	; grab a byte off the track pointer
	0E80: 68 F9     CMP   A,#$F9

	0E82: D0 3E     BNE   $0EC2		; if (A != #$F9) end the routine

	0E84: E4 47     MOV   A,$47
	0E86: 24 1A     AND   A,$1A

	0E88: F0 0B     BEQ   $0E95		; if( ($47 & $1A) == 0 ) goto $0E95;

	0E8A: 8F 04 10  MOV   $10,#$04

$0E8D:

	0E8D: 3F 5E 0C  CALL  skip_track_byte	; increment the track pointer by one byte without reading the track_byte value.

	0E90: 6E 10 FA  DBNZ  $10,$0E8D	; loop 4 times (advance 4 bytes on the track pointer)

	0E93: 2F 2D     BRA   $0EC2		; return;

$0E95:

	0E95: 3F 5E 0C  CALL  skip_track_byte

	0E98: 3F 5C 0C  CALL  get_track_byte

; Alternate entry point $0E9B - command F9
; Hyrule Magic calls this a PSlide (pitch slide?)

	0E9B: D4 A1     MOV   $A1+X,A 	; store the first argument here

	0E9D: 3F 5C 0C  CALL  get_track_byte	; retrieve the next argument (of three)

	0EA0: D4 A0     MOV   $A0+X,A 	; $A0+X = byte 2; this is the amount of frames it takes to attain the target pitch.

	0EA2: 3F 5C 0C  CALL  get_track_byte	; grab byte 3; the target pitch value?

	0EA5: 60        CLRC
	0EA6: 84 50     ADC   A,$50		; add in the master pitch control value
	0EA8: 95 F0 02  ADC   A,$02F0+X 	; add in channel pitch control

; Alternate entry point $0EAB

	; input_value is the value of A when this routine is called

	0EAB: 28 7F     AND   A,#$7F
	0EAD: D5 80 03  MOV   $0380+X,A	; $0380+X = input_value & 0x7F;
	0EB0: 80        SETC
	0EB1: B5 61 03  SBC   A,$0361+X	; A -= $0361+X
	0EB4: FB A0     MOV   Y,$A0+X		; Y = $A0+X
	0EB6: 6D        PUSH  Y
	0EB7: CE        POP   X			; X = Y

	0EB8: 3F CE 0E  CALL  $0ECE		; A = (($0380+X - $0361+X) / $A0+X)

	0EBB: D5 70 03  MOV   $0370+X,A	; fractional portion

	0EBE: DD        MOV   A,Y
	0EBF: D5 71 03  MOV   $0371+X,A	; high byte = integer portion

$0EC2:

	0EC2: 6F        RET			; return;

; Subroutine $0EC3

	0EC3: F5 61 03  MOV   A,$0361+X
	0EC6: C4 11     MOV   $11,A	; $11 is the Pitch table index.

	0EC8: F5 60 03  MOV   A,$0360+X
	0ECB: C4 10     MOV   $10,A

	0ECD: 6F        RET


; **************************************************************
; Subroutine $0ECE
; Inputs: the carry flag, A, X

	0ECE: ED        NOTC		; Invert the Carry Flag
	0ECF: 6B 12     ROR   $12	; $12 is negative if carry was set, positive if not

	0ED1: 10 03     BPL   positive_input ; if(A > 0) goto positive_input;

	0ED3: 48 FF     EOR   A,#$FF
	0ED5: BC        INC   A		; A = |A|

positive_input:

	0ED6: 8D 00     MOV   Y,#$00
	0ED8: 9E        DIV   YA,X	; 
	0ED9: 2D        PUSH  A		; Push the 8-bit quotient of A / X
	0EDA: E8 00     MOV   A,#$00
	0EDC: 9E        DIV   YA,X	; A = (A % X) / X
	0EDD: EE        POP   Y		; Y = A / X
	0EDE: F8 44     MOV   X,$44	; Restore X's old value

; $0EE0 alternate entry point

	0EE0: F3 12 06  BBC7  $12,was_clear

; this section makes the number negative if the number passed in was negative

	0EE3: DA 14     MOVW  $14,YA
	0EE5: BA 0E     MOVW  YA,$0E
	0EE7: 9A 14     SUBW  YA,$14	; YA = $0E - YA

was_clear:

	0EE9: 6F        RET		; return (fixed point fraction of A divided by X)

; end of Subroutine $0ECE

; ---------------------------------------

; Stack based jump table used in routine $0C4E

Command_Jump_Table:

0EEA: dw $0C66	; command E0
0EEC: dw $0CBF	; command E1
0EEE: dw $0CCD
0EF0: dw $0CE6
0EF2: dw $0CF2
0EF4: dw $0D0D	; command E5 (Global Volume)
0EF6: dw $0D1C
0EF8: dw $0D2E	; command E7
0EFA: dw $0D33	; command E8
0EFC: dw $0D45
0EFE: dw $0D48
0F00: dw $0D4C
0F02: dw $0D58	; command E
0F04: dw $0D79	; command ED
0F06: dw $0D82	; command EE
0F08: dw $0D9F	; command EF
0F0A: dw $0CFD	; command F0
0F0C: dw $0D5B
0F0E: dw $0D5F
0F10: dw $0D75
0F12: dw $0D9B
0F14: dw $0DC2	; command F5
0F16: dw $0DF9	; command F6
0F18: dw $0E00	; command F7 (Echo and Filters)
0F1A: dw $0DD8
0F1C: dw $0E9B
0F1E: dw $0E68 	; command FA (bank number?)

; Num_Parameters_For_Commands:

0F20: db $01	; command E0 number of parameters
0F21: db $01	; command E1 number of parameters
0F22: db $02	; command E2 number of parameters
0F23: db $03	; command E3 number of parameters
0F24: db $00
0F25: db $01	; command E5 number of parameters
0F26: db $02
0F27: db $01
0F28: db $02
0F29: db $01
0F2A: db $01
0F2B: db $03
0F2C: db $00
0F2D: db $01	; command ED number of parameters
0F2E: db $02
0F2F: db $03
0F30: db $01	; command F0 number of parameters
0F31: db $03
0F32: db $03
0F33: db $00
0F34: db $01
0F35: db $03
0F36: db $00	; command F6 number of parameters
0F37: db $03
0F38: db $03
0F39: db $03 
0F3A: db $01	; command FA number of parameters

; no idea what this remaining data is for ...

0F3B: db $02
0F3C: db $00
0F3D: db $00
0F3E: db $00

; Routine entry point
; Unexplored territory for MathOnNapkins so far! Yay!

$0F3F:

	0F3F: F4 90     MOV   A,$90+X		; A = $90+X;

	0F41: F0 09     BEQ   $0F4C		; if($90+X == 0) goto $0F4C;

	0F43: E8 00     MOV   A,#$00
	0F45: 8D 03     MOV   Y,#$03
	0F47: 9B 90     DEC   $90+X		; A = 0x00; Y = 0x03; $90+X-- ;

	0F49: 3F D2 0F  CALL  $0FD2		; this is volume ramp in action

$0F4C:

	0F4C: FB C1     MOV   Y,$C1+X		; Y = $C1+X

	0F4E: F0 23     BEQ   $0F73		; if($C1+X == 0) goto $0F73;

	0F50: F5 E0 02  MOV   A,$02E0+X	; A = $02E0+X

	0F53: DE C0 1B  CBNE  $C0+X,$0F71	; if($02E0+X != $C0+X) goto $0F71

	0F56: 09 47 5E  OR    ($5E),($47)

	0F59: F5 D0 02  MOV   A,$02D0+X

	0F5C: 10 07     BPL   $0F65		; if($02D0+X >= 0) goto $0F65;

	0F5E: FC        INC   Y

	0F5F: D0 04     BNE   $0F65		; if(Y != 0) goto $0F65;

	0F61: E8 80     MOV   A,#$80		; A = 0x80;

	0F63: 2F 04     BRA   $0F69		; goto $0F69;

$0F65:

	0F65: 60        CLRC
	0F66: 95 D1 02  ADC   A,$02D1+X

$0F69:

	0F69: D5 D0 02  MOV   $02D0+X,A

	0F6C: 3F 5B 11  CALL  $115B		;

	0F6F: 2F 07     BRA   $0F78

$0F71:

	0F71: BB C0     INC   $C0+X

$0F73:

	0F73: E8 FF     MOV   A,#$FF

	0F75: 3F 66 11  CALL  $1166

$0F78:

	0F78: F4 91     MOV   A,$91+X

	0F7A: F0 09     BEQ   $0F85

	0F7C: E8 30     MOV   A,#$30
	0F7E: 8D 03     MOV   Y,#$03
	0F80: 9B 91     DEC   $91+X

	0F82: 3F D2 0F  CALL  $0FD2	; execute pan sweep increment for the frame

	0F85: E4 47     MOV   A,$47
	0F87: 24 5E     AND   A,$5E

	0F89: F0 46     BEQ   $0FD1	; if($47 & $5E) goto $0FD1; // return;

	0F8B: F5 31 03  MOV   A,$0331+X
	0F8E: FD        MOV   Y,A

	0F8F: F5 30 03  MOV   A,$0330+X
	0F92: DA 10     MOVW  $10,YA	; $10.w = $0330+X.w

; Routine entry point

	0F94: 7D        MOV   A,X
	0F95: 9F        XCN   A
	0F96: 5C        LSR   A		; The classic x -> (x-1) * 0x10
	0F97: C4 12     MOV   $12,A	; $12 = A;

Volume_Right:

	0F99: EB 11     MOV   Y,$11		; Y = $11

	0F9B: F6 79 11  MOV   A,$1179+Y
	0F9E: 80        SETC
	0F9F: B6 78 11  SBC   A,$1178+Y	; A = $1179+Y = $1178+Y

	0FA2: EB 10     MOV   Y,$10		; Y = $10;
	0FA4: CF        MUL   YA		; YA = $10 * A

	0FA5: DD        MOV   A,Y		
	0FA6: EB 11     MOV   Y,$11		; A = Y; Y = $11
	0FA8: 60        CLRC
	0FA9: 96 78 11  ADC   A,$1178+Y	; A += $1178;
	0FAC: FD        MOV   Y,A		; Y = A;

	0FAD: F5 21 03  MOV   A,$0321+X	; fully adjusted volume
	0FB0: CF        MUL   YA

	0FB1: F5 51 03  MOV   A,$0351+X	; some kind of pan argument...
	0FB4: 1C        ASL   A			; A = $0351+X << 1;

	0FB5: 13 12 01  BBC0  $12, Volume_Left

	0FB8: 1C        ASL   A			; A = $0351+X << 2;

Volume_Left:

	0FB9: DD        MOV   A,Y		; A = final volume result for this channel / side

	0FBA: 90 03     BCC   $0FBF

	0FBC: 48 FF     EOR   A,#$FF
	0FBE: BC        INC   A			; guess this inverts the phase of the signal?

$0FBF:

	0FBF: EB 12     MOV   Y,$12

	0FC1: 3F EF 09  CALL  $09EF		; Write the Volume Left for this voice.

	0FC4: 8D 14     MOV   Y,#$14
	0FC6: E8 00     MOV   A,#$00
	0FC8: 9A 10     SUBW  YA,$10		
	0FCA: DA 10     MOVW  $10,YA		; $10 = #$1400 - $10; // this is what causes a pan of 0x0A to be neutral.
	0FCC: AB 12     INC   $12		; makes it so we're going to write to VxVOLR instead of VxVOLL next time

	0FCE: 33 12 C8  BBC1  $12, Volume_Right	; fancy way of saying if( $12 < 0x02 )

$0FD1:

	0FD1: 6F        RET

; ********************************************************
; subroutine $0FD2

	0FD2: 09 47 5E  OR    $5E,$47		; $5E |= $47;

; alternate entry point $0FD5

	0FD5: DA 14     MOVW  $14,YA
	0FD7: DA 16     MOVW  $16,YA		; $14 = $16 = YA
	0FD9: 4D        PUSH  X
	0FDA: EE        POP   Y
	0FDB: 60        CLRC

	0FDC: D0 0A     BNE   $0FE8

	0FDE: 98 1F 16  ADC   $16,#$1F	; er... if the channel we're playing on is channel 0....

	0FE1: E8 00     MOV   A,#$00
	0FE3: D7 14     MOV   ($14)+Y,A
	0FE5: FC        INC   Y

	0FE6: 2F 09     BRA   $0FF1

$0FE8:

	0FE8: 98 10 16  ADC   $16,#$10	; $16 += 0x10;

	0FEB: 3F EF 0F  CALL  $0FEF

	0FEE: FC        INC   Y			; Y++;

	0FEF: F7 14     MOV   A,($14)+Y	; A = ($14)+Y

$0FF1:

	0FF1: 97 16     ADC   A,($16)+Y
	0FF3: D7 14     MOV   ($14)+Y,A	; ($14)+Y += ($16)+Y;

	0FF5: 6F        RET			; return;

; ***************************************************************
; Subroutine $0FF6

	0FF6: F4 71     MOV   A,$71+X		; check this flag

	0FF8: F0 65     BEQ   $105F		; if($71+X == 0) goto $105F;

	0FFA: 9B 71     DEC   $71+X		; $71+X--; 

	0FFC: F0 05     BEQ   $1003		; if($71+X == 0) goto $1003;

	0FFE: E8 02     MOV   A,#$02

	1000: DE 70 5C  CBNE  $70+X, $105F	; if($70+X != 0x02) goto $105F;

$1003:

	1003: F4 80     MOV   A,$80+X		; call loop iteration (counts down)
	1005: C4 17     MOV   $17,A		; $17 = $80+X

	1007: F4 30     MOV   A,$30+X		
	1009: FB 31     MOV   Y,$31+X		; $30+X.w is the current track pointer

$100B:

	100B: DA 14     MOVW  $14,YA		; $14.w = $30+X.w

	100D: 8D 00     MOV   Y,#$00

$100F:

	100F: F7 14     MOV   A,($14)+Y	; get the next byte off the track

	1011: F0 1E     BEQ   $1031		; if(track_byte == 0) goto $1031

	1013: 30 07     BMI   $101C		; if(track_byte >= 0x80) goto $101C

read_track_data:

	1015: FC        INC   Y			; otherwise ignore the track_byte and move on

	1016: 30 40     BMI   $1058		; if(Y >= 0x80) goto $1058

	1018: F7 14     MOV   A,($14)+Y	; grab the next byte on the track

	101A: 10 F9     BPL   read_track_data	; if(track_byte < 0x80) 

$101C:

	101C: 68 C8     CMP   A,#$C8		

	101E: F0 3F     BEQ   $105F		; if(track_byte == 0xC8) goto $105F

	1020: 68 EF     CMP   A,#$EF		

	1022: F0 29     BEQ   $104D		; if(track_byte == 0xEF) goto $104D; (it's a call loop)

	1024: 68 E0     CMP   A,#$E0

	1026: 90 30     BCC   $1058		; if(track_byte < 0xE0) goto $1058; (it's an instrument change)

	1028: 6D        PUSH  Y			; we're going to fake like we performed a command (bytes 0xE0 to 0xFA)
	1029: FD        MOV   Y,A		; Y = A;

	102A: AE        POP   A
	102B: 96 40 0E  ADC   A,$0E40+Y	; add in the number of parameters
	102E: FD        MOV   Y,A		; Y = A + $0E40+Y ; // skips ahead to the next item in the track data

	102F: 2F DE     BRA   $100F

$1031:

	1031: E4 17     MOV   A,$17

	1033: F0 23     BEQ   $1058		;

	1035: 8B 17     DEC   $17		; decrease the call loop counter

	1037: D0 0A     BNE   call_loop_notdone	; if it's nonzero, goto $1043 and handle the call loop

	1039: F5 31 02  MOV   A,$0231+X	; if the call loop has finished, pull the return address from $0230[2]
	103C: 2D        PUSH  A

	103D: F5 30 02  MOV   A,$0230+X
	1040: EE        POP   Y			; YA = $0231+X.w

	1041: 2F C8     BRA   $100B		; and return to handling data

call_loop_notdone

	1043: F5 41 02  MOV   A,$0241+X	; load the address of the call loop
	1046: 2D        PUSH  A

	1047: F5 40 02  MOV   A,$0240+X
	104A: EE        POP   Y			; YA = $0240+X.w

	104B: 2F BE     BRA   $100B		; and go to it

; CallLoop command

	104D: FC        INC   Y			; grab the low byte of the call loop address

	104E: F7 14     MOV   A,($14)+Y
	1050: 2D        PUSH  A
	1051: FC        INC   Y

	1052: F7 14     MOV   A,($14)+Y	; grab the high byte of the call loop address
	1054: FD        MOV   Y,A
	1055: AE        POP   A			; YA = target address for the call loop

	1056: 2F B3     BRA   $100B		; loop back and start working through the data in the call loop

; handles instrument changes in this context (I think)

$1058:

	1058: E4 47     MOV   A,$47		; indicates which voices to mute?
	105A: 8D 5C     MOV   Y,#$5C 		; KEYOFF register

	105C: 3F EF 09  CALL  $09EF		; writes $47 to KOFF

$105F:

	105F: F2 13     CLR7  $13		; clear bit seven of $13

	1061: F4 A0     MOV   A,$A0+X		; A = $A0+X

	1063: F0 19     BEQ   $107E		; if($A0+X == 0) goto $107E;

	1065: F4 A1     MOV   A,$A1+X

	1067: F0 04     BEQ   $106D		; if($A1+X == 0) goto $106D;

	1069: 9B A1     DEC   $A1+X

	106B: 2F 11     BRA   $107E		; goto $107E;

$106D:

	106D: E4 1A     MOV   A,$1A
	106F: 24 47     AND   A,$47

	1071: D0 0B     BNE   $107E		; if($1A & $47) goto $107E;

	1073: E2 13     SET7  $13
	1075: E8 60     MOV   A,#$60
	1077: 8D 03     MOV   Y,#$03		; YA = 0x0360
	1079: 9B A0     DEC   $A0+X		; $A0+X--;

	107B: 3F D5 0F  CALL  $0FD5		; perform pitch slide

$107E:

	107E: 3F C3 0E  CALL  $0EC3		; update $10.w with $0360+X.w

	1081: F4 B1     MOV   A,$B1+X		; vibrato flag.. and probably a bit more

	1083: F0 4C     BEQ   $10D1		; if($B1+X == 0) goto $10D1; (essentially means don't use vibrato if zero)

	1085: F5 B0 02  MOV   A,$02B0+X	; $02B0+X is the vibrato set point 

	1088: DE B0 44  CBNE  $B0+X, $10CF	; if( $02B0+X != $B0+X) goto $10CF

	108B: F5 00 01  MOV   A,$0100+X
	108E: 75 B1 02  CMP   A,$02B1+X

	1091: D0 05     BNE   $1098		; if($0100+X != $02B1+X) goto $1098;

	1093: F5 C1 02  MOV   A,$02C1+X	; A = $02C1+X

	1096: 2F 0D     BRA   $10A5		; goto $10A5;

$1098:

	1098: 40        SETP			; sets direct page to $100

	1099: BB 00     INC   $00+X		; increment $0100+X 
	109B: 20        CLRP			; sets direct page to $00
	109C: FD        MOV   Y,A

	109D: F0 02     BEQ   $10A1		; if(!A) goto $10A1;

	109F: F4 B1     MOV   A,$B1+X		; A = $B1+X

$10A1:

	10A1: 60        CLRC
	10A2: 95 C0 02  ADC   A,$02C0+X	; A += $02C0+X (vibrato step variable)

$10A5:

	10A5: D4 B1     MOV   $B1+X,A		; $B1+X = A

	10A7: F5 A0 02  MOV   A,$02A0+X	
	10AA: 60        CLRC
	10AB: 95 A1 02  ADC   A,$02A1+X
	10AE: D5 A0 02  MOV   $02A0+X,A	; $02A0+X += $02A1+X;

; Jump Location $10B1
$10B1:

	10B1: C4 12     MOV   $12,A
	10B3: 1C        ASL   A
	10B4: 1C        ASL   A

	10B5: 90 02     BCC   $10B9

	10B7: 48 FF     EOR   A,#$FF

$10B9:

	10B9: FD        MOV   Y,A
	10BA: F4 B1     MOV   A,$B1+X		
	10BC: 68 F1     CMP   A,#$F1

	10BE: 90 05     BCC   $10C5		; if($B1+X < 0xF1) goto $10C5;

	10C0: 28 0F     AND   A,#$0F
	10C2: CF        MUL   YA

	10C3: 2F 04     BRA   $10C9

$10C5:

	10C5: CF        MUL   YA
	10C6: DD        MOV   A,Y
	10C7: 8D 00     MOV   Y,#$00

$10C9:

	10C9: 3F 46 11  CALL  $1146		; YA = abs(YA), $10 is adjusted...?

$10CC:

	10CC: 5F 6C 09  JMP   $096C

$10CF:

	10CF: BB B0     INC   $B0+X		; $B0+X did not match the set point value ($02B0+X) so increment it for now.

$10D1:

	10D1: E3 13 F8  BBS7  $13,$10CC

	10D4: 6F        RET

; **************************************************************
; Subroutine $10D5
; This routine is sort of like the master of actual NSPC data processing
; the tracker, if you will.

	10D5: F2 13     CLR7  $13			; Lower this flag for now. (I really am not sure what it signifies)

	10D7: F4 C1     MOV   A,$C1+X

	10D9: F0 09     BEQ   no_tremelo		; if($C1+X == 0) goto $10E4

	10DB: F5 E0 02  MOV   A,$02E0+X

	10DE: DE C0 03  CBNE  $C0+X, no_tremelo	; if($02E0+X != $C0+X) goto no_tremelo;

	10E1: 3F 4E 11  CALL  $114E			; does volume adjustment (and other things)

no_tremelo: 						; tenatative name

	10E4: F5 31 03  MOV   A,$0331+X
	10E7: FD        MOV   Y,A

	10E8: F5 30 03  MOV   A,$0330+X
	10EB: DA 10     MOVW  $10,YA			; $10.w = $0330+X.w
	
	10ED: F4 91     MOV   A,$91+X

	10EF: F0 0A     BEQ   $10FB			; if($91+X == 0) goto $10FB;

	10F1: F5 41 03  MOV   A,$0341+X
	10F4: FD        MOV   Y,A			; Y = $0341+X

	10F5: F5 40 03  MOV   A,$0340+X		; A = $0340+X
								;$0340[2]+X is a hexadecimal fraction representing the ratio of panned volume to... i dunno.

$10FB:

	10F8: 3F 30 11  CALL  $1130

	10FB: F3 13 03  BBC7  $13,$1101

	10FE: 3F 94 0F  CALL  $0F94

	1101: F2 13     CLR7  $13

	1103: 3F C3 0E  CALL  $0EC3

	1106: F4 A0     MOV   A,$A0+X

	1108: F0 0E     BEQ   $1118		; if($A0+X == 0) goto $1118;

	110A: F4 A1     MOV   A,$A1+X		

	110C: D0 0A     BNE   $1118		; if($A1+X) goto $1118;

	110E: F5 71 03  MOV   A,$0371+X
	1111: FD        MOV   Y,A
	1112: F5 70 03  MOV   A,$0370+X	; YA = $0370.w; // this is the pitch slide step variable

	1115: 3F 30 11  CALL  $1130		; perform the pitch slide

$1118:

	1118: F4 B1     MOV   A,$B1+X		; now handle vibrato

	111A: F0 B5     BEQ   $10D1		; if no vibrato, goto $10D1

	111C: F5 B0 02  MOV   A,$02B0+X

	111F: DE B0 AF  CBNE  $B0+X,$10D1	; if($B0+X != $02B0+X) goto $10D1

	1122: EB 51     MOV   Y,$51		; Y = music delay timer
	1124: F5 A1 02  MOV   A,$02A1+X	; A = ????
	1127: CF        MUL   YA
	1128: DD        MOV   A,Y
	1129: 60        CLRC
	112A: 95 A0 02  ADC   A,$02A0+X

	112D: 5F B1 10  JMP   $10B1

; ****************************************************************
; Subroutine $1130

	1130: E2 13     SET7  $13
	1132: CB 12     MOV   $12,Y

	1134: 3F E0 0E  CALL  $0EE0	; basically, if YA is negative, it makes it positive.

	1137: 6D        PUSH  Y
	1138: EB 51     MOV   Y,$51
	113A: CF        MUL   YA	; YA = Music delay timer * fractional part of pitch modulation setting
	113B: CB 14     MOV   $14,Y
	113D: 8F 00 15  MOV   $15,#$00	; $14.w = YA & 0xFF;
	1140: EB 51     MOV   Y,$51
	1142: AE        POP   A
	1143: CF        MUL   YA	; YA = $51 * 
	1144: 7A 14     ADDW  YA,$14	; details are messy but this is basically the multiplication of the music delay timer and the pitch slide step variable.
	
; alternate entry point $1146
$1146:

	1146: 3F E0 0E  CALL  $0EE0	; YA = abs(YA);
	
	1149: 7A 10     ADDW  YA,$10
	114B: DA 10     MOVW  $10,YA	; add the result to the current pitch value
	
	114D: 6F        RET

; ***************************************************
; Subroutine $114E

	114E: E2 13     SET7  $13 		; interrupt thingy?

	1150: EB 51     MOV   Y,$51		; this is going to make volume scale by the delay timer
	1152: F5 D1 02  MOV   A,$02D1+X
	1155: CF        MUL   YA		; YA = ($02D1+X * $51)
	1156: DD        MOV   A,Y		; A = Y;
	1157: 60        CLRC
	1158: 95 D0 02  ADC   A,$02D0+X	; A += $02D0+X

; Alternate Entry Point $115B
$115B:

	115B: 1C        ASL   A			; A <<= 1;

	115C: 90 02     BCC   $1160		; if(carry_clear) goto $1160;

	115E: 48 FF     EOR   A,#$FF		; otherwise, invert the bits of C

$1160:

	1160: FB C1     MOV   Y,$C1+X
	1162: CF        MUL   YA		; YA = $C1+X * A;
	1163: DD        MOV   A,Y		; A = Y;
	1164: 48 FF     EOR   A,#$FF		; A ^= 0xFF;

; Subroutine $1166 (alt entry point)

	1166: EB 59     MOV   Y,$59		; Y = master_volume;
	1168: CF        MUL   YA

	1169: F5 10 02  MOV   A,$0210+X	; A = note volume
	116C: CF        MUL   YA		; multiply together

	116D: F5 01 03  MOV   A,$0301+X	; A = channel volume
	1170: CF        MUL   YA		; multiply together

	1171: DD        MOV   A,Y
	1172: CF        MUL   YA		; A = A^2

	1173: DD        MOV   A,Y
	1174: D5 21 03  MOV   $0321+X,A	; this is the final adjusted volume

	1177: 6F        RET

; **************************************************

; data references, probably

1178: 00        NOP
1179: 01        TCALL 0
117A: 03 07 0D  BBS0  $07,$1189
117D: 15 1E 29  OR    A,$291E+X
1180: 34 42     AND   A,$42+X
1182: 51        TCALL 5
1183: 5E 67 6E  CMP   Y,$6E67
1186: 73 77 7A  BBC3  $77,$0A02
1189: 7C        ROR   A
118A: 7D        MOV   A,X
118B: 7E 7F     CMP   Y,$7F

EchoFilters:
	; echo filter set 0

	118D: db $7F        
	118E: db $00
	118F: db $00
	1190: db $00
	1191: db $00
	1192: db $00
	1193: db $00
	1194: db $00

	; echo filter set 1

	1195: db $58
	1196: db $BF
	1197: db $DB
	1198: db $F0
	1199: db $FE
	119A: db $07
	119B: db $0C
	119C: db $0C

	; echo filter set 2

	119D: db $0C
	119E: db $21
	119F: db $2B
	11A0: db $2B
	11A1: db $13
	11A2: db $FE
	11A3: db $F3
	11A4: db $F9
	
	; echo filter set 3

	11A5: db $34
	11A6: db $33
	11A7: db $00
	11A8: db $D9
	11A9: db $E5
	11AA: db $01
	11AB: db $FC
	11AC: db $EB

RegisterList:

	11AD: db $2C	; Echo volume left (ECHOVOLL)
	11AE: db $3C	; Echo volume right (ECHOVOLR)
	11AF: db $0D	; Echo feedback bits
	11B0: db $4D	; Echo enable bits
	11B1: db $6C	; FLG register
	11B2: db $4C	; Key-on voices
	11B3: db $5C	; Muted voices
	11B4: db $3D	; Noise enabled voices
	11B5: db $2D	; Pitch modulation enabled voices
	11B6: db $5C	; Muted voices

LoadValueFrom:

	; Like the table above, there are ten entries on this list. These addresses correspond to the register list above.
	; Each of these normal RAM addresses contains value to write to the respective DSP Register in the above list
	; e.g. if $61 contains the value #$50, then DSP register $2C will end up receiving the value #$50 

	11B7: db $61	; -> EVOLL 
	11B8: db $63	; -> EVOLR 
	11B9: db $4E	; -> EFB   
	11BA: db $4A	; -> EON  
	11BB: db $48	; -> FLG	
	11BC: db $45	; -> KON
	11BD: db $0E	; -> KOFF
	11BE: db $49	; -> NON
	11BF: db $4B	; -> PMON
	11C0: db $46	; -> KOFF

Pitch:		; tentative label name

; block 0

	11C1: db $5F
	11C2: db $08

; block 1

	11C3: db $DE
	11C4: db $08

; block 2

	11C5: db $65
	11C6: db $09

; block 3

	11C7: db $F4
	11C8: db $09

; block 4

	11C9: db $8C
	11CA: db $0A

; block 5

	11CB: db $2C
	11CC: db $0B

; block 6

	11CD: db $D6
	11CE: db $0B

; block 7

	11CF: db $8B
	11D0: db $0C

; block 8

	11D1: db $4A
	11D2: db $0D

; block 9

	11D3: db $14 
	11D4: db $0E
 
; block A

	11D5: db $EA
	11D6: db $0E

; block B

	11D7: db $CD
	11D8: db $0F

; block C

	11D9: db $BE
	11DA: db $10 

; end of the actual blocks?

; block D

	11DB: db $2A
	11DC: db $56

; block E

	11DD: db $65
	11DE: db $72

; block F

	11DF: db $20
	11E0: db $53

; block $10

	11E1: db $31
	11E2: db $2E

; block $11

	11E3: db $32
	11E4: db $30

; block $12

	11E5: db $2A 

; **************************************************************
; $11E6 Subroutine
; Waits for data to be loaded from the CPU side. part of special song command FF

	11E6: E8 AA     MOV   A,#$AA
	11E8: C5 F4 00  MOV   $00F4,A

	11EB: E8 BB     MOV   A,#$BB
	11ED: C5 F5 00  MOV   $00F5,A

$11F0:

	11F0: E5 F4 00  MOV   A,$00F4
	11F3: 68 CC     CMP   A,#$CC	; Wait for Data to be fed to the SPC from the main processor. #$CC signals the start of a data transfer

	11F5: D0 F9     BNE   $11F0   

	11F7: 2F 20     BRA   $1219

$11F9:

	11F9: EC F4 00  MOV   Y,$00F4

	11FC: D0 FB     BNE   $11F9

$11FE:

	11FE: 5E F4 00  CMP   Y,$00F4

	1201: D0 0F     BNE   $1212

	1203: E5 F5 00  MOV   A,$00F5
	1206: CC F4 00  MOV   $00F4,Y
	1209: D7 14     MOV   ($14)+Y,A
	120B: FC        INC   Y

	120C: D0 F0     BNE   $11FE

	120E: AB 15     INC   $15

	1210: 2F EC     BRA   $11FE

$1212:

	1212: 10 EA     BPL   $11FE

	1214: 5E F4 00  CMP   Y,$00F4

	1217: 10 E5     BPL   $11FE

$1219:

	1219: E5 F6 00  MOV   A,$00F6	; Retrieve the location to write the bytes to?
	121C: EC F7 00  MOV   Y,$00F7
	121F: DA 14     MOVW  $14,YA	; Store this at $0014

	1221: EC F4 00  MOV   Y,$00F4 ; Retrieve the number of bytes that will be written
	1224: E5 F5 00  MOV   A,$00F5
	1227: CC F4 00  MOV   $00F4,Y

	122A: D0 CD     BNE   $11F9		; if the number of bytes != 0

	122C: CD 31     MOV   X,#$31		; signal telling that mofo that we're done?
	122E: C9 F1 00  MOV   $00F1,X
	
	1231: 6F        RET			; return;

; End of Subroutine.
;***********************************************************

; Subroutine $1232

	1232: E4 02     MOV   A,$02
	1234: 28 3F     AND   A,#$3F
	1236: 5D        MOV   X,A		; X = $02 & 0x3F

	1237: F5 DC 18  MOV   A,$18DC+X
	123A: C5 E2 03  MOV   $03E2,A		; $03E2 = $18DC+X

	123D: 8D 0E     MOV   Y,#$0E		; Y = 0x0E
	123F: CD 80     MOV   X,#$80		; X = 0x80
	1241: C9 C1 03  MOV   $03C1,X		; $03C1 = 0x80

loop_back:

	1244: E5 CB 03  MOV   A,$03CB		; 
	1247: 25 C1 03  AND   A,$03C1		; A = ($03C1 & $03CB);

	124A: F0 0B     BEQ   next_slot	; if(A == 0) goto sfx2_next_slot;

	124C: 60        CLRC
	124D: F6 A0 03  MOV   A,$03A0+Y
	1250: 96 D0 03  ADC   A,$03D0+Y	; A = ($03A0+Y + $03D0+Y)
	1253: 64 02     CMP   A,$02

	1255: F0 37     BEQ   $128E		; if($02 == A) 

sfx2_next_slot:

	1257: DC        DEC   Y
	1258: DC        DEC   Y
	1259: 4C C1 03  LSR   $03C1		; Y -= 2; $03C1 >>= 1;

	125C: D0 E6     BNE   loop_back	; if($03C1 != 0) goto loop_back;

	125E: 2F 33     BRA   $1293

; Subroutine $1260 (alt entry point)
; Used with sounde effects and .... other stuff?

	1260: E4 03     MOV   A,$03		; A = $03 (sfx 3)
	1262: 28 3F     AND   A,#$3F		; A &= 0x3F
	1264: 5D        MOV   X,A		; X = ($03 & 0x3F)

	1265: F5 D8 19  MOV   A,$19D8+X	; 
	1268: C5 E2 03  MOV   $03E2,A		; $03E2 = $19D8+X

	126B: 8D 0E     MOV   Y,#$0E		; Y = 0x0E
	126D: CD 80     MOV   X,#$80
	126F: C9 C1 03  MOV   $03C1,X		; $03C1 = 0x80

sfx3_loop_point:

	1272: E5 CD 03  MOV   A,$03CD
	1275: 25 C1 03  AND   A,$03C1			; A = ($03CD & $03C1);

	1278: F0 0B     BEQ   sfx3_next_slot	; if(A == 0) goto sfx3_next_slot:

	127A: 60        CLRC
	127B: F6 A0 03  MOV   A,$03A0+Y		
	127E: 96 D0 03  ADC   A,$03D0+Y		; A = ($03A0+Y + $03D0+Y)
	1281: 64 03     CMP   A,$03			

	1283: F0 09     BEQ   $128E			; if(A == sfx3) goto $128E

sfx3_next_slot:

	1285: DC        DEC   Y				; otherwise keep looking for a slot to send it to.
	1286: DC        DEC   Y
	1287: 4C C1 03  LSR   $03C1			; $03C1 starts as 0x80, and goes to 0x40, 0x20, etc...

	128A: D0 E6     BNE   sfx3_loop_point	; if($03C1 != 0) goto sfx3_loop_point;

	128C: 2F 05     BRA   $1293			; if there's no open slot... too bad.

$128E:

	128E: CC C0 03  MOV   $03C0,Y			; $03C0 = Y

	1291: 2F 15     BRA   $12A8			; 

; Jump point $1293

	1293: 60        CLRC
	1294: CD 1A     MOV   X,#$1A		; X = 0x1A

	1296: E8 80     MOV   A,#$80
	1298: C5 C1 03  MOV   $03C1,A		; $03C1 = 0x80
	129B: 8D 0E     MOV   Y,#$0E		; Y = 0x0E

loop_back_2:

	129D: 26        AND   A,(X)		; A = (0x80 & $1A)

	129E: F0 08     BEQ   $12A8		; if this voice is not muted, then branch

	12A0: DC        DEC   Y
	12A1: DC        DEC   Y
	12A2: 4C C1 03  LSR   $03C1		; $03C1 >>= 1;
	12A5: 5C        LSR   A			; A >>= 1;

	12A6: 90 F5     BCC   loop_back_2	; A and $03C1 are sliding right, so if it runs out of bits...

$12A8:

	12A8: CC C0 03  MOV   $03C0,Y		; $03C0 = Y
	12AB: CC C8 03  MOV   $03C8,Y		; $03C8 = Y

	12AE: E5 C1 03  MOV   A,$03C1
	12B1: C5 C9 03  MOV   $03C9,A		; $03C9 = $03C1
	12B4: 04 1A     OR    A,$1A
	12B6: C4 1A     MOV   $1A,A		; $1A |= A

	12B8: E9 E2 03  MOV   X,$03E2		; X = $03E2

	12BB: F0 06     BEQ   $12C3		; if(X == 0)

	12BD: 05 E3 03  OR    A,$03E3
	12C0: C5 E3 03  MOV   $03E3,A		; $03E3 |= $1A | $03C1;

; Subroutine $12C3 (alt entry point)

	12C3: E5 04 00  MOV   A,$0004
	12C6: 28 10     AND   A,#$10		; A = ($04 & 0x10); // seems like this is some kind of check of what music bank is being used.

	12C8: F0 08     BEQ   $12D2		; if(!A) goto $12D2;

	12CA: E5 C1 03  MOV   A,$03C1
	12CD: 25 E3 03  AND   A,$03E3

	12D0: F0 14     BEQ   $12E6		; if($03C1 & $03E3) goto $12E6; //(return;)

$12D2:

	12D2: E5 C1 03  MOV   A,$03C1
	12D5: 24 4A     AND   A,$4A		; A = $03C1 & ECHOEN

	12D7: F0 0D     BEQ   $12E6		; if this voice has not been echo enabled.

	12D9: E4 4A     MOV   A,$4A
	12DB: 80        SETC
	12DC: A5 C1 03  SBC   A,$03C1
	12DF: C4 4A     MOV   $4A,A		; $4A -= $03C1; // (deactivate echo enable on this voice.)
	12E1: 8D 4D     MOV   Y,#$4D

	12E3: 3F F7 09  CALL  WriteToDsp(A,Y) ; write to the ECHOEN dsp register.

$12E6:

	12E6: 6F        RET

; I'm not sure if this code is ever executed

12E7: E9 C4 03  MOV   X,$03C4
12EA: C9 C0 03  MOV   $03C0,X			; $03C0 = $03C4;

12ED: EC C5 03  MOV   Y,$03C5
12F0: CC C1 03  MOV   $03C1,Y			; $03C1 = $03C5;

12F3: E5 C1 03  MOV   A,$03C1			; value comes from $03C1
12F6: 8D 5C     MOV   Y,#$5C			; write to KOFF

12F8: 3F F7 09  CALL  WriteToDsp(A,Y)	; write to the dsp register that mutes voices.
12FB: 3F 69 15  CALL  $1569			;

12FE: 6F        RET

; Play a sound effect?

12FF: C4 05     MOV   $05,A		; $05 = A
1301: 68 05     CMP   A,#$05

1303: D0 06     BNE   $130B		; if(A != 0x05) goto $130B

1305: E9 CF 03  MOV   X,$03CF

1308: D0 01     BNE   $130B		; else if($03CF != 0) goto $130B

130A: 6F        RET			; else return;

; $130B SUBROUTINE

	130B: CD 00     MOV   X,#$00		
	130D: C9 E4 03  MOV   $03E4,X			; $03E4 = #$00	; fade out for sfx set to 0
	1310: CD 0E     MOV   X,#$0E			; X = 0x0E

	1312: E4 01     MOV   A,$01		
	1314: D5 A0 03  MOV   $03A0+X,A		; $03A0+X = $01	; $01 ambient track value (sfx1)

	1317: E8 03     MOV   A,#$03		
	1319: D5 A1 03  MOV   $03A1+X,A		; $03A1+X = 0x03

	131C: E8 00     MOV   A,#$00
	131E: D5 80 02  MOV   $0280+X,A		; $0280+X = 0x00

	1321: E8 80     MOV   A,#$80
	1323: C5 CF 03  MOV   $03CF,A			; $03CF = 0x80
	1326: 8D 5C     MOV   Y,#$5C			; Writing to KOFF

	1328: 3F F7 09  CALL  WriteToDsp(A,Y)	; mutes voice 7.

	132B: E2 1A     SET7  $1A			; Indicate in RAM that voice 7 is muted.
	132D: F8 01     MOV   X,$01			; X = $01
	132F: F5 FF 17  MOV   A,$17FF+X		; 
	1332: C4 01     MOV   $01,A			; $01 = $17FF+X

	1334: D0 01     BNE   $1337			; if( $01 ) goto $1337; // seems like some sound effects will mute other sound effects

	1336: 6F        RET

$1337:

	1337: CD 0C     MOV   X,#$0C		; X = 0x0C
	1339: E4 01     MOV   A,$01		; A = $01
	133B: D5 A0 03  MOV   $03A0+X,A	; $03A0+X = $01

	133E: E8 03     MOV   A,#$03
	1340: D5 A1 03  MOV   $03A1+X,A	; $03A1+X = 0x03

	1343: E8 00     MOV   A,#$00
	1345: D5 80 02  MOV   $0280+X,A	; $0280+X = 0x00
	1348: C2 1A     SET6  $1A		; $1A |= 0x40 (mutes voice 6?)

	134A: E8 40     MOV   A,#$40		; value to be written
	134C: 8D 5C     MOV   Y,#$5C		; writing to KOFF

	134E: 3F F7 09  CALL  WriteToDsp(A,Y)	; mute voice 6

	1351: E8 C0     MOV   A,#$C0
	1353: C5 CF 03  MOV   $03CF,A		; $03CF = 0xC0
	1356: 05 E3 03  OR    A,$03E3
	1359: C5 E3 03  MOV   $03E3,A		; $03E3 |= 0xC0

	135C: E8 3F     MOV   A,#$3F
	135E: 25 CB 03  AND   A,$03CB
	1361: C5 CB 03  MOV   $03CB,A		; $03CB &= 0x3F

	1364: E8 3F     MOV   A,#$3F
	1366: 25 CD 03  AND   A,$03CD
	1369: C5 CD 03  MOV   $03CD,A		; $03CD &= 0x3F

	136C: 6F        RET

; $136D SUBROUTINE

	136D: E4 01     MOV   A,$01	; $01 designates the current sound effect to play (channel 6)

	136F: 30 03     BMI   $1374	; if ($01 < 0) goto sfx1_negative;

	1371: D0 8C     BNE   $12FF	; else if($01 != 0) This means there's a sound effect to play.

	1373: 6F        RET		; else return;

sfx1_negative:

	1374: C4 05     MOV   $05,A	; $05 = $01

	1376: E5 CF 03  MOV   A,$03CF

	1379: F0 05     BEQ   $1380	; if($03CF == 0) return;

	137B: E8 78     MOV   A,#$78
	137D: C5 E4 03  MOV   $03E4,A	; $03E4 = 0x78, this tells the sound effect to start fading out

	1380: 6F        RET		; return;

; END OF $136D SUBROUTINE

; Jump ocation $1381
; This routine seems to fade out a sound effect, gradually reducing its volume?

	1381: 8C E4 03  DEC   $03E4		; Decrease sound effect volume by 1?
	1384: E5 E4 03  MOV   A,$03E4		;

	1387: D0 0C     BNE   $1395		; if($03E4 != 0)

	1389: E8 05     MOV   A,#$05		; A = 0x05; 5 is the silencing command.
	138B: C4 01     MOV   $01,A		; $01 = 0x05; silencing command for the ambient track

	138D: 3F 0B 13  CALL  $130B		; implement the silencing command

	1390: E8 00     MOV   A,#$00		; then clear the ambient track input to zero
	1392: C4 01     MOV   $01,A		; $01 = 0x00; nothing commang

	1394: 6F        RET

; What happens if($03E4 != 0) (i.e. the sound effect hasn't completely faded out)

1395: 5C        LSR   A			; divide by 2
1396: C5 E5 03  MOV   $03E5,A		; $03E5 = $03E4 >> 1; 
1399: 8D 70     MOV   Y,#$70		; V7VOLL

139B: 3F F7 09  CALL  WriteToDsp(A,Y)	; Write to voice 7 volume left

139E: FC        INC   Y			; V7VOLR
139F: E5 E5 03  MOV   A,$03E5		; $03E5 is the argument for the volume

13A2: 3F F7 09  CALL  WriteToDsp(A,Y)	; Write to voice 7 volume right

13A5: 8D 60     MOV   Y,#$60
13A7: E5 E5 03  MOV   A,$03E5		

13AA: 3F F7 09  CALL  WriteToDsp(A,Y)	; Write to voice 6 volume left

13AD: FC        INC   Y
13AE: E5 E5 03  MOV   A,$03E5

13B1: 3F F7 09  CALL  WriteToDsp(A,Y)	; Write to voice 6 volume right

13B4: 5F 4D 14  JMP   $144D			; Jump back to the calling routine to finish processing the sound effect
							; Since sfx1 hasn't completely faded out, we still have to deal with it.
							; albeit, with reducing volume over time.

;*********************************************************

; SUBROUTINE $13B7

	13B7: E4 02     MOV   A,$02	; A = $02 (input sfx 2)

	13B9: D0 48     BNE   $1403	; if($02 != 0), i.e. if there's actually a sound to play.

	13BB: 6F        RET		; else return;

; Subroutine $13BC

	13BC: E4 03     MOV   A,$03	; A = $03 (input sfx 3)

	13BE: D0 01     BNE   $13C1	; if($03 != 0), i.e. if there's actually a sound to play

	13C0: 6F        RET

$13C1:

	13C1: E8 FF     MOV   A,#$FF	; A = 0xFF

	13C3: 2E 1A 02  CBNE  $1A,$13C8 	; if($1A != 0xFF) (i.e. if there is an

	13C6: 2F 3A     BRA   $1402		; else return;

$13C8:

	13C8: 3F 60 12  CALL  $1260		; 

	13CB: E9 C0 03  MOV   X,$03C0		; X = $03C0

	13CE: E4 03     MOV   A,$03
	13D0: 28 C0     AND   A,#$C0
	13D2: D5 D0 03  MOV   $03D0+X,A	; $03D0+X = ($03 & 0xC0);
	
	13D5: E4 03     MOV   A,$03
	13D7: 28 3F     AND   A,#$3F
	13D9: D5 A0 03  MOV   $03A0+X,A	; $03A0+X = ($03 & 0x3F);

	13DC: E8 03     MOV   A,#$03
	13DE: D5 A1 03  MOV   $03A1+X,A	; $03A1+X = 0x03;

	13E1: E8 00     MOV   A,#$00
	13E3: D5 80 02  MOV   $0280+X,A	; $0280+X = 0x00;

	13E6: E5 C1 03  MOV   A,$03C1
	13E9: 05 CD 03  OR    A,$03CD
	13EC: C5 CD 03  MOV   $03CD,A		; $03CD = ($03C1 | $03CD);

	13EF: E5 C1 03  MOV   A,$03C1
	13F2: 8D 5C     MOV   Y,#$5C
	13F4: 3F F7 09  CALL  WriteToDsp(A,Y)	; Keys off this voice

	13F7: F5 A0 03  MOV   A,$03A0+X
	13FA: 5D        MOV   X,A			; X = $03A0+X

	13FB: F5 99 19  MOV   A,$1999+X	
	13FE: C4 03     MOV   $03,A			; sfx3 = $1999+X; // (with $03A0 as the X register)

	1400: D0 BF     BNE   $13C1			; if(sfx3 != 0) goto $13C1;

$1402:

	1402: 6F        RET				; return;

;**************************************************

$1403:

	1403: E8 FF     MOV   A,#$FF			; A = 0xFF

	1405: 2E 1A 02  CBNE  $1A, not_all_mute	; if not all voices are muted...

	1408: 2F 3A     BRA   $1444		; if all voices are muted, return;

not_all_mute:

	140A: 3F 32 12  CALL  $1232

	140D: E9 C0 03  MOV   X,$03C0		; X = $03C0;

	1410: E4 02     MOV   A,$02
	1412: 28 3F     AND   A,#$3F
	1414: D5 A0 03  MOV   $03A0+X,A	; $03A0+X = ($02 & 0x3F);

	1417: E4 02     MOV   A,$02
	1419: 28 C0     AND   A,#$C0
	141B: D5 D0 03  MOV   $03D0+X,A	; $03D0+X = ($02 & 0xC0);

	141E: E8 03     MOV   A,#$03
	1420: D5 A1 03  MOV   $03A1+X,A	; $03A1+X = 0x03;

	1423: E8 00     MOV   A,#$00
	1425: D5 80 02  MOV   $0280+X,A	; $0280+X = 0;

	1428: E5 C1 03  MOV   A,$03C1
	142B: 05 CB 03  OR    A,$03CB
	142E: C5 CB 03  MOV   $03CB,A		; $03CB |= $03C1;

	1431: E5 C1 03  MOV   A,$03C1		; A = $03C1
	1434: 8D 5C     MOV   Y,#$5C
	1436: 3F F7 09  CALL  WriteToDsp(A,Y)	; mute the voices that $03C1 indicates 

	1439: F5 A0 03  MOV   A,$03A0+X
	143C: 5D        MOV   X,A		; X = $03A0+X

	143D: F5 9D 18  MOV   A,$189D+X
	1440: C4 02     MOV   $02,A		; $02 = $189D+X

	1442: D0 BF     BNE   $1403

	1444: 6F        RET			; return;

; **********************************************************
; 1445 SUBROUTINE

	; sfx1 handler

	1445: E5 E4 03  MOV   A, $03E4	; check if fade out is in progress
	
	1448: F0 03     BEQ   $144D ; if($03E4 == 0) goto $144D;

	144A: 5F 81 13  JMP   $1381 ; else // fade out is in progress

$144D:

	144D: E5 CF 03  MOV   A,$03CF
	1450: C5 E0 03  MOV   $03E0,A		; $03E0 = $03CF

	1453: F0 30     BEQ   $1485		; if(!$03CF) return;

	1455:	CD 0E     MOV   X,#$0E		; X = 0x0E;
	1457: E8 80     MOV   A,#$80		; A = 0x80;
	1459: C5 C1 03  MOV   $03C1,A		; $03C1 = 0x80;

$145C:

	145C: 0C E0 03  ASL   $03E0		; $03E0 <<= 1;

	145F: 90 1B     BCC   $147C		; If the top bit of $03E0 was clear goto $147C

	1461: C9 C0 03  MOV   $03C0,X		; If it wasn't clear, then $03C0 = X
	1464: 7D        MOV   A,X		; A = X
	1465: 9F        XCN   A			; exchange nibbles on A
	1466: 5C        LSR   A			; A >>= 1;
	1467: C5 C2 03  MOV   $03C2,A		; $03C2 = ($03C0 << 3) more or less...
	
	146A: F5 D0 03  MOV   A,$03D0+X	; A = $03D0 + X
	146D: C4 20     MOV   $20,A		; $20 = $03D0 + X
	
	146F: F5 A1 03  MOV   A,$03A1+X	;

	1472: D0 12     BNE   $1486		; if( $03A1+X ) goto $1486;

	1474: F5 A0 03  MOV   A,$03A0+X	;

	1477: F0 03     BEQ   $147C		; if( $03A0+X == 0 ) goto $147C;

	1479: 5F FC 15  JMP   $15FC		; try to resume sfx1

$147C:

	147C: 4C C1 03  LSR   $03C1		; $03C1 >>= 1;
	147F: 1D        DEC   X			
	1480: 1D        DEC   X			; X -= 2;
	1481: C8 0A     CMP   X,#$0A

	1483: 10 D7     BPL   $145C		; if( (X - 0x0A) >= 0) goto $145C

$1485:

	1485: 6F        RET			; return;

$1486:

	1486: C9 C0 03  MOV   $03C0,X		; $03C0 = X;
	1489: F5 A1 03  MOV   A,$03A1+X
	148C: 9C        DEC   A
	148D: D5 A1 03  MOV   $03A1+X,A	; $03A1+X--;

	1490: F0 03     BEQ   $1495		; if($03A1+X == 0) goto $1495;

	1492: 5F 7C 14  JMP   $147C		; rejected! (look for another sound effect, this one isn't ready yet)

$1495:

	1495: F5 A0 03  MOV   A,$03A0+X	; 
	1498: 1C        ASL   A			; 
	1499: FD        MOV   Y,A		; Y = ($03A0+X) * 2 

	149A: F6 BF 17  MOV   A,$17BF+Y	; assignment of data for sfx1 sound effects
	149D: D5 91 03  MOV   $0391+X,A	; $0391+X = $17BF+Y
	14A0: C4 2D     MOV   $2D,A		; $2D = $17BF+Y

	14A2: F6 BE 17  MOV   A,$17BE+Y
	14A5: D5 90 03  MOV   $0390+X,A	; $0390+X = $17BE+Y
	14A8: C4 2C     MOV   $2C,A		; $2C = $17BE+Y

	14AA: 5F 19 16  JMP   $1619

; ********************************************************
; $14AD SUBROUTINE
; appears to similarly handle sfx1... kind of confused now

	14AD: E5 CB 03  MOV   A,$03CB		
	14B0: C5 CC 03  MOV   $03CC,A		; $03CC = $03CB

	14B3: F0 2E     BEQ   $14E3		; if($03CC == 0) return;

	14B5: CD 0E     MOV   X,#$0E		; X = 0x0E
	14B7: E8 80     MOV   A,#$80
	14B9: C5 C1 03  MOV   $03C1,A		; $03C1 = 0x80

$14BC:

	14BC: 0C CC 03  ASL   $03CC		; $03CC << = 1

	14BF: 90 1B     BCC   $14DC		; if the top bit of $03CC was clear, goto $14DC;

	14C1: C9 C0 03  MOV   $03C0,X		; $03C0 = X
	14C4: 7D        MOV   A,X		;
	14C5: 9F        XCN   A			;
	14C6: 5C        LSR   A			; A = ((X & 0x0F) << 4) | (X & 0xF0) >> 4)) >> 1;
	14C7: C5 C2 03  MOV   $03C2,A		; $03C2 = A

	14CA: F5 D0 03  MOV   A,$03D0+X
	14CD: C4 20     MOV   $20,A		; $20 = $03D0+X

	14CF: F5 A1 03  MOV   A,$03A1+X

	14D2: D0 10     BNE   $14E4		; if($03A1+X != 0) goto $14E4;

	14D4: F5 A0 03  MOV   A,$03A0+X

	14D7: F0 03     BEQ   $14DC		; if($03A0+X == 0) goto $14DC;

	14D9: 5F FC 15  JMP   $15FC		; if a voice is available, use it for this sfx

; jump location $14DC
$14DC:

	14DC: 4C C1 03  LSR   $03C1
	14DF: 1D        DEC   X
	14E0: 1D        DEC   X			; $03C1 >> 1; X -= 2;

	14E1: 10 D9     BPL   $14BC		if(X >= 0) goto $14BC;

	14E3: 6F        RET			; return;

$14E4:

	14E4: C9 C0 03  MOV   $03C0,X		; $03C0 = X
	14E7: F5 A1 03  MOV   A,$03A1+X
	14EA: 9C        DEC   A
	14EB: D5 A1 03  MOV   $03A1+X,A	; ($03A1+X)--;

	14EE: F0 03     BEQ   $14F3		; if($03A1 == 0) goto $14F3;

	14F0: 5F DC 14  JMP   $14DC

$14F3:

	14F3: F5 A0 03  MOV   A,$03A0+X
	14F6: 1C        ASL   A
	14F7: FD        MOV   Y,A		; Y = $03A0+X << 1;

	14F8: F6 1F 18  MOV   A,$181F+Y	; assignment of data for sfx2 sound effects
	14FB: D5 91 03  MOV   $0391+X,A	; $0391+X = $181F+Y
	14FE: C4 2D     MOV   $2D,A		; $2D = $181F+Y

	1500: F6 1E 18  MOV   A,$181E+Y
	1503: D5 90 03  MOV   $0390+X,A	; $0390+X = $181E+Y
	1506: C4 2C     MOV   $2C,A		; $2C = $181E+Y

	1508: 5F 19 16  JMP   $1619

; END OF SUBROUTINE $14AD

; Subroutine $150B, used for handling sfx3

	150B: E5 CD 03  MOV   A,$03CD
	150E: C5 CE 03  MOV   $03CE,A		; $03CE = $03CD;

	1511: F0 2E     BEQ   $1541		; if($03CD == 0) return;

	1513: CD 0E     MOV   X,#$0E		; X = 0x0E;
	1515: E8 80     MOV   A,#$80	
	1517: C5 C1 03  MOV   $03C1,A		; $03C1 = 0x80;

$151A:

	151A: 0C CE 03  ASL   $03CE		; msb = $03CE & 0x80; $03CE <<= 1;

	151D: 90 1B     BCC   $153A		; if(!msb) goto $153A

	151F: C9 C0 03  MOV   $03C0,X		; $03C0 = X

	1522: 7D        MOV   A,X
	1523: 9F        XCN   A
	1524: 5C        LSR   A
	1525: C5 C2 03  MOV   $03C2,A		; $03C2 = ((X >> 4) | (X << 4)) >> 1;

	1528: F5 D0 03  MOV   A,$03D0+X
	152B: C4 20     MOV   $20,A		; $20 = $03D0+X

	152D: F5 A1 03  MOV   A,$03A1+X
	
	1530: D0 10     BNE   $1542		; if($03A1+X != 0) goto $1542;

	1532: F5 A0 03  MOV   A,$03A0+X

	1535: F0 03     BEQ   $153A		; if($03A0+X != 0) goto $153A;

	1537: 5F FC 15  JMP   $15FC

$153A:

	153A: 4C C1 03  LSR   $03C1
	153D: 1D        DEC   X
	153E: 1D        DEC   X			; $03C1 >>= 1; X -= 2;

	153F: 10 D9     BPL   $151A		; if(X >= 0) goto $151A;

$1541:

	1541: 6F        RET

$1542:

	1542: C9 C0 03  MOV   $03C0,X		; $03C0 = X;

	1545: F5 A1 03  MOV   A,$03A1+X
	1548: 9C        DEC   A
	1549: D5 A1 03  MOV   $03A1+X,A	; ($03A1+X)--;

	154C: F0 03     BEQ   $1551		; if($03A1+X == 0) goto $1551

	154E: 5F 3A 15  JMP   $153A

	1551: F5 A0 03  MOV   A,$03A0+X
	1554: 1C        ASL   A
	1555: FD        MOV   Y,A		; Y = $03A0+X << 1;

	1556: F6 1B 19  MOV   A,$191B+Y	; A = $191B+Y (with $03A0 * 2 as the Y register)
	1559: D5 91 03  MOV   $0391+X,A	; $0391+X = A
	155C: C4 2D     MOV   $2D,A		; $2D = A

	155E: F6 1A 19  MOV   A,$191A+Y	; A = $191A+Y (same Y value)
	1561: D5 90 03  MOV   $0390+X,A	; $0390+X = A
	1564: C4 2C     MOV   $2C,A		; $2D = A

	1566: 5F 19 16  JMP   $1619

; Subroutine $1569

	1569: E8 00     MOV   A,#$00
	156B: E9 C0 03  MOV   X,$03C0
	156E: D5 A0 03  MOV   $03A0+X,A	; X = $03C0; $03A0+X = 0;

	1571: E4 1A     MOV   A,$1A		
	1573: 80        SETC
	1574: A5 C1 03  SBC   A,$03C1		
	1577: C4 1A     MOV   $1A,A		; $1A -= $03C1;
	
	1579: E5 C1 03  MOV   A,$03C1
	157C: 25 CB 03  AND   A,$03CB		

	157F: F0 0C     BEQ   $158D		; if( !($03CB & $03C1) ) goto $158D;

	1581: E5 CB 03  MOV   A,$03CB
	1584: 80        SETC
	1585: A5 C1 03  SBC   A,$03C1
	1588: C5 CB 03  MOV   $03CB,A		; $03CB -= $03C1;

	158B: 2F 1E     BRA   $15AB

$158D:

	158D: E5 C1 03  MOV   A,$03C1
	1590: 25 CD 03  AND   A,$03CD

	1593: F0 0C     BEQ   $15A1		; if( !($03C1 & $03CD) ) goto $15A1;

	1595: E5 CD 03  MOV   A,$03CD
	1598: 80        SETC
	1599: A5 C1 03  SBC   A,$03C1
	159C: C5 CD 03  MOV   $03CD,A		; $03CD -= $03C1;

	159F: 2F 0A     BRA   $15AB		; goto $15AB;

$15A1:

	15A1: E5 CF 03  MOV   A,$03CF		; sfx1 channels?
	15A4: 80        SETC
	15A5: A5 C1 03  SBC   A,$03C1
	15A8: C5 CF 03  MOV   $03CF,A		; $03CF -= $03C1;

$15AB:

	15AB: D8 44     MOV   $44,X
	15AD: F5 11 02  MOV   A,$0211+X	; $0211+X is apparently the instrument number for each voice.

	15B0: 3F 66 0C  CALL  $0C66

	15B3: E5 C1 03  MOV   A,$03C1
	15B6: 25 C3 03  AND   A,$03C3		

	15B9: F0 1B     BEQ   $15D6		; if(!($03C1 & $03C3) ) goto $15D6;

	15BB: 24 4A     AND   A,$4A		; A = ECHOEN

	15BD: D0 17     BNE   $15D6

	15BF: E4 4A     MOV   A,$4A
	15C1: 60        CLRC
	15C2: 85 C1 03  ADC   A,$03C1
	15C5: C4 4A     MOV   $4A,A		; $4A += $03C1; // as in, enable this voice
	15C7: 8D 4D     MOV   Y,#$4D		; writing to the EON register

	15C9: 3F F7 09  CALL  WriteToDsp(A,Y)	; enable this voice for the echo buffer

	15CC: E5 E3 03  MOV   A,$03E3
	15CF: 80        SETC
	15D0: A5 C1 03  SBC   A,$03C1
	15D3: C5 E3 03  MOV   $03E3,A
	15D6: E9 C0 03  MOV   X,$03C0

	15D9: 6F        RET

; End of Subroutine $1569
; *****************************************************

$15DA:

	15DA: E5 C1 03  MOV   A,$03C1
	15DD: 25 CF 03  AND   A,$03CF
	
	15E0: D0 0E     BNE   $15F0		; if($03C1 & $03CF) goto $15F0;

	15E2: E5 C1 03  MOV   A,$03C1
	15E5: 25 CB 03  AND   A,$03CB

	15E8: D0 0C     BNE   $15F6		; if($03C1 & $03CB) goto $15F6;

	15EA: 3F 69 15  CALL  $1569

	15ED: 5F 3A 15  JMP   $153A

$15F0:

	15F0: 3F 69 15  CALL  $1569

	15F3: 5F 7C 14  JMP   $147C

$15F6:

	15F6: 3F 69 15  CALL  $1569

	15F9: 5F DC 14  JMP   $14DC

; Jump point $15FC

	15FC: 3F C3 12  CALL  $12C3		; Deals with echo enable for this voice... why here, not sure.

	15FF: C9 C0 03  MOV   $03C0,X		; $03C0 = X;

	1602: F5 91 03  MOV   A,$0391+X	;
	1605: FD        MOV   Y,A		; 

	1606: F5 90 03  MOV   A,$0390+X	;
	1609: DA 2C     MOVW  $2C,YA		; $2C.w = $0390+X.w;

	160B: F5 B0 03  MOV   A,$03B0+X
	160E: 9C        DEC   A
	160F: D5 B0 03  MOV   $03B0+X,A	; ($03B0+X)--; basically

	1612: F0 03     BEQ   $1617		; if($03B0+X == 0) goto $1617;

	1614: 5F C9 16  JMP   $16C9		; else goto $16C9;

; this code gets executed if $03B0+X is zero...?

	1617: 3A 2C     INCW  $2C		; $2C++;

; Jump location $1619

	1619: E5 C0 03  MOV   A,$03C0
	161C: 9F        XCN   A
	161D: 5C        LSR   A
	161E: C5 C2 03  MOV   $03C2,A		; $03C2 = (($03C0 << 4) | ($03C0 >> 4)) >> 1;

	1621: CD 00     MOV   X,#$00
	1623: E7 2C     MOV   A,($2C+X)	; A = ($2C);

	1625: F0 B3     BEQ   $15DA		; if(!A) goto $15DA;

	1627: 30 71     BMI   $169A

	1629: EC C0 03  MOV   Y,$03C0		; Y = $03C0;

	162C: D6 B1 03  MOV   $03B1+Y,A	; $03B1+Y = ($2C)
	162F: 3A 2C     INCW  $2C		; $2C++;

	1631: E7 2C     MOV   A,($2C+X)
	1633: C4 10     MOV   $10,A		; $10 = ($2C)

	1635: 30 63     BMI   $169A		; if($10 < 0) goto $169A;

	1637: 5D        MOV   X,A		
	1638: E5 C1 03  MOV   A,$03C1
	163B: 25 CF 03  AND   A,$03CF		; X = ($2C) 

	163E: F0 2E     BEQ   $166E		; if( !($03C1 & $03CF) ) goto $166E;

	1640: 7D        MOV   A,X		; A = X

	1641: F0 05     BEQ   $1648

	1643: E9 E5 03  MOV   X,$03E5		; X = $03E5

	1646: D0 4E     BNE   $1696

	1648: C4 10     MOV   $10,A
	164A: EC C2 03  MOV   Y,$03C2		; ????

	164D: 3F F7 09  CALL  WriteToDsp(A,Y)

	1650: CD 00     MOV   X,#$00
	1652: 3A 2C     INCW  $2C

	1654: E7 2C     MOV   A,($2C+X)

	1656: 10 0D     BPL   $1665

	1658: 5D        MOV   X,A
	1659: E4 10     MOV   A,$10
	165B: EC C2 03  MOV   Y,$03C2		; ????
	165E: FC        INC   Y

	165F: 3F F7 09  CALL  WriteToDsp(A,Y)

	1662: 7D        MOV   A,X

	1663: 2F 35     BRA   $169A

	1665: EC C2 03  MOV   Y,$03C2		; ????
	1668: FC        INC   Y

	1669: 3F F7 09  CALL  WriteToDsp(A,Y)

	166C: 2F 28     BRA   $1696

$166E:

	166E: 7D        MOV   A,X		; A = X
	166F: E9 C0 03  MOV   X,$03C0		; X = $03C0
	1672: 1C        ASL   A			; A *= 2
	1673: D5 21 03  MOV   $0321+X,A	; $0321+X = A

	1676: E8 0A     MOV   A,#$0A
	1678: D5 51 03  MOV   $0351+X,A	; $0351+X = 0x0A

	167B: E3 20 08  BBS7  $20,$1686

	167E: C3 20 0A  BBS6  $20,$168B

	1681: 8F 0A 11  MOV   $11,#$0A	; Has to do with Pitch settings

	1684: D0 08     BNE   $168E

; don't modify the pitch?

	1686: 8F 10 11  MOV   $11,#$10

	1689: D0 03     BNE   $168E

	168B: 8F 04 11  MOV   $11,#$04	;

	168E: 8F 00 10  MOV   $10,#$00

	1691: 3F 94 0F  CALL  $0F94		;

	1694: CD 00     MOV   X,#$00		
	1696: 3A 2C     INCW  $2C		; get ready to grab the next sfx byte

	1698: E7 2C     MOV   A,($2C+X)	; A = ($2C);

	169A: 68 E0     CMP   A,#$E0

	169C: D0 03     BNE   $16A1		; if(A != 0xE0) goto $16A1

	; side note... this point is reached after many seconds

	169E: 5F 4A 17  JMP   $174A	 	; $3E00 table being used in this routine
	
$16A1:

	16A1: 68 F9     CMP   A,#$F9		; 

	16A3: F0 67     BEQ   $170C

	16A5: 68 F1     CMP   A,#$F1

	16A7: F0 78     BEQ   $1721

	16A9: 68 FF     CMP   A,#$FF

	16AB: D0 06     BNE   $16B3

	16AD: E9 C0 03  MOV   X,$03C0

	16B0: 5F 95 14  JMP   $1495

	16B3: E9 C0 03  MOV   X,$03C0
	16B6: FD        MOV   Y,A

	16B7: 3F 02 09  CALL  $0902		; handle a note

	16BA: E5 C1 03  MOV   A,$03C1		; A = $03C1 ( these is the voices to key on in next subroutine )

	16BD: 3F 90 17  CALL  $1790		; clear KOFF, write to KON with above value

	16C0: E9 C0 03  MOV   X,$03C0		; X = $03C0;

	16C3: F5 B1 03  MOV   A,$03B1+X
	16C6: D5 B0 03  MOV   $03B0+X,A	; $03B0+X = $03B1+X

; jump location $16C9

	16C9: F2 13     CLR7  $13		; unreserve voice 7
	16CB: E9 C0 03  MOV   X,$03C0		; 

	16CE: F4 A0     MOV   A,$A0+X		; A = $A0+X;

	16D0: F0 05     BEQ   $16D7		; if($A0+X == 0) goto $16D7;

	16D2: 3F 76 17  CALL  $1776

	16D5: 2F 0F     BRA   $16E6

; insert label

	16D7: E8 02     MOV   A,#$02
	16D9: 75 B0 03  CMP   A,$03B0+X	; $03B0

	16DC: D0 08     BNE   $16E6

	16DE: E5 C1 03  MOV   A,$03C1		; variable
	16E1: 8D 5C     MOV   Y,#$5C		; KOFF register

	16E3: 3F F7 09  CALL  WriteToDsp(A,Y)

	16E6: E9 C0 03  MOV   X,$03C0

	16E9: E4 2D     MOV   A,$2D
	16EB: D5 91 03  MOV   $0391+X,A

	16EE: E4 2C     MOV   A,$2C		;
	16F0: D5 90 03  MOV   $0390+X,A	; update $0390+X.w (word value) with the current pointer ($2C.w)

	16F3: E5 C1 03  MOV   A,$03C1		;
	16F6: 25 CF 03  AND   A,$03CF		;

	16F9: D0 0B     BNE   $1706		; if($03C1 & $03CF) goto $1706

	16FB: E5 C1 03  MOV   A,$03C1		;
	16FE: 25 CB 03  AND   A,$03CB		;

	1701: D0 06     BNE   $1709		; if($03C1 & $03CB) goto $1709

	1703: 5F 3A 15  JMP   $153A

	1706: 5F 7C 14  JMP   $147C

	1709: 5F DC 14  JMP   $14DC		;

$170C:

	170C: CD 00     MOV   X,#$00
	170E: 3A 2C     INCW  $2C		; X = 0x00; $2C++;

	1710: E7 2C     MOV   A,($2C+X)	; grab the next sfx byte
	1712: E9 C0 03  MOV   X,$03C0		
	1715: D8 44     MOV   $44,X
	1717: FD        MOV   Y,A		; Y = A = ($2C); X = $03C0; $44 = X;

	1718: 3F 02 09  CALL  $0902		; play a "note" of the sound effect, I guess?

	171B: E5 C1 03  MOV   A,$03C1		; A = $03C1

	171E: 3F 90 17  CALL  $1790		;

	1721: CD 00     MOV   X,#$00
	1723: 3A 2C     INCW  $2C		; $2C++; X = 0x00;

	1725: E7 2C     MOV   A,($2C+X)	; 
	1727: E9 C0 03  MOV   X,$03C0		;
	172A: D4 A1     MOV   $A1+X,A		; X = $03C0; $A1+X = ($2C);

	172C: CD 00     MOV   X,#$00		;
	172E: 3A 2C     INCW  $2C		; X = 0x00; $2C++;

	1730: E7 2C     MOV   A,($2C+X)	;
	1732: E9 C0 03  MOV   X,$03C0
	1735: D4 A0     MOV   $A0+X,A		; X = $03C0; $A0+X = A;
	1737: 2D        PUSH  A			; temp = A;

	1738: CD 00     MOV   X,#$00		
	173A: 3A 2C     INCW  $2C		; X = 0x00; $2C++;

	173C: E7 2C     MOV   A,($2C+X)	;
	173E: EE        POP   Y			;
	173F: E9 C0 03  MOV   X,$03C0		;
	1742: D8 44     MOV   $44,X		; A = ($2C+X); Y = temp; X = $03C0; $44 = $03C0;

	1744: 3F AB 0E  CALL  $0EAB		; $0370 (word) = hex fraction of A divided by $A0+X

	1747: 5F C0 16  JMP   $16C0		; goto $16C0;

; this relates to the usage of $3E00 (mystery table)

	174A: CD 00     MOV   X,#$00			
	174C: 3A 2C     INCW  $2C			; X = 0x00; $2C++; 

	174E: E7 2C     MOV   A,($2C+X)		
	1750: 8D 09     MOV   Y,#$09
	1752: CF        MUL   YA			
	1753: 5D        MOV   X,A			; X = 0x09 * ($2C)
	1754: EC C2 03  MOV   Y,$03C2
	1757: 8F 08 12  MOV   $12,#$08

	175A: F5 00 3E  MOV   A,$3E00+X		; Table contains 9 byte chunks of data for each sound effect type.

	175D: 3F F7 09  CALL  WriteToDsp(A,Y)	; 

	1760: 3D        INC   X
	1761: FC        INC   Y

	1762: 6E 12 F5  DBNZ  $12, $175A		; loop 8 times, writing to:
							; L/R volume, Pitch scaler, VxSRCN, VxADSR1, VxADSR2, and VxGAIN
							; using entries from the $3E00+X table

	1765: F5 00 3E  MOV   A,$3E00+X		; the last (9th) value for each instrument is written to $0221+Y
	1768: EC C0 03  MOV   Y,$03C0
	176B: D6 21 02  MOV   $0221+Y,A		; simialar to the musical instruments, this is a pitch multiplier

	176E: E8 00     MOV   A,#$00
	1770: D6 20 02  MOV   $0220+Y,A		; lower byte for the pitch multiplier is always zero for sound effects.

	1773: 5F 17 16  JMP   $1617

; end of the routine?

	1776: E2 13     SET7  $13			; indicate that... uh... the channel is reserved?
	1778: E8 60     MOV   A,#$60			
	177A: 8D 03     MOV   Y,#$03			; A = 0x60; Y = 0x03
	177C: 9B A0     DEC   $A0+X			; decrement the sfx timer?

	177E: 3F D5 0F  CALL  $0FD5			; perform pitch slide for this frame

	1781: F5 61 03  MOV   A,$0361+X
	1784: FD        MOV   Y,A			; Y = $0361+X

	1785: F5 60 03  MOV   A,$0360+X		
	1788: DA 10     MOVW  $10,YA			; $10.w = $0360+X
	178A: 8F 00 47  MOV   $47,#$00		; $47 = 0x00;

	178D: 5F 6C 09  JMP   $096C			; me thinks $10 is pitch input

; Subroutine 1790

	1790: 2D        PUSH  A
	1791: 8D 5C     MOV   Y,#$5C			; writing to the KOFF [key off] register
	1793: E8 00     MOV   A,#$00			; enables all voices
	1795: 3F F7 09  CALL  WriteToDsp(A,Y)

	1798: AE        POP   A				; the argument byte (from the caller)
	1799: 8D 4C     MOV   Y,#$4C			; writing to KON [key on]

	179B: 5F F7 09  JMP   WriteToDsp(A,Y)

; $179E to $17BF is null data, not used 
; actual used data will be placed at $17C0, which is all the sound effects data

