;***************************************************************** ; ; 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 adda.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 lsl.w #3,d0 ; 8 bytes per entry adda.w d0,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