Files
dino-game/music/playlzs16.asm
T
2024-08-20 08:29:14 -04:00

200 lines
3.9 KiB
NASM

;
; LZSS Compressed SAP player for 16 match bits
; --------------------------------------------
;
; (c) 2020 DMSC
; Code under MIT license, see LICENSE file.
;
; This player uses:
; Match length: 8 bits (1 to 256)
; Match offset: 8 bits (1 to 256)
; Min length: 2
; Total match bits: 16 bits
;
; Compress using:
; lzss -b 16 -o 8 -m 1 input.rsap test.lz12
;
; Assemble this file with MADS assembler, the compressed song is expected in
; the `test.lz16` file at assembly time.
;
; The plater needs 256 bytes of buffer for each pokey register stored, for a
; full SAP file this is 2304 bytes.
;
org $e0
song_start_ptr .ds 2
song_end_ptr .ds 2
chn_copy .ds 9
chn_pos .ds 9
bptr .ds 2
cur_pos .ds 1
chn_bits .ds 1
bit_data .ds 1
;POKEY = $D200
org $2000
;player
jmp play_frame
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Song Initialization - this runs in the first tick:
;
.proc init_song
;POKEY_INIT
mva #0 AUDCTL
sta AUDCTL+$10
mva #3 SKSTAT
sta SKSTAT+$10
;clear buffers
lda #0
tax
@
:9 sta buffers+#*$100,x
inx
bne @-
mva #1 bit_data
; here initializes song pointer:
adw song_start_ptr #1 song_ptr
mva #>(buffers+255) cbuf+2
; Init all channels:
ldx #8
ldy #0
clear
; Read just init value and store into buffer and POKEY
jsr get_byte
sta POKEY, x
sta pokey_save,x
sty chn_copy, x
cbuf
sta buffers + 255
inc cbuf + 2
dex
bpl clear
; Initialize buffer pointer:
sty bptr
sty cur_pos
rts
.endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Play one frame of the song
;
.proc play_frame
; play old frame on second pokey
ldx #8
@ lda pokey_save,x
sta POKEY+$10,x
dex
bpl @-
lda #>buffers
sta bptr+1
ldy #0
lda (song_start_ptr),y
sta chn_bits
ldx #8
; Loop through all "channels", one for each POKEY register
chn_loop:
lsr chn_bits
bcs skip_chn ; C=1 : skip this channel
lda chn_copy, x ; Get status of this stream
bne do_copy_byte ; If > 0 we are copying bytes
; We are decoding a new match/literal
lsr bit_data ; Get next bit
bne got_bit
jsr get_byte ; Not enough bits, refill!
ror ; Extract a new bit and add a 1 at the high bit (from C set above)
sta bit_data ;
got_bit:
jsr get_byte ; Always read a byte, it could mean "match size/offset" or "literal byte"
bcs store ; Bit = 1 is "literal", bit = 0 is "match"
sta chn_pos, x ; Store in "copy pos"
jsr get_byte
sta chn_copy, x ; Store in "copy length"
; And start copying first byte
do_copy_byte:
dec chn_copy, x ; Decrease match length, increase match position
inc chn_pos, x
ldy chn_pos, x
; Now, read old data, jump to data store
lda (bptr), y
store:
ldy cur_pos
sta POKEY, x ; Store to output and buffer
sta pokey_save,x
sta (bptr), y
skip_chn:
; Increment channel buffer pointer
inc bptr+1
dex
bpl chn_loop ; Next channel
inc cur_pos
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Check for ending of song and jump to the next frame
;
check_end_song
cpw song_ptr song_end_ptr
scc:jsr init_song
rts
.endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
get_byte
lda song_ptr: $ffff ;song_data+1
inw song_ptr
rts
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
/* start
mwa #song_data song_start_ptr
mwa #song_end song_end_ptr
jsr init_song
@
lda:cmp:req 20
jsr player
lda $d01f ;consol
cmp #7
seq:jsr init_song
jmp @- */
pokey_save
.ds 9
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.align $100
buffers
.ds 256 * 9
;song_data
; ins 'InGame.lzss'
;song_end
; run start