From 3aacf3d2cedfdeca49ceb57533389870bfc688a9 Mon Sep 17 00:00:00 2001 From: sik Date: Sun, 23 Jul 2017 03:20:35 -0300 Subject: Now with pausing and other niceties --- src-z80/build.z80 | 8 +- src-z80/core/bgm.z80 | 185 ++++++++++++++++++++------------ src-z80/core/macro.z80 | 41 +++++++ src-z80/core/main.z80 | 113 +++++++++----------- src-z80/core/sfx.z80 | 48 +++++++-- src-z80/core/vars.z80 | 18 +++- src-z80/player/fm.z80 | 30 ++++-- src-z80/player/misc.z80 | 55 ++++++++++ src-z80/player/pcm (copia).z80 | 236 +++++++++++++++++++++++++++++++++++++++++ src-z80/player/pcm.z80 | 197 +++++++++++++++++----------------- src-z80/player/psg.z80 | 6 +- 11 files changed, 685 insertions(+), 252 deletions(-) create mode 100644 src-z80/core/macro.z80 create mode 100644 src-z80/player/pcm (copia).z80 (limited to 'src-z80') diff --git a/src-z80/build.z80 b/src-z80/build.z80 index 1aaa709..2f7fd5f 100644 --- a/src-z80/build.z80 +++ b/src-z80/build.z80 @@ -1,11 +1,15 @@ - include "src-z80/core/main.z80" + jp EntryPoint ; Jump to the entry point + db 0,0,0,0,0 ; Padding to 0008h + + include "src-z80/core/macro.z80" include "src-z80/player/pcm.z80" + include "src-z80/core/main.z80" include "src-z80/core/bgm.z80" include "src-z80/core/sfx.z80" include "src-z80/core/direct.z80" include "src-z80/player/fm.z80" include "src-z80/player/psg.z80" include "src-z80/player/misc.z80" - + include "src-z80/player/freq.z80" include "src-z80/core/vars.z80" diff --git a/src-z80/core/bgm.z80 b/src-z80/core/bgm.z80 index 338a7a6..b48d87a 100644 --- a/src-z80/core/bgm.z80 +++ b/src-z80/core/bgm.z80 @@ -25,13 +25,14 @@ PlayBGM: PollPCM - xor a ; Command parsed - ld (RAM_Command), a + xor a ; Playing a BGM immediately unpauses playback + ld (RAM_Paused), a + inc a ld hl, RAM_BGMData ; Set BGM as playing - ld (hl), $01 + ld (hl), a inc l ; No delays! - ld (hl), $01 + ld (hl), a inc l ; Store BGM start bank ld (hl), c inc l ; Store BGM start address (low) @@ -44,55 +45,111 @@ PlayBGM: ld hl, ProcessBGM ; Tell Echo to process BGM ld (DoTick_BGM+1), hl - jp IdleLoop ; End of subroutine + jp EndOfCommand ; End of subroutine ;**************************************************************************** -; ResumeBGM [command $06] -; Resumes a stopped BGM +; PauseBGM [command $08] +; Pauses a playing BGM ;---------------------------------------------------------------------------- ; breaks: all ;**************************************************************************** -ResumeBGM: - xor a ; Command parsed - ld (RAM_Command), a +PauseBGM: + ld a, (RAM_BGMPlaying) ; Is BGM even playing? + or a + jp z, EndOfCommand + + ld a, 1 ; Halt BGM playback + ld (RAM_Paused), a ;---------------------------------------------------------------------------- - - ld b, 8 ; Restore all FM channels - ld de, RAM_Locked+7 -.restorefm: + ld b, $7F ; Mute all FM channels + ld c, 7 + ld hl, RAM_Locked+7 +.mutefm: PollPCM - - ld a, (de) ; Check if this channel is locked + ld a, (hl) or a - jp nz, .fmlocked - + jr nz, .nofmmute + ld a, c + call SetFMVolTempLoad +.nofmmute: PollPCM + dec l + dec c + jp p, .mutefm - dec b ; Restore FM channel - call RestoreFM - inc b - -.fmlocked: - dec e ; Go for next channel to restore - dec b - jp nz, .restorefm + ld b, 4 ; Mute all PSG channels + ld c, $0F + ld de, RAM_Locked+8 + ld hl, RAM_PSGData +.mutepsg: + PollPCM + ld a, (de) + or a + jr nz, .nopsgmute + ld a, (hl) + and $80 + or c, + ld (hl), a +.nopsgmute: + PollPCM + ld a, l + add 16 + ld l, a + inc e + djnz .mutepsg ;---------------------------------------------------------------------------- - ld a, (RAM_Status) ; Show BGM playback in Echo's status - or $02 - ld (RAM_Status), a + ld a, (RAM_Locked+6) ; Mute PCM channel + or a + call z, StopPCM - ld hl, RAM_BGMData ; Set BGM as playing - ld (hl), $01 +;---------------------------------------------------------------------------- + + jp EndOfCommand ; End of subroutine + +;**************************************************************************** +; ResumeBGM [command $06] +; Resumes a stopped BGM +;---------------------------------------------------------------------------- +; breaks: all +;**************************************************************************** + +ResumeBGM: + ld a, (RAM_BGMPlaying) ; Was BGM even playing? + or a + jp z, EndOfCommand - ld hl, ProcessBGM ; Tell Echo to process BGM - ld (DoTick_BGM+1), hl + xor a + ld (RAM_Paused), a ; Resume BGM playback - jp IdleLoop ; End of subroutine + ld b, 4 ; Restore PSG channels + ld de, RAM_Locked+11 + ld hl, RAM_PSGData+63 +.resumepsg: + PollPCM + ld c, (hl) + ld a, l + sub 15 + ld l, a + ld a, (de) + or a + jr nz, .nopsgresume + ld a, (hl) + and $80 + or c + ld (hl), a +.nopsgresume: + PollPCM + dec l + dec e + djnz .resumepsg + + call RefreshVolume ; Restore remaining channels + jp EndOfCommand ; End of subroutine ;**************************************************************************** ; ProcessBGM @@ -197,6 +254,9 @@ ProcessBGMEventFF: jp c, SetFMParamBGM cp $FA ; Events $F8-$F9: set FM register jp c, SetFMRegBGM + jp z, SetFlagsBGM ; Events $FA-$FB: set/clear flags + cp $FB + jp z, ClearFlagsBGM PollPCM ; FFFFFFFFF bad event >:( ProcessBGMEnd: @@ -234,10 +294,8 @@ StopBGMEvent: jp DoTick_BGMSkip ; End of subroutine StopBGMCmd: - xor a ; Command parsed - ld (RAM_Command), a call StopBGM ; We're just a wrapper - jp IdleLoop ; End of subroutine + jp EndOfCommand ; End of subroutine StopBGM: ld a, (RAM_Status) ; Hide BGM playback in Echo's status @@ -271,7 +329,7 @@ ClearBGM: ld b, 4 ; Reset all PSG channels ld de, RAM_PSGData+48+15 ld hl, RAM_Locked+11 -.mutepsg: +.killpsg: PollPCM ld (hl), $00 ; Reset BGM volume @@ -282,22 +340,22 @@ ClearBGM: ld a, (hl) ; Mute PSG channel if it isn't locked or a - jr nz, .nopsgmute + jr nz, .nopsgkill xor a ld (de), a -.nopsgmute: +.nopsgkill: PollPCM dec e dec l - djnz .mutepsg + djnz .killpsg ;---------------------------------------------------------------------------- ld b, 8 ; Reset all FM channels ld de, RAM_BGMFMVol+7 -.resetfm: +.killfm: PollPCM ld a, $7F ; Reset BGM volume @@ -328,10 +386,10 @@ ClearBGM: inc b .nofmkill: dec l - djnz .resetfm + djnz .killfm ;---------------------------------------------------------------------------- - + ld hl, RAM_BGMFMPan ; Reset panning status (for restoring) ld a, $C0 ld b, 8 @@ -339,6 +397,9 @@ ClearBGM: ld (hl), a inc l djnz .initpanstat + + xor a ; Reset flags + ld (RAM_Flags), a ret ; End of subroutine @@ -349,19 +410,11 @@ ClearBGM: LoopBGM: PollPCM - - ex de, hl ; Get looping address - inc l - ld c, (hl) - inc l - ld e, (hl) - inc l - ld d, (hl) - dec l - dec l - dec l - ex de, hl - + + ld hl, (RAM_BGMLoopPoint+1) ; Get looping address + ld a, (RAM_BGMLoopPoint) + ld c, a + jp ProcessBGMRun ; End of subroutine ;**************************************************************************** @@ -371,17 +424,9 @@ LoopBGM: SetLoopBGM: PollPCM - - ex de, hl - inc l ; Store loop point address - ld (hl), c - inc l - ld (hl), e - inc l - ld (hl), d - dec l - dec l - dec l - ex de, hl - + + ld a, c ; Store loop point address + ld (RAM_BGMLoopPoint), a + ld (RAM_BGMLoopPoint+1), hl + jp ProcessBGMRun ; End of subroutine diff --git a/src-z80/core/macro.z80 b/src-z80/core/macro.z80 new file mode 100644 index 0000000..eedd527 --- /dev/null +++ b/src-z80/core/macro.z80 @@ -0,0 +1,41 @@ +;**************************************************************************** +; PollPCM +; Used to update PCM while not idle +;---------------------------------------------------------------------------- +; breaks: af +;**************************************************************************** + +PollPCM: macro + ld a, ($4000) + rrca + rst $08 + endm + +;**************************************************************************** +; BankSwitch +; Switches into a new bank (won't update player status!) +;---------------------------------------------------------------------------- +; input A .... New bank to switch into +; input HL ... Must be $60xx +;---------------------------------------------------------------------------- +; breaks ..... AF +;**************************************************************************** + +BankSwitch: macro + ld (hl), a + rrca + ld (hl), a + rrca + ld (hl), a + rrca + ld (hl), a + rrca + ld (hl), a + rrca + ld (hl), a + rrca + ld (hl), a + ld (hl), h + rrca + ld (hl), a + endm diff --git a/src-z80/core/main.z80 b/src-z80/core/main.z80 index 4eb6e5a..387b879 100644 --- a/src-z80/core/main.z80 +++ b/src-z80/core/main.z80 @@ -4,10 +4,11 @@ ;**************************************************************************** EntryPoint: - ld sp, RAM_Stack ; Init stack + xor a ; Reset Echo status (we don't clear + ld (RAM_Status), a ; RAM_Command since Echo_Init fills in values + ld (RAM_Command2), a ; before Echo gets to run!) - xor a ; Reset Echo status - ld (RAM_Status), a + ld sp, RAM_Stack ; Init stack ld hl, $7F11 ; Mute PSG ld (hl), $9F @@ -87,23 +88,12 @@ EntryPoint: jp IdleLoop ; Go into idle loop -;**************************************************************************** -; PollPCM -; Used to update PCM while not idle -;---------------------------------------------------------------------------- -; breaks: af -;**************************************************************************** - -PollPCM: macro - ld a, ($4000) - rrca - call c, UpdatePCM - endm - ;**************************************************************************** ; RunCommand ; Checks which command to run ;---------------------------------------------------------------------------- +; notes: doesn't return +;---------------------------------------------------------------------------- ; To-do: replace with pointer list? ;**************************************************************************** @@ -122,17 +112,36 @@ RunCommand: jp z, ResumeBGM dec a ; Command $07: set PCM rate jp z, SetPCMRate + dec a ; Command $08: pause BGM + jp z, PauseBGM PollPCM - xor a ; Bad command, ignore >:( - ld (RAM_Command), a + ; Bad command, ignore >:( + +;**************************************************************************** +; EndOfCommand +; Cleans up when a command finishes +;---------------------------------------------------------------------------- +; notes: doesn't return +;**************************************************************************** +EndOfCommand: + ld hl, ($1FF8) ; Copy second slot into first + ld ($1FFC), hl + ld hl, ($1FFA) + ld ($1FFE), hl + + xor a ; Free up second slot + ld (RAM_Command2), a + PollPCM ;**************************************************************************** ; IdleLoop ; Loop that runs when not processing SFX or BGM +;---------------------------------------------------------------------------- +; notes: doesn't return (d'oh) ;**************************************************************************** IdleLoop: @@ -153,13 +162,11 @@ IdleLoop: ;**************************************************************************** ; DoTick ; Called whenever a new tick triggers +;---------------------------------------------------------------------------- +; notes: doesn't return ;**************************************************************************** DoTick: -; ld a, (ix+0) -; bit 0, a -; call nz, UpdatePCM - PollPCM ld (ix+0), $27 ; Retrigger the timer @@ -181,6 +188,9 @@ DoTick_SFXSkip: PollPCM + ld a, (RAM_Paused) ; BGMs are paused? + or a + jr nz, DoTick_BGMSkip DoTick_BGM: ; Process BGMs jp DoTick_BGMSkip DoTick_BGMSkip: @@ -194,58 +204,31 @@ DoTick_PSGSkip: jp IdleLoop ; End of subroutine -;**************************************************************************** -; BankSwitch -; Switches into a new bank (won't update player status!) -; -; input A .... New bank to switch into -; input HL ... Must be $6000 -; breaks ..... AF -;**************************************************************************** - -BankSwitch: macro - ld (hl), a - rrca - ld (hl), a - rrca - ld (hl), a - rrca - ld (hl), a - rrca - ld (hl), a - rrca - ld (hl), a - rrca - ld (hl), a - ld (hl), h - rrca - ld (hl), a - endm - ;**************************************************************************** ; LoadList [command $01] ; Loads the pointer list ;**************************************************************************** LoadList: - ld hl, RAM_ComBank ; Get command parameters - ld c, (hl) - inc l - ld e, (hl) - inc l - ld d, (hl) - ex de, hl - - xor a ; Command parsed - ld (RAM_Command), a +; ld hl, RAM_ComBank ; Get command parameters +; ld c, (hl) +; inc l +; ld e, (hl) +; inc l +; ld d, (hl) +; ex de, hl + + ld hl, (RAM_ComAddr) ; Get command parameters + ld a, (RAM_ComBank) + ld c, a ld de, RAM_PointerList ; Where the pointer list starts -.loop: +.loadloop: call GetParam ; Get high byte address ld a, b ; Is it the end of the list? or a - jp z, .end + jp z, .loadend ld (de), a ; Store high byte address inc d @@ -261,10 +244,10 @@ LoadList: dec d ; Go for next byte dec d inc e - jp .loop + jp .loadloop -.end: - jp IdleLoop ; End of subroutine +.loadend: + jp EndOfCommand ; End of subroutine ;**************************************************************************** ; GetParam diff --git a/src-z80/core/sfx.z80 b/src-z80/core/sfx.z80 index 4bca4c7..8c5e7dd 100644 --- a/src-z80/core/sfx.z80 +++ b/src-z80/core/sfx.z80 @@ -25,9 +25,6 @@ PlaySFX: PollPCM - xor a ; Command parsed - ld (RAM_Command), a - ld hl, RAM_SFXData ; Set SFX as playing ld (hl), $01 inc l ; No delays! @@ -45,7 +42,7 @@ PlaySFX: ld (DoTick_SFX+1), hl PollPCM - jp IdleLoop ; End of subroutine + jp EndOfCommand ; End of subroutine ;**************************************************************************** ; ProcessSFX @@ -153,6 +150,14 @@ ProcessSFXRun: jp c, SetFMParamSFX cp $FA ; Events $F8-$F9: set FM register jp c, SetFMRegSFX + jp z, SetFlagsSFX ; Events $FA-$FB: set/clear flags + cp $FB + jp z, ClearFlagsSFX + + cp $FC + jp z, LoopSFX ; Event $FC: loop SFX + cp $FD + jp z, SetLoopSFX ; Event $FD: set loop point ;**************************************************************************** ; StopSFX* [command $03, event $FF] @@ -166,10 +171,8 @@ StopSFXEvent: jp DoTick_SFXSkip ; End of subroutine StopSFXCmd: - xor a ; Command parsed - ld (RAM_Command), a call StopSFX ; We're just a wrapper - jp IdleLoop ; End of subroutine + jp EndOfCommand ; End of subroutine StopSFX: PollPCM @@ -283,9 +286,36 @@ ClearSFX: .fmfree: dec e ; Go for next FM channel to unlock - dec b - jp nz, .unlockfm + djnz .unlockfm ;---------------------------------------------------------------------------- ret ; End of subroutine + +;**************************************************************************** +; LoopSFX [event $FC] +; Makes a SFX loop +;**************************************************************************** + +LoopSFX: + PollPCM + + ld hl, (RAM_SFXLoopPoint+1) ; Get looping address + ld a, (RAM_SFXLoopPoint) + ld c, a + + jp ProcessSFXRun ; End of subroutine + +;**************************************************************************** +; SetLoopSFX [event $FD] +; Sets the SFX loop point +;**************************************************************************** + +SetLoopSFX: + PollPCM + + ld a, c ; Store loop point address + ld (RAM_SFXLoopPoint), a + ld (RAM_SFXLoopPoint+1), hl + + jp ProcessSFXRun ; End of subroutine diff --git a/src-z80/core/vars.z80 b/src-z80/core/vars.z80 index cd7162d..79e4a1d 100644 --- a/src-z80/core/vars.z80 +++ b/src-z80/core/vars.z80 @@ -42,13 +42,23 @@ RAM_SFXPlaying: ds 1 ; Set if a SFX is playing RAM_SFXDelay: ds 1 ; How many ticks to wait RAM_SFXBank: ds 1 ; Current SFX bank RAM_SFXAddress: ds 2 ; Current SFX address +RAM_SFXLoopPoint: ds 3 ; SFX loop point + +RAM_Paused: ds 1 ; Set if BGM stream is paused + +RAM_PCMBank1: db 1 ; (not implemented yet) +RAM_PCMAddr1: dw 1 ; (not implemented yet) +RAM_PCMBank2: db 1 ; (not implemented yet) +RAM_PCMAddr2: dw 1 ; (not implemented yet) RAM_Scratch: ds 32 ; Scratch bytes, may be useful when ; buffering to speed up to avoid bank ; switching conflicts ds $F0-($&$FF), $FF -RAM_PCMBuffer: ds 16 ; PCM buffer +RAM_PCMBuffer: ds 0 ; PCM buffer +RAM_PCMBuffer1: ds 8 ; (not implemented yet) +RAM_PCMBuffer2: ds 8 ; (not implemented yet) ;**************************************************************************** ; Pointer list starts being stored from here @@ -71,6 +81,12 @@ RAM_Stack: equ $1FE0 ; Where stack starts RAM_GlobalVol: equ $1FE0 ; Global volume for all channels RAM_Status: equ $1FF0 ; Current playback status RAM_RefreshVol: equ $1FF1 ; Set to refresh all volumes +RAM_Flags: equ $1FF2 ; Track flags + RAM_Command: equ $1FFF ; Command type RAM_ComAddr: equ $1FFD ; Command address parameter RAM_ComBank: equ $1FFC ; Command bank parameter + +RAM_Command2: equ $1FFB ; (second slot for all the above) +RAM_ComAddr2: equ $1FF9 +RAM_ComBank2: equ $1FF8 diff --git a/src-z80/player/fm.z80 b/src-z80/player/fm.z80 index 505e849..d5d49ba 100644 --- a/src-z80/player/fm.z80 +++ b/src-z80/player/fm.z80 @@ -432,7 +432,13 @@ LoadFMDirect: ;**************************************************************************** SetFMVolSFX: - call SetFMVolSFXEvent ; We're just a wrapper + push af + PollPCM + call GetParam ; Get new volume + PollPCM + pop af + + call SetFMVolLoad ; We're just a wrapper jp ProcessSFXRun ; End of subroutine SetFMVolBGM: @@ -487,12 +493,21 @@ SetFMVolBGM: call SetFMVolLoad ; We're just a wrapper jp ProcessBGMRun ; End of subroutine -SetFMVolSFXEvent: - push af - PollPCM - call GetParam ; Get new volume - PollPCM - pop af +;---------------------------------------------------------------------------- +; input a = channel ID +; input b = new volume level +;---------------------------------------------------------------------------- + +SetFMVolTempLoad: + push bc + push de + push hl + jp SetFMVolDoIt + +;---------------------------------------------------------------------------- +; input a = channel ID (bottom 3 bits) +; input b = new volume level +;---------------------------------------------------------------------------- SetFMVolLoad: push bc @@ -508,6 +523,7 @@ SetFMVolLoad: ld (hl), b pop af +SetFMVolDoIt: push af ld h, RAM_FMData>>8 ; Get address of FM data add RAM_FMData&$FF diff --git a/src-z80/player/misc.z80 b/src-z80/player/misc.z80 index dee980e..56e11b4 100644 --- a/src-z80/player/misc.z80 +++ b/src-z80/player/misc.z80 @@ -1,6 +1,8 @@ ;**************************************************************************** ; SetDelay* [event $FE, events $D0-$DF] ; Adds a delay in playback +;---------------------------------------------------------------------------- +; breaks: c, de, hl ;**************************************************************************** SetDelaySFX: @@ -45,6 +47,58 @@ SetDelayShort: ret ; End of subroutine +;**************************************************************************** +; SetFlags [event $FA] +; Sets some of the flags. +;---------------------------------------------------------------------------- +; breaks: c, de, hl +;**************************************************************************** + +SetFlagsSFX: + call SetFlags + jp ProcessSFXRun + +SetFlagsBGM: + call SetFlags + jp ProcessBGMRun + +SetFlags: + PollPCM ; Get which flags to set + call GetParam + PollPCM + + ld a, (RAM_Flags) ; Set the flags + or b + ld (RAM_Flags), a + + ret ; End of subroutine + +;**************************************************************************** +; ClearFlags [event $FB] +; Clears some of the flags. +;---------------------------------------------------------------------------- +; breaks: c, de, hl +;**************************************************************************** + +ClearFlagsSFX: + call ClearFlags + jp ProcessSFXRun + +ClearFlagsBGM: + call ClearFlags + jp ProcessBGMRun + +ClearFlags: + PollPCM ; Get which flags to clear + call GetParam + PollPCM + + ld a, (RAM_Flags) ; Clear the flags + and b + ld (RAM_Flags), a + + ret ; End of subroutine + ;**************************************************************************** ; RefreshVolume ; Reloads the volume for all channels. @@ -69,6 +123,7 @@ RefreshVolume: inc l inc e dec c + PollPCM jr nz, .fixfmvol ld hl, $1FE8 ; Update PSG volume diff --git a/src-z80/player/pcm (copia).z80 b/src-z80/player/pcm (copia).z80 new file mode 100644 index 0000000..ae7b34a --- /dev/null +++ b/src-z80/player/pcm (copia).z80 @@ -0,0 +1,236 @@ +;**************************************************************************** +; UpdatePCM +; Updates PCM output upon a timer event +;**************************************************************************** + +UpdatePCM: + ret ; $C9 = RET = no PCM playback + ; $D0 = RET NC = PCM playback + + exx ; Switch to PCM registers + +.doagain: + ld (ix+0), $27 ; Acknowledge timer + ld (ix+1), $1F + + ld a, (hl) ; Fetch next sample + inc a ; Check if it's the end of the waveform + jr z, .stop + ld (ix+0), $2A ; Nope, send sample to YM2612 + ld (ix+1), a + + inc l ; Update buffer position + jr z, .reload ; Need to buffer more? + +.nopcm: + exx ; Switch to normal registers + ret ; End of subroutine + +.stop: + ld a, $C9 ; Stop playback + ld (UpdatePCM), a + ld (ix+0), $2A ; Turn off DAC + ld (ix+1), $80 + ld (ix+0), $2B + ld (ix+1), $00 + exx ; Switch to normal registers + ret ; End of subroutine + +.reload: + ld a, (RAM_LastBank) ; Bank switch if needed + cp c + jp z, .noswitchu + ld a, c + ld (RAM_LastBank), a + ld hl, $6000 + BankSwitch +.noswitchu: + + ld hl, RAM_PCMBuffer ; Load samples into the buffer + ld a, c + ex de, hl + + ldi + ldi + ldi + ldi + + ldi + ldi + ldi + ldi + + ldi + ldi + ldi + ldi + + ldi + ldi + ldi + ldi + + ex de, hl + ld c, a + + ld a, e + or a + jp nz, .nobankchg ; Update high bytes of address if needed + inc d + jp nz, .nobankchg + ld d, $80 + inc c +.nobankchg: + + ld l, RAM_PCMBuffer&$FF ; Go back to the beginning of the buffer + jp .doagain ; We took so long we should play the next + ; sample already ._.' + +;**************************************************************************** +; PlayPCM* [event $0C] +; Plays a PCM sample +;---------------------------------------------------------------------------- +; input c .... current bank +; input hl ... current address +;---------------------------------------------------------------------------- +; breaks: af, b +;**************************************************************************** + +PlayPCMSFX: + call PlayPCM ; We're just a wrapper + jp ProcessSFXRun ; End of subroutine + +PlayPCMBGM: + PollPCM + + ld a, (RAM_Locked+6) ; Check if channel is free + or a + jp nz, ProcessBGMSkip1 ; Don't play sample if locked + + call PlayPCM ; We're just a wrapper + jp ProcessBGMRun ; End of subroutine + +PlayPCM: + ld a, (RAM_GlobalVol+$0C) ; Are we allowed to play PCM? + or a + ret z + + call GetParam ; Get sample ID + + ld a, b + exx ; We'll modify PCM data now + + ld h, RAM_PointerList>>8 ; Get offset in pointer list + ld l, a + + ld d, (hl) ; Get PCM address + inc h + ld e, (hl) + inc h + ld c, (hl) + + ld hl, $6000 ; Initial bank switch + ld a, c + ld (RAM_LastBank), a + BankSwitch + + ld h, RAM_PCMBuffer>>8 ; Set buffer where the sample starts + ld a, e + or $F0 + ld l, a + + ld b, l +.load1st: ; Copy initial samples into the buffer + ld a, (de) + ld (hl), a + inc e + inc l + jp nz, .load1st + ld l, b + + ld a, e ; Check if the sample should skip ahead + or a ; already + jp nz, .noskip1st + inc d + jp nz, .noskip1st + ld d, $80 + inc c +.noskip1st: + + exx ; Back to standard registers + ld a, $D0 ; Enable PCM playback + ld (UpdatePCM), a + + ld (ix+0), $2B ; Turn on DAC + ld (ix+1), $80 + ld (ix+0), $2A + ld (ix+1), $80 + + ret ; End of subroutine + +;**************************************************************************** +; StopPCM* +; Stops a PCM sample +;**************************************************************************** + +StopPCMSFX: + call StopPCM ; We're just a wrapper + jp ProcessSFXRun ; End of subroutine + +StopPCMBGM: + PollPCM + + ld a, (RAM_Locked+6) ; Check if channel is free + or a + jp nz, ProcessBGMRun ; Don't stop sample if locked + + call StopPCM ; We're just a wrapper + jp ProcessBGMRun ; End of subroutine + +StopPCM: + ld a, $C9 ; Stop PCM playback + ld (UpdatePCM), a + + ld (ix+0), $2B ; Disable DAC + ld (ix+1), $00 + + ret ; End of subroutine + +;**************************************************************************** +; LockChannelPCM [event $EC] +; Locks the PCM channel +;**************************************************************************** + +LockChannelPCM: + ld a, $01 ; Lock PCM channel + ld (RAM_Locked+6), a + + call StopPCM ; Stop PCM playback + jp ProcessSFXRun ; End of subroutine + +;**************************************************************************** +; SetPCMRate [command $07] +; Changes the sample rate of PCM +;**************************************************************************** + +SetPCMRate: + ld a, (RAM_ComBank) ; Get new rate + cpl + ld b, a + + xor a ; Parsed command already + ld (RAM_Command), a + + ld a, b ; Set high bits of timer + ld (ix+0), $24 + rrca + rrca + or $C0 + ld (ix+1), a + + ld a, b ; Set low bits of timer + ld (ix+0), $25 + and $03 + ld (ix+1), a + + jp IdleLoop ; End of subroutine diff --git a/src-z80/player/pcm.z80 b/src-z80/player/pcm.z80 index 99feb6d..2b7bcc4 100644 --- a/src-z80/player/pcm.z80 +++ b/src-z80/player/pcm.z80 @@ -1,100 +1,21 @@ -;**************************************************************************** -; PlayPCM* [event $0C] -; Plays a PCM sample -;---------------------------------------------------------------------------- -; input c .... current bank -; input hl ... current address -;---------------------------------------------------------------------------- -; breaks: af, b -;**************************************************************************** - -PlayPCMSFX: - call PlayPCM ; We're just a wrapper - jp ProcessSFXRun ; End of subroutine - -PlayPCMBGM: - PollPCM - - ld a, (RAM_Locked+6) ; Check if channel is free - or a - jp nz, ProcessBGMSkip1 ; Don't play sample if locked - - call PlayPCM ; We're just a wrapper - jp ProcessBGMRun ; End of subroutine - -PlayPCM: - ld a, (RAM_GlobalVol+$0C) ; Are we allowed to play PCM? - or a - ret z - - call GetParam ; Get sample ID - - ld a, b - exx ; We'll modify PCM data now - - ld h, RAM_PointerList>>8 ; Get offset in pointer list - ld l, a - - ld d, (hl) ; Get PCM address - inc h - ld e, (hl) - inc h - ld c, (hl) - - ld hl, $6000 ; Initial bank switch - ld a, c - ld (RAM_LastBank), a - BankSwitch - - ld h, RAM_PCMBuffer>>8 ; Set buffer where the sample starts - ld a, e - or $F0 - ld l, a - - ld b, l -.load1st: ; Copy initial samples into the buffer - ld a, (de) - ld (hl), a - inc e - inc l - jp nz, .load1st - ld l, b - - ld a, e ; Check if the sample should skip ahead - or a ; already - jp nz, .noskip1st - inc d - jp nz, .noskip1st - ld d, $80 - inc c -.noskip1st: - - ;ld b, $01 ; Play PCM! - exx ; Back to standard registers - xor a ; Enable PCM playback - ld (UpdatePCM), a - - ld (ix+0), $2B ; Turn on DAC - ld (ix+1), $80 - ld (ix+0), $2A - ld (ix+1), $80 - - ret ; End of subroutine - ;**************************************************************************** ; UpdatePCM ; Updates PCM output upon a timer event ;**************************************************************************** UpdatePCM: - ret ; RET = no PCM playback - ; NOP = PCM playback + ret ; $C9 = RET = no PCM playback + ; $D0 = RET NC = PCM playback exx ; Switch to PCM registers .doagain: ld (ix+0), $27 ; Acknowledge timer ld (ix+1), $1F + ;push hl + ;ld hl, $1F27 + ;ld ($4000), hl + ;pop hl ld a, (hl) ; Fetch next sample inc a ; Check if it's the end of the waveform @@ -110,7 +31,9 @@ UpdatePCM: ret ; End of subroutine .stop: - ld b, $00 ; Stop playback +; ld b, $00 ; Stop playback + ld a, $C9 ; Stop playback + ld (UpdatePCM), a ld (ix+0), $2A ; Turn off DAC ld (ix+1), $80 ld (ix+0), $2B @@ -209,6 +132,88 @@ UpdatePCM: jp .doagain ; We took so long we should play the next ; sample already ._.' +;**************************************************************************** +; PlayPCM* [event $0C] +; Plays a PCM sample +;---------------------------------------------------------------------------- +; input c .... current bank +; input hl ... current address +;---------------------------------------------------------------------------- +; breaks: af, b +;**************************************************************************** + +PlayPCMSFX: + call PlayPCM ; We're just a wrapper + jp ProcessSFXRun ; End of subroutine + +PlayPCMBGM: + PollPCM + + ld a, (RAM_Locked+6) ; Check if channel is free + or a + jp nz, ProcessBGMSkip1 ; Don't play sample if locked + + call PlayPCM ; We're just a wrapper + jp ProcessBGMRun ; End of subroutine + +PlayPCM: + ld a, (RAM_GlobalVol+$0C) ; Are we allowed to play PCM? + or a + ret z + + call GetParam ; Get sample ID + + ld a, b + exx ; We'll modify PCM data now + + ld h, RAM_PointerList>>8 ; Get offset in pointer list + ld l, a + + ld d, (hl) ; Get PCM address + inc h + ld e, (hl) + inc h + ld c, (hl) + + ld hl, $6000 ; Initial bank switch + ld a, c + ld (RAM_LastBank), a + BankSwitch + + ld h, RAM_PCMBuffer>>8 ; Set buffer where the sample starts + ld a, e + or $F0 + ld l, a + + ld b, l +.load1st: ; Copy initial samples into the buffer + ld a, (de) + ld (hl), a + inc e + inc l + jp nz, .load1st + ld l, b + + ld a, e ; Check if the sample should skip ahead + or a ; already + jp nz, .noskip1st + inc d + jp nz, .noskip1st + ld d, $80 + inc c +.noskip1st: + + exx ; Back to standard registers + ld a, $D0 ; Enable PCM playback + ld (UpdatePCM), a + + ld (ix+0), $2B ; Turn on DAC + ld (ix+1), $80 + ld (ix+0), $2A + ld (ix+1), $80 + + ret ; End of subroutine + ;**************************************************************************** ; StopPCM* ; Stops a PCM sample @@ -257,21 +262,21 @@ LockChannelPCM: SetPCMRate: ld a, (RAM_ComBank) ; Get new rate cpl - ld b, a - xor a ; Parsed command already - ld (RAM_Command), a - - ld a, b ; Set high bits of timer - ld (ix+0), $24 + ld b, a ; Set high bits of timer + ld hl, $4000 + ld (hl), $24 rrca rrca or $C0 - ld (ix+1), a + inc l + ld (hl), a ld a, b ; Set low bits of timer - ld (ix+0), $25 + dec l + ld (hl), $25 and $03 - ld (ix+1), a + inc l + ld (hl), a - jp IdleLoop ; End of subroutine + jp EndOfCommand ; End of subroutine diff --git a/src-z80/player/psg.z80 b/src-z80/player/psg.z80 index b88978c..6ddaae7 100644 --- a/src-z80/player/psg.z80 +++ b/src-z80/player/psg.z80 @@ -10,8 +10,10 @@ UpdatePSG: push bc ld a, (hl) ; Get channel volume - bit 7, a - jr nz, .noskip +; bit 7, a +; jr nz, .noskip + or a + jp m, .noskip ld b, $0F inc l jp .skip -- cgit v1.2.3