136 lines
4.2 KiB
NASM
136 lines
4.2 KiB
NASM
; -----------------------------------------------------------
|
|
; sound.asm - minimal SID sound driver using voice 1
|
|
; sfx_init - set master volume, silence voice 1
|
|
; sfx_play - start effect A (SFX_SCORE, SFX_MISS, etc.)
|
|
; sfx_update - call once per frame to handle duration/slides
|
|
; -----------------------------------------------------------
|
|
|
|
; ---- one-time setup: master volume on, voice 1 silent ----
|
|
sfx_init:
|
|
lda #$0f ; max volume, no filter
|
|
sta SID_VOL
|
|
lda #0
|
|
sta SID_V1CR ; gate off, no waveform
|
|
sta sfx_timer
|
|
rts
|
|
|
|
; ---- start playing effect A ----
|
|
sfx_play:
|
|
tax
|
|
; gate off first (retrigger envelope)
|
|
lda #0
|
|
sta SID_V1CR
|
|
; load parameters from the table
|
|
lda sfx_flo,x
|
|
sta SID_V1FL
|
|
lda sfx_fhi,x
|
|
sta SID_V1FH
|
|
lda sfx_ad,x
|
|
sta SID_V1AD
|
|
lda sfx_sr,x
|
|
sta SID_V1SR
|
|
lda #$00 ; pulse width mid-point for pulse wave
|
|
sta SID_V1PL
|
|
lda #$08
|
|
sta SID_V1PH
|
|
lda sfx_wave,x ; waveform + gate bit
|
|
sta SID_V1CR
|
|
lda sfx_dur,x
|
|
sta sfx_timer
|
|
lda sfx_slide,x
|
|
sta sfx_sld
|
|
rts
|
|
|
|
; ---- per-frame update: pitch slide + gate off when done ----
|
|
sfx_update:
|
|
lda sfx_timer
|
|
beq sfu_done ; nothing playing
|
|
dec sfx_timer
|
|
bne sfu_slide
|
|
; duration expired: gate off
|
|
lda #0
|
|
sta SID_V1CR
|
|
rts
|
|
sfu_slide:
|
|
; apply pitch slide (signed: positive = up, negative = down)
|
|
lda sfx_sld
|
|
beq sfu_done
|
|
bmi sfu_down
|
|
; slide up
|
|
clc
|
|
adc SID_V1FH
|
|
sta SID_V1FH
|
|
rts
|
|
sfu_down:
|
|
; slide down (sfx_sld is negative, e.g. $fe = -2)
|
|
clc
|
|
adc SID_V1FH ; adding a negative = subtracting
|
|
sta SID_V1FH
|
|
bcs sfu_done ; no underflow
|
|
lda #0
|
|
sta SID_V1FH ; clamp at zero
|
|
sfu_done:
|
|
rts
|
|
|
|
; ---- effect parameter tables (indexed by SFX ID) ----
|
|
|
|
; initial frequency low byte
|
|
sfx_flo:
|
|
!byte $00 ; SFX_SCORE: freq $1C00
|
|
!byte $00 ; SFX_MISS: freq $0800
|
|
!byte $00 ; SFX_OVER: freq $2000
|
|
!byte $00 ; SFX_CURSOR: freq $0A00
|
|
!byte $00 ; SFX_SELECT: freq $1000
|
|
|
|
; initial frequency high byte
|
|
sfx_fhi:
|
|
!byte $1c ; SFX_SCORE
|
|
!byte $08 ; SFX_MISS
|
|
!byte $20 ; SFX_OVER
|
|
!byte $0a ; SFX_CURSOR
|
|
!byte $10 ; SFX_SELECT
|
|
|
|
; attack/decay ($XY: X=attack 0-F, Y=decay 0-F)
|
|
sfx_ad:
|
|
!byte $00 ; SFX_SCORE: instant attack, instant decay
|
|
!byte $00 ; SFX_MISS: instant attack, instant decay
|
|
!byte $09 ; SFX_OVER: instant attack, slow decay
|
|
!byte $00 ; SFX_CURSOR: instant attack, instant decay
|
|
!byte $00 ; SFX_SELECT: instant attack, instant decay
|
|
|
|
; sustain/release ($XY: X=sustain 0-F, Y=release 0-F)
|
|
sfx_sr:
|
|
!byte $a8 ; SFX_SCORE: medium sustain, medium release
|
|
!byte $f5 ; SFX_MISS: full sustain, medium release
|
|
!byte $08 ; SFX_OVER: zero sustain, medium release
|
|
!byte $50 ; SFX_CURSOR: low sustain, instant release
|
|
!byte $98 ; SFX_SELECT: medium sustain, medium release
|
|
|
|
; waveform + gate ($XY: bit7=noise, bit6=pulse, bit5=saw, bit4=tri, bit0=gate)
|
|
sfx_wave:
|
|
!byte $11 ; SFX_SCORE: triangle + gate
|
|
!byte $81 ; SFX_MISS: noise + gate
|
|
!byte $21 ; SFX_OVER: sawtooth + gate
|
|
!byte $41 ; SFX_CURSOR: pulse + gate
|
|
!byte $11 ; SFX_SELECT: triangle + gate
|
|
|
|
; duration in frames
|
|
sfx_dur:
|
|
!byte 8 ; SFX_SCORE
|
|
!byte 10 ; SFX_MISS
|
|
!byte 50 ; SFX_OVER
|
|
!byte 3 ; SFX_CURSOR
|
|
!byte 8 ; SFX_SELECT
|
|
|
|
; pitch slide per frame (signed: + = up, - = down, 0 = none)
|
|
sfx_slide:
|
|
!byte 0 ; SFX_SCORE: steady
|
|
!byte $fe ; SFX_MISS: slide down (-2)
|
|
!byte $fd ; SFX_OVER: slide down (-3)
|
|
!byte 0 ; SFX_CURSOR: steady
|
|
!byte 2 ; SFX_SELECT: slide up (+2)
|
|
|
|
; ---- driver state ----
|
|
sfx_timer: !byte 0 ; frames remaining for current effect
|
|
sfx_sld: !byte 0 ; current slide value
|