*****************************
* NinjaTracker+ Player
*
* by Jesse Blue
*
* thanks to:
* Huibert Aalbers, Olivier Goguel, Jon Christopher Co, John Valdezco, John Brooks
* Brutal Deluxe, Digarok, Saga Musix, yzi, djh0ffman
*
*****************************

                        dsk ntpplayer.bin
                        org $0f0000
                        mx  %00


; all calls to the player must be JSLs with 16 bit registers
; copy this into your program in order to call the player:

NinjaTrackerPlus        ent
NTPprepare              =   NinjaTrackerPlus
NTPplay                 =   NinjaTrackerPlus+3
NTPstop                 =   NinjaTrackerPlus+6
NTPgetvuptr             =   NinjaTrackerPlus+9
NTPgete8ptr             =   NinjaTrackerPlus+12
NTPforcesongpos         =   NinjaTrackerPlus+15



; prepare
; Prepares music, copies all instruments into sound ram and inits the sound interrupt.
; input:  call with X=address low, Y=address high of pointer to the ntp file in memory
; output: X=address low, Y=address high of pointer to instruments (main program can reuse memory from here)
;         when carry bit is set, an error occurred. Either the player did not find a NTP module at the given location
;         or the version of the NTP module is not supported.
                        jmp prepare

; play
; Starts previously prepared music.
; input:  call with A=0 loop song, else play song only once
; output: -
                        jmp play

; stop
; Stops a currently playing music, turns off all oscillators used by the player and restores the sound interrupt.
; input:  -
; outout: -
                        jmp stop

; getvuptr
; Returns a pointer to vu data (1 word number of tracks, then one word for every track with its volume).
; input:  -
; output: X=address low, Y=address high of pointer
                        jmp getvuptr

; gete8ptr
; Returns a pointer to where the player stores information about the last 8xx command found. Can be used for timing purposes.
; input:  -
; output: X=address low, Y=address high of pointer
                        jmp gete8ptr

; forcesongpos
; Forces the player to jump to a certain pattern (like command B).
; input:  A=songpos
; output: carry bit is set when the song position does not exist (error)
                        jmp forcesongpos


*-------------------------------

; to stay out of the way, do not use the direct page at all
; use DP only for faster access to sound registers
; the assembled code should not be bank relative (meaning: not compiled to a fixed bank)

sound_control           =   $3c                     ;really at $e1c03c
sound_data              =   $3d                     ;really at $e1c03d
sound_address           =   $3e                     ;really at $e1c03e

sound_interrupt_ptr     =   $e1002c
irq_volume              =   $e100ca

max_tracks_available    =   15                      ;the GS has 32 voices = 16 tracks, 1 used for interrupt, so 15 left

max_pattern_line        =   64                      ;there are 64 lines in a pattern

;-------------------------- helper functions

read_head               ldal 0,x
                        rts

read_pattern            ldal 0,x
                        rts

read_instrument         ldal 0,x
                        rts

;-----------------------------------------------------------------------------------------
; prepare
;-----------------------------------------------------------------------------------------

prepare                 =     *
                        sei
                        phb
                        phd
                        phk
                        plb

                        clc
                        xce
                        rep #$30
                        mx  %00

                        lda #$c000
                        tcd

                        jsr clear_memory

                        stx ptr_header
                        sty ptr_header+2

                        jsr check_header
                        bcs prepare_1

                        jsr extract_header_info
                        jsr copy_instruments_to_doc
                        jsr setup_music
                        jsr setup_interrupt
                        jsr setup_master_volume

                        ldx ptr_instruments
                        ldy ptr_instruments+2

                        pld
                        plb
                        cli
                        clc
                        rtl

prepare_1               pld
                        plb
                        cli
                        sec
                        rtl

;--------------------------

clear_memory            = *
                        phx
                        ldx #zero_out_end-zero_out_begin-2
]loop                   stz zero_out_begin,x
                        dex
                        dex
                        bpl ]loop
                        plx
                        rts 

;--------------------------

header_str              asc 'nfc!'

check_header            = *
; patch ptr into header
                        lda ptr_header
                        sta read_head+1
                        lda ptr_header+1
                        sta read_head+2

; check header string
                        ldx #0
                        jsr read_head
                        cmp header_str
                        bne check_header_1

                        inx
                        inx
                        jsr read_head
                        cmp header_str+2
                        bne check_header_1
         
; check version
                        inx
                        inx
                        jsr read_head
                        and #$ff
                        bne check_header_1

                        clc
                        rts

check_header_1          sec
                        rts

;--------------------------

extract_header_info     = *

; get basic settings
                        ldx #5
                        jsr read_head
                        inx
                        inx
                        pha
                        and #$ff
                        sta number_of_tracks
                        sta vu_number_of_tracks
                        asl
                        sta number_of_tracks2
                        asl
                        sta number_of_tracks4
                        pla
                        xba
                        and #$ff
                        sta number_of_instruments
                        asl
                        sta number_of_instruments2

                        jsr read_head
                        inx
                        and #$ff
                        sta number_of_patterns

                        jsr read_head
                        inx
                        and #$ff
                        sta pattern_order_length

; get which track uses which output channel
                        ldy #0
]loop                   jsr read_head
                        inx
                        and #%111
                        asl
                        asl
                        asl
                        asl
                        sta track_channels,y
                        iny
                        iny
                        cpy number_of_tracks2
                        blt ]loop

; get instrument data
                        ldy #0

]loop                   jsr read_head
                        inx
                        and #$ff
                        sta instrument_types,y

                        jsr read_head
                        inx
                        inx
                        sta instrument_lengths,y

                        jsr read_head
                        inx
                        and #$ff
                        sta instrument_volumes,y

                        jsr read_head
                        inx
                        and #$f
                        asl
                        phy
                        tay
                        lda note_freq_ptrs_offset,y
                        ply
                        sta instrument_finetune,y

                        jsr read_head
                        inx
                        and #$ff
                        sta instrument_osc_a_ptr,y
                        sta instrument_osc_b_ptr,y

                        jsr read_head
                        inx
                        and #$ff
                        sta instrument_osc_a_siz,y
                        sta instrument_osc_b_siz,y

                        iny
                        iny
                        cpy number_of_instruments2
                        blt ]loop

                        jsr generate_osc_settings

; get pattern order
                        ldy #0
]loop                   jsr read_head
                        inx
                        and #$ff
                        sta pattern_order,y
                        iny
                        cpy pattern_order_length
                        blt ]loop

; calc pointer to notes
                        txa
                        clc
                        adc ptr_header
                        sta ptr_notes
                        lda ptr_header+2
                        adc #0
                        sta ptr_notes+2

; patch note ptr
                        lda ptr_notes
                        sta read_pattern+1
                        lda ptr_notes+1
                        sta read_pattern+2

; calculate pattern length (= number of tracks x 4 x 64)
                        lda number_of_tracks
                        xba
                        sta pattern_length

; calculate pattern pointers
                        phx
                        lda ptr_notes
                        sta pattern_pointers
                        lda ptr_notes+2
                        sta pattern_pointers+2
                        ldy #0
                        ldx #1
]loop                   lda pattern_pointers,y
                        clc
                        adc pattern_length
                        sta pattern_pointers+4,y
                        lda pattern_pointers+2,y
                        adc #0
                        sta pattern_pointers+6,y
                        iny
                        iny
                        iny
                        iny
                        inx
                        cpx number_of_patterns
                        blt ]loop
                        plx

; get ptr to instruments: it's the last calculated pattern pointer plus one pattern length
                        lda pattern_pointers,y
                        clc
                        adc pattern_length
                        sta ptr_instruments
                        lda pattern_pointers+2,y
                        adc #0
                        sta ptr_instruments+2

; patch instrument ptr
                        lda ptr_instruments
                        sta read_instrument+1
                        lda ptr_instruments+1
                        sta read_instrument+2

                        rts

;--------------------------

generate_osc_opti       dw 0
generate_osc_opti_next  dw 0

generate_osc_settings   = *                             ;from instruments, generate control bytes for osc A and B

                        phx
                        ldy #0

]loop                   lda instrument_types+2,y        ;see if the next instrument has an optimal length
                        and #%100
                        sta generate_osc_opti_next
                        
                        lda instrument_types,y
                        asl
                        tax

                        jsr (generate_osc_sett_tbl,x)

                        iny
                        iny
                        cpy number_of_instruments2
                        blt ]loop

                        plx
                        rts

generate_osc_sett_tbl   dw  generate_osc_0,generate_osc_1a,generate_osc_2,generate_osc_3 ;normal samples
                        dw  generate_osc_0,generate_osc_1b,generate_osc_2,generate_osc_3 ;sample has an optimal size

generate_osc_0          = *
                        lda #%010                       ;type 0: normal sample, use one-shot for osc A
                        sta instrument_osc_a_ctl,y
                        lda #%001                       ;stop osc B
                        sta instrument_osc_b_ctl,y
                        rts

generate_osc_1a         = *
                        lda #%110                       ;type 1a: simple looped sample, use swap mode for osc A
                        sta instrument_osc_a_ctl,y
                        lda #%111                       ;use swap mode for osc B
                        sta instrument_osc_b_ctl,y
                        rts

generate_osc_1b          = *
                        lda #%000                       ;type 1b: simple looped sample with optimal length, use free run mode for osc A
                        sta instrument_osc_a_ctl,y
                        lda #%001                       ;stop osc B
                        sta instrument_osc_b_ctl,y
                        rts

generate_osc_2          = *
                        lda generate_osc_opti_next      ;type 2: this is the header for the next instrument which is looped
                        bne generate_osc_2_1

                        lda #%1110                      ;loop has no optimal length: use swap mode for osc A with interrupt
                        sta instrument_osc_a_ctl,y
                        lda #%0111                      ;swap mode for osc B when A is done
                        sta instrument_osc_b_ctl,y

                        bra generate_osc_2_2

generate_osc_2_1        = *
                        lda #%110                       ;loop has optimal length: use swap mode for osc A
                        sta instrument_osc_a_ctl,y
                        lda #%001                       ;use free run mode for osc B when A is done
                        sta instrument_osc_b_ctl,y

generate_osc_2_2        = *
                        lda instrument_osc_a_ptr+2,y    ;since osc B plays the loop instrument, copy its ptr and siz parameters
                        sta instrument_osc_b_ptr,y

                        lda instrument_osc_a_siz+2,y
                        sta instrument_osc_b_siz,y
                        
generate_osc_3          = *
                        rts                             ;type 3: do nothing; it is played via loop header instrument (type 2)

;--------------------------

copy_instruments_to_doc = *
						;;++JGA we don't want this
                        ;;jsr clear_docram

                        ldy #0

]loop                   lda instrument_lengths,y
                        sta copy_instrument_length

                        jsr copy_instrument

                        lda read_instrument+1
                        clc
                        adc copy_instrument_length
                        sta read_instrument+1
                        bcc copy_instruments_1
                        inc read_instrument+3
copy_instruments_1      = *

                        iny
                        iny
                        cpy number_of_instruments2

                        blt ]loop
                        rts

copy_instrument         = *
                        sep #$20
                        mx  %10

]loop                   lda sound_control
                        bmi ]loop
                        
                        ora #%01100000
                        sta sound_control

                        stz sound_address
                        lda instrument_osc_a_ptr,y
                        sta sound_address+1
                        
                        ldx #0
]loop                   jsr read_instrument
                        inx
                        sta sound_data
                        cpx copy_instrument_length
                        blt ]loop

                        rep #$20
                        mx  %00

                        rts

;--------------------------

clear_docram            = *
                        sep #$20
                        mx  %10

]loop                   lda sound_control
                        bmi ]loop
                        
                        ora #%01100000
                        sta sound_control

                        stz sound_address
                        stz sound_address+1
                        
                        ldx #0
                        lda #0
]loop                   sta sound_data
                        inx
                        bne ]loop

                        rep #$20
                        mx  %00

                        rts

;--------------------------

setup_music             = *

; reset pointers
                        stz timer
                        
                        lda #6
                        sta tempo

                        stz ptr_within_pattern
                        stz pattern_order_ptr

; get pointer to first pattern to play
                        ldx pattern_order_ptr
                        lda pattern_order,x
                        and #$ff
                        asl
                        asl
                        tax
                        lda pattern_pointers,x
                        sta read_pattern+1
                        lda pattern_pointers+1,x
                        sta read_pattern+2
                        
                        rts

;--------------------------

