;-------------------------------------------------------------------------------
; GoatTracker V1.4f gamemusic playroutine.
;
; NOTE: This playroutine source code does not fall under the GPL license!
; Use it freely for any purpose, commercial or noncommercial.
;
; You'll have to supply the address of the musicdata yourself, and call
; RELOCATEMUSIC every time a new music module has been loaded to that address.
;
; You also have to create the sound effect tables yourself, see example2.s for
; details. Remember that higher sound effect numbers have higher priority.
;
; It's recommended to place the playroutine at a page start. That's because the
; effect code contains selfmodifying jumps that only modify the low-byte.
; There's a conditional DASM define to catch a page-cross error, though.
;-------------------------------------------------------------------------------

                processor 6502

          ;Address of music data
;mt_musicdata    =

          ;4 consecutive zeropage addresses required
;mt_zpbase       =

          ;Memory defines

mt_instad       = mt_musicdata-2           ;These are known
mt_instsr       = mt_musicdata-1
mt_instpulse    = mt_musicdata
mt_instpulsespd = mt_musicdata+1
mt_instpulselow = mt_musicdata+2
mt_instpulsehigh = mt_musicdata+3
mt_instfilter   = mt_musicdata+4
mt_instwave     = mt_musicdata+5

mt_wavetbl      = mt_musicdata+6           ;These are yet unknown
mt_notetbl      = mt_musicdata+6
mt_songtbllo    = mt_musicdata+6
mt_songtblhi    = mt_musicdata+6
mt_patttbllo    = mt_musicdata+6
mt_patttblhi    = mt_musicdata+6
mt_filttbl      = mt_musicdata+6

        ; Constants for musicdata relocation

REL_ADDONE      = 0
REL_INSTRSIZE   = 1
REL_WAVESIZE    = 2
REL_SONGSIZE    = 3
REL_PATTSIZE    = 4
REL_SUBONE      = $80
REL_END         = $ff

        ; Special note values

KEYOFF          = $5e           ;Keyoff clears the gatebit
REST            = $5f
NOCMD           = $60           ;Instrument & command byte do not exist
FIRSTPACKEDREST = $c0
PACKEDREST      = $00
ENDPATT         = $ff

        ; Instrument numbers in patterndata

INST1           = $08

        ; Orderlist commands

REPEAT          = $d0
TRANSDOWN       = $e0
TRANSUP         = $f0
LOOPSONG        = $ff

;-------------------------------------------------------------------------------
; MUSIC
;
; Plays one frame of music + sound effects. Do not call this if music is being
; loaded or if RELOCATEMUSIC hasn't been called yet after loading new music
; data!
;-------------------------------------------------------------------------------

music:          ldx #$00
mt_chnloop:     lda #$00
                bmi mt_noinit
                sta mt_chnsongnum,x
                inc mt_chnloop+1
                lda #$00
                sta mt_chnrepeat,x
                sta mt_chntrans,x
                sta mt_chnsongptr,x
                sta mt_chnpackrest,x
                sta mt_chnwave,x
                sta mt_chnwavetbl,x
                lda #$ff
                sta mt_chnnewnote,x
                sta mt_chnpattptr,x
                lda #$05
                sta mt_chntick,x
                sta mt_chntempo,x
                txa
                bne mt_nofiltinit
                sta $d415                       ;Reset cutoff lowbyte
                jsr mt_setfiltersub             ;Set filter 0
mt_nofiltinit:  jmp mt_nextchn
mt_noinit:      ldy mt_chntick,x
                bne mt_nonewnotes
                jmp mt_newnotes
mt_nonewnotes:  bpl mt_noreload
mt_inittick:    ldy mt_chntempo,x
                cpy #$02
                bcs mt_noreload
                tya
                eor #$01
                sta mt_chntempo,x
                lda mt_musicdata+4,y
                tay
mt_noreload:    dey
                tya
                sta mt_chntick,x
                lda mt_chnpattptr,x             ;Check for pattern end
                cmp #ENDPATT
                bcc mt_effects
mt_nextpatt:    ldy mt_chnsongnum,x
mt_songtblloaccess:
                lda mt_songtbllo,y
                sta mt_zpbase
