257 lines
8.1 KiB
NASM
257 lines
8.1 KiB
NASM
;*****************************************************************
|
|
;
|
|
; Light Speed Player v1.11
|
|
; Fastest Amiga MOD player ever :)
|
|
; Written By Arnaud Carré (aka Leonard / OXYGENE)
|
|
; Adapted to demo framework (and optimized) by platon42.
|
|
;
|
|
; https://github.com/arnaud-carre/LSPlayer
|
|
; twitter: @leonard_coder
|
|
;
|
|
; "small & fast" player version ( average time: 1 scanline )
|
|
; Less than 512 bytes of code!
|
|
; You can also use generated "insane" player code for even more half scanline replayer (-insane option)
|
|
;
|
|
; LSP_MusicInit Initialize a LSP driver + relocate score&bank music data
|
|
; LSP_MusicPlayTick Play a LSP music (call it per frame)
|
|
; LSP_MusicGetPos Get mod seq pos (see -setpos option in LSPConvert)
|
|
; LSP_MusicSetPos Set mod seq pos (see -getpos option in LSPConvert)
|
|
;
|
|
;*****************************************************************
|
|
|
|
;------------------------------------------------------------------
|
|
;
|
|
; LSP_MusicPlayTick
|
|
;
|
|
; In: a5: should be $dff000
|
|
; Scratched regs: d0-d2/a0-a4
|
|
; Out:None
|
|
;
|
|
;------------------------------------------------------------------
|
|
LSP_MusicPlayTick:
|
|
addq.w #1,fw_MusicFrameCount(a6)
|
|
lea fw_LspByteStream(a6),a3
|
|
move.l (a3),a0 ; fw_LspByteStream, byte stream
|
|
move.l fw_LspCodeTableAddr(a6),a2 ; code table
|
|
|
|
.process
|
|
moveq.l #0,d0
|
|
move.b (a0)+,d0
|
|
beq.s .cextended
|
|
add.w d0,d0
|
|
move.w (a2,d0.w),d0 ; code
|
|
bne.s .cmdExec
|
|
.noInstBS
|
|
move.l a0,(a3) ; fw_LspByteStream, store byte stream if coming from early out
|
|
rts
|
|
|
|
.cextended
|
|
add.w #$0100,d0
|
|
move.b (a0)+,d0
|
|
beq.s .cextended
|
|
add.w d0,d0
|
|
move.w (a2,d0.w),d0 ; code
|
|
lea fw_LspEscCodeRewind(a6),a1
|
|
cmp.w (a1)+,d0 ; fw_LspEscCodeRewind
|
|
beq.s .r_rewind
|
|
cmp.w (a1)+,d0 ; fw_LspEscCodeSetBpm
|
|
beq.s .r_chgBpm
|
|
cmp.w (a1)+,d0 ; fw_LspEscCodeGetPos
|
|
bne.s .cmdExec
|
|
|
|
.r_setPos
|
|
move.b (a0)+,fw_LspCurrentSeq+1(a6)
|
|
bra.s .process
|
|
|
|
.r_rewind
|
|
move.l fw_LspByteStreamLoop(a6),a0
|
|
move.l fw_LspWordStreamLoop(a6),fw_LspWordStream(a6)
|
|
bra.s .process
|
|
|
|
.r_chgBpm
|
|
move.b (a0)+,fw_LspCurrentBpm+1(a6) ; BPM
|
|
bra.s .process
|
|
|
|
.cmdExec
|
|
add.b d0,d0
|
|
bcc.s .noVd
|
|
move.b (a0)+,aud3+ac_vol+1(a5)
|
|
.noVd add.b d0,d0
|
|
bcc.s .noVc
|
|
move.b (a0)+,aud2+ac_vol+1(a5)
|
|
.noVc add.b d0,d0
|
|
bcc.s .noVb
|
|
move.b (a0)+,aud1+ac_vol+1(a5)
|
|
.noVb add.b d0,d0
|
|
bcc.s .noVa
|
|
move.b (a0)+,aud0+ac_vol+1(a5)
|
|
.noVa
|
|
move.l a0,(a3)+ ; fw_LspByteStream, store byte stream ptr
|
|
move.l (a3),a0 ; fw_LspWordStream, word stream
|
|
|
|
tst.b d0
|
|
beq.s .noPa
|
|
|
|
add.b d0,d0
|
|
bcc.s .noPd
|
|
move.w (a0)+,aud3+ac_per(a5)
|
|
.noPd add.b d0,d0
|
|
bcc.s .noPc
|
|
move.w (a0)+,aud2+ac_per(a5)
|
|
.noPc add.b d0,d0
|
|
bcc.s .noPb
|
|
move.w (a0)+,aud1+ac_per(a5)
|
|
.noPb add.b d0,d0
|
|
bcc.s .noPa
|
|
move.w (a0)+,aud0+ac_per(a5)
|
|
.noPa
|
|
tst.w d0
|
|
beq.s .noInstWS
|
|
|
|
moveq.l #0,d1
|
|
move.l fw_LspInstruments(a6),a2 ; instrument table
|
|
lea fw_LspResetv+4*4(a6),a4
|
|
|
|
lea aud+3*ac_SIZEOF(a5),a1
|
|
moveq.l #4-1,d2
|
|
.vloop add.w d0,d0
|
|
bcs.s .setIns
|
|
add.w d0,d0
|
|
; suppress M68kUnexpectedConditionalInstruction
|
|
move.l -(a4),a3 ; take loop data
|
|
bcc.s .skip
|
|
move.l (a3)+,ac_ptr(a1) ; and update pointer/len with it
|
|
move.w (a3)+,ac_len(a1) ; (usually triggered from previous frame)
|
|
bra.s .skip
|
|
.setIns
|
|
add.w (a0)+,a2
|
|
add.w d0,d0
|
|
bcc.s .noReset
|
|
bset d2,d1
|
|
move.w d1,dmacon(a5)
|
|
.noReset
|
|
move.l (a2)+,ac_ptr(a1)
|
|
move.w (a2)+,ac_len(a1)
|
|
move.l a2,-(a4) ; set reset values for next iteration to contain loop data
|
|
.skip lea -ac_SIZEOF(a1),a1
|
|
dbra d2,.vloop
|
|
|
|
move.l fw_LspDmaConPatch(a6),a1 ; dmacon patch
|
|
move.b d1,(a1) ; dmacon
|
|
|
|
.noInstWS
|
|
move.l a0,fw_LspWordStream(a6) ; store word stream
|
|
rts
|
|
|
|
;------------------------------------------------------------------
|
|
;
|
|
; LSP_MusicInit
|
|
;
|
|
; In: a0: LSP music data (any memory)
|
|
; a1: LSP sound bank (chip memory)
|
|
;
|
|
;------------------------------------------------------------------
|
|
LSP_DataError:
|
|
illegal
|
|
LSP_MusicInit:
|
|
cmp.l #'LSP1',(a0)+
|
|
bne.s LSP_DataError
|
|
move.l (a0)+,d0 ; unique id
|
|
cmp.l (a1),d0 ; check that sample bank is this one
|
|
bne.s LSP_DataError
|
|
|
|
cmp.w #$010b,(a0)+ ; v1.11 minimal major & minor version of latest compatible
|
|
blt.s LSP_DataError
|
|
moveq.l #0,d1
|
|
bset d1,(a0) ; test and mark this music score as "relocated"
|
|
bne.s .noRelocate
|
|
move.l a1,d1
|
|
.noRelocate
|
|
addq.w #2,a0 ; skip relocation flag
|
|
lea fw_LspCurrentBpm(a6),a3
|
|
move.w (a0)+,(a3)+ ; fw_LspCurrentBpm
|
|
move.l a0,(a3)+ ; fw_LspInstruments, LSP data has -12 offset on instrument tab (to win 2 cycles in fast player :))
|
|
move.w (a0)+,(a3)+ ; fw_LspEscCodeRewind
|
|
move.l (a0)+,(a3)+ ; fw_LspEscCodeSetBpm/fw_LspEscCodeGetPos
|
|
move.l (a0)+,(a3)+ ; fw_LspMusicLength
|
|
|
|
move.w (a0)+,d0 ; instrument count
|
|
add.w d0,d0
|
|
subq.w #1,d0
|
|
.relocLoop
|
|
add.l d1,(a0)+
|
|
addq.l #2,a0
|
|
dbra d0,.relocLoop
|
|
|
|
move.w (a0)+,d0 ; codes table size
|
|
move.l a0,fw_LspCodeTableAddr(a6) ; code table
|
|
add.w d0,d0
|
|
add.w d0,a0
|
|
|
|
; read sequence timing infos (if any)
|
|
move.w (a0)+,d0
|
|
move.w d0,(a3)+ ; fw_LspSeqCount
|
|
move.l a0,(a3)+ ; fw_LspSeqTable
|
|
clr.w (a3)+ ; fw_LspCurrentSeq
|
|
move.w d0,d1
|
|
lsl.w #3,d1 ; 8 bytes per entry
|
|
adda.w d1,a0
|
|
|
|
movem.l (a0)+,d0/d1/d2 ; word stream size/byte stream loop point/word stream loop point
|
|
move.l a0,(a3)+ ; fw_LspStreamBase
|
|
lea (a0,d0.l),a1 ; byte stream
|
|
move.l a1,(a3)+ ; fw_LspByteStream
|
|
move.l a0,(a3)+ ; fw_LspWordStream
|
|
add.l d1,a1
|
|
add.l d2,a0
|
|
move.l a1,(a3)+ ; fw_LspByteStreamLoop
|
|
move.l a0,(a3)+ ; fw_LspWordStreamLoop
|
|
bset #1,$bfe001 ; disabling this fucking Low pass filter!!
|
|
rts
|
|
|
|
;------------------------------------------------------------------
|
|
;
|
|
; LSP_MusicSetPos
|
|
;
|
|
; In: d0: seq position (from 0 to last seq of the song)
|
|
; Out:None
|
|
;
|
|
; Force the replay pointer to a seq position. If music wasn't converted
|
|
; using -setpos option, this func does nothing
|
|
;
|
|
;------------------------------------------------------------------
|
|
LSP_MusicSetPos:
|
|
lea fw_LspSeqCount(a6),a1
|
|
cmp.w (a1)+,d0 ; fw_LspSeqCount
|
|
bge.s .noTimingInfo
|
|
move.l (a1)+,a0 ; fw_LspSeqTable
|
|
move.w d0,(a1)+ ; fw_LspCurrentSeq
|
|
lsl.w #3,d0
|
|
lea 8(a0,d0.w),a0
|
|
move.l (a1)+,d0 ; fw_LspStreamBase
|
|
move.l -(a0),d1
|
|
add.l d0,d1
|
|
move.l d1,(a1)+ ; fw_LspByteStream
|
|
move.l -(a0),d1
|
|
add.l d0,d1
|
|
move.l d1,(a1)+ ; fw_LspWordStream
|
|
.noTimingInfo
|
|
rts
|
|
|
|
IF 0
|
|
;------------------------------------------------------------------
|
|
;
|
|
; LSP_MusicGetPos
|
|
;
|
|
; In: None
|
|
; Out: d0: seq position (from 0 to last seq of the song)
|
|
;
|
|
; Get the current seq position. If music wasn't converted with
|
|
; -getpos option, this func just returns 0
|
|
;
|
|
;------------------------------------------------------------------
|
|
LSP_MusicGetPos:
|
|
move.w fw_LspCurrentSeq(a6),d0
|
|
rts
|
|
ENDC
|