aboutsummaryrefslogtreecommitdiff
path: root/src-z80
diff options
context:
space:
mode:
Diffstat (limited to 'src-z80')
-rw-r--r--src-z80/build.z808
-rw-r--r--src-z80/core/bgm.z80185
-rw-r--r--src-z80/core/macro.z8041
-rw-r--r--src-z80/core/main.z80113
-rw-r--r--src-z80/core/sfx.z8048
-rw-r--r--src-z80/core/vars.z8018
-rw-r--r--src-z80/player/fm.z8030
-rw-r--r--src-z80/player/misc.z8055
-rw-r--r--src-z80/player/pcm (copia).z80236
-rw-r--r--src-z80/player/pcm.z80197
-rw-r--r--src-z80/player/psg.z806
11 files changed, 685 insertions, 252 deletions
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
@@ -88,22 +89,11 @@ 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:
@@ -195,57 +205,30 @@ 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:
@@ -46,6 +48,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
@@ -210,6 +133,88 @@ UpdatePCM:
; 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