;****************************************************************************
; PsgKeyOnOp [SONAOP_KEYON_PSG1,PSG2,PSG3]
; Handles key-on events in a stream for square PSG channels.
;----------------------------------------------------------------------------
; input b ..... channel ID (bits 1-0 only)
; input c ..... current stream bank
; input hl .... current stream address
;----------------------------------------------------------------------------
; output c .... new stream bank
; output hl ... new stream address
;----------------------------------------------------------------------------
; modifies .... a,bc,de,hl,a'
;****************************************************************************
PsgKeyOnOp:
CheckOwner ; Start attack phase (but only if
CallIfOwner PsgSetAttack ; we control this channel)
; fallthrough to PsgSetPitchOp...
;****************************************************************************
; PsgSetPitchOp [SONAOP_PITCH_PSG1,PSG2,PSG3]
; Handles the stream event for changing the pitch for square PSG channels.
;----------------------------------------------------------------------------
; input b ..... channel ID (bits 1-0 only)
; input c ..... current stream bank
; input hl .... current stream address
;----------------------------------------------------------------------------
; output c .... new stream bank
; output hl ... new stream address
;----------------------------------------------------------------------------
; modifies .... a,bc,de,hl,a'
;****************************************************************************
PsgSetPitchOp:
PollPcm
CheckOwner
ld a, i ; Compute pointer to the pitch
and PsgPitch-BgmPsgPitch ; value for this channel
ld e, a
ld a, b
and $03
add a, a
add a, e
add a, BgmPsgPitch&$FF
ld d, BgmPsgPitch>>8
ld e, a
call ReadPitchArg ; Read pitch argument and store it
RetIfNotOwner ; If this is a BGM and the channel
RetIfSfx ; wasn't taken over by a SFX, we need
PollPcm ; to also copy it over to the output
; so UpdatePsg can see it
ex de, hl ; Swap away HL since we need to
; preserve it but the instructions
; below require HL to work
ld a, (hl) ; Read BGM pitch
inc l
ld b, (hl)
ex af, af' ; Change pointer to point to the
ld a, l ; output pitch as seen by UpdatePsg
add PsgPitch-BgmPsgPitch
ld l, a
ex af, af'
ld (hl), b ; Save BGM pitch as output pitch
dec l
ld (hl), a
ex de, hl ; Restore HL back
ret ; End of subroutine
;****************************************************************************
; NoiseKeyOnOp [SONAOP_KEYON_PSG4]
; Handles key-on events in a stream for the noise channel.
;----------------------------------------------------------------------------
; input b ..... channel ID (bits 1-0 only)
; input c ..... current stream bank
; input hl .... current stream address
;----------------------------------------------------------------------------
; output c .... new stream bank
; output hl ... new stream address
;----------------------------------------------------------------------------
; modifies .... a,bc,de,hl,a'
;****************************************************************************
NoiseKeyOnOp:
CheckOwner ; Start attack phase (but only if
CallIfOwner PsgSetAttack ; we control this channel)
; fallthrough to NoiseSetPitchOp...
;****************************************************************************
; NoiseSetPitchOp [SONAOP_PITCH_PSG4]
; Handles the stream event for changing the pitch for the noise channel.
;----------------------------------------------------------------------------
; input c ..... current stream bank
; input hl .... current stream address
;----------------------------------------------------------------------------
; output c .... new stream bank
; output hl ... new stream address
;----------------------------------------------------------------------------
; modifies .... a,bc,de,hl,a'
;****************************************************************************
NoiseSetPitchOp:
CheckOwner
ReadArgByte ; Read new noise mode
RetIfNotOwner ; Don't touch the noise channel if
; we don't control it
ld a, b ; Mask the noise mode bits (is this
and $07 ; really needed?)
OldPsgNoise: equ $+1
cp $FF ; Only change noise pitch if it changed
ret z ; since last time (to prevent noticeable
ld (OldPsgNoise), a ; phase resets)
or $E0 ; Write new noise mode
ld (PsgPort), a ; directly to the PSG
ret ; End of subroutine
;****************************************************************************
; PsgSetAttack
;
; Sets a PSG channel's ADSR envelope into its attack phase. Used by the two
; PSG key-on handlers since this is common to both square and noise channels.
;----------------------------------------------------------------------------
; input b .... channel ID (bits 1-0 only)
;----------------------------------------------------------------------------
; modifies ... a,de
;****************************************************************************
PsgSetAttack:
call GetPsgAdsrPtr ; Get pointer to the ADSR's phase
; state for this channel
xor a ; Set PSG envelope to the
ld (de), a ; attack phase
ret ; Back to caller
;****************************************************************************
; PsgKeyOffOp [SONAOP_KEYOFF_PSG1,PSG2,PSG3,PSG4]
; Handles key-on events in a stream for square and noise PSG channels.
;----------------------------------------------------------------------------
; input b ..... channel ID (bits 1-0 only)
; input c ..... current stream bank
; input hl .... current stream address
;----------------------------------------------------------------------------
; output c .... new stream bank
; output hl ... new stream address
;----------------------------------------------------------------------------
; modifies .... a,bc,de,hl,a'
;****************************************************************************
PsgKeyOffOp:
CheckOwner ; Do nothing if we don't have
RetIfNotOwner ; control over this channel
call GetPsgAdsrPtr ; Get pointer to the ADSR's phase
; state for this channel
PollPcm
ld a, PSGPHASE_RELEASE ; Set PSG envelope to the
ld (de), a ; release phase
ret ; Back to caller