diff options
Diffstat (limited to 'src-z80/player')
| -rw-r--r-- | src-z80/player/fm.z80 | 784 | ||||
| -rw-r--r-- | src-z80/player/freq.z80 | 105 | ||||
| -rw-r--r-- | src-z80/player/misc.z80 | 31 | ||||
| -rw-r--r-- | src-z80/player/pcm.z80 | 139 | ||||
| -rw-r--r-- | src-z80/player/psg.z80 | 667 |
5 files changed, 1726 insertions, 0 deletions
diff --git a/src-z80/player/fm.z80 b/src-z80/player/fm.z80 new file mode 100644 index 0000000..40cf5da --- /dev/null +++ b/src-z80/player/fm.z80 @@ -0,0 +1,784 @@ +;**************************************************************************** +; NoteOnFM +; Does a "note on" for a FM channel +;**************************************************************************** + +NoteOnFMSFX: + call NoteOnFM ; We're just a wrapper + jp ProcessSFXRun ; End of subroutine + +NoteOnFMBGM: + ld b, a + PollPCM + + push hl + ld a, b + and $07 ; Check if channel is free + ld hl, RAM_Locked + add l + ld l, a + ld a, (hl) + pop hl + or a + jp nz, ProcessBGMSkip1 ; Don't play if locked + + ld a, b + call NoteOnFM ; We're just a wrapper + jp ProcessBGMRun ; End of subroutine + +NoteOnFM: + and $07 ; Get channel ID + ld (ix+0), $28 ; Note off + ld (ix+1), a + + ld b, a + ex af, af' + PollPCM + + ld a, b ; Determine which port to write + and $04 + rrca + ld iyl, a + + PollPCM + call GetParam ; Get note + PollPCM + + ex af, af' + push de + push hl + + ld d, a + and $03 ; Index of first frequency register + add $A4 + ld e, a + + PollPCM + + ld h, FMFreqTable>>8 ; Get address of note + ld a, b + and $1F + add FMFreqTable&$FF + ld l, a + + PollPCM + + ld a, b ; Set new frequency + and $E0 + rrca + rrca + ld b, a + ld a, (hl) + or b + ld (iy+0), e + ld (iy+1), a + + PollPCM + + ld a, e + sub 4 + ld e, a + dec l + ld a, (hl) + ld (iy+0), e + ld (iy+1), a + + PollPCM + + ld a, d ; Note on! + or $F0 + ld (ix+0), $28 + ld (ix+1), a + + pop hl + pop de + ret ; End of subroutine + +;**************************************************************************** +; NoteOffFM +; Does a "note off" for a FM channel +;**************************************************************************** + +NoteOffFMSFX: + call NoteOffFM ; We're just a wrapper + jp ProcessSFXRun ; End of subroutine + +NoteOffFMBGM: + ld b, a + PollPCM + ld a, b + + push hl + and $07 ; Check if channel is free + ld hl, RAM_Locked + add l + ld l, a + ld a, (hl) + pop hl + or a + jp nz, ProcessBGMSkip ; Don't stop if locked + + ld a, b + call NoteOffFM ; We're just a wrapper + jp ProcessBGMRun ; End of subroutine + +NoteOffFM: + and $07 ; Get channel ID + ld (ix+0), $28 ; Note off + ld (ix+1), a + ret ; End of subroutine + +;**************************************************************************** +; SetFMNote* +; Sets the note of a FM channel without "note on" +;**************************************************************************** + +SetNoteFMSFX: + call SetNoteFM ; We're just a wrapper + jp ProcessSFXRun ; End of subroutine + +SetNoteFMBGM: + ld b, a + PollPCM + ld a, b + + push hl + and $07 ; Check if channel is free + ld hl, RAM_Locked + add l + ld l, a + ld a, (hl) + pop hl + or a + jp nz, ProcessBGMSkip2 ; Don't change if locked + + ld a, b + call SetNoteFM ; We're just a wrapper + jp ProcessBGMRun ; End of subroutine + +SetNoteFM: + push af + ld b, a + PollPCM + + ld a, b ; Determine which port to write + and $04 + rrca + ld iyl, a + + PollPCM + call GetParam ; Get high byte + PollPCM + + pop af + push de + + and $07 + ld d, a + and $03 ; Index of first frequency register + add $A4 + ld e, a + + PollPCM + + ld (iy+0), e ; Load high byte + ld (iy+1), b + + PollPCM ; Load low byte + call GetParam + PollPCM + + ld a, e + sub 4 + ld e, a + + ld (iy+0), e + ld (iy+1), b + + PollPCM + pop de + ret ; End of subroutine + +;**************************************************************************** +; LoadFM* +; Loads a FM instrument +;**************************************************************************** + +LoadFMSFX: + call LoadFMEvent ; We're just a wrapper + jp ProcessSFXRun ; End of subroutine + +LoadFMBGM: + and $07 ; Get channel ID + ld b, a + PollPCM + + push de + push bc + ld a, b + ld de, RAM_BGMFMInstr ; Store instrument ID + add e + ld e, a + PollPCM + call GetParam + PollPCM + ex de, hl + ld (hl), b + ex de, hl + ld e, c + pop bc + ld c, e + pop de + + PollPCM + + push hl ; Check if channel is free + ld hl, RAM_Locked + ld a, b + add l + ld l, a + ld a, (hl) + pop hl + or a + jp nz, ProcessBGMSkip ; Don't load if locked + + PollPCM + + ld a, b + and $07 + push hl + ld hl, RAM_BGMFMInstr + add l + ld l, a + ld b, (hl) + pop hl + + push af + PollPCM + pop af + + call LoadFMDirect ; We're just a wrapper + jp ProcessBGMRun ; End of subroutine + +LoadFMEvent: + and $07 ; Get channel ID + + ex af, af' + PollPCM + call GetParam ; Get instrument ID + PollPCM + ex af, af' +LoadFMDirect: + + push af + and $04 ; Determine which port to write + rrca + ld iyl, a + PollPCM + pop af + + push bc + push de + push hl + + ld h, RAM_PointerList>>8 ; Get instrument address + ld l, b + ld d, (hl) + inc h + ld e, (hl) + inc h + ld c, (hl) + ex de, hl + + push af + PollPCM + + ld b, 28/4 ; Load FM instrument into our scratch buffer, + ld de, RAM_Scratch ; so we don't conflict with PCM bank +.getinstr: ; switch (which would slow down A LOT) + ld a, b + ex af, af' + call GetParam + ex de, hl + ld (hl), b + ex de, hl + inc e + call GetParam + ex de, hl + ld (hl), b + ex de, hl + inc e + call GetParam + ex de, hl + ld (hl), b + ex de, hl + inc e + call GetParam + ex de, hl + ld (hl), b + ex de, hl + inc e + ex af, af' + ld b, a + djnz .getinstr + call GetParam + ex de, hl + ld (hl), b + ex de, hl + + PollPCM + + pop af ; Kill ADSR + ld b, a + call KillFM + ld a, b + + ld de, RAM_FMData ; Get address of FM data + and $07 + add e + ld e, a + + push af + and $03 ; Register index for operator + add $B0 + + ld hl, RAM_Scratch ; Get address of buffer with the instrument + ; data + + ex af, af' + PollPCM ; Write operator + ex af, af' + ld (iy+0), a + ld b, (hl) + inc l + ld (iy+1), b + + ex af, af' ; Store $B0 register in FM data buffer + ld a, b ; Also store it in the FM channel information + ld (de), a ; table since we need it when changing the + ld a, e ; FM channel volume + add 8 + ld e, a + PollPCM + ex af, af' + + sub $B0-$30 + + ex af, af' ; Write registers $30-$3C + PollPCM + ex af, af' + + ld (iy+0), a + ld b, (hl) + ld (iy+1), b + add 4 + inc l + ld (iy+0), a + ld b, (hl) + ld (iy+1), b + add 4 + inc l + ld (iy+0), a + ld b, (hl) + ld (iy+1), b + add 4 + inc l + ld (iy+0), a + ld b, (hl) + ld (iy+1), b + add 4 + inc l + + ld b, 4 ; Write registers $40-$4C +.reg40: ; Also store the registers in the FM channel + ld c, a ; information field since we'll need them to + push af ; set the FM channel volume + PollPCM + ld (iy+0), c + ld a, (hl) + ld (iy+1), a + ld (de), a + ld a, e + add 8 + ld e, a + pop af + add 4 + inc l + djnz .reg40 + + ld b, 20/4 ; Write registers $50-$5C +.reg50: + ld c, b + ex af, af' + PollPCM + ex af, af' + + ld (iy+0), a + ld b, (hl) + ld (iy+1), b + add 4 + inc l + ld (iy+0), a + ld b, (hl) + ld (iy+1), b + add 4 + inc l + ld (iy+0), a + ld b, (hl) + ld (iy+1), b + add 4 + inc l + ld (iy+0), a + ld b, (hl) + ld (iy+1), b + add 4 + + inc l + ld b, c + djnz .reg50 + + PollPCM + + ex de, hl + ld a, l + sub 8*6 + ld l, a + ld b, (hl) + add 8 + ld l, a + + PollPCM + + pop af + pop hl + pop de + pop bc + ret + + ;jp SetFMVolLoad ; End of subroutine + +;**************************************************************************** +; SetFMVol* +; Sets the volume of a FM channel +;**************************************************************************** + +SetFMVolSFX: + call SetFMVolEvent ; We're just a wrapper + jp ProcessSFXRun ; End of subroutine + +SetFMVolBGM: + and $07 + ld b, a + + PollPCM + + push de + push bc + ld a, b + ld de, RAM_BGMFMVol ; Store BGM volume + add e + ld e, a + PollPCM + call GetParam + PollPCM + ex de, hl + ld (hl), b + ex de, hl + ld e, c + pop bc + ld c, e + pop de + + PollPCM + + push hl + ld a, b ; Check if channel is free + ld hl, RAM_Locked + add l + ld l, a + ld a, (hl) + pop hl + or a + jp nz, ProcessBGMSkip ; Don't change if locked + + PollPCM + + ld a, b + push hl + ld hl, RAM_BGMFMVol + add l + ld l, a + ld b, (hl) + pop hl + + push af + PollPCM + pop af + + call SetFMVolBGMEvent ; We're just a wrapper + jp ProcessBGMRun ; End of subroutine + +SetFMVolEvent: + push af + PollPCM + call GetParam ; Get new volume + PollPCM + pop af + +SetFMVolBGMEvent: + push bc + push de + push hl + + ld hl, RAM_FMVolume ; Store new volume + and $07 + add l + ld l, a + ld (hl), b + + ex af, af' + PollPCM + ld a, l ; Get address of FM data + add 8 + ld l, a + ex af, af' + +SetFMVolLoad: + push af + ;ld iyh, $40 ; Determine which port to write + and $04 + rrca + ld iyl, a + PollPCM + pop af + + and $03 ; Index of first volume register + add $40 + ld c, a + + PollPCM + + ld a, (hl) ; Get algorithm + and $07 + ld e, a + + PollPCM + + ld a, l + add 8 + ld l, a + ld a, e ; Process operator #1 + cp $07 + jr c, .noop1 + ld a, (hl) + add b + cp $7F + jr c, .notooloud1 + ld a, $7F +.notooloud1: + ld (iy+0), c + ld (iy+1), a +.noop1: + ld a, c + add 4 + ld c, a + + PollPCM + + ld a, l + add 8 + ld l, a + ld a, e ; Process operator #2 + cp $05 + jr c, .noop2 + ld a, (hl) + add b + cp $7F + jr c, .notooloud2 + ld a, $7F +.notooloud2: + ld (iy+0), c + ld (iy+1), a +.noop2: + ld a, c + add 4 + ld c, a + + PollPCM + + ld a, l + add 8 + ld l, a + ld a, e ; Process operator #3 + cp $04 + jr c, .noop3 + ld a, (hl) + add b + cp $7F + jr c, .notooloud3 + ld a, $7F +.notooloud3: + ld (iy+0), c + ld (iy+1), a +.noop3: + ld a, c + add 4 + ld c, a + + PollPCM + + ld a, l + add 8 + ld l, a + ld a, (hl) ; Process operator #4 + add b + cp $7F + jr c, .notooloud4 + ld a, $7F +.notooloud4: + ld (iy+0), c + ld (iy+1), a + + PollPCM + + pop hl + pop de + pop bc + ret ; End of subroutine + +;**************************************************************************** +; SetFMParam* +; Sets the different parameters of a FM channel +;**************************************************************************** + +SetFMParamSFX: + call SetFMParam ; We're just a wrapper + jp ProcessSFXRun ; End of subroutine + +SetFMParamBGM: + ld b, a + PollPCM + ld a, b + + push hl + and $07 ; Check if channel is free + ld hl, RAM_Locked + add l + ld l, a + ld a, (hl) + pop hl + or a + jp nz, ProcessBGMSkip1 ; Don't modify if locked + + ld a, b + call SetFMParam ; We're just a wrapper + jp ProcessBGMRun ; End of subroutine + +SetFMParam: + ld b, a + PollPCM + + ;ld iyh, $40 ; Determine which port to write + ld a, b + and $04 + rrca + ld iyl, a + + ld a, b + ex af, af' + PollPCM + call GetParam ; Get parameters + PollPCM + ex af, af' + + and $03 ; Get channel ID + add $B4 + ld (iy+0), a ; Set new parameters + ld (iy+1), b + + ret ; End of subroutine + +;**************************************************************************** +; LockChannelFM [events $E0-$E7] +; Locks a FM channel +;**************************************************************************** + +LockChannelFM: + and $07 + ld b, a + PollPCM + + push hl + ld h, RAM_Locked>>8 ; Get address of channel to lock + ld a, b + add RAM_Locked&$FF + ld l, a + ld (hl), $01 ; Lock channel + pop hl + + PollPCM + + ld a, b ; Determine which port to write + and $04 + rrca + ld iyl, a + + ld a, b ; Reset stereo + and $03 + add a + add a + add $B4 + ld (iy+0), a + ld (iy+1), $C0 + + jp ProcessSFXRun ; End of subroutine + +;**************************************************************************** +; KillFM +; Kills a FM channel +;**************************************************************************** + +KillFM: + push af + push de + + and $03 ; Load dummy FM instrument + add $40 + ld c, 6 + ld hl, DummyFMInstr +.loaddummy: + ex af, af' + PollPCM + ex af, af' + ld e, (hl) + + ld (iy+0), a + ld (iy+1), e + add 4 + ld (iy+0), a + ld (iy+1), e + add 4 + ld (iy+0), a + ld (iy+1), e + add 4 + ld (iy+0), a + ld (iy+1), e + add 4 + + inc l + dec c + jp nz, .loaddummy + + pop de + PollPCM + pop af + + ld c, a ; Reset ADSR + or $F0 + ld (ix+0), $28 + ld (ix+1), a + ld (ix+0), $28 + ld (ix+1), c + + PollPCM + ret ; End of subroutine diff --git a/src-z80/player/freq.z80 b/src-z80/player/freq.z80 new file mode 100644 index 0000000..a469c0b --- /dev/null +++ b/src-z80/player/freq.z80 @@ -0,0 +1,105 @@ +;**************************************************************************** +; PSGFreqTable +; Frequency table for all PSG notes +;**************************************************************************** + + ds $100-($&$FF), $FF +PSGFreqTable: + db $83, $35 ; C-4 - 851 + db $83, $32 ; C#4 - 803 + db $86, $2F ; D-4 - 758 + db $8B, $2C ; D#4 - 715 + db $83, $2A ; E-4 - 675 + db $8D, $27 ; F-4 - 637 + db $89, $25 ; F#4 - 601 + db $88, $23 ; G-4 - 568 + db $88, $21 ; G#4 - 536 + db $8A, $1F ; A-4 - 506 + db $8D, $1D ; A#4 - 477 + db $82, $1C ; B-4 - 450 + db $89, $1A ; C-5 - 425 + db $81, $19 ; C#5 - 401 + db $8B, $17 ; D-5 - 379 + db $85, $16 ; D#5 - 357 + db $81, $15 ; E-5 - 337 + db $8E, $13 ; F-5 - 318 + db $8C, $12 ; F#5 - 300 + db $8C, $11 ; G-5 - 284 + db $8C, $10 ; G#5 - 268 + db $8D, $0F ; A-5 - 253 + db $8E, $0E ; A#5 - 238 + db $81, $0E ; B-5 - 225 + db $84, $0D ; C-6 - 212 + db $88, $0C ; C#6 - 200 + db $8D, $0B ; D-6 - 189 + db $82, $0B ; D#6 - 178 + db $88, $0A ; E-6 - 168 + db $8F, $09 ; F-6 - 159 + db $86, $09 ; F#6 - 150 + db $8E, $08 ; G-6 - 142 + db $86, $08 ; G#6 - 134 + db $8E, $07 ; A-6 - 126 + db $87, $07 ; A#6 - 119 + db $80, $07 ; B-6 - 112 + db $8A, $06 ; C-7 - 106 + db $84, $06 ; C#7 - 100 + db $8E, $05 ; D-7 - 94 + db $89, $05 ; D#7 - 89 + db $84, $05 ; E-7 - 84 + db $8F, $04 ; F-7 - 79 + db $8B, $04 ; F#7 - 75 + db $87, $04 ; G-7 - 71 + db $83, $04 ; G#7 - 67 + db $8F, $03 ; A-7 - 63 + db $8B, $03 ; A#7 - 59 + db $88, $03 ; B-7 - 56 + db $85, $03 ; C-8 - 53 + db $82, $03 ; C#8 - 50 + db $8F, $02 ; D-8 - 47 + db $8C, $02 ; D#8 - 44 + db $8A, $02 ; E-8 - 42 + db $87, $02 ; F-8 - 39 + db $85, $02 ; F#8 - 37 + db $83, $02 ; G-8 - 35 + db $81, $02 ; G#8 - 33 + db $8F, $01 ; A-8 - 31 + db $8D, $01 ; A#8 - 29 + db $8C, $01 ; B-8 - 28 + db $8A, $01 ; C-9 - 26 + db $89, $01 ; C#9 - 25 + db $87, $01 ; D-9 - 23 + db $86, $01 ; D#9 - 22 + db $85, $01 ; E-9 - 21 + db $83, $01 ; F-9 - 19 + db $82, $01 ; F#9 - 18 + db $81, $01 ; G-9 - 17 + db $80, $01 ; G#9 - 16 + db $8F, $00 ; A-9 - 15 + db $8E, $00 ; A#9 - 14 + db $8E, $00 ; B-9 - 14 + +;**************************************************************************** +; FMFreqTable +; Frequency table for all FM notes +;**************************************************************************** + +FMFreqTable: + dw 644, 681, 722, 765 + dw 810, 858, 910, 964 + dw 1021, 1081, 1146, 1214 + +;**************************************************************************** +; DummyFMInstr +; Dummy FM instrument to mute FM channels... +; +; To-do: put this in its own file? Although I'd like for this table to stay +; in this area in memory +;**************************************************************************** + +DummyFMInstr: + db $7F ; $40..$4C + db $1F ; $50..$5C + db $1F ; $60..$6C + db $1F ; $70..$7C + db $0F ; $80..$8C + db $00 ; $90..$9C diff --git a/src-z80/player/misc.z80 b/src-z80/player/misc.z80 new file mode 100644 index 0000000..6373ab0 --- /dev/null +++ b/src-z80/player/misc.z80 @@ -0,0 +1,31 @@ +;**************************************************************************** +; SetDelay* [event $FE] +; Adds a delay in playback +;**************************************************************************** + +SetDelaySFX: + call SetDelay ; We're just a wrapper + jp DoTick_SFXSkip ; End of subroutine + +SetDelayBGM: + call SetDelay ; We're just a wrapper + jp DoTick_BGMSkip ; End of subroutine + +SetDelay: + PollPCM + call GetParam ; Get delay + PollPCM + + ex de, hl + ld (hl), d ; Store new address + dec l + ld (hl), e + dec l + ld (hl), c + + PollPCM + + dec l ; Store new delay + ld (hl), b + + ret ; End of subroutine diff --git a/src-z80/player/pcm.z80 b/src-z80/player/pcm.z80 new file mode 100644 index 0000000..44bc236 --- /dev/null +++ b/src-z80/player/pcm.z80 @@ -0,0 +1,139 @@ +;**************************************************************************** +; PlayPCM* +; Plays a PCM sample +;**************************************************************************** + +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: + call GetParam ; Get sample ID + + ld a, b + exx ; We'll modify PCM data now + ld b, $01 ; Play PCM! + + 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 ; Restore $6000 back to HL + exx ; Back to standard variables + + 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: + ;ld (ix+0), $24 ; Reset timer + ;ld (ix+1), $FE + ;ld (ix+0), $25 + ;ld (ix+1), $03 + ld (ix+0), $27 + ld (ix+1), $1F + + exx ; Switch to PCM registers + + ld a, b ; Do any playback? + or a + jr z, .nopcm + + ld a, (RAM_LastBank) ; Bank switch? + cp c + jp z, .noswitchu + ld a, c + ld (RAM_LastBank), a + BankSwitch +.noswitchu: + + ld a, (de) ; Get sample + inc a ; Is it end of waveform? + jr z, .stop ; If so, stop + ld (ix+0), $2A ; Nope, send sample to YM2612 + ld (ix+1), a + + inc e ; Get address for next sample + jr nz, .nopcm + inc d + jr nz, .nopcm + ld d, $80 + inc c + +.nopcm: + exx ; Go back to normal registers + ret ; End of subroutine + +.stop: + ld b, $00 ; Stop playback + ld (ix+0), $2A ; Turn off DAC + ld (ix+1), $80 + ld (ix+0), $2B + ld (ix+1), $00 + exx ; Go back to normal registers + 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: + exx ; Stop PCM playback + ld b, $00 + exx + + 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 diff --git a/src-z80/player/psg.z80 b/src-z80/player/psg.z80 new file mode 100644 index 0000000..46df82a --- /dev/null +++ b/src-z80/player/psg.z80 @@ -0,0 +1,667 @@ +;**************************************************************************** +; UpdatePSG +; Updates PSG output +;**************************************************************************** + +UpdatePSG: + ld hl, RAM_PSGData+48 ; PSG envelope data of *last* channel + ld b, 3 ; Go through all channels +.loop: + push bc + + ld a, (hl) ; Get channel volume + bit 7, a + jr nz, .noskip + ld b, $0F + inc l + jp .skip +.noskip: + and $7F + ld b, a + + inc l ; Add global volume + ld a, (hl) + add b + ld b, a + + PollPCM + push bc + + inc l ; Get current address of envelope + ld c, (hl) + inc l + ld e, (hl) + inc l + ld d, (hl) + ex de, hl + +.readenv: + PollPCM + call GetParam ; Get next byte + PollPCM + + ld a, b + cp $FE ; Set loop point? + jp z, .envsetloop + cp $FF ; Loop envelope? + jp z, .envloop + + ld iyl, b ; Keep byte safe somewhere... + PollPCM + + ex de, hl ; Store new address + ld (hl), d + dec l + ld (hl), e + dec l + ld (hl), c + dec l + + pop bc + PollPCM + + db $FD,$7D ; ld a, iyl ; Mix envelope with volume + add b + ld b, a + + cp $10 ; Check for overflow + jr c, .notmute + ld b, $0F +.notmute: + +.skip: + PollPCM + + ld a, b ; Set PSG channel volume + rlca + rlca + rlca + pop bc + or b + rrca + rrca + rrca + or $90 + ld ($7F11), a + + ld a, l ; Go for next channel + sub 16+1 + ld l, a + PollPCM + dec b + jp p, .loop + + jp DoTick_PSGSkip ; End of subroutine + +.envsetloop: + PollPCM + inc e ; Where we store the loop point + + ex de, hl ; Store loop point + ld (hl), c + inc l + ld (hl), e + inc l + ld (hl), d + ex de, hl + + dec e ; Back to where we were... + dec e + dec e + jp .readenv ; Go for next byte + +.envloop: + PollPCM + inc e ; Where we store the loop point + + ex de, hl ; Retrieve loop point + ld c, (hl) + inc l + ld e, (hl) + inc l + ld d, (hl) + ex de, hl + + dec e ; Back to where we were... + dec e + dec e + jp .readenv ; Go for next byte + +;**************************************************************************** +; NoteOnPSG* +; Does a "note on" for a PSG channel +;**************************************************************************** + +NoteOnPSGSFX: + call NoteOnPSG ; We're just a wrapper + jp ProcessSFXRun ; End of subroutine + +NoteOnPSGBGM: + ld b, a + PollPCM + ld a, b + + push hl + and $03 ; Check if channel is free + ld hl, RAM_Locked+8 + add l + ld l, a + ld a, (hl) + pop hl + or a + jp nz, ProcessBGMSkip1 ; Don't play if locked + + ld a, b + call NoteOnPSG ; We're just a wrapper + jp ProcessBGMRun ; End of subroutine + +NoteOnPSG: + and $03 + ld b, a + ;push af + ex af, af' + PollPCM + + push hl ; Set channel volume + ld h, RAM_PSGData>>8 + ld a, b + rrca + rrca + rrca + rrca + ld l, a + ld a, (hl) + or $80 + ld (hl), a + + PollPCM + push de + + inc l ; Now we'll reset the envelope address... + inc l + ld d, h + ld a, l + add 6 + ld e, a + + PollPCM + + ld a, (de) ; Reset envelope address + ld (hl), a + inc l + inc e + ld a, (de) + ld (hl), a + inc l + inc e + ld a, (de) + ld (hl), a + + pop de + pop hl + + 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 + pop hl + + ret ; End of subroutine + +;**************************************************************************** +; NoteOnNoise* +; Does a "note on" for the noise PSG channel +;**************************************************************************** + +NoteOnNoiseSFX: + call NoteOnNoise ; We're just a wrapper + jp ProcessSFXRun ; End of subroutine + +NoteOnNoiseBGM: + ld a, (RAM_Locked+11) ; Check if channel is free + or a + jp nz, ProcessBGMSkip1 ; Don't play if locked + + call NoteOnNoise ; We're just a wrapper + jp ProcessBGMRun ; End of subroutine + +NoteOnNoise: + PollPCM + push hl + + ld hl, RAM_PSGData+48 ; Set channel volume + ld a, (hl) + or $80 + ld (hl), a + + PollPCM + push de + + inc l ; Now we'll reset the envelope address... + inc l + ld d, h + ld a, l + add 6 + ld e, a + + PollPCM + + ld a, (de) ; Reset envelope address + ld (hl), a + inc l + inc e + ld a, (de) + ld (hl), a + inc l + inc e + ld a, (de) + ld (hl), a + + pop de + pop hl + +SetNoteNoise: + PollPCM + call GetParam ; Get noise type + PollPCM + + ld a, $E0 ; Set new noise type + or b + ld ($7F11), a + + ret ; End of subroutine + +;**************************************************************************** +; NoteOffPSG* +; Does a "note off" for a PSG channel +;**************************************************************************** + +NoteOffPSGSFX: + call NoteOffPSG ; We're just a wrapper + jp ProcessSFXRun ; End of subroutine + +NoteOffPSGBGM: + ld b, a + PollPCM + ld a, b + + push hl + and $03 ; Check if channel is free + ld hl, RAM_Locked+8 + add l + ld l, a + ld a, (hl) + pop hl + or a + jp nz, ProcessBGMRun ; Don't stop if locked + + ld a, b + call NoteOffPSG ; We're just a wrapper + jp ProcessBGMRun ; End of subroutine + +NoteOffPSG: + and $03 + ld b, a + PollPCM + + push hl ; Mark channel as not playing + ld h, RAM_PSGData>>8 + ld a, b + rrca + rrca + rrca + rrca + ld l, a + ld a, (hl) + and $7F + ld (hl), a + pop hl + + ret ; End of subroutine + +;**************************************************************************** +; SetPSGVol* +; Sets the volume of a PSG channel +;**************************************************************************** + +SetPSGVolSFX: + and $03 ; Get channel ID + + ex af, af' + PollPCM + call GetParam ; Get volume + PollPCM + ex af, af' + + push hl + ld h, RAM_PSGData>>8 ; Set new volume + rrca + rrca + rrca + rrca + ld l, a + ld a, (hl) + and $80 + or b + ld (hl), a + pop hl + + jp ProcessSFXRun ; End of subroutine + +SetPSGVolBGM: + and $03 ; Get channel ID + + ex af, af' + PollPCM + call GetParam ; Get volume + PollPCM + ex af, af' + + push de + push hl + + push af + ld de, RAM_Locked+8 ; Check if channel is locked + add e ; Keep results for later + ld e, a + ld a, (de) + ld e, a + + PollPCM + pop af + + ld h, RAM_PSGData>>8 ; Store new volume + rrca + rrca + rrca + rrca + add 15 + ld l, a + ld (hl), b + + PollPCM + + ld a, e ; Is channel locked? + or a + jr nz, .nosetvol + + ld a, l ; Set new volume + sub 15 + ld l, a + ld a, (hl) + and $80 + or b + ld (hl), a + + PollPCM + +.nosetvol: + pop hl + pop de + + jp ProcessBGMRun ; End of subroutine + +;**************************************************************************** +; LoadPSG* +; Loads a PSG instrument +;**************************************************************************** + +LoadPSGSFX: + and $03 ; Get channel number + + ex af, af' + PollPCM + call GetParam ; Get instrument ID + PollPCM + ex af, af' + + push de + push hl + + ld d, RAM_PointerList>>8 ; Get position in pointer list + ld e, b + + ld h, RAM_PSGData>>8 ; Where to store address + rrca + rrca + rrca + rrca + add 8+2+(RAM_PSGData&$FF) + ld l, a + + PollPCM + + ld a, (de) ; Store PSG envelope start address + ld (hl), a + inc d + dec l + ld a, (de) + ld (hl), a + inc d + dec l + ld a, (de) + ld (hl), a + + PollPCM + + ld a, l ; Reset volume + sub 8 + ld l, a + ld (hl), $00 + + pop hl + pop de + jp ProcessSFXRun ; End of subroutine + +;---------------------------------------------------------------------------- + +LoadPSGBGM: + and $03 ; Get channel number + + ex af, af' + PollPCM + call GetParam ; Get instrument ID + PollPCM + ex af, af' + + push de + push hl + + ld d, RAM_PointerList>>8 ; Get position in pointer list + ld e, b + + ld hl, RAM_Locked+8 ; Get if channel is locked + push af + add l + ld l, a + pop af + ld b, (hl) + + ld h, RAM_PSGData>>8 ; Where to store BGM instrument data + rrca + rrca + rrca + rrca + add 15 + ld l, a + + PollPCM + + ld (hl), a ; Reset volume for BGM + dec l + + ld a, (de) ; Store PSG envelope address for BGM + ld (hl), a + inc d + dec l + ld a, (de) + ld (hl), a + inc d + dec l + ld a, (de) + ld (hl), a + + PollPCM + + ld a, b ; Don't set PSG envelope if locked + or a + jp z, .noloadlocked + pop hl + pop de + jp ProcessBGMRun +.noloadlocked: + PollPCM + + ld d, h ; Set PSG envelope + ld a, l + sub 12-8 + ld e, a + + ld a, (hl) + ld (de), a + inc l + inc e + ld a, (hl) + ld (de), a + inc l + inc e + ld a, (hl) + ld (de), a + + PollPCM + + ld a, l ; Reset volume + sub 8 + ld l, a + ld (hl), $00 + + pop hl + pop de + jp ProcessBGMRun ; End of subroutine + +;**************************************************************************** +; SetNotePSG* +; Sets the note of a PSG channel without "note on" +;**************************************************************************** + +SetNotePSGSFX: + call SetNotePSG ; We're just a wrapper + jp ProcessSFXRun ; End of subroutine + +SetNotePSGBGM: + ld b, a + PollPCM + ld a, b + + push hl + and $0F ; Check if channel is free + ;ld hl, RAM_Locked + ;add l + ld h, RAM_Locked>>8 + add RAM_Locked&$FF + ld l, a + ld a, (hl) + pop hl + or a + jp nz, ProcessBGMSkip2 ; Don't play if locked + + ld a, b + call SetNotePSG ; We're just a wrapper + jp ProcessBGMRun ; End of subroutine + +SetNotePSG: + and $03 ; Get channel number + + ex af, af' + PollPCM + call GetParam ; Get first byte + PollPCM + ex af, af' + + push de ; PSG port address + ld de, $7F11 + + rrca ; Set first frequency byte + rrca + rrca + or b + or $80 + ld (de), a + + PollPCM + call GetParam ; Get second byte + PollPCM + + ex de, hl + ld (hl), b ; Set second frequency byte + ex de, hl + pop de + + ret ; End of subroutine + +;**************************************************************************** +; SetNoteNoise* +; Sets the note of the noise PSG channel without "note on" +;**************************************************************************** + +SetNoteNoiseSFX: + call SetNoteNoise ; We're just a wrapper + jp ProcessSFXRun ; End of subroutine + +SetNoteNoiseBGM: + ld a, (RAM_Locked+11) ; Check if channel is free + or a + jp nz, ProcessBGMSkip1 ; Don't play if locked + + call SetNoteNoise ; We're just a wrapper + jp ProcessBGMRun ; End of subroutine + +;**************************************************************************** +; LockChannelPSG [events $E8-$EB] +; Locks a PSG channel +;**************************************************************************** + +LockChannelPSG: + ld b, a + PollPCM + push hl + + ld h, RAM_Locked>>8 ; Get address of channel to lock + ld a, b + and $0F + add RAM_Locked&$FF + ld l, a + + ld (hl), $01 ; Lock channel + + PollPCM + + ld a, b ; Stop channel + rrca + rrca + rrca + rrca + ld l, a + ld h, RAM_PSGData>>8 + ld (hl), $00 + + pop hl + jp ProcessSFXRun ; End of subroutine |