setup_interrupt         = *
                        ldal  sound_interrupt_ptr
                        sta   backup_interrupt_ptr
                        ldal  sound_interrupt_ptr+2
                        sta   backup_interrupt_ptr+2

                        lda   #$5c
                        stal  sound_interrupt_ptr
                        phk
                        phk
                        pla
                        stal  sound_interrupt_ptr+2
                        lda   #interrupt_handler
                        stal  sound_interrupt_ptr+1

                        sep   #$20
                        mx    %10

]loop                   lda   sound_control
                        bmi   ]loop

                        and   #%10011111            ; disable auto-inc. and access DOC reg.
                        sta   sound_control

                        ldy   #0
]loop                   lda   timer_sound_settings,y
                        sta   sound_address
                        iny
                        lda   timer_sound_settings,y
                        sta   sound_data
                        iny
                        cpy   #7*2
                        bne   ]loop

                        rep #$20
                        mx  %00

                        lda   #reference_freq
                        sta   osc_interrupt_freq
                        sta   new_osc_interrupt_freq

                        rts

reference_freq          =     249                   ; interrupt frequence
timer_sound_settings    =     *                     ; set up oscillator 30 for interrupts
                        dfb   $1e,reference_freq    ; frequency low register
                        dfb   $3e,0                 ; frequency high register
                        dfb   $5e,0                 ; volume register, volume = 0
                        dfb   $9e,0                 ; wavetable pointer register, point to 0
                        dfb   $de,0                 ; wavetable size register, 256 byte length
                        dfb   $e1,$3e               ; oscillator enable register
                        dfb   $be,$08               ; mode register, set to free run

;--------------------------

setup_master_volume     = *
                        sep #$20
	                    mx  %10
	         
	                    ldal irq_volume
	                    and #%0000_1111
	                    sta sound_control

                        rep #$20
	                    mx  %00
                        rts

;-----------------------------------------------------------------------------------------
; play
;-----------------------------------------------------------------------------------------

play                    = *
                        phb
                        phk
                        plb

                        sta play_song_once

                        lda #1
                        sta playing
                        
                        plb
                        clc
                        rtl

;-----------------------------------------------------------------------------------------
; stop
;-----------------------------------------------------------------------------------------

stop                    = *
                        sei
                        phb
                        phd
                        phk
                        plb

                        lda   #$c000
                        tcd
                        
                        stz   playing                   ; stop player

                        sep   #$20
                        mx    %10

]loop                   lda   sound_control             ; kill sound
                        bmi   ]loop
                        and   #%10011111                ; disable auto-inc. and access DOC reg.
                        sta   sound_control

                        ldx   number_of_tracks2
                        beq   stop_1
                        lda   #$a0                      ; stop all oscillators in use
                        sta   sound_address
                        lda   #1
]loop                   sta   sound_data
                        inc   sound_address
                        dex
                        bne   ]loop

stop_1                  = *
                        lda   #$a0+30                   ; stop both interrupt oscillators
                        sta   sound_address
                        lda   #1
                        sta   sound_data
                        inc   sound_address
                        sta   sound_data

                        rep   #$20
                        mx    %00

                        lda   backup_interrupt_ptr      ; restore old interrupt ptr
                        stal  sound_interrupt_ptr
                        lda   backup_interrupt_ptr+2
                        stal  sound_interrupt_ptr+2

                        cli
                        pld
                        plb
                        clc
                        rtl

;-----------------------------------------------------------------------------------------
; getvuptr
;-----------------------------------------------------------------------------------------

getvuptr                = *
                        phk
                        phk
                        pla

                        and #$ff
                        tay
                        ldx #vu_number_of_tracks

                        clc
                        rtl

;-----------------------------------------------------------------------------------------
; gete8ptr
;-----------------------------------------------------------------------------------------

gete8ptr                = *
                        phk
                        phk
                        pla

                        and #$ff
                        tay
                        ldx #last_effect_8_param

                        clc
                        rtl

;-----------------------------------------------------------------------------------------
; forcesongpos
;-----------------------------------------------------------------------------------------

forcesongpos            = *
                        sei
                        phb

                        phk
                        plb

                        cmp pattern_order_length
                        bge forcesongpos_1

                        sta force_pattern_jump_p
                        lda #1
                        sta force_pattern_jump

                        plb
                        cli
                        clc
                        rtl

forcesongpos_1          = *
                        plb
                        cli
                        sec
                        rtl

;-----------------------------------------------------------------------------------------
; interupt handler (=the player)
;-----------------------------------------------------------------------------------------

interrupt_handler       = *
                        phb
                        phd

                        phk
                        plb

                        clc
                        xce
                        rep #$30
                        mx  %00

                        lda #$c000
                        tcd

                        sep #$20
                        mx  %10

]loop                   lda   sound_control
                        bmi   ]loop
                        and   #%10011111                ; disable auto-inc. and access DOC reg.
                        sta   sound_control

                        lda   #$e0
                        sta   sound_address             ; reads the interrupt register
                        lda   sound_data                ; to know which oscillator generated
                        lda   sound_data                ; the interrupt

                        and   #%00111110
                        lsr
                        cmp   #$1e
                        beq   tracker_interrupt         ; it's the 50Hz interrupt

                        and   #%11111110                ; get the track number where the interrupt occured
                        sta   oscillator

                        ldy   oscillator                ; y = track*2
                        ldx   curr_sample,y
                        dex
                        dex                             ; x = ptr into instrument tables

                        lda   reg_tbl_ptr,y
                        sta   sound_address
                        lda   instrument_osc_b_ptr,x
                        sta   sound_data

                        lda   reg_tbl_siz,y
                        sta   sound_address
                        lda   instrument_osc_b_siz,x
                        sta   sound_data

                        lda   reg_tbl_ctl,y
                        sta   sound_address
                        lda   instrument_osc_b_ctl,x
                        ora   track_channels,y
                        ora   #1
                        sta   sound_data

                        rep   #$30
                        mx    %00

jump_to_interrupt_end   = *
                        jmp   interrupt_handler_end


tracker_interrupt       = *                             ; it's the 50Hz interrupt
                        rep   #$30
                        mx    %00

                        lda   playing
                        beq   jump_to_interrupt_end

                        lda   timer
                        beq   parse_tracks              ;fetch track information only when timer=0
                        
                        inc
                        cmp   tempo
                        blt   tracker_interrupt_1
                        lda   #0
tracker_interrupt_1     sta   timer

                        jsr   handle_effects
                        jmp   talk_to_doc

;--------------------------

parse_tracks             = *                            ;fetch track information
                        inc   timer

                        lda   delay_pattern
                        beq   parse_tracks_2

                        dec   delay_pattern
                        jsr   handle_effects
                        jmp   talk_to_doc

parse_tracks_2          = *
                        jsr   check_pattern_jump        ;if we reached the end of the pattern or there was a pattern jump, handle it

                        ldy   #0
                        ldx   ptr_within_pattern
                        lda   #$ffff
                        sta   loop_position_jump

parse_tracks_loop       = *
                        jsr   read_pattern
                        pha
                        and   #$ff
                        asl
                        sta   note
                        pla
                        xba
                        and   #$ff
                        asl
                        sta   sample
                        inx
                        inx

                        jsr   read_pattern
                        pha
                        and   #$f
                        asl
                        sta   effect
                        pla
                        xba
                        and   #$ff
                        sta   effect_param
                        inx
                        inx

                        phx
                        jsr   setup_effect
                        plx

                        iny
                        iny
                        
                        cpy   number_of_tracks2
                        blt   parse_tracks_loop

                        lda   loop_position_jump        ;if there is an active loop, jump
                        bmi   parse_tracks_1
                        tax
parse_tracks_1          = *
                        stx   ptr_within_pattern



talk_to_doc             = *                             ;for each track: talk to ensoniq doc
                        sep #$20
                        mx  %10

]loop                   lda   sound_control
                        bmi   ]loop
                        and   #%10011111                ; DOC reg.
                        sta   sound_control

                        ldy #0
]loop                   lda what_to_do,y
                        bne talk_to_doc_0

talk_to_doc_loop        iny
                        iny

                        cpy   number_of_tracks2
                        blt   ]loop

talk_to_doc_timer       = *
                        ldy   new_osc_interrupt_freq
                        cpy   osc_interrupt_freq
                        beq   talk_to_doc_timer_1

                        sty   osc_interrupt_freq        ;set new interrupt frequency

                        lda   #30
                        sta   sound_address
                        lda   osc_interrupt_freq
                        sta   sound_data
                        lda   #$20+30
                        sta   sound_address
                        lda   osc_interrupt_freq+1
                        sta   sound_data
talk_to_doc_timer_1     = *

interrupt_handler_end   = *
                        sep #$30
                        pld
                        plb
                        clc
                        rtl

talk_to_doc_0           = *
                        mx  %10
; values can be combined by setting bits
; %10000000 = set control (and turn oscillators off before)
; %00000100 = set wave ptr/size
; %00000010 = set freq
; %00000001 = set volume
; %00000000 = do nothing
                        bpl talk_to_doc_1

                        lda reg_tbl_ctl,y           ;stop
                        sta sound_address
                        lda #1
                        sta sound_data
                        inc sound_address
                        sta sound_data

                        lda what_to_do,y
talk_to_doc_1           = *
                        bit #%00000001
                        beq talk_to_doc_2

                        lda reg_tbl_vol,y           ;set volume
                        sta sound_address
                        lda osc_volume,y
                        sta sound_data
                        inc sound_address
                        sta sound_data

                        lda what_to_do,y
talk_to_doc_2           = *
                        bit #%00000010
                        beq talk_to_doc_3

                        tya                         ;set freq
                        sta sound_address
                        lda osc_freq,y
                        sta sound_data
                        inc sound_address
                        sta sound_data

                        lda reg_tbl_freqhi,y
                        sta sound_address
                        lda osc_freq+1,y
                        sta sound_data
                        inc sound_address
                        sta sound_data

                        lda what_to_do,y
talk_to_doc_3           = *
                        bit #%00000100
                        beq talk_to_doc_4

                        ldx osc_instrument,y        ;set wave ptr/size via instrument

                        lda reg_tbl_ptr,y
                        sta sound_address

                        lda what_to_do,y
                        bmi talk_to_doc_3_1

                        lda instrument_osc_b_ptr,x  ;if we don't set the control byte, make sure we change the instrument
                        sta sound_data              ;in such a way that a looped instrument will play its loop
                        inc sound_address
                        sta sound_data

                        lda reg_tbl_siz,y
                        sta sound_address
                        lda instrument_osc_b_siz,x
                        sta sound_data
                        inc sound_address
                        sta sound_data

                        bra talk_to_doc_4

talk_to_doc_3_1         = *
                        lda instrument_osc_a_ptr,x  ;if we set the control byte, change the instrument in the normal fashion
                        sta sound_data
                        inc sound_address
                        lda instrument_osc_b_ptr,x
                        sta sound_data

                        lda reg_tbl_siz,y
                        sta sound_address
                        lda instrument_osc_a_siz,x
                        sta sound_data
                        inc sound_address
                        lda instrument_osc_b_siz,x
                        sta sound_data

talk_to_doc_4           = *
                        lda what_to_do,y
                        bpl talk_to_doc_5

                        lda osc_volume,y            ;update vu meter
                        sta vu_data,y

                        ldx osc_instrument,y        ;set control via instrument

                        lda reg_tbl_ctl,y
                        sta sound_address
                        lda instrument_osc_a_ctl,x
                        ora track_channels,y
                        sta sound_data
                        inc sound_address
                        lda instrument_osc_b_ctl,x
                        ora track_channels,y
                        sta sound_data

talk_to_doc_5           = *
                        jmp talk_to_doc_loop

                        mx  %00

;--------------------------

check_pattern_jump      = *
                        ldx   pattern_jump
                        jmp   (check_pattern_jump_tbl,x)

check_pattern_jump_tbl  = *
                        dw    check_pattern_end
                        dw    handle_pattern_jump
                        dw    handle_pattern_break

;--------------------------

check_pattern_end       = *
    	                lda   force_pattern_jump
                        beq   check_pattern_end_0
                        
                        lda   force_pattern_jump_p
                        sta   pattern_jump_param
                        stz   force_pattern_jump
                        bra   handle_pattern_jump

check_pattern_end_0     = *
                        lda   ptr_within_pattern        ;check if we're at the end of the pattern
                        cmp   pattern_length
                        blt   check_pattern_end_4

                        stz   ptr_within_pattern        ;reset pointer within pattern
                        stz   loop_position             ;reset loop in pattern
                        stz   loop_position_active

check_pattern_end_1     = *
                        ldx   pattern_order_ptr         ;end of pattern; set next pattern
                        inx