mt_songtblhiaccess:
                lda mt_songtblhi,y
                sta mt_zpbase+1
                ldy mt_chnsongptr,x
mt_nextpattloop:lda (mt_zpbase),y
                iny
                cmp #REPEAT
                bcc mt_noloopsong
                cmp #TRANSDOWN
                bcc mt_repeat
                cmp #LOOPSONG
                bcc mt_trans
mt_loopsong:    lda (mt_zpbase),y
                tay
                bcs mt_nextpattloop
mt_repeat:      sbc #REPEAT-1
                sta mt_chnrepeat,x
                jmp mt_nextpattloop
mt_trans:       sbc #TRANSUP-1
                sta mt_chntrans,x
                jmp mt_nextpattloop
mt_noloopsong:  sta mt_chnpattnum,x
                lda mt_chnrepeat,x
                beq mt_norepeat
                dec mt_chnrepeat,x
                dey
mt_norepeat:    tya
                sta mt_chnsongptr,x
                inc mt_chnpattptr,x
                lda mt_chnnewnote,x
                bpl mt_effects2
                jmp mt_cmddowavearp2

mt_effects:     lda mt_chnnewnote,x
                bmi mt_pulsemod
mt_effects2:    ldy mt_chninstnum,x
                dec mt_chnnewnote,x
                bpl mt_newnoteinit
                lda mt_instad,y                   ;Load ADSR
                sta mt_chnad,x
                lda mt_instsr,y
                ldy mt_chncommand,x
                cpy #$06
                bne mt_defaultsr
                lda mt_chncmddata,x
mt_defaultsr:   sta mt_chnsr,x
                jmp mt_pulseok                    ;Start note now

mt_newnoteinit: lda #$00
                sta mt_chnarpcount,x
                lda mt_instpulse,y
                beq mt_skippulse
                pha
                and #$f0
                sta mt_chnpulsedir,x
                pla
                and #$0f
                sta mt_chnpulse,x
mt_skippulse:   lda mt_instwave,y
                sta mt_chnwavetbl,x
                lda mt_instfilter,y
                beq mt_nofilterchange
                jsr mt_setfiltersub
mt_nofilterchange:
                jmp mt_nextchn

mt_pulsemod:    ldy mt_chninstnum,x
                lda mt_instpulsespd,y
                and #$fe
                beq mt_pulseok
                sta mt_zpbase
                lda mt_chnpulsedir,x
                lsr
                bcs mt_pulsesub
mt_pulseadd:    asl
                adc mt_zpbase
                pha
                lda mt_chnpulse,x
                adc #$00
                sta mt_chnpulse,x
                cmp mt_instpulsehigh,y
                jmp mt_pulsedone
mt_pulsesub:    asl
                sec
                sbc mt_zpbase
                pha
                lda mt_chnpulse,x
                sbc #$00
                sta mt_chnpulse,x
                cmp mt_instpulselow,y
mt_pulsedone:   pla
                adc #$00
                sta mt_chnpulsedir,x
mt_pulseok:     ldy mt_chnwavetbl,x
                bne mt_dowavetbl
                ldy mt_chncommand,x             ;Do only continuous effects
                beq mt_arpeggio                 ;Arpeggio is most common so
                lda #$00                        ;optimize for it
                sta mt_zpbase+1                 ;Clear speed highbyte
                lda mt_contcmdtbllo-1,y
                sta mt_contjump+1
                lda mt_chncmddata,x
mt_contjump:    jmp mt_portaup

mt_dowavetbl:   jsr mt_dowavesub
                jmp mt_nextchn

mt_arpeggio:    lda mt_chncmddata,x
                beq mt_nextchn
                asl
                lda mt_chnarpcount,x
                pha
                adc #$01
                cmp #$06
                bcc mt_arpnotover
                lda #$00
mt_arpnotover:  sta mt_chnarpcount,x
                pla
                lsr
                cmp #$01
                bcc mt_arp1
                bne mt_arp0
mt_arp2:        lda mt_chncmddata,x
                and #$0f
                bpl mt_arpfreq2
mt_arp0:        lda #$00
                bpl mt_arpfreq2
