Sona 0.50 Source

Sona 0.50/src-z80/psg_volume.z80

;****************************************************************************
; PsgSetVolume [SONAOP_VOLUME_PSG1..PSG4]
; Handles volume events for PSG channels.
;----------------------------------------------------------------------------
; input b ..... channel ID (bits 1~0 only)
; input c ..... current bank
; input hl .... current address
;----------------------------------------------------------------------------
; output c .... new bank
; output hl ... new address
;----------------------------------------------------------------------------
; modifies .... a,bc,de,hl,a'
;****************************************************************************

PsgSetVolume:
    PollPcm
    CheckOwner
    
    ld      a, b                        ; Isolate channel ID
    and     $03
    ld      b, a
    
    add     a, RealPsgVol&$FF           ; Compute pointer to where the final
    ld      (PsgSetVolume_RealPtr), a   ; PSG volume (what the hardware will
                                        ; see) will be stored later
    
    ld      a, i                        ; Get pointer to where channel
    and     SfxPsgVol-BgmPsgVol         ; volume is stored
    add     a, b
    add     a, BgmPsgVol&$FF
    ld      d, BgmPsgVol>>8
    ld      e, a
    
    call    ReadVolArg                  ; Read volume value
    
    RetIfNotOwner                       ; Don't touch the PSG hardware volume
                                        ; if we don't own this channel
    
    ; fallthrough to RawPsgSetVolume...

;****************************************************************************
; RawPsgSetVolume
;
; The piece of code that takes the SonaStream-formatted PSG volume and
; converts it to what the PSG actually takes and stores it so the update
; code can do its thing properly.
;
; Isolated into its own subroutine since it's used by RestorePsg too.
;----------------------------------------------------------------------------
; input de ... pointer to volume
;----------------------------------------------------------------------------
; modifies .... a,b,de
;----------------------------------------------------------------------------
; Before calling PsgSetVolume_RealPtr must be overwritten to point to where
; to write the result (the postprocessed PSG volume).
;****************************************************************************

RawPsgSetVolume:
    PollPcm
    
    ld      a, (de)                     ; Check if volume would be too quiet
    cp      40                          ; for the PSG and clamp it if so (it
    jr      c, PsgSetVolume_NotMute     ; prevents overflow issues below)
    ld      a, 40
PsgSetVolume_NotMute:
    
    ld      b, a                        ; Volume is given in YM2612 units
    add     a, b                        ; (-0.75dB per step) but PSG uses
    add     a, b                        ; different units (-2dB per step)
    rrca                                ; so convert the value accordingly
    rrca
    rrca
    and     $0F
    
PsgSetVolume_RealPtr: equ $+1
    ld      e, 0                        ; Store new precomputed value
    ld      (de), a
    
    ret                                 ; End of subroutine