check_pattern_end_2     = *
                        cpx   pattern_order_length
                        blt   check_pattern_end_3

                        lda   play_song_once
                        beq   check_pattern_end_2_1

                        stz   playing                   ;stop playing after this song
                        rts

check_pattern_end_2_1   = *
                        ldx   #0

check_pattern_end_3     = *
                        stx   pattern_order_ptr

                        lda   pattern_order,x           ;set new offset position to new pattern
                        and   #$ff
                        asl
                        asl
                        tax
                        lda   pattern_pointers,x
                        sta   read_pattern+1
                        lda   pattern_pointers+1,x
                        sta   read_pattern+2

check_pattern_end_4     = *
                        rts

;--------------------------

handle_pattern_jump     = *                             ;jump to a specific pattern order position
                        stz pattern_jump

                        stz loop_position               ;reset loop in pattern
                        stz loop_position_active

                        ldx pattern_jump_param
                        jmp check_pattern_end_2

;--------------------------

handle_pattern_break    = *                             ;stop pattern here and go to next pattern but start at specific line
                        stz pattern_jump

                        ldx pattern_jump_param
                        lda pattern_break_ptrs,x
                        and #$ff
                        beq handle_pattern_break_1
                        
                        tax
                        lda #0
                        clc

]loop                   adc number_of_tracks4           ;poor man's multply
                        dex
                        bne ]loop

handle_pattern_break_1  = *
                        sta ptr_within_pattern

                        stz loop_position               ;reset loop in pattern
                        stz loop_position_active

                        jmp check_pattern_end_1

;--------------------------

setup_effect_jump_rts   rts
setup_effect_jump_tbl   = *
                        dw    setup_arpeggio
                        dw    setup_slide_up
                        dw    setup_slide_down
                        dw    setup_slide_to_note
                        dw    setup_vibrato
                        dw    setup_volslide            ;Continue 'Slide to note', but also do Volume slide
                        dw    setup_volslide            ;Continue 'Vibrato', but also do Volume slide
                        dw    setup_tremolo
                        dw    setup_gs_panning          ;IIGS panning
                        dw    setup_effect_jump_rts     ;Not supported: Set sample offset
                        dw    setup_volslide
                        dw    setup_positionjump
                        dw    setup_setvolume
                        dw    setup_patternbreak
                        dw    setup_e_effects
                        dw    setup_setspeed

setup_e_effect_jump_tbl = *
                        dw    setup_effect_jump_rts     ;Not supported: Set filter on/off
                        dw    fineslide_up
                        dw    fineslide_down
                        dw    set_glissando
                        dw    set_vibrato_waveform
                        dw    set_sample_finetune
                        dw    set_loop_pattern
                        dw    set_tremolo_waveform
                        dw    setup_effect_jump_rts     ;unused
                        dw    setup_retrigger
                        dw    volslide_up
                        dw    volslide_down
                        dw    setup_note_cut
                        dw    setup_note_delay
                        dw    setup_delay_pattern
                        dw    setup_effect_jump_rts     ;Not supported: Invert loop

setup_effect            = *
                        lda   #0                        ;by default, do nothing
                        sta   what_to_do,y
                        sta   vu_data,y                 ;reset vu meter

; if sample is defined, set it
; and set volume according to instrument

                        lda   sample
                        beq   setup_effect_2

; if sample is defined, always set the volume from the instrument
                        dec                             ;the 1st sample is at position 0 in all tables
                        dec
                        sta   osc_instrument,y          ;store which instrument to play

                        tax                             ;use default volume from sample
                        lda   instrument_volumes,x
                        sta   curr_volume,y             ;backup volume setting in track
                        asl
                        tax
                        lda   volume_lookup,x
                        sta   osc_volume,y              ;store volume for osc

                        lda   what_to_do,y
                        ora   #%00000001                ;mark that we want to set the volume
                        sta   what_to_do,y

                        lda   sample
                        cmp   curr_sample,y
                        beq   setup_effect_1

                        sta   curr_sample,y             ;if it's a different sample than before, tell the doc

                        lda   what_to_do,y
                        ora   #%00000100                ;mark that we want to set the instrument
                        sta   what_to_do,y

setup_effect_1          = *
                        lda   note                      ;repeat last note if no note was set
                        bne   setup_effect_2
                        lda   curr_note,y
                        beq   setup_effect_2
                        sta   note

                        lda   what_to_do,y
                        ora   #%00000100                ;mark that we want to set the instrument
                        sta   what_to_do,y

setup_effect_2          = *

                        lda   effect
                        sta   curr_effect,y
                        tax
                        jsr   (setup_effect_jump_tbl,x)

;if there is no note but a sample, then change the oscillators wavptr and wavsiz, so that an ongoing loop swaps to the new sample

check_play_note  = *

; if note is defined, play it

                        lda   note
                        beq   check_play_note_5         ;no note, don't play

                        sta   curr_note,y               ;backup note

                        ldx   curr_sample,y
                        beq   check_play_note_5         ;no last sample defined, do not play the note

                        lda   instrument_finetune-2,x   ;the 1st sample is at position 0 in all tables
                        clc
                        adc   note
                        tax
                        lda   note_freq_ptrs,x          ;use note and sample's finetune and look up a frequency
                        sta   curr_ptrfinetune,y
                        tax
                        lda   freq_finetune,x
                        sta   osc_freq,y                ;store freq for osc

                        lda   what_to_do,y
                        ora   #%10000110                ;store that we want to set frequency, restart the sample and control
                        sta   what_to_do,y

check_play_note_5       = *
                        rts

;--------------------------

setup_arpeggio          = *
                        lda effect_param
                        beq setup_arpeggio_2            ;no arpeggio, turn off if it was running before

                        lda note                        ;if we have a new note, use it
                        bne setup_arpeggio_1
                        lda arpeggio_note1,y            ;else use last played
                        beq setup_arpeggio_2            ;no last note - do nothing

                        sta note                        ;make sure we play the last note again

setup_arpeggio_1        = *
                        sta arpeggio_note1,y

                        lda effect_param
                        and #$f0
                        lsr
                        lsr
                        lsr
                        clc
                        adc note
                        sta arpeggio_note2,y

                        lda effect_param
                        and #$f
                        asl
                        clc
                        adc note
                        sta arpeggio_note3,y

                        lda #$8000
setup_arpeggio_2        = *
                        sta arpeggio_ptr,y

                        rts

;--------------------------

setup_slide_up          = *
                        lda effect_param
                        asl
                        sta slide_delta,y

                        lda note                        ;if there is no note, continue sliding
                        bne setup_slide_up_1

                        jmp handle_slide_up
setup_slide_up_1        rts

;--------------------------

setup_slide_down        = *
                        lda effect_param
                        asl
                        sta slide_delta,y

                        lda note                        ;if there is no note, continue sliding
                        bne setup_slide_down_1

                        jmp handle_slide_down
setup_slide_down_1      rts

;--------------------------

setup_slide_to_note     = *
                        lda effect_param
                        beq setup_slide_to_note_1       ;if there is a speed set, use this, else keep whatever is there
                        asl
                        sta slide_delta,y
setup_slide_to_note_1   = *

                        lda note                        ;if there is a note set, use this as target, else keep whatever is there
                        beq setup_slide_to_note_2

                        sta slide_target_note,y         ;if a note is set, this is our target to slide to
                        ldx curr_sample,y
                        lda instrument_finetune-2,x
                        clc
                        adc note
                        tax
                        lda note_freq_ptrs,x            ;find the target in the freq table to slide to
                        sta slide_target,y

                        stz note                        ;with this command, the note is a parameter and is not played
                        lda what_to_do,y
                        and #%00000101
                        sta what_to_do,y
setup_slide_to_note_2   = *
                        rts

;--------------------------

setup_vibrato           = *
                        lda effect_param
                        and #$f0                        ;If either x or y are 0, then the old vibrato values will be used.
                        beq setup_vibrato_1
                        lsr
                        lsr
                        lsr
                        sta vibrato_rate,y
setup_vibrato_1         = *

                        lda effect_param
                        and #$f
                        beq setup_vibrato_2
                        xba
                        lsr                             ;*128
                        clc
                        adc vibrato_tableoffset,y
                        sta vibrato_table,y
setup_vibrato_2         = *

                        lda #0                          ;reset position in vibrato table
                        sta vibrato_pos,y
                        rts

;--------------------------

setup_tremolo           = *
                        lda effect_param
                        and #$f0
                        beq setup_tremolo_1
                        lsr
                        lsr
                        lsr
                        sta tremolo_rate,y
setup_tremolo_1         = *

                        lda effect_param
                        and #$f
                        beq setup_tremolo_2
                        xba
                        lsr                             ;*128
                        clc
                        adc tremolo_tableoffset,y
                        sta tremolo_table,y
setup_tremolo_2         = *

                        lda #0                          ;reset position in tremolo table: this is actually a bug in protracker
                        sta tremolo_pos,y

                        rts

;--------------------------

setup_gs_panning        = *
                        lda effect_param
                        cmp #8
                        bge setup_gs_panning_1          ;GS panning: if < 8, then we set the channel for this track
                        asl
                        asl
                        asl
                        asl
                        sta track_channels,y
                        rts
setup_gs_panning_1      sta last_effect_8_param         ;if it is not a panning effect, store in shared register for timing purposes
                        rts

;--------------------------

setup_volslide          = *
                        lda effect_param
                        beq setup_volslide_1

                        cmp #$10
                        bge setup_volslide_1

                        lda #0
                        sec
                        sbc effect_param
                        sta volslide_delta,y

                        rts

setup_volslide_1        = *
                        and #$f0                        ;If both x and y are non-zero, the y value is ignored (assumed to be 0).
                        lsr
                        lsr
                        lsr
                        lsr
                        sta volslide_delta,y

                        rts

;--------------------------

setup_setvolume         = *
                        lda effect_param
                        cmp #64
                        blt setup_setvolume_1
                        lda #64
setup_setvolume_1       sta curr_volume,y
                        asl
                        tax
                        lda volume_lookup,x
                        sta osc_volume,y

                        lda   what_to_do,y
                        ora   #%00000001                ;store that we want to set the volume immediately
                        sta   what_to_do,y
                        rts

;--------------------------

setup_positionjump      = *
                        lda effect_param                ;Legal values are from 0 to 127
                        and #$7f
                        sta pattern_jump_param

                        lda #2
                        sta pattern_jump

                        rts

;--------------------------

setup_patternbreak      = *
                        lda effect_param
                        sta pattern_jump_param

                        lda #4
                        sta pattern_jump

                        rts

;--------------------------

setup_e_effects         = *
                        lda effect_param
                        and #$f0
                        lsr
                        lsr
                        lsr
                        sta curr_e_effect,y
                        tax
                        lda effect_param
                        and #$f
                        sta effect_param
                        jmp (setup_e_effect_jump_tbl,x)

;--------------------------

setup_setspeed          = *
                        lda effect_param
                        bne setup_setspeed_2
                        lda #1                          ;when 0, stop music or set to 1 ?

setup_setspeed_1        = *
                        sta tempo
                        rts

setup_setspeed_2        = *
                        cmp #$20                        ;when < 32, assume set tempo
                        blt setup_setspeed_1

                        sec                             ;else interrupt timer
                        sbc #$20
                        asl
                        tax
                        lda bpm_to_freq,x
                        sta new_osc_interrupt_freq
                        rts

;--------------------------

fineslide_up            = *
                        asl effect_param

                        lda curr_ptrfinetune,y
                        clc
                        adc effect_param
                        cmp #max_finetune_ptr
                        blt fineslide_up_1
                        lda #max_finetune_ptr

fineslide_up_1          sta curr_ptrfinetune,y

                        tax
                        lda freq_finetune,x
                        sta osc_freq,y

                        lda   what_to_do,y
                        ora   #%00000010                ;store that we want to set the freq for this track
                        sta   what_to_do,y
                        rts

;--------------------------

fineslide_down          = *
                        asl effect_param
                        
                        lda curr_ptrfinetune,y
                        sec
                        sbc effect_param
                        bpl fineslide_down_1
                        lda #0

fineslide_down_1        sta curr_ptrfinetune,y

                        tax
                        lda freq_finetune,x
                        sta osc_freq,y

                        lda   what_to_do,y
                        ora   #%00000010                ;store that we want to set the freq for this track
                        sta   what_to_do,y
                        rts

;--------------------------

set_glissando           = *
                        lda effect_param               ;only 0 and 1 are valid, but PT doesn't check that
                        sta glissando,y
                        rts