mt_arp1:        lda mt_chncmddata,x
                and #$70
                lsr
                lsr
                lsr
                lsr
mt_arpfreq2:    clc
                adc mt_chnnote,x
                tay
mt_arpfreq:     lda mt_freqtbllo,y
                sta mt_chnfreqlo,x
                lda mt_freqtblhi,y
                sta mt_chnfreqhi,x

mt_nextchn:     lda mt_chnsfx,x
                bne mt_dosfx
                lda mt_chnfreqlo,x
                sta $d400,x
                lda mt_chnfreqhi,x
                sta $d401,x
                lda mt_chnwave,x
                sta $d404,x
                lda mt_chnad,x
                sta $d405,x
                lda mt_chnsr,x
                sta $d406,x
mt_noadsr:      lda mt_chnpulsedir,x
                sta $d402,x
                lda mt_chnpulse,x
mt_loadpulse2:  sta $d403,x
mt_noloadregs:  lda mt_chnnext,x
                beq mt_alldone
                tax
                jmp mt_chnloop
mt_alldone:     lda #$ff
                sta mt_chnloop+1

mt_filtstep:    lda #$00
                beq mt_filtskip
mt_filttime:    ldy #$00
                bne mt_filtmod
                jsr mt_setfiltersub
                jmp mt_filtskip
mt_filtmod:     dec mt_filttime+1
mt_filtcutoff:  lda #$00
                sec
mt_filtcutoffadd:sbc #$00
                sta mt_filtcutoff+1
                sta $d416
mt_filtskip:
mt_d418reg:     lda #$00
                and #$ff
                sta $d418
                rts


        ;Sound FX code

mt_dosfx:       ldy mt_chnsfxnum,x
                lda mt_sfxtbllo,y
                sta mt_zpbase
                lda mt_sfxtblhi,y
                sta mt_zpbase+1
                ldy mt_chnsfx,x
                cpy #$03
                bcs mt_dosfx_initdone
                inc mt_chnsfx,x
mt_dosfx_hardrestart:
                lda #$00
                sta $d404,x
                sta $d405,x
                sta $d406,x
                sta mt_chnsfxdelay,x
                sta mt_chnwave,x
                sta mt_chnwavetbl,x
                beq mt_noloadregs

mt_dosfx_initdone:
                lda mt_chnsfxdelay,x          ;Sound effect delay?
                beq mt_dosfx_nodelay
                iny
                adc #$00                      ;Carry is 1 here
mt_dosfx_setdelay:
                sta mt_chnsfxdelay,x
                bne mt_noloadregs
mt_dosfx_nodelay:
                sty mt_zpbase+2
                lda (mt_zpbase),y
                bne mt_dosfx_noend
mt_dosfx_end:   sta mt_chnsfx,x
                beq mt_dosfx_hardrestart
mt_dosfx_noend: cmp #$e0                      ;Set delay?
                bcs mt_dosfx_setdelay
                and #$7f
                tay
                lda mt_freqtbllo,y            ;Get frequency
                sta $d400,x
                lda mt_freqtblhi,y
                sta $d401,x
                ldy mt_zpbase+2
                iny
                lda (mt_zpbase),y              ;Then take a look at the coming
                beq mt_dosfx_nowavechange     ;byte
                cmp #$82                      ;Is it a waveform or a note?
                bcs mt_dosfx_nowavechange
                sta $d404,x
                iny
mt_dosfx_nowavechange:
                tya
                sta mt_chnsfx,x               ;Store changed index
                ldy #$00
                lda (mt_zpbase),y              ;Load ADSR
                sta $d405,x
                iny
                lda (mt_zpbase),y
                sta $d406,x
                iny
                lda (mt_zpbase),y              ;Load pulse
                sta $d402,x
                jmp mt_loadpulse2

mt_newpackedrest:
                inc mt_chnpattptr,x
                sta mt_chnpackrest,x
                bne mt_packedrestcommon
mt_newnotes:    dec mt_chntick,x
                lda mt_chnpackrest,x
                beq mt_nopackedrest
mt_packedrestcommon:
                inc mt_chnpackrest,x
                jmp mt_rest
