From 8fdf49b8e53fd3063ccc2eb51c49c3b6e4d073bb Mon Sep 17 00:00:00 2001 From: sik Date: Mon, 22 Jan 2018 19:19:19 -0300 Subject: Echo 1.6 release... kind of a mess, will clean up in further commits I guess --- src-z80/player/fm.z80 | 60 ++++++++++- src-z80/player/freq.z80 | 6 +- src-z80/player/pcm (copia).z80 | 236 +++++++++++++++++++++++++++++++++++++++++ src-z80/player/psg.z80 | 130 +++++++++++++++++++---- 4 files changed, 406 insertions(+), 26 deletions(-) create mode 100644 src-z80/player/pcm (copia).z80 (limited to 'src-z80/player') diff --git a/src-z80/player/fm.z80 b/src-z80/player/fm.z80 index d5d49ba..8afd0e7 100644 --- a/src-z80/player/fm.z80 +++ b/src-z80/player/fm.z80 @@ -49,8 +49,9 @@ NoteOnFM: PollPCM call GetParam ; Get note PollPCM - ex af, af' + +SetFMSemitone: push de push hl @@ -175,8 +176,8 @@ SetNoteFMBGM: jp ProcessBGMRun ; End of subroutine SetNoteFM: - push af ld b, a + ex af, af' PollPCM ld a, b ; Determine which port to write @@ -188,7 +189,11 @@ SetNoteFM: call GetParam ; Get high byte PollPCM - pop af + ld a, b ; Is it a semitone? + add a, a + jp c, .freqtone + + ex af, af' push de and $07 @@ -217,6 +222,14 @@ SetNoteFM: pop de ret ; End of subroutine +;---------------------------------------------------------------------------- + +.freqtone: + inc a + ld b, a + ex af, af' + jp SetFMSemitone + ;**************************************************************************** ; LoadFM* [events $40~$47] ; Loads a FM instrument @@ -678,6 +691,16 @@ SetFMParamSFX: PollPCM call GetParam ; Get parameters PollPCM + + ld a, (RAM_Mono) ; Is stereo disabled? (always turn on both + or a ; speakers in that case) + jr z, .sfxpanok + ld a, b + or $C0 + ld b, a + PollPCM +.sfxpanok: + ex af, af' and $03 ; Get channel ID @@ -701,6 +724,16 @@ SetFMParamBGM: PollPCM call GetParam ; Get parameters PollPCM + + ld a, (RAM_Mono) ; Is stereo disabled? (always turn on both + or a ; speakers in that case) + jr z, .bgmpanok + ld a, b + or $C0 + ld b, a + PollPCM +.bgmpanok: + ex af, af' push hl @@ -880,6 +913,14 @@ KillFM: dec c jp nz, .loaddummy + ld e, 0 ; Make the pitch so low it's unherable + add 4 ; because the above is STILL not enough + ld (iy+0), a ; sometimes. If you ever notice a very low + ld (iy+1), e ; pitch waveform... this is why + sub 4 + ld (iy+0), a + ld (iy+1), e + pop hl pop de PollPCM @@ -941,3 +982,16 @@ RestoreFM: PollPCM ret ; End of subroutine + +;**************************************************************************** +; SetStereo [command $09] +; Toggles whether stereo is enabled or not. +;---------------------------------------------------------------------------- +; notes: doesn't return +;**************************************************************************** + +SetStereo: + ld a, (RAM_ComBank) ; Just copy the argument as-is + ld (RAM_Mono), a + + jp EndOfCommand ; End of subroutine diff --git a/src-z80/player/freq.z80 b/src-z80/player/freq.z80 index 7f963e5..6aae77b 100644 --- a/src-z80/player/freq.z80 +++ b/src-z80/player/freq.z80 @@ -94,9 +94,9 @@ FMFreqTable: ;**************************************************************************** PSGShiftTable: - db 0 - db 2, 4, 6, 8, 10, 12 - db -2, -4, -6, -8, -10, -12 + db 0*2 ; $0x + db 1*2, 2*2, 3*2, 4*2, 6*2, 8*2, 12*2 ; $1x..$7x + db -1*2, -2*2, -3*2, -4*2, -6*2, -8*2, -12*2 ; $8x..$Ex ;**************************************************************************** ; DummyFMInstr 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/psg.z80 b/src-z80/player/psg.z80 index 6ddaae7..892931a 100644 --- a/src-z80/player/psg.z80 +++ b/src-z80/player/psg.z80 @@ -8,10 +8,10 @@ UpdatePSG: ld b, 3 ; Go through all channels .loop: push bc + xor a + ld iyl, a ld a, (hl) ; Get channel volume -; bit 7, a -; jr nz, .noskip or a jp m, .noskip ld b, $0F @@ -74,7 +74,7 @@ UpdatePSG: .skip: PollPCM - + ld a, b ; Set PSG channel volume rlca rlca @@ -86,6 +86,63 @@ UpdatePSG: rrca or $90 ld ($7F11), a + + PollPCM + push bc + + ld a, l ; Get current semitone + add 11-1 + ld l, a + ld b, (hl) + sub 11-1 + ld l, a + + ld a, b ; Oh, don't tocuh it? + inc a + jr z, .notone + + PollPCM + + db $FD,$7D ; ld a, iyl ; Get semitone shift + and $F0 + rrca + rrca + rrca + rrca + ex de, hl + ld h, PSGShiftTable>>8 + add PSGShiftTable&$FF + ld l, a + ld c, (hl) + ex de, hl + + PollPCM + + ld a, b ; Compute resulting semitone + add c + + ex de, hl ; Get corresponding frequency + ld h, PSGFreqTable>>8 + ld l, a + ld c, (hl) + inc l + ld b, (hl) + + PollPCM + + ld a, e ; Get PSG channel + and $30 + add a + or c + + ld hl, $7F11 ; Set new frequency + ld (hl), a + ld (hl), b + ex de, hl + + PollPCM +.notone: + pop bc ld a, l ; Go for next channel sub 16+1 @@ -200,31 +257,22 @@ NoteOnPSG: ld a, (de) ld (hl), a + ld a, e pop de pop hl + ex af, af' PollPCM call GetParam ; Get note PollPCM - - ;pop af ex af, af' - push hl - push de - ld h, PSGFreqTable>>8 ; Get address of frequency data - ld l, b - ld de, $7F11 - rrca ; Set new frequency - rrca - rrca - ld b, (hl) - or b - ld (de), a - inc l - ld a, (hl) - ld (de), a - pop de +SetSemitonePSG: + push hl ; Store new semitone + inc a + ld h, RAM_PSGData>>8 + ld l, a + ld (hl), b pop hl ret ; End of subroutine @@ -336,6 +384,14 @@ NoteOffPSG: ld a, (hl) and $7F ld (hl), a + + PollPCM + + ld a, l ; Don't waste time with semitone shifting + add 11 + ld l, a + ld a, $FF + ld (hl), a pop hl ret ; End of subroutine @@ -595,6 +651,27 @@ SetNotePSG: PollPCM call GetParam ; Get first byte PollPCM + + ld a, b ; Select by semitone? + add a, a + jp c, .freqtone + ex af, af' + + push hl ; Mark semitone as not valid + ld l, a + ex af, af' + PollPCM + ld a, l + rrca + rrca + rrca + rrca + add a, 11 + ld l, a + ld h, RAM_PSGData>>8 + ld (hl), $FF + pop hl + PollPCM ex af, af' push de ; PSG port address @@ -618,6 +695,19 @@ SetNotePSG: ret ; End of subroutine +;---------------------------------------------------------------------------- + +.freqtone: + ld b, a + PollPCM + ex af, af' + rrca + rrca + rrca + rrca + add 10 + jp SetSemitonePSG + ;**************************************************************************** ; SetNoteNoise* ; Sets the note of the noise PSG channel without "note on" -- cgit v1.2.3