;--------------------------

set_vibrato_waveform    = *
                        lda effect_param
                        cmp #8
                        bge set_vibrato_waveform_1

                        and #%11
                        asl
                        tax

                        lda waveforms,x
                        sta vibrato_tableoffset,y

                        lda effect_param
                        and #%100
                        sta vibrato_retrig,y

set_vibrato_waveform_1  = *
                        rts

;--------------------------

set_sample_finetune     = *
                        ldx sample
                        bne set_sample_finetune_1
                        ldx curr_sample,y
                        beq set_sample_finetune_2
 
set_sample_finetune_1   = *
                        phx
                        lda effect_param
                        asl
                        tax
                        lda note_freq_ptrs_offset,x
                        plx
                        sta instrument_finetune-2,x

set_sample_finetune_2   = *
                        rts

;--------------------------

set_loop_pattern        = *
                        lda effect_param            ;0=record position, else loop
                        bne set_loop_pattern_1

                        lda ptr_within_pattern      ;record pattern position
                        sta loop_position
                        rts

set_loop_pattern_1      = *                         ;start or continue loop
                        lda loop_position_active
                        bne set_loop_pattern_2

                        lda #1                      ;start loop
                        sta loop_position_active
                        lda effect_param
                        sta loop_repeat_count
                        lda loop_position
                        sta loop_position_jump
                        rts

set_loop_pattern_2      = *                         ;continue loop, enough repetitions?
                        dec loop_repeat_count
                        beq set_loop_pattern_3

                        lda loop_position
                        sta loop_position_jump
                        rts

set_loop_pattern_3      = *                         ;loop has ended
                        stz loop_position_active
                        rts

;--------------------------

set_tremolo_waveform    = *
                        lda effect_param
                        cmp #8
                        bge set_tremolo_waveform_1

                        and #%11
                        asl
                        tax

                        lda waveforms,x
                        sta tremolo_tableoffset,y

                        lda effect_param
                        and #%100
                        sta tremolo_retrig,y

set_tremolo_waveform_1  = *
                        rts

;--------------------------

setup_retrigger         = *
                        lda effect_param
                        sta retrigger_steps,y
                        lda #0
                        sta retrigger_count,y
                        rts

;--------------------------

volslide_up             = *
                        lda curr_volume,y
                        clc
                        adc effect_param
                        cmp #64
                        blt volslide_up_1
                        lda #64

volslide_up_1           = *
                        sta curr_volume,y

                        asl
                        tax
                        lda   volume_lookup,x
                        sta   osc_volume,y              ;store volume for osc

                        lda   what_to_do,y
                        ora   #%00000001                ;store that we want to set the volume for this track
                        sta   what_to_do,y

                        rts

;--------------------------

volslide_down           = *
                        lda curr_volume,y
                        sec
                        sbc effect_param
                        bpl volslide_up_1
                        lda #0
                        bra volslide_up_1

;--------------------------

setup_note_cut          = *
                        lda effect_param
                        sta note_cut,y
                        rts

;--------------------------

setup_note_delay        = *
                        lda note
                        beq setup_note_delay_1

                        sta note_delay_note,y

                        lda effect_param
                        sta note_delay_count,y

                        stz note

setup_note_delay_1      = *
                        rts

;--------------------------

setup_delay_pattern     = *
                        lda effect_param
                        sta delay_pattern
                        rts

;--------------------------

handle_effect_jump_tbl  = *
                        dw    handle_arpeggio
                        dw    handle_slide_up
                        dw    handle_slide_down
                        dw    handle_slide_to_note
                        dw    handle_vibrato
                        dw    handle_effect_5
                        dw    handle_effect_6
                        dw    handle_tremolo
                        dw    handle_effect_nothing
                        dw    handle_effect_nothing
                        dw    handle_volslide
                        dw    handle_effect_nothing
                        dw    handle_effect_nothing
                        dw    handle_effect_nothing
                        dw    handle_effect_nothing
                        dw    handle_effect_nothing

handle_e_eff_jump_tbl   dw    handle_effect_nothing
                        dw    handle_effect_nothing
                        dw    handle_effect_nothing
                        dw    handle_effect_nothing
                        dw    handle_effect_nothing
                        dw    handle_effect_nothing
                        dw    handle_effect_nothing
                        dw    handle_effect_nothing
                        dw    handle_effect_nothing
                        dw    handle_retrigger
                        dw    handle_effect_nothing
                        dw    handle_effect_nothing
                        dw    handle_note_cut
                        dw    handle_note_delay
                        dw    handle_effect_nothing
                        dw    handle_effect_nothing

handle_effects          = *             ;when a non-tracker line is encountered, do what the last effect needs to do
                        ldy #0

]loop                   lda #0
                        sta what_to_do,y

                        ldx curr_effect,y
                        jsr (handle_effect_jump_tbl,x)

                        iny
                        iny
                        cpy number_of_tracks2
                        blt ]loop

handle_effect_nothing   rts

;--------------------------

handle_arpeggio         = *
                        lda arpeggio_ptr,y
                        beq handle_arpeggio_5

                        inc
                        cmp #$8003
                        blt handle_arpeggio_1
                        lda #$8000
handle_arpeggio_1       = *
                        sta arpeggio_ptr,y

                        cmp #$8000
                        bne handle_arpeggio_2
                        lda arpeggio_note1,y
                        bra handle_arpeggio_4

handle_arpeggio_2       = *
                        cmp #$8001
                        bne handle_arpeggio_3
                        lda arpeggio_note2,y
                        bra handle_arpeggio_4

handle_arpeggio_3       = *
                        lda arpeggio_note3,y

handle_arpeggio_4       = *
                        sta note
                        sta curr_note,y

                        lda curr_sample,y
                        sta sample

                        jmp check_play_note

handle_arpeggio_5       = *
                        rts

;--------------------------

handle_slide_up         = *
                        lda curr_ptrfinetune,y
                        clc
                        adc slide_delta,y
                        cmp #max_finetune_ptr
                        blt handle_slide_up_1
                        lda #max_finetune_ptr

handle_slide_up_1       sta curr_ptrfinetune,y

                        tax
                        lda freq_finetune,x
                        sta osc_freq,y

                        lda   what_to_do,y
                        ora   #%00000010                ;store that we want to set the freq for this track
                        sta   what_to_do,y
                        rts

;--------------------------

handle_slide_down       = *
                        lda curr_ptrfinetune,y
                        sec
                        sbc slide_delta,y
                        cmp #max_finetune_ptr
                        blt handle_slide_down_1
                        lda #0

handle_slide_down_1     sta curr_ptrfinetune,y

                        tax
                        lda freq_finetune,x
                        sta osc_freq,y

                        lda   what_to_do,y
                        ora   #%00000010                ;store that we want to set the freq for this track
                        sta   what_to_do,y
                        rts

;--------------------------

handle_slide_to_note    = *
                        lda glissando,y
                        beq handle_slide_to_note_0

;when glissando is on, we have to slide in semitones
                        lda curr_note,y
                        cmp slide_target_note,y
                        beq handle_slide_to_note_3
                        bge handle_slide_to_note_g1

                        inc
                        inc
                        bra handle_slide_to_note_g2

handle_slide_to_note_g1 = *
                        dec
                        dec

handle_slide_to_note_g2 = *
                        sta curr_note,y

                        ldx curr_sample,y
                        lda instrument_finetune-2,x
                        clc
                        adc curr_note,y
                        tax
                        lda note_freq_ptrs,x
                        bra handle_slide_to_note_2

;no glissando

handle_slide_to_note_0  = *
                        lda curr_ptrfinetune,y
                        cmp slide_target,y
                        beq handle_slide_to_note_3
                        bge handle_slide_to_note_4

                        clc
                        adc slide_delta,y
                        cmp slide_target,y
                        blt handle_slide_to_note_2
handle_slide_to_note_1  = *
                        lda slide_target,y
handle_slide_to_note_2  = *
                        sta curr_ptrfinetune,y
                        tax
                        lda freq_finetune,x
                        sta osc_freq,y

                        lda   what_to_do,y
                        ora   #%00000010                ;store that we want to set the freq for this track
                        sta   what_to_do,y
handle_slide_to_note_3  = *
                        rts

handle_slide_to_note_4  = *
                        sec
                        sbc slide_delta,y
                        cmp slide_target,y
                        bge handle_slide_to_note_2
                        bra handle_slide_to_note_1

;--------------------------

handle_vibrato          = *
                        lda vibrato_table,y
                        clc
                        adc vibrato_pos,y
                        tax
                        lda sine_tbl,x
                        clc
                        adc curr_ptrfinetune,y
                        tax
                        lda freq_finetune,x
                        sta osc_freq,y

                        lda   what_to_do,y
                        ora   #%00000010                ;store that we want to set the freq for this track
                        sta   what_to_do,y

                        lda vibrato_pos,y
                        clc
                        adc vibrato_rate,y
                        cmp #128
                        blt handle_vibrato_1

                        ldx vibrato_retrig,y
                        bne handle_vibrato_2

                        and #127
handle_vibrato_1        sta vibrato_pos,y
handle_vibrato_2        rts

;--------------------------

handle_effect_5         = *
                        jsr handle_slide_to_note        ;Continue 'Slide to note', but also do Volume slide
                        jmp handle_volslide

;--------------------------

handle_effect_6         = *
                        jsr handle_vibrato              ;Continue 'Vibrato', but also do Volume slide
                        jmp handle_volslide

;--------------------------

handle_tremolo          = *
                        lda tremolo_table,y
                        clc
                        adc tremolo_pos,y
                        tax
                        lda sine_tbl,x
                        lsr                             ;divide by 2 because sine table is factors of 2
                        clc
                        adc curr_volume,y
                        asl
                        tax
                        lda volume_lookup,x
                        sta osc_volume,y

                        lda   what_to_do,y
                        ora   #%00000001                ;store that we want to set the vol for this track
                        sta   what_to_do,y

                        lda tremolo_pos,y
                        clc
                        adc tremolo_rate,y
                        cmp #128
                        blt handle_tremolo_1

                        ldx tremolo_retrig,y
                        bne handle_tremolo_2

                        and #127
handle_tremolo_1        sta tremolo_pos,y
handle_tremolo_2        rts


;--------------------------

handle_volslide         = *
                        ldx #0
                        lda curr_volume,y
                        clc
                        adc volslide_delta,y
                        bmi handle_volslide_1           ;when < 0 then 0

                        ldx #64
                        cmp #64
                        bge handle_volslide_1           ;when > 64 then 64

                        tax

handle_volslide_1       = *
                        txa
                        sta   curr_volume,y             ;backup volume setting in track
                        asl
                        tax
                        lda   volume_lookup,x
                        sta   osc_volume,y              ;store volume for osc

                        lda   what_to_do,y
                        ora   #%00000001                ;store that we want to set the volume for this track
                        sta   what_to_do,y

                        rts

;--------------------------

handle_e_effects        = *
                        ldx curr_e_effect,y
                        jmp (handle_e_eff_jump_tbl,x)

;--------------------------

handle_retrigger        = *
                        lda retrigger_count,y
                        inc
                        cmp retrigger_steps,y
                        blt handle_retrigger_2

                        lda curr_sample,y
                        beq handle_retrigger_1

                        lda what_to_do,y            ;do retrigger
                        ora #%11000100
                        sta what_to_do,y

handle_retrigger_1      = *
                        lda #0
handle_retrigger_2      = *
                        sta retrigger_count,y

                        rts

;--------------------------

handle_note_cut         = *
                        lda note_cut,y
                        beq handle_note_cut_1
                        dec
                        sta note_cut,y
                        bne handle_note_cut_1

                        lda #0
                        sta curr_volume,y
                        sta osc_volume,y

                        lda what_to_do,y            ;store that we want to set the volume
                        ora #%00000001
                        sta what_to_do,y

handle_note_cut_1       = *
                        rts

;--------------------------

handle_note_delay       = *
                        lda note_delay_count,y
                        dec
                        sta note_delay_count,y
                        bne handle_note_delay_1

                        lda note_delay_note,y
                        sta note

                        jmp check_play_note

handle_note_delay_1     = *
                        rts

;--------------------------

volume_lookup           = *
                        dw 0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60
                        dw 64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124
                        dw 128,132,136,140,144,148,152,156,160,164,168,172,176,180,184,188
                        dw 192,196,200,204,208,212,216,220,224,228,232,236,240,244,248,252
                        dw 255,255