mt_nopackedrest:ldy mt_chnpattnum,x
mt_patttblloaccess:
                lda mt_patttbllo,y
                sta mt_zpbase
mt_patttblhiaccess:
                lda mt_patttblhi,y
                sta mt_zpbase+1
                ldy mt_chnpattptr,x
                lda (mt_zpbase),y
                iny
                cmp #NOCMD                      ;Do command+databytes exist?
                bcc mt_cmd
                cmp #FIRSTPACKEDREST
                bcs mt_newpackedrest
                sbc #NOCMD-1
                sta mt_zpbase+2
                bcs mt_nocmd
mt_cmd:         sta mt_zpbase+2
                lda (mt_zpbase),y
                and #$f8
                beq mt_skipinst                 ;Instrument number 0 lets
                sta mt_chninstnum,x             ;the instrument stay the same
mt_skipinst:    lda (mt_zpbase),y
                and #$07
                sta mt_chncommand,x
                iny
                lda (mt_zpbase),y
                sta mt_chncmddata,x
                iny
mt_nocmd:       lda (mt_zpbase),y
                cmp #ENDPATT
                beq mt_endpatt
                tya
mt_endpatt:     sta mt_chnpattptr,x
                ldy mt_chncommand,x
                lda mt_zpbase+2
                cmp #KEYOFF                   ;Keyoff or rest?
                beq mt_keyoff
                bcs mt_rest
mt_normalnote:  adc mt_chntrans,x
                sta mt_setnote+1
                cpy #$03                      ;Or toneportamento?
                beq mt_setnote
                ldy mt_chninstnum,x
                lda mt_instpulsespd,y         ;Pulsespd bit 0: hardrestart
                lsr                           ;flag
                lda #$01
                sta mt_chnnewnote,x
                bcs mt_nohardrestart
                lda #$00
                sta mt_chnad,x
                sta mt_chnsr,x
mt_nohardrestart:
                ldy mt_chnwavetbl,x
                beq mt_keyoff2
                jsr mt_dowavesub              ;Exec wavetable also here
mt_keyoff2:	clc
mt_keyoff:      lda mt_chnwave,x              ;Keyoff: reset gatebit
                and #$fe
                sta mt_chnwave,x
                bcs mt_rest
mt_setnote:	lda #$00
                sta mt_chnnote,x
mt_rest:        ldy mt_chncommand,x
                lda mt_tick0cmdtbllo,y
                sta mt_tick0jump+1
                lda mt_chncmddata,x
mt_tick0jump:   jmp mt_setfilter

mt_freqadd:     lda mt_chnfreqlo,x
                adc mt_zpbase
                sta mt_chnfreqlo,x
                lda mt_chnfreqhi,x
                adc mt_zpbase+1
                sta mt_chnfreqhi,x
                rts

mt_freqsub:     lda mt_chnfreqlo,x
                sbc mt_zpbase
                sta mt_chnfreqlo,x
                lda mt_chnfreqhi,x
                sbc mt_zpbase+1
                sta mt_chnfreqhi,x
                rts

mt_cmpfreq:     lda mt_chnfreqhi,x
                cmp mt_freqtblhi,y
                bne mt_cmpfreqdone
                lda mt_chnfreqlo,x
                cmp mt_freqtbllo,y
mt_cmpfreqdone: rts

mt_makespeed:   asl
                rol mt_zpbase+1
                asl
                rol mt_zpbase+1
                sta mt_zpbase
                rts

        ;Effects. All entrypoints must reside on the same page!

mt_cmddonothing:jmp mt_nextchn

mt_cmddowavearp:lda mt_chnnewnote,x
                bpl mt_cmddonothing
mt_cmddowavearp2:
                ldy mt_chnwavetbl,x
                beq mt_cdwa_nowave
                jmp mt_dowavetbl
mt_cdwa_nowave: ldy mt_chncommand,x
                bne mt_cmddonothing
                jmp mt_arpeggio

mt_starttoneportamento:
                lda #$00
                sta mt_chnarpcount,x
                beq mt_cmddowavearp

mt_setfilter:   jsr mt_setfiltersub
                jmp mt_cmddowavearp

