Sona 0.50 Source

Sona 0.50/src-z80/psg_key.z80

;****************************************************************************
; 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