6

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.

2
  • 2
    I'm going to just give you some anecdotal advice. I could be way off... But my gut says the 'high pitch' and 'stutter/click' you describe sound suspiciously like your code has has hit a BRK and stopped executing - leaving the SID kinda hanging in whatever state it was in when the break occurred. I've personally had my own code abruptly stop and had the SID left dangling in 'super high pitch whine' mode, or 'brp brp brp stutter mode'. Granted, this is going back 20 or 30 years and my memory isn't what it once was, but I'd go over the logic again with a fine tooth comb.
    – Geo...
    Sep 13 at 18:53
  • 1
    I'll definitely look over it again, but the code hasn't hit a 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. Sep 14 at 10:26
10

As only a fragment of your code is available for review, it's hard to assess as the devil is generally in the detail.

However, from your VOICE_1_FREQ_HI ;$D401 reference, I note that you seem to be reading from the SID registers (unless VOICE_1_FREQ_HI is a shadow copy you maintain yourself).

The SID registers are write only (except $19-$1C) so what you are reading and storing and comparing with is undefined.

1
  • 2
    Yep, that did the trick. I should have figured they were write only- these things usually are. Sep 14 at 22:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.