I created this little sound driver for sound effects, it makes a classic "laser beam" sound you would hear in old arcade games. There's just one problem, and it's a bit of a strange one.
I have the program set up so that it outputs a constant low tone (note C, octave 3) Pressing the fire button on the joystick makes the laser sound by decrementing the pitch in a loop that terminates once the pitch is back where it was before pressing the button. The driver is executed every game loop, and uses two flag variables, the first tells the driver to decrement the current playing sound and the second sets up the loop, which is cleared immediately after initializing the loop. The first flag isn't cleared until the sound effect is done playing.
The thing is, if you press the fire button just after the game begins, after the laser sound is done the pitch becomes very high and stays that way, even though it shouldn't. If you wait about a second after startup and press the button, this doesn't happen. Rather, the sound when the laser effect isn't playing becomes a low repeated clicking. It seems that there is a "warm up" period for the Commodore 64 SID but I couldn't find any mention of it in the literature. It could also be a bug in my code, so I will display it here:
doSFX:
; HOW THIS WORKS:
; There are 8 sound effects, one for each bit.
; If a sound effect needs to play
; a request is made by setting that sfx's bit in both sfx_flags and sfx_init_flags
; This routine will see the flags and perform the init routine, after which the init
; flag is cleared. The sfx_flags aren't cleared until the sound effect is done playing.
pha
bit sfx_flags ;is bit 7 set?
bpl skip_sfx_7 ;if not, skip this section
;laser sound effect
bit sfx_init_flags ;is bit 7 set?
bpl skip_sfx_7_init ;if not, skip the init routine.
;init code goes here
lda VOICE_1_FREQ_HI ;$D401, get the current frequency
sta sound_snapshot ;back it up
lda sfx_init_flags
and #%01111111 ;clear bit 7, skipping the init code until sfx is done.
sta sfx_init_flags
;end of init code
; IF THIS REQUEST IS PROCESSED TOO SOON AFTER THE SOUND IS INITIALIZED BY THE GAME,
; THIS ROUTINE WILL FREEZE THE NOTE AT A HIGH PITCH. IF YOU WAIT A SECOND
; THEN PRESS THE BUTTON, THE SOUND STOPS AND YOU HEAR A CLICKING PATTERN. EITHER WAY,
; THE ORIGINAL NOTE DOESN'T COME BACK EVEN THOUGH IT SHOULD.
skip_sfx_7_init:
dec VOICE_1_FREQ_HI
lda VOICE_1_FREQ_HI
cmp sound_snapshot ;is it back to where it was when we started?
bne skip_sfx_7
;end code goes here
LDA sound_snapshot
sta VOICE_1_FREQ_HI
lda sfx_flags
and #%01111111 ;clear this flag.
sta sfx_flags
;end of end code
skip_sfx_7:
;add more sfx later
pla
rts
The joystick routine simply sets bit 7 of both flag variables when the fire button is pressed, but only if they aren't already set.
BRK
. I neglected to mention this in the original question but I also programmed a hardware sprite that can be moved with the joystick, and it still moves even after the sound plays. Also, I've noticed that if I press the button again while the "whine mode" occurs, it whines again, unless I wait a couple seconds and then press it, at which point it goes back to clicking.