max_finetune_ptr        = 3574
freq_finetune           = *
                        dw 38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38
                        dw 38,38,38,38,38,38,39,39,39,39,39,39,39,39,39,39
                        dw 39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39
                        dw 39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39
                        dw 39,39,39,39,40,40,40,40,40,40,40,40,40,40,40,40
                        dw 40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40
                        dw 40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,41
                        dw 41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41
                        dw 41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41
                        dw 41,41,41,41,41,41,41,41,42,42,42,42,42,42,42,42
                        dw 42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42
                        dw 42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,43
                        dw 43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43
                        dw 43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43
                        dw 43,43,43,43,44,44,44,44,44,44,44,44,44,44,44,44
                        dw 44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44
                        dw 44,44,44,44,44,44,44,44,45,45,45,45,45,45,45,45
                        dw 45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45
                        dw 45,45,45,45,45,45,45,45,45,45,46,46,46,46,46,46
                        dw 46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46
                        dw 46,46,46,46,46,46,46,46,46,46,46,47,47,47,47,47
                        dw 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47
                        dw 47,47,47,47,47,47,47,47,47,47,48,48,48,48,48,48
                        dw 48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48
                        dw 48,48,48,48,48,48,48,48,49,49,49,49,49,49,49,49
                        dw 49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49
                        dw 49,49,49,49,49,50,50,50,50,50,50,50,50,50,50,50
                        dw 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50
                        dw 51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51
                        dw 51,51,51,51,51,51,51,51,51,51,51,52,52,52,52,52
                        dw 52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52
                        dw 52,52,52,52,53,53,53,53,53,53,53,53,53,53,53,53
                        dw 53,53,53,53,53,53,53,53,53,53,53,53,53,54,54,54
                        dw 54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54
                        dw 54,54,54,54,55,55,55,55,55,55,55,55,55,55,55,55
                        dw 55,55,55,55,55,55,55,55,55,55,55,56,56,56,56,56
                        dw 56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56
                        dw 56,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57
                        dw 57,57,57,57,57,57,57,58,58,58,58,58,58,58,58,58
                        dw 58,58,58,58,58,58,58,58,58,58,58,59,59,59,59,59
                        dw 59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,60
                        dw 60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60
                        dw 60,60,61,61,61,61,61,61,61,61,61,61,61,61,61,61
                        dw 61,61,61,61,61,62,62,62,62,62,62,62,62,62,62,62
                        dw 62,62,62,62,62,62,62,63,63,63,63,63,63,63,63,63
                        dw 63,63,63,63,63,63,63,63,64,64,64,64,64,64,64,64
                        dw 64,64,64,64,64,64,64,64,64,65,65,65,65,65,65,65
                        dw 65,65,65,65,65,65,65,65,65,66,66,66,66,66,66,66
                        dw 66,66,66,66,66,66,66,66,66,67,67,67,67,67,67,67
                        dw 67,67,67,67,67,67,67,67,68,68,68,68,68,68,68,68
                        dw 68,68,68,68,68,68,68,69,69,69,69,69,69,69,69,69
                        dw 69,69,69,69,69,69,70,70,70,70,70,70,70,70,70,70
                        dw 70,70,70,70,71,71,71,71,71,71,71,71,71,71,71,71
                        dw 71,71,72,72,72,72,72,72,72,72,72,72,72,72,72,73
                        dw 73,73,73,73,73,73,73,73,73,73,73,73,74,74,74,74
                        dw 74,74,74,74,74,74,74,74,75,75,75,75,75,75,75,75
                        dw 75,75,75,75,75,76,76,76,76,76,76,76,76,76,76,76
                        dw 76,77,77,77,77,77,77,77,77,77,77,77,78,78,78,78
                        dw 78,78,78,78,78,78,78,78,79,79,79,79,79,79,79,79
                        dw 79,79,79,80,80,80,80,80,80,80,80,80,80,81,81,81
                        dw 81,81,81,81,81,81,81,81,82,82,82,82,82,82,82,82
                        dw 82,82,83,83,83,83,83,83,83,83,83,83,84,84,84,84
                        dw 84,84,84,84,84,84,85,85,85,85,85,85,85,85,85,85
                        dw 86,86,86,86,86,86,86,86,86,87,87,87,87,87,87,87
                        dw 87,87,88,88,88,88,88,88,88,88,88,89,89,89,89,89
                        dw 89,89,89,89,90,90,90,90,90,90,90,90,91,91,91,91
                        dw 91,91,91,91,92,92,92,92,92,92,92,92,92,93,93,93
                        dw 93,93,93,93,93,94,94,94,94,94,94,94,95,95,95,95
                        dw 95,95,95,95,96,96,96,96,96,96,96,96,97,97,97,97
                        dw 97,97,97,98,98,98,98,98,98,98,99,99,99,99,99,99
                        dw 99,100,100,100,100,100,100,100,101,101,101,101,101,101,101,102
                        dw 102,102,102,102,102,103,103,103,103,103,103,103,104,104,104,104
                        dw 104,104,105,105,105,105,105,105,106,106,106,106,106,106,106,107
                        dw 107,107,107,107,107,108,108,108,108,108,108,109,109,109,109,109
                        dw 110,110,110,110,110,110,111,111,111,111,111,111,112,112,112,112
                        dw 112,113,113,113,113,113,113,114,114,114,114,114,115,115,115,115
                        dw 115,116,116,116,116,116,117,117,117,117,117,118,118,118,118,118
                        dw 119,119,119,119,119,120,120,120,120,120,121,121,121,121,121,122
                        dw 122,122,122,123,123,123,123,123,124,124,124,124,125,125,125,125
                        dw 125,126,126,126,126,127,127,127,127,128,128,128,128,128,129,129
                        dw 129,129,130,130,130,130,131,131,131,131,132,132,132,132,133,133
                        dw 133,133,134,134,134,134,135,135,135,136,136,136,136,137,137,137
                        dw 137,138,138,138,139,139,139,139,140,140,140,141,141,141,141,142
                        dw 142,142,143,143,143,143,144,144,144,145,145,145,146,146,146,146
                        dw 147,147,147,148,148,148,149,149,149,150,150,150,151,151,151,152
                        dw 152,152,153,153,153,154,154,154,155,155,155,156,156,156,157,157
                        dw 158,158,158,159,159,159,160,160,160,161,161,162,162,162,163,163
                        dw 164,164,164,165,165,165,166,166,167,167,167,168,168,169,169,170
                        dw 170,170,171,171,172,172,172,173,173,174,174,175,175,176,176,176
                        dw 177,177,178,178,179,179,180,180,181,181,182,182,183,183,184,184
                        dw 184,185,185,186,186,187,187,188,189,189,190,190,191,191,192,192
                        dw 193,193,194,194,195,195,196,197,197,198,198,199,199,200,201,201
                        dw 202,202,203,204,204,205,205,206,207,207,208,208,209,210,210,211
                        dw 212,212,213,214,214,215,216,216,217,218,218,219,220,220,221,222
                        dw 223,223,224,225,225,226,227,228,228,229,230,231,232,232,233,234
                        dw 235,235,236,237,238,239,240,240,241,242,243,244,245,246,246,247
                        dw 248,249,250,251,252,253,254,255,256,256,257,258,259,260,261,262
                        dw 263,264,265,266,267,268,270,271,272,273,274,275,276,277,278,279
                        dw 280,282,283,284,285,286,287,289,290,291,292,294,295,296,297,299
                        dw 300,301,303,304,305,307,308,309,311,312,314,315,317,318,319,321
                        dw 322,324,325,327,329,330,332,333,335,337,338,340,342,343,345,347
                        dw 348,350,352,354,356,357,359,361,363,365,367,369,371,373,375,377
                        dw 379,381,383,385,388,390,392,394,397,399,401,403,406,408,411,413
                        dw 416,418,421,423,426,429,431,434,437,439,442,445,448,451,454,457
                        dw 460,463,466,469,473,476,479,482,486,489,493,496,500,504,507,511
                        dw 515,519,523,527,531,535,539,543,548,552,556,561,566,570,575,580
                        dw 585,590,595,600,605,611,616,622,627,633,639,645,651,657,663,670
                        dw 676,683,690,697,704,711,719,726,734,742,750,758,767,775,784,793
                        dw 802,812,821,831,841,852,862,873,885,896,908,920,932,945,958,972
                        dw 986,1000,1015,1030,1045,1061,1078,1095,1113,1131,1150,1169,1190,1210,1232,1254
                        dw 1278,1302,1327,1353,1380,1408,1437,1468,1500,1533,1568,1605,1643,1683,1725,1769
                        dw 1816,1865,1917,1971,2029,2091,2156,2226,2300,2379,2464,2555

note_freq_ptrs          = *
note_freq_ptrs_0        = *
                        dw 0,204,396,578,748,914,1066,1210,1346,1474,1594,1706,1814,1916,2012,2104
                        dw 2188,2272,2348,2420,2488,2552,2612,2668,2722,2772,2820,2866,2908,2950,2988,3024
                        dw 3058,3090,3120,3148,3176,3200,3224,3248,3268,3288,3308,3326,3342,3358,3374,3388
                        dw 3402,3414,3426,3438,3448,3458,3468,3476,3486,3494,3500,3508,3514,3522,3528,3534
                        dw 3538,3544,3548,3554,3558,3562,3566,3568,3572
note_freq_ptrs_1        = *
                        dw 0,228,420,600,770,930,1082,1224,1360,1488,1608,1720,1828,1928,2024,2114
                        dw 2198,2280,2354,2426,2494,2558,2618,2674,2728,2778,2826,2870,2914,2954,2992,3028
                        dw 3060,3092,3122,3150,3178,3202,3226,3250,3270,3290,3310,3328,3344,3360,3376,3390
                        dw 3402,3416,3428,3440,3450,3460,3470,3478,3488,3496,3502,3510,3516,3522,3528,3534
                        dw 3540,3544,3550,3554,3558,3562,3566,3570,3572,3572
note_freq_ptrs_2        = *
                        dw 0,252,442,622,790,950,1100,1242,1376,1502,1622,1734,1840,1940,2036,2124
                        dw 2210,2288,2364,2434,2502,2564,2624,2680,2734,2784,2832,2876,2918,2958,2996,3032
                        dw 3064,3096,3126,3154,3180,3206,3230,3252,3274,3294,3312,3330,3346,3362,3378,3392
                        dw 3404,3416,3428,3440,3452,3462,3470,3480,3488,3496,3504,3510,3518,3522,3528,3534
                        dw 3540,3546,3550,3554,3558,3562,3566,3570,3572,3572
note_freq_ptrs_3        = *
                        dw 0,276,464,642,810,968,1118,1258,1392,1518,1636,1748,1854,1952,2046,2136
                        dw 2220,2298,2372,2444,2510,2572,2632,2688,2740,2790,2838,2882,2924,2964,3000,3036
                        dw 3068,3100,3130,3158,3184,3210,3232,3254,3276,3296,3314,3332,3348,3364,3378,3392
                        dw 3406,3418,3430,3442,3452,3462,3472,3480,3488,3496,3504,3510,3518,3524,3530,3536
                        dw 3540,3546,3550,3554,3560,3564,3566,3570,3574,3574
note_freq_ptrs_4        = *
                        dw 0,300,488,664,830,988,1136,1276,1408,1532,1650,1762,1866,1964,2058,2146
                        dw 2230,2308,2382,2452,2518,2580,2638,2694,2746,2796,2844,2888,2928,2968,3004,3040
                        dw 3072,3104,3134,3162,3188,3212,3236,3258,3278,3298,3316,3334,3350,3366,3380,3394
                        dw 3408,3420,3432,3444,3454,3464,3472,3482,3490,3498,3504,3512,3518,3524,3530,3536
                        dw 3542,3546,3550,3556,3560,3564,3566,3570,3574,3574
note_freq_ptrs_5        = *
                        dw 0,324,510,686,850,1006,1154,1292,1424,1548,1664,1774,1878,1976,2070,2156
                        dw 2240,2318,2390,2460,2526,2588,2646,2702,2754,2802,2848,2892,2934,2972,3010,3044
                        dw 3076,3108,3138,3164,3190,3216,3238,3260,3280,3300,3318,3336,3352,3368,3382,3396
                        dw 3410,3422,3434,3444,3454,3464,3474,3482,3490,3498,3506,3512,3520,3526,3532,3536
                        dw 3542,3546,3552,3556,3560,3564,3568,3570,3574,3574