mt_setsustain:  ldy mt_chnnewnote,x
                bpl mt_cmddonothing
                sta mt_chnsr,x
                jmp mt_cmddowavearp2

mt_settempo:    bmi mt_settempoone
                sta mt_chntempo
                sta mt_chntempo+7
                sta mt_chntempo+14
                bpl mt_cmddowavearp
mt_settempoone: and #$7f
                sta mt_chntempo,x
                bpl mt_cmddowavearp

mt_portaup:     jsr mt_makespeed
                clc
mt_dofreqadd:   jsr mt_freqadd
                jmp mt_nextchn
mt_portadown:   jsr mt_makespeed
                sec
mt_dofreqsub:   jsr mt_freqsub
                jmp mt_nextchn

mt_vibrato:     sta mt_zpbase
                and #$0f
                sta mt_zpbase+2
                lda mt_chnarpcount,x
                bmi mt_novibdir
                cmp mt_zpbase+2
                bcc mt_novibdir2
                beq mt_novibdir
                eor #$ff
mt_novibdir:    clc
mt_novibdir2:   adc #$02
mt_vibdone:     sta mt_chnarpcount,x
                lsr
                bcc mt_dofreqadd
                bcs mt_dofreqsub

mt_toneportamento:
                ldy mt_chnnote,x
                pha
                jsr mt_makespeed
                pla
                beq mt_tpfound
                jsr mt_cmpfreq
                beq mt_tpalldone
                bcs mt_tpdown
mt_tpup:        jsr mt_freqadd
                jsr mt_cmpfreq
                bcs mt_tpfound
mt_tpalldone:
mt_tpnotyet:    jmp mt_nextchn
mt_tpdown:      jsr mt_freqsub
                jsr mt_cmpfreq
                bcs mt_tpnotyet
mt_tpfound:     jmp mt_arpfreq

mt_setfiltersub:tay
mt_filttblaccess:
                lda mt_filttbl,y
                beq mt_sfsmod
                sta $d417
mt_filttblaccess2:
                lda mt_filttbl+1,y
                sta mt_d418reg+1
mt_filttblaccess3:
                lda mt_filttbl+2,y
                beq mt_sfscutoffskip
                sta mt_filtcutoff+1
                sta $d416
mt_sfscutoffskip:
                lda #$00
                beq mt_sfscommon
mt_filttblaccess3b:
mt_sfsmod:      lda mt_filttbl+2,y
                sta mt_filtcutoffadd+1
mt_filttblaccess2b:
                lda mt_filttbl+1,y
mt_sfscommon:   sta mt_filttime+1
mt_filttblaccess4:
                lda mt_filttbl+3,y
                sta mt_filtstep+1
                rts

mt_dowavesub:
mt_wavetblaccess:
                lda mt_wavetbl,y
                beq mt_skipwave
                sta mt_chnwave,x
mt_skipwave:
mt_notetblaccess:
                lda mt_notetbl,y
                bmi mt_wavetblabs
                clc
                adc mt_chnnote,x
mt_wavetblabs:  and #$7f
                sta mt_zpbase
mt_wavetblplusaccess:
                lda mt_wavetbl+1,y
                cmp #$ff
                bcc mt_nowaveend
mt_notetblplusaccess:
                lda mt_notetbl+1,y
                beq mt_nowaveloop
                ldy mt_chninstnum,x
                adc mt_instwave,y             ;Carry is cleared
                adc #$fe
                bne mt_nowaveloop
mt_nowaveend:   iny
                tya
mt_nowaveloop:  sta mt_chnwavetbl,x
                ldy mt_zpbase
                lda mt_freqtbllo,y
                sta mt_chnfreqlo,x
                lda mt_freqtblhi,y
                sta mt_chnfreqhi,x
                rts



                if (mt_cmddonothing & $ff00)!=(mt_toneportamento & $ff00)
                err
                endif

;-------------------------------------------------------------------------------
; PLAYTUNE
;
; Initializes a tune specified by A (0 = first subtune).
;-------------------------------------------------------------------------------

playtune:       sta init_adc+1
                asl
init_adc:       adc #$00
                sta mt_chnloop+1
                rts