note_freq_ptrs_6        = *
                        dw 0,348,532,706,870,1026,1172,1310,1440,1562,1678,1788,1892,1988,2080,2168
                        dw 2250,2326,2400,2468,2534,2596,2654,2708,2760,2808,2854,2898,2938,2978,3014,3048
                        dw 3080,3112,3140,3168,3194,3218,3242,3262,3284,3302,3320,3338,3354,3370,3384,3398
                        dw 3410,3424,3436,3446,3456,3466,3474,3484,3492,3500,3506,3514,3520,3526,3532,3538
                        dw 3542,3548,3552,3556,3560,3564,3568,3572,3574,3574
note_freq_ptrs_7        = *
                        dw 0,372,556,728,892,1044,1190,1326,1456,1578,1692,1802,1904,2000,2092,2178
                        dw 2260,2336,2408,2478,2542,2602,2660,2714,2766,2814,2860,2902,2944,2982,3018,3052
                        dw 3084,3116,3144,3172,3196,3220,3244,3266,3286,3306,3324,3340,3356,3372,3386,3400
                        dw 3412,3424,3436,3448,3458,3468,3476,3484,3492,3500,3508,3514,3520,3526,3532,3538
                        dw 3544,3548,3552,3556,3560,3564,3568,3572,3574,3574
note_freq_ptrs_8        = *
                        dw 0,0,204,396,578,750,912,1064,1208,1344,1472,1592,1708,1814,1916,2012
                        dw 2104,2188,2272,2348,2420,2488,2552,2612,2668,2722,2772,2820,2866,2908,2950,2988
                        dw 3024,3058,3090,3120,3148,3176,3200,3224,3248,3268,3288,3308,3326,3342,3358,3374
                        dw 3388,3402,3416,3428,3438,3448,3458,3468,3478,3486,3494,3502,3508,3516,3522,3528
                        dw 3534,3540,3544,3548,3554,3558,3562,3566,3568,3568
note_freq_ptrs_9        = *
                        dw 0,28,230,422,602,772,932,1084,1226,1362,1488,1608,1722,1828,1928,2024
                        dw 2114,2198,2278,2356,2426,2494,2558,2618,2674,2728,2778,2826,2870,2914,2954,2992
                        dw 3028,3060,3092,3122,3152,3178,3204,3228,3250,3270,3290,3310,3328,3344,3360,3376
                        dw 3390,3404,3416,3428,3440,3450,3460,3470,3478,3486,3494,3502,3510,3516,3522,3528
                        dw 3534,3540,3544,3550,3554,3558,3562,3566,3568,3568
note_freq_ptrs_a        = *
                        dw 0,52,254,444,622,810,950,1100,1242,1376,1502,1622,1734,1840,1940,2036
                        dw 2124,2210,2288,2364,2434,2502,2564,2624,2680,2734,2784,2832,2876,2918,2958,2996
                        dw 3032,3064,3096,3126,3154,3182,3206,3230,3252,3274,3294,3312,3330,3346,3362,3378
                        dw 3392,3406,3418,3430,3442,3452,3462,3472,3480,3488,3496,3504,3510,3516,3524,3530
                        dw 3536,3540,3546,3550,3554,3558,3562,3566,3570,3570
note_freq_ptrs_b        = *
                        dw 0,80,280,468,646,812,972,1120,1260,1394,1520,1638,1750,1854,1952,2046
                        dw 2136,2220,2298,2372,2444,2510,2572,2632,2688,2740,2790,2838,2882,2924,2964,3000
                        dw 3036,3068,3100,3130,3158,3184,3210,3232,3254,3276,3296,3314,3332,3348,3364,3378
                        dw 3392,3406,3420,3432,3442,3452,3462,3472,3480,3490,3496,3504,3512,3516,3524,3530
                        dw 3536,3540,3546,3550,3554,3560,3562,3566,3570,3570
note_freq_ptrs_c        = *
                        dw 0,104,302,490,666,832,988,1138,1278,1410,1534,1652,1762,1866,1964,2058
                        dw 2146,2230,2308,2382,2452,2518,2580,2640,2694,2746,2796,2844,2888,2928,2968,3004
                        dw 3040,3072,3104,3134,3162,3188,3212,3236,3258,3278,3298,3316,3334,3350,3366,3382
                        dw 3394,3408,3420,3432,3444,3454,3464,3474,3482,3490,3498,3506,3512,3518,3524,3530
                        dw 3536,3542,3546,3552,3556,3560,3564,3568,3570,3570
note_freq_ptrs_d        = *
                        dw 0,128,326,510,686,852,1006,1154,1294,1424,1548,1664,1774,1878,1976,2070
                        dw 2156,2240,2318,2390,2460,2526,2588,2646,2702,2754,2802,2848,2892,2934,2972,3010
                        dw 3044,3076,3108,3138,3164,3190,3216,3238,3260,3280,3300,3318,3336,3352,3368,3382
                        dw 3396,3410,3422,3434,3444,3454,3464,3474,3482,3490,3498,3506,3512,3518,3526,3532
                        dw 3536,3542,3546,3552,3556,3560,3564,3568,3570,3570
note_freq_ptrs_e        = *
                        dw 0,156,352,536,710,874,1028,1174,1312,1442,1564,1680,1790,1892,1988,2080
                        dw 2168,2250,2326,2400,2468,2534,2596,2654,2708,2760,2808,2854,2898,2938,2978,3014
                        dw 3048,3080,3112,3140,3168,3194,3218,3242,3262,3284,3302,3320,3338,3354,3370,3384
                        dw 3398,3412,3424,3436,3444,3456,3464,3474,3484,3492,3500,3506,3514,3520,3526,3532
                        dw 3536,3542,3548,3552,3556,3560,3564,3568,3572,3572
note_freq_ptrs_f        = *
                        dw 0,180,374,558,730,892,1046,1190,1328,1456,1578,1694,1802,1904,2000,2092
                        dw 2178,2260,2336,2408,2478,2542,2602,2660,2714,2766,2814,2860,2902,2944,2982,3018
                        dw 3052,3084,3116,3144,3172,3196,3222,3244,3266,3286,3306,3324,3340,3356,3372,3386
                        dw 3400,3412,3424,3436,3446,3458,3466,3476,3484,3492,3500,3508,3514,3520,3526,3532
                        dw 3538,3544,3548,3552,3556,3560,3564,3568,3572,3572
max_freq_ptr            = 146
note_freq_ptrs_offset   = *
                        dw note_freq_ptrs_0-note_freq_ptrs
                        dw note_freq_ptrs_1-note_freq_ptrs
                        dw note_freq_ptrs_2-note_freq_ptrs
                        dw note_freq_ptrs_3-note_freq_ptrs
                        dw note_freq_ptrs_4-note_freq_ptrs
                        dw note_freq_ptrs_5-note_freq_ptrs
                        dw note_freq_ptrs_6-note_freq_ptrs
                        dw note_freq_ptrs_7-note_freq_ptrs
                        dw note_freq_ptrs_8-note_freq_ptrs
                        dw note_freq_ptrs_9-note_freq_ptrs
                        dw note_freq_ptrs_a-note_freq_ptrs
                        dw note_freq_ptrs_b-note_freq_ptrs
                        dw note_freq_ptrs_c-note_freq_ptrs
                        dw note_freq_ptrs_d-note_freq_ptrs
                        dw note_freq_ptrs_e-note_freq_ptrs
                        dw note_freq_ptrs_f-note_freq_ptrs

waveforms               dw 0,2048,4096,4096 ;random=square in protracker!

sine_tbl                = *
                        dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
                        dw 0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,0,0,0,0,0
                        dw 0,0,0,2,2,2,2,2,2,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,2,2,2,2,2,2,0,0,0,0,0,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,0,0
                        dw 0,0,2,2,2,2,4,4,4,4,4,6,6,6,6,6,6,6,6,6,6,6,4,4,4,4,4,2,2,2,2,0,0,0,$fffe,$fffe,$fffe,$fffe,$fffc,$fffc,$fffc,$fffc,$fffc,$fffa,$fffa,$fffa,$fffa,$fffa,$fffa,$fffa,$fffa,$fffa,$fffa,$fffa,$fffc,$fffc,$fffc,$fffc,$fffc,$fffe,$fffe,$fffe,$fffe,0
                        dw 0,0,2,2,4,4,4,6,6,6,6,8,8,8,8,8,8,8,8,8,8,8,6,6,6,6,4,4,4,2,2,0,0,0,$fffe,$fffe,$fffc,$fffc,$fffc,$fffa,$fffa,$fffa,$fffa,$fff8,$fff8,$fff8,$fff8,$fff8,$fff8,$fff8,$fff8,$fff8,$fff8,$fff8,$fffa,$fffa,$fffa,$fffa,$fffc,$fffc,$fffc,$fffe,$fffe,0
                        dw 0,0,2,2,4,4,6,6,8,8,8,8,$a,$a,$a,$a,$a,$a,$a,$a,$a,8,8,8,8,6,6,4,4,2,2,0,0,0,$fffe,$fffe,$fffc,$fffc,$fffa,$fffa,$fff8,$fff8,$fff8,$fff8,$fff6,$fff6,$fff6,$fff6,$fff6,$fff6,$fff6,$fff6,$fff6,$fff8,$fff8,$fff8,$fff8,$fffa,$fffa,$fffc,$fffc,$fffe,$fffe,0
                        dw 0,2,2,4,4,6,6,8,8,$a,$a,$a,$c,$c,$c,$c,$c,$c,$c,$c,$c,$a,$a,$a,8,8,6,6,4,4,2,2,0,$fffe,$fffe,$fffc,$fffc,$fffa,$fffa,$fff8,$fff8,$fff6,$fff6,$fff6,$fff4,$fff4,$fff4,$fff4,$fff4,$fff4,$fff4,$fff4,$fff4,$fff6,$fff6,$fff6,$fff8,$fff8,$fffa,$fffa,$fffc,$fffc,$fffe,$fffe
                        dw 0,2,2,4,6,6,8,8,$a,$a,$c,$c,$c,$e,$e,$e,$e,$e,$e,$e,$c,$c,$c,$a,$a,8,8,6,6,4,2,2,0,$fffe,$fffe,$fffc,$fffa,$fffa,$fff8,$fff8,$fff6,$fff6,$fff4,$fff4,$fff4,$fff2,$fff2,$fff2,$fff2,$fff2,$fff2,$fff2,$fff4,$fff4,$fff4,$fff6,$fff6,$fff8,$fff8,$fffa,$fffa,$fffc,$fffe,$fffe
                        dw 0,2,4,4,6,8,8,$a,$c,$c,$e,$e,$e,$10,$10,$10,$10,$10,$10,$10,$e,$e,$e,$c,$c,$a,8,8,6,4,4,2,0,$fffe,$fffc,$fffc,$fffa,$fff8,$fff8,$fff6,$fff4,$fff4,$fff2,$fff2,$fff2,$fff0,$fff0,$fff0,$fff0,$fff0,$fff0,$fff0,$fff2,$fff2,$fff2,$fff4,$fff4,$fff6,$fff8,$fff8,$fffa,$fffc,$fffc,$fffe
                        dw 0,2,4,6,6,8,$a,$c,$c,$e,$e,$10,$10,$12,$12,$12,$12,$12,$12,$12,$10,$10,$e,$e,$c,$c,$a,8,6,6,4,2,0,$fffe,$fffc,$fffa,$fffa,$fff8,$fff6,$fff4,$fff4,$fff2,$fff2,$fff0,$fff0,$ffee,$ffee,$ffee,$ffee,$ffee,$ffee,$ffee,$fff0,$fff0,$fff2,$fff2,$fff4,$fff4,$fff6,$fff8,$fffa,$fffa,$fffc,$fffe
                        dw 0,2,4,6,8,$a,$c,$c,$e,$10,$10,$12,$12,$14,$14,$14,$14,$14,$14,$14,$12,$12,$10,$10,$e,$c,$c,$a,8,6,4,2,0,$fffe,$fffc,$fffa,$fff8,$fff6,$fff4,$fff4,$fff2,$fff0,$fff0,$ffee,$ffee,$ffec,$ffec,$ffec,$ffec,$ffec,$ffec,$ffec,$ffee,$ffee,$fff0,$fff0,$fff2,$fff4,$fff4,$fff6,$fff8,$fffa,$fffc,$fffe
                        dw 0,2,4,6,8,$a,$c,$e,$10,$12,$12,$14,$14,$16,$16,$16,$16,$16,$16,$16,$14,$14,$12,$12,$10,$e,$c,$a,8,6,4,2,0,$fffe,$fffc,$fffa,$fff8,$fff6,$fff4,$fff2,$fff0,$ffee,$ffee,$ffec,$ffec,$ffea,$ffea,$ffea,$ffea,$ffea,$ffea,$ffea,$ffec,$ffec,$ffee,$ffee,$fff0,$fff2,$fff4,$fff6,$fff8,$fffa,$fffc,$fffe
                        dw 0,2,4,6,$a,$c,$e,$10,$10,$12,$14,$16,$16,$16,$18,$18,$18,$18,$18,$16,$16,$16,$14,$12,$10,$10,$e,$c,$a,6,4,2,0,$fffe,$fffc,$fffa,$fff6,$fff4,$fff2,$fff0,$fff0,$ffee,$ffec,$ffea,$ffea,$ffea,$ffe8,$ffe8,$ffe8,$ffe8,$ffe8,$ffea,$ffea,$ffea,$ffec,$ffee,$fff0,$fff0,$fff2,$fff4,$fff6,$fffa,$fffc,$fffe
                        dw 0,2,6,8,$a,$c,$e,$10,$12,$14,$16,$16,$18,$18,$1a,$1a,$1a,$1a,$1a,$18,$18,$16,$16,$14,$12,$10,$e,$c,$a,8,6,2,0,$fffe,$fffa,$fff8,$fff6,$fff4,$fff2,$fff0,$ffee,$ffec,$ffea,$ffea,$ffe8,$ffe8,$ffe6,$ffe6,$ffe6,$ffe6,$ffe6,$ffe8,$ffe8,$ffea,$ffea,$ffec,$ffee,$fff0,$fff2,$fff4,$fff6,$fff8,$fffa,$fffe
                        dw 0,2,6,8,$a,$e,$10,$12,$14,$16,$18,$18,$1a,$1a,$1c,$1c,$1c,$1c,$1c,$1a,$1a,$18,$18,$16,$14,$12,$10,$e,$a,8,6,2,0,$fffe,$fffa,$fff8,$fff6,$fff2,$fff0,$ffee,$ffec,$ffea,$ffe8,$ffe8,$ffe6,$ffe6,$ffe4,$ffe4,$ffe4,$ffe4,$ffe4,$ffe6,$ffe6,$ffe8,$ffe8,$ffea,$ffec,$ffee,$fff0,$fff2,$fff6,$fff8,$fffa,$fffe
                        dw 0,2,6,8,$c,$e,$10,$14,$16,$18,$18,$1a,$1c,$1c,$1e,$1e,$1e,$1e,$1e,$1c,$1c,$1a,$18,$18,$16,$14,$10,$e,$c,8,6,2,0,$fffe,$fffa,$fff8,$fff4,$fff2,$fff0,$ffec,$ffea,$ffe8,$ffe8,$ffe6,$ffe4,$ffe4,$ffe2,$ffe2,$ffe2,$ffe2,$ffe2,$ffe4,$ffe4,$ffe6,$ffe8,$ffe8,$ffea,$ffec,$fff0,$fff2,$fff4,$fff8,$fffa,$fffe

ramp_tbl                = *
                        dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
                        dw 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe
                        dw 4,4,4,4,4,4,4,4,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc
                        dw 6,6,6,6,6,6,4,4,4,4,4,4,4,4,4,4,4,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffa,$fffa,$fffa,$fffa,$fffa
                        dw 8,8,8,8,8,6,6,6,6,6,6,6,6,4,4,4,4,4,4,4,4,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffa,$fffa,$fffa,$fffa,$fffa,$fffa,$fffa,$fffa,$fff8,$fff8,$fff8,$fff8
                        dw $a,$a,$a,$a,8,8,8,8,8,8,6,6,6,6,6,6,6,4,4,4,4,4,4,2,2,2,2,2,2,0,0,0,0,0,0,0,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffa,$fffa,$fffa,$fffa,$fffa,$fffa,$fffa,$fff8,$fff8,$fff8,$fff8,$fff8,$fff8,$fff6,$fff6,$fff6
                        dw $c,$c,$c,$a,$a,$a,$a,$a,$a,8,8,8,8,8,6,6,6,6,6,4,4,4,4,4,4,2,2,2,2,2,0,0,0,0,0,$fffe,$fffe,$fffe,$fffe,$fffe,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffa,$fffa,$fffa,$fffa,$fffa,$fff8,$fff8,$fff8,$fff8,$fff8,$fff6,$fff6,$fff6,$fff6,$fff6,$fff6,$fff4,$fff4
                        dw $e,$e,$e,$c,$c,$c,$c,$a,$a,$a,$a,$a,8,8,8,8,8,6,6,6,6,4,4,4,4,4,2,2,2,2,0,0,0,0,0,$fffe,$fffe,$fffe,$fffe,$fffc,$fffc,$fffc,$fffc,$fffc,$fffa,$fffa,$fffa,$fffa,$fff8,$fff8,$fff8,$fff8,$fff8,$fff6,$fff6,$fff6,$fff6,$fff6,$fff4,$fff4,$fff4,$fff4,$fff2,$fff2
                        dw $10,$10,$10,$e,$e,$e,$e,$c,$c,$c,$c,$a,$a,$a,$a,8,8,8,8,6,6,6,6,4,4,4,4,2,2,2,2,0,0,0,$fffe,$fffe,$fffe,$fffe,$fffc,$fffc,$fffc,$fffc,$fffa,$fffa,$fffa,$fffa,$fff8,$fff8,$fff8,$fff8,$fff6,$fff6,$fff6,$fff6,$fff4,$fff4,$fff4,$fff4,$fff2,$fff2,$fff2,$fff2,$fff0,$fff0
                        dw $12,$12,$10,$10,$10,$10,$e,$e,$e,$c,$c,$c,$c,$a,$a,$a,$a,8,8,8,6,6,6,6,4,4,4,2,2,2,2,0,0,0,$fffe,$fffe,$fffe,$fffe,$fffc,$fffc,$fffc,$fffa,$fffa,$fffa,$fffa,$fff8,$fff8,$fff8,$fff6,$fff6,$fff6,$fff6,$fff4,$fff4,$fff4,$fff4,$fff2,$fff2,$fff2,$fff0,$fff0,$fff0,$fff0,$ffee
                        dw $14,$14,$12,$12,$12,$10,$10,$10,$10,$e,$e,$e,$c,$c,$c,$a,$a,$a,8,8,8,6,6,6,6,4,4,4,2,2,2,0,0,0,$fffe,$fffe,$fffe,$fffc,$fffc,$fffc,$fffa,$fffa,$fffa,$fffa,$fff8,$fff8,$fff8,$fff6,$fff6,$fff6,$fff4,$fff4,$fff4,$fff2,$fff2,$fff2,$fff0,$fff0,$fff0,$fff0,$ffee,$ffee,$ffee,$ffec
                        dw $16,$16,$14,$14,$14,$12,$12,$12,$10,$10,$10,$e,$e,$e,$c,$c,$c,$a,$a,8,8,8,6,6,6,4,4,4,2,2,2,0,0,0,$fffe,$fffe,$fffe,$fffc,$fffc,$fffc,$fffa,$fffa,$fffa,$fff8,$fff8,$fff8,$fff6,$fff6,$fff4,$fff4,$fff4,$fff2,$fff2,$fff2,$fff0,$fff0,$fff0,$ffee,$ffee,$ffee,$ffec,$ffec,$ffec,$ffea
                        dw $18,$18,$16,$16,$16,$14,$14,$12,$12,$12,$10,$10,$10,$e,$e,$c,$c,$c,$a,$a,$a,8,8,6,6,6,4,4,4,2,2,0,0,0,$fffe,$fffe,$fffc,$fffc,$fffc,$fffa,$fffa,$fffa,$fff8,$fff8,$fff6,$fff6,$fff6,$fff4,$fff4,$fff4,$fff2,$fff2,$fff0,$fff0,$fff0,$ffee,$ffee,$ffee,$ffec,$ffec,$ffea,$ffea,$ffea,$ffe8
                        dw $1a,$1a,$18,$18,$16,$16,$16,$14,$14,$12,$12,$12,$10,$10,$e,$e,$e,$c,$c,$a,$a,8,8,8,6,6,4,4,4,2,2,0,0,0,$fffe,$fffe,$fffc,$fffc,$fffc,$fffa,$fffa,$fff8,$fff8,$fff8,$fff6,$fff6,$fff4,$fff4,$fff2,$fff2,$fff2,$fff0,$fff0,$ffee,$ffee,$ffee,$ffec,$ffec,$ffea,$ffea,$ffea,$ffe8,$ffe8,$ffe6
                        dw $1c,$1c,$1a,$1a,$18,$18,$16,$16,$16,$14,$14,$12,$12,$10,$10,$e,$e,$e,$c,$c,$a,$a,8,8,8,6,6,4,4,2,2,0,0,0,$fffe,$fffe,$fffc,$fffc,$fffa,$fffa,$fff8,$fff8,$fff8,$fff6,$fff6,$fff4,$fff4,$fff2,$fff2,$fff2,$fff0,$fff0,$ffee,$ffee,$ffec,$ffec,$ffea,$ffea,$ffea,$ffe8,$ffe8,$ffe6,$ffe6,$ffe4
                        dw $1e,$1e,$1c,$1c,$1a,$1a,$18,$18,$16,$16,$14,$14,$12,$12,$10,$10,$10,$e,$e,$c,$c,$a,$a,8,8,6,6,4,4,2,2,0,0,0,$fffe,$fffe,$fffc,$fffc,$fffa,$fffa,$fff8,$fff8,$fff6,$fff6,$fff4,$fff4,$fff2,$fff2,$fff0,$fff0,$fff0,$ffee,$ffee,$ffec,$ffec,$ffea,$ffea,$ffe8,$ffe8,$ffe6,$ffe6,$ffe4,$ffe4,$ffe2