;-------------------------------------------------------------------------------
; PLAYSFX
;
; Plays a sound effect indicated by A (0 = first sound effect). X is the
; channel number (0-2). Modifies X & Y!
;-------------------------------------------------------------------------------

playsfx:        ldy mt_sfxchntbl,x              ;Convert to SID reg. index
                ldx mt_chnsfx,y                 ;Channel already playing an
                beq psfx_chnok                  ;effect?
                cmp mt_chnsfxnum,y              ;Then, must check priority
                bcc psfx_done
psfx_chnok:     sta mt_chnsfxnum,y
                lda #$01
                sta mt_chnsfx,y
psfx_done:      rts

;-------------------------------------------------------------------------------
; RELOCATEMUSIC
;
; Modifies playroutine addresses to reflect the current song(s) loaded. This
; uses the same zeropage addresses as MUSIC (the playroutine itself), so don't
; call it while this is running!
;-------------------------------------------------------------------------------

relocatemusic:  lda #<(mt_musicdata+4)
                sta mt_zpbase
                lda #>(mt_musicdata+4)
                sta mt_zpbase+1
                ldx #$00
rel_loop:       lda reladrtbllo,x
                sta mt_zpbase+2
                lda reladrtblhi,x
                sta mt_zpbase+3
                clc
                ldy reladdtbl,x
                bmi rel_subone
                bne rel_noaddone
rel_addone:     lda #$01
                bne rel_ok
rel_noaddone:   lda mt_musicdata-1,y
rel_ok:         adc mt_zpbase
                sta mt_zpbase
                ldy #$00
                sta (mt_zpbase+2),y
                lda mt_zpbase+1
                adc #$00
                sta mt_zpbase+1
rel_storecommon:iny
                sta (mt_zpbase+2),y
                inx
                bne rel_loop
rel_subone:     cpy #REL_END
                beq rel_done
                ldy #$00
                lda mt_zpbase
                sbc #$00                        ;Carry = 0
                sta (mt_zpbase+2),y
                lda mt_zpbase+1
                sbc #$00
                bne rel_storecommon
rel_done:       rts

mt_tick0cmdtbllo:dc.b <mt_cmddowavearp
                dc.b <mt_cmddowavearp
                dc.b <mt_cmddowavearp
                dc.b <mt_starttoneportamento
                dc.b <mt_cmddowavearp
                dc.b <mt_setfilter
                dc.b <mt_setsustain
                dc.b <mt_settempo

mt_contcmdtbllo:dc.b <mt_portaup
                dc.b <mt_portadown
                dc.b <mt_toneportamento
                dc.b <mt_vibrato
                dc.b <mt_cmddonothing
                dc.b <mt_cmddonothing
                dc.b <mt_cmddonothing

mt_chnnote:     dc.b 0
mt_chnfreqlo:   dc.b 0
mt_chnfreqhi:   dc.b 0
mt_chnnewnote:  dc.b 0
mt_chncommand:  dc.b 0
mt_chncmddata:  dc.b 0
mt_chninstnum:  dc.b INST1

                dc.b 0,0,0,0,0,0,INST1
                dc.b 0,0,0,0,0,0,INST1

mt_chnwave:     dc.b 0
mt_chnwavetbl:  dc.b 0
mt_chnpulse:    dc.b 0
mt_chnpulsedir: dc.b 0
mt_chnarpcount: dc.b 0
mt_chnpackrest: dc.b 0
mt_chnrepeat:   dc.b 0

                dc.b 0,0,0,0,0,0,0
                dc.b 0,0,0,0,0,0,0

mt_chnsongptr:  dc.b 0
mt_chnsongnum:  dc.b 0
mt_chnpattptr:  dc.b 0
mt_chnpattnum:  dc.b 0
mt_chntick:     dc.b 0
mt_chntempo:    dc.b 0
mt_chntrans:    dc.b 0

                dc.b 0,0,0,0,0,0,0
                dc.b 0,0,0,0,0,0,0

mt_chnad:       dc.b 0
mt_chnsr:       dc.b 0
mt_chnsfx:      dc.b 0
mt_chnsfxnum:   dc.b 0
mt_chnsfxdelay: dc.b 0
mt_chnunused:   dc.b 0
mt_chnnext:     dc.b 7

                dc.b 0,0,0,0,0,0,14
                dc.b 0,0,0,0,0,0