square_tbl              = *
                        dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
                        dw 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe,$fffe
                        dw 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc,$fffc
                        dw 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,$fffa,$fffa,$fffa,$fffa,$fffa,$fffa,$fffa,$fffa,$fffa,$fffa,$fffa,$fffa,$fffa,$fffa,$fffa,$fffa,$fffa,$fffa,$fffa,$fffa,$fffa,$fffa,$fffa,$fffa,$fffa,$fffa,$fffa,$fffa,$fffa,$fffa,$fffa,$fffa
                        dw 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,$fff8,$fff8,$fff8,$fff8,$fff8,$fff8,$fff8,$fff8,$fff8,$fff8,$fff8,$fff8,$fff8,$fff8,$fff8,$fff8,$fff8,$fff8,$fff8,$fff8,$fff8,$fff8,$fff8,$fff8,$fff8,$fff8,$fff8,$fff8,$fff8,$fff8,$fff8,$fff8
                        dw $a,$a,$a,$a,$a,$a,$a,$a,$a,$a,$a,$a,$a,$a,$a,$a,$a,$a,$a,$a,$a,$a,$a,$a,$a,$a,$a,$a,$a,$a,$a,$a,$fff6,$fff6,$fff6,$fff6,$fff6,$fff6,$fff6,$fff6,$fff6,$fff6,$fff6,$fff6,$fff6,$fff6,$fff6,$fff6,$fff6,$fff6,$fff6,$fff6,$fff6,$fff6,$fff6,$fff6,$fff6,$fff6,$fff6,$fff6,$fff6,$fff6,$fff6,$fff6
                        dw $c,$c,$c,$c,$c,$c,$c,$c,$c,$c,$c,$c,$c,$c,$c,$c,$c,$c,$c,$c,$c,$c,$c,$c,$c,$c,$c,$c,$c,$c,$c,$c,$fff4,$fff4,$fff4,$fff4,$fff4,$fff4,$fff4,$fff4,$fff4,$fff4,$fff4,$fff4,$fff4,$fff4,$fff4,$fff4,$fff4,$fff4,$fff4,$fff4,$fff4,$fff4,$fff4,$fff4,$fff4,$fff4,$fff4,$fff4,$fff4,$fff4,$fff4,$fff4
                        dw $e,$e,$e,$e,$e,$e,$e,$e,$e,$e,$e,$e,$e,$e,$e,$e,$e,$e,$e,$e,$e,$e,$e,$e,$e,$e,$e,$e,$e,$e,$e,$e,$fff2,$fff2,$fff2,$fff2,$fff2,$fff2,$fff2,$fff2,$fff2,$fff2,$fff2,$fff2,$fff2,$fff2,$fff2,$fff2,$fff2,$fff2,$fff2,$fff2,$fff2,$fff2,$fff2,$fff2,$fff2,$fff2,$fff2,$fff2,$fff2,$fff2,$fff2,$fff2
                        dw $10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$fff0,$fff0,$fff0,$fff0,$fff0,$fff0,$fff0,$fff0,$fff0,$fff0,$fff0,$fff0,$fff0,$fff0,$fff0,$fff0,$fff0,$fff0,$fff0,$fff0,$fff0,$fff0,$fff0,$fff0,$fff0,$fff0,$fff0,$fff0,$fff0,$fff0,$fff0,$fff0
                        dw $12,$12,$12,$12,$12,$12,$12,$12,$12,$12,$12,$12,$12,$12,$12,$12,$12,$12,$12,$12,$12,$12,$12,$12,$12,$12,$12,$12,$12,$12,$12,$12,$ffee,$ffee,$ffee,$ffee,$ffee,$ffee,$ffee,$ffee,$ffee,$ffee,$ffee,$ffee,$ffee,$ffee,$ffee,$ffee,$ffee,$ffee,$ffee,$ffee,$ffee,$ffee,$ffee,$ffee,$ffee,$ffee,$ffee,$ffee,$ffee,$ffee,$ffee,$ffee
                        dw $14,$14,$14,$14,$14,$14,$14,$14,$14,$14,$14,$14,$14,$14,$14,$14,$14,$14,$14,$14,$14,$14,$14,$14,$14,$14,$14,$14,$14,$14,$14,$14,$ffec,$ffec,$ffec,$ffec,$ffec,$ffec,$ffec,$ffec,$ffec,$ffec,$ffec,$ffec,$ffec,$ffec,$ffec,$ffec,$ffec,$ffec,$ffec,$ffec,$ffec,$ffec,$ffec,$ffec,$ffec,$ffec,$ffec,$ffec,$ffec,$ffec,$ffec,$ffec
                        dw $16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$ffea,$ffea,$ffea,$ffea,$ffea,$ffea,$ffea,$ffea,$ffea,$ffea,$ffea,$ffea,$ffea,$ffea,$ffea,$ffea,$ffea,$ffea,$ffea,$ffea,$ffea,$ffea,$ffea,$ffea,$ffea,$ffea,$ffea,$ffea,$ffea,$ffea,$ffea,$ffea
                        dw $18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$ffe8,$ffe8,$ffe8,$ffe8,$ffe8,$ffe8,$ffe8,$ffe8,$ffe8,$ffe8,$ffe8,$ffe8,$ffe8,$ffe8,$ffe8,$ffe8,$ffe8,$ffe8,$ffe8,$ffe8,$ffe8,$ffe8,$ffe8,$ffe8,$ffe8,$ffe8,$ffe8,$ffe8,$ffe8,$ffe8,$ffe8,$ffe8
                        dw $1a,$1a,$1a,$1a,$1a,$1a,$1a,$1a,$1a,$1a,$1a,$1a,$1a,$1a,$1a,$1a,$1a,$1a,$1a,$1a,$1a,$1a,$1a,$1a,$1a,$1a,$1a,$1a,$1a,$1a,$1a,$1a,$ffe6,$ffe6,$ffe6,$ffe6,$ffe6,$ffe6,$ffe6,$ffe6,$ffe6,$ffe6,$ffe6,$ffe6,$ffe6,$ffe6,$ffe6,$ffe6,$ffe6,$ffe6,$ffe6,$ffe6,$ffe6,$ffe6,$ffe6,$ffe6,$ffe6,$ffe6,$ffe6,$ffe6,$ffe6,$ffe6,$ffe6,$ffe6
                        dw $1c,$1c,$1c,$1c,$1c,$1c,$1c,$1c,$1c,$1c,$1c,$1c,$1c,$1c,$1c,$1c,$1c,$1c,$1c,$1c,$1c,$1c,$1c,$1c,$1c,$1c,$1c,$1c,$1c,$1c,$1c,$1c,$ffe4,$ffe4,$ffe4,$ffe4,$ffe4,$ffe4,$ffe4,$ffe4,$ffe4,$ffe4,$ffe4,$ffe4,$ffe4,$ffe4,$ffe4,$ffe4,$ffe4,$ffe4,$ffe4,$ffe4,$ffe4,$ffe4,$ffe4,$ffe4,$ffe4,$ffe4,$ffe4,$ffe4,$ffe4,$ffe4,$ffe4,$ffe4
                        dw $1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$ffe2,$ffe2,$ffe2,$ffe2,$ffe2,$ffe2,$ffe2,$ffe2,$ffe2,$ffe2,$ffe2,$ffe2,$ffe2,$ffe2,$ffe2,$ffe2,$ffe2,$ffe2,$ffe2,$ffe2,$ffe2,$ffe2,$ffe2,$ffe2,$ffe2,$ffe2,$ffe2,$ffe2,$ffe2,$ffe2,$ffe2,$ffe2

pattern_break_ptrs      = *
                        dfb 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0
                        dfb 10,11,12,13,14,15,16,17,18,19,0,0,0,0,0,0
                        dfb 20,21,22,23,24,25,26,27,28,29,0,0,0,0,0,0
                        dfb 30,31,32,33,34,35,36,37,38,39,0,0,0,0,0,0
                        dfb 40,41,42,43,44,45,46,47,48,49,0,0,0,0,0,0
                        dfb 50,51,52,53,54,55,56,57,58,59,0,0,0,0,0,0
                        dfb 60,61,62,63,0,0,0,0,0,0,0,0,0,0,0,0
                        dfb 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
                        dfb 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
                        dfb 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
                        dfb 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
                        dfb 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
                        dfb 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
                        dfb 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
                        dfb 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
                        dfb 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

bpm_to_freq             = *
                        dw 64,66,68,70,72,74,76,78,80,82,84,86,88,90,92,94
                        dw 96,98,100,102,104,106,108,110,112,114,116,118,120,122,124,125
                        dw 127,129,131,133,135,137,139,141,143,145,147,149,151,153,155,157
                        dw 159,161,163,165,167,169,171,173,175,177,179,181,183,185,187,189
                        dw 191,193,195,197,199,201,203,205,207,209,211,213,215,217,219,221
                        dw 223,225,227,229,231,233,235,237,239,241,243,245,247,249,251,253
                        dw 255,257,259,261,263,265,267,269,271,273,275,277,279,281,283,285
                        dw 287,289,291,293,295,297,299,301,303,305,307,309,311,313,315,317
                        dw 319,321,323,325,327,329,331,333,335,337,339,341,343,345,347,349
                        dw 351,353,355,357,359,361,363,365,367,369,371,372,374,376,378,380
                        dw 382,384,386,388,390,392,394,396,398,400,402,404,406,408,410,412
                        dw 414,416,418,420,422,424,426,428,430,432,434,436,438,440,442,444
                        dw 446,448,450,452,454,456,458,460,462,464,466,468,470,472,474,476
                        dw 478,480,482,484,486,488,490,492,494,496,498,500,502,504,506,508

reg_tbl_freqhi          = *
                        dw 32,34,36,38,40,42,44,46,48,50,52,54,56,58,60
reg_tbl_vol             = *
                        dw 64,66,68,70,72,74,76,78,80,82,84,86,88,90,92
reg_tbl_ptr             = *
                        dw 128,130,132,134,136,138,140,142,144,146,148,150,152,154,156
reg_tbl_ctl             = *
                        dw 160,162,164,166,168,170,172,174,176,178,180,182,184,186,188
reg_tbl_siz             = *
                        dw 192,194,196,198,200,202,204,206,208,210,212,214,216,218,220

;--------------------------

zero_out_begin          = *                             ;for init, we're writing zeros from here

ptr_header              ds  4                           ;pointer to file start
ptr_notes               ds  4                           ;pointer to music notes
ptr_instruments         ds  4                           ;pointer to instrument start

play_song_once          dw  0                           ;0=loop song, else do stop song after one play

number_of_tracks        dw  0                           ;1-15
number_of_instruments   dw  0                           ;1-255
number_of_patterns      dw  0                           ;1-255
pattern_length          dw  0                           ;pattern length in bytes (=4 bytes x number_of_tracks x 64, can be 3584 bytes max.)
track_channels          ds  max_tracks_available*2      ;1 word of stereo setting for each track
pattern_order_length    dw  0                           ;how many entries there are in pattern_order
pattern_order           ds  256                         ;in which order the patterns should be played

instrument_types        ds  512                         ;1 word per instrument
instrument_lengths      ds  512
instrument_volumes      ds  512
instrument_finetune     ds  512                         ;instrument finetune value * 2
instrument_osc_a_ptr    ds  512
instrument_osc_b_ptr    ds  512
instrument_osc_a_siz    ds  512
instrument_osc_b_siz    ds  512
instrument_osc_a_ctl    ds  512
instrument_osc_b_ctl    ds  512

copy_instrument_length  dw  0

pattern_pointers        ds  1024                        ;for every pattern, calculate the offset into memory

number_of_tracks2       dw  0                           ;number of tracks x 2
number_of_instruments2  dw  0                           ;number_of_instruments x 2
number_of_tracks4       dw  0                           ;number of tracks x 4 = number of bytes in a pattern line

backup_interrupt_ptr    ds  4

playing                 dw  0                           ;0=not playing, 1=playing
tempo                   dw  0
timer                   dw  0

pattern_jump            dw  0                           ;0=no jump, 2=pattern_jump_param has next songpos, 4=pattern_jump_param has next pointer in pattern
pattern_jump_param      dw  0
force_pattern_jump      dw  0                           ;0=no jump, else force jump on next occasion
force_pattern_jump_p    dw  0                           ;jump to this songpos

loop_position           dw  0                           ;position where to jump to in the current frame
loop_repeat_count       dw  0                           ;number of times the loop should be repeated
loop_position_active    dw  0                           ;0=loop not running, else=loop running
loop_position_jump      dw  0                           ;$ffff=no position jump, else=jump to this position

pattern_order_ptr       dw  0                           ;current position in the pattern order
ptr_within_pattern      dw  0                           ;offset in bytes to current line in the pattern

note                    dw  0                           ;read note*2
sample                  dw  0                           ;read sample*2
effect                  dw  0                           ;read effect*2
effect_param            dw  0                           ;just the effect parameter

oscillator              dw  0

osc_interrupt_freq      dw  0
new_osc_interrupt_freq  dw  0

delay_pattern           dw  0                           ;after the current line, do a delay of X rows

what_to_do              ds  max_tracks_available*2      ;what to send to the shound chip (bit field)

;the last line that we got from the pattern
curr_note               ds  max_tracks_available*2      ;note number * 2
curr_sample             ds  max_tracks_available*2      ;sample number * 2
curr_effect             ds  max_tracks_available*2      ;effect number * 2
curr_e_effect           ds  max_tracks_available*2      ;e-effect number * 2
curr_ptrfinetune        ds  max_tracks_available*2      ;ptr into the big finetune table
curr_volume             ds  max_tracks_available*2      ;the volume for this track (0-64)

arpeggio_ptr            ds  max_tracks_available*2      ;when 0, arpeggio is off, $8000=note 1, $8001=note 2, $8003=note 3
arpeggio_note1          ds  max_tracks_available*2
arpeggio_note2          ds  max_tracks_available*2
arpeggio_note3          ds  max_tracks_available*2

slide_delta             ds  max_tracks_available*2
slide_target            ds  max_tracks_available*2
slide_target_note       ds  max_tracks_available*2

vibrato_tableoffset     ds  max_tracks_available*2
vibrato_table           ds  max_tracks_available*2
vibrato_rate            ds  max_tracks_available*2
vibrato_pos             ds  max_tracks_available*2
vibrato_retrig          ds  max_tracks_available*2

tremolo_tableoffset     ds  max_tracks_available*2
tremolo_table           ds  max_tracks_available*2
tremolo_rate            ds  max_tracks_available*2
tremolo_pos             ds  max_tracks_available*2
tremolo_retrig          ds  max_tracks_available*2

volslide_delta          ds  max_tracks_available*2

retrigger_steps         ds  max_tracks_available*2
retrigger_count         ds  max_tracks_available*2

note_cut                ds  max_tracks_available*2

note_delay_count        ds  max_tracks_available*2
note_delay_note         ds  max_tracks_available*2

osc_freq                ds  max_tracks_available*2
osc_volume              ds  max_tracks_available*2
osc_instrument          ds  max_tracks_available*2

glissando               ds  max_tracks_available*2      ;0=no glissando, 1=glissando

last_effect_8_param     dw  0

vu_number_of_tracks     dw  0
vu_data                 ds  max_tracks_available*2

zero_out_end            = *                             ;for init, we're writing zeros until here