mt_sfxchntbl:   dc.b 0,7,14

mt_freqtblhi:   dc.b $01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$02
                dc.b $02,$02,$02,$02,$02,$02,$03,$03,$03,$03,$03,$04
                dc.b $04,$04,$04,$05,$05,$05,$06,$06,$06,$07,$07,$08
                dc.b $08,$09,$09,$0a,$0a,$0b,$0c,$0c,$0d,$0e,$0f,$10
                dc.b $11,$12,$13,$14,$15,$17,$18,$19,$1b,$1d,$1e,$20
                dc.b $22,$24,$26,$29,$2b,$2e,$30,$33,$36,$3a,$3d,$41
                dc.b $45,$49,$4d,$52,$57,$5c,$61,$67,$6d,$74,$7b,$82
                dc.b $8a,$92,$9b,$a4,$ae,$b8,$c3,$cf,$db,$e8,$f6,$ff

mt_freqtbllo:   dc.b $15,$25,$36,$49,$5c,$71,$87,$9f,$b7,$d1,$ed,$0a
                dc.b $2a,$4a,$6d,$92,$b9,$e3,$0f,$3e,$6f,$a3,$db,$15
                dc.b $54,$95,$db,$25,$73,$c7,$1e,$7c,$de,$47,$b6,$2b
                dc.b $a8,$2b,$b7,$4b,$e7,$8e,$3d,$f8,$bd,$8e,$6c,$57
                dc.b $50,$57,$6e,$96,$cf,$1c,$7b,$f0,$7b,$1d,$d8,$ae
                dc.b $a0,$af,$dd,$2d,$9f,$38,$f7,$e0,$f6,$3b,$b1,$5d
                dc.b $40,$5e,$bb,$5a,$3f,$70,$ef,$c1,$ed,$76,$63,$ba
                dc.b $80,$bc,$76,$b4,$7f,$e0,$de,$83,$da,$ed,$c7,$ff

reladrtbllo:    dc.b <(mt_wavetblplusaccess+1)
                dc.b <(mt_wavetblaccess+1)
                dc.b <(mt_notetblplusaccess+1)
                dc.b <(mt_notetblaccess+1)
                dc.b <(mt_songtblloaccess+1)
                dc.b <(mt_songtblhiaccess+1)
                dc.b <(mt_patttblloaccess+1)
                dc.b <(mt_patttblhiaccess+1)
                dc.b <(mt_filttblaccess+1)
                dc.b <(mt_filttblaccess2+1)
                dc.b <(mt_filttblaccess3+1)
                dc.b <(mt_filttblaccess2b+1)
                dc.b <(mt_filttblaccess4+1)
                dc.b <(mt_filttblaccess3b+1)

reladrtblhi:    dc.b >(mt_wavetblplusaccess+1)
                dc.b >(mt_wavetblaccess+1)
                dc.b >(mt_notetblplusaccess+1)
                dc.b >(mt_notetblaccess+1)
                dc.b >(mt_songtblloaccess+1)
                dc.b >(mt_songtblhiaccess+1)
                dc.b >(mt_patttblloaccess+1)
                dc.b >(mt_patttblhiaccess+1)
                dc.b >(mt_filttblaccess+1)
                dc.b >(mt_filttblaccess2+1)
                dc.b >(mt_filttblaccess3+1)
                dc.b >(mt_filttblaccess2b+1)
                dc.b >(mt_filttblaccess4+1)
                dc.b >(mt_filttblaccess3b+1)

reladdtbl:      dc.b REL_INSTRSIZE
                dc.b REL_SUBONE
                dc.b REL_WAVESIZE
                dc.b REL_SUBONE
                dc.b REL_WAVESIZE
                dc.b REL_SONGSIZE
                dc.b REL_SONGSIZE
                dc.b REL_PATTSIZE
                dc.b REL_PATTSIZE
                dc.b REL_ADDONE
                dc.b REL_ADDONE
                dc.b REL_SUBONE
                dc.b REL_ADDONE
                dc.b REL_SUBONE
                dc.b REL_END

