; VBISOUND.SRC, rev. 2.4›; By Chris Chabris, 7-14-83›; For ANTIC Magazine››; VBI routine to play constant tone/distortion music independent of mainline program execution›; Call from BASIC with:›;       Q=USR(ADR(SET$))›; No additional calls are necessary except the following if you want to turn off the routine:›;       Q=USR(ADR(RESET$))››; PROGRAM EQUATES FOLLOW:››TABLE   EQU     $00CB           ; Address of current music table stored as a string›AUDF1   EQU     $D200           ; Audio frequency (pitch)for voice #1›AUDC1   EQU     $D201           ; Audio control (volume/distortion) for voice #1›XITVBV  EQU     $E462           ; Exit deferred VBI O.S. vector›SETVBV  EQU     $E45C           ; Set VBI O.S. vector›AUDCTL  EQU     $D208           ; POKEY AUDio ConTroL register››; DEFERRED VBI ROUTINE FOLLOWS:››        ORG     $0600           ; This program is not relocatable›        LDX     #00             ; Initialize the X- and Y-registers›        LDY     #00›LOOP1   JSR     MX2             ; Multiply the X-register by two for 2-byte table›        LDA     V0ADR,X         ; Get address of next voice's table of notes and durations›        STA     TABLE           ; Put it on page 0 for indirect indexed addressing›        LDA     V0ADR+1,X›        STA     TABLE+1›        JSR     DX2             ; Now divide X by two for the next table›        LDA     STATUS,X›        BNE     NEXT            ; If status>0 (voice inactive) go do next voice›        DEC     DUR,X           ; Decrement this voice's duration counter›        BNE     NEXT            ; If >0, note or pause is still in progress, so go try the next voice›        LDY     COUNT,X         ; Get the index into the music table to find next note, duration›        LDA     (TABLE),Y›CEND    CMP     #$FF            ; $FF means end this voice until the status becomes zero again›        BNE     CREP            ; If not $FF, check for the next command option›        LDA     #01             ; A one in the status register turns off the voice›        STA     STATUS,X›        LDA     #00›        JSR     MX2›        STA     AUDF1,X         ; Turn off this voice by storing a zero in its Audio Frequency›        STA     AUDC1,X         ;   and Audio Control registers›        JSR     DX2›        JMP     NEXT            ; And go on to try the next voice›CREP    CMP     #$FE            ; $FE means immemdiately repeat the preceding music for this voice›        BNE     NOTE            ; If not $FE, try to play the next note›        LDA     #00›        STA     COUNT,X         ; Reset index to zero, indicating the start of the music table›        LDA     #01             ; Mark a duration of one so that the next VBI will restart the music›        STA     DUR,X›        LDA     #00›        STA     PAUSE,X         ; Turn off a pause that might have been in progress›        JMP     NEXT            ; Try the next voice›NOTE    PHA                     ; Save the frequency value in the accumulator›        LDA     PAUSE,X         ; Check to see whether a pause was in progress›        BNE     PLAY            ; >0 indicates yes - a pause has just terminated›        LDA     #03             ; No - so set up a pause of 3/60 second›        STA     DUR,X           ; Using the duration counter›        STA     PAUSE,X         ; And setting the pause register›        LDA     #00›        JSR     MX2›        STA     AUDF1,X         ; Don't forget to turn off the sound!›        JSR     DX2›        PLA                     ; Pop stack›        JMP     NEXT            ;   to go on to the next voice›PLAY    LDA     #00             ; The pause is over - reset the pause register›        STA     PAUSE,X›        PLA                     ; Retrieve the next frequency value›        JSR     MX2›        STA     AUDF1,X         ;   and put it into the Audio Frequency register for this voice›        LDA     #$A6            ; Give it a pure distortion (10) and volume of 6›        STA     AUDC1,X         ; so put 16*distortion+volume into the Audio Control register›        JSR     DX2›        INY                     ; Increment index to get this note's duration›        LDA     (TABLE),Y›        STA     DUR,X           ; Store it to begin the countdown›        INY                     ; Increment the index for the next VBI›        TYA›        STA     COUNT,X         ;   and save it until then›NEXT    INX                     ; Increment counter of # of voices processed›        CPX     NUMV            ; Have we processed all voices specified?›        BNE     AGAIN           ; No - go jump to the beginning (too far to branch)›        JMP     DONE            ; Yes - so go and end the interrupt›AGAIN   JMP     LOOP1           ; Go back to the start of the loop to process the next voice››; SUBROUTINES FOLLOW:››MX2     PHA                     ; This routine simply multiplies the value in the›        TXA                     ;   X-register by two for various uses›        ASL     A›        TAX›        PLA›        RTS›DX2     PHA                     ; This one reverses the multiply done in the›        TXA                     ;   routine above›        LSR     A›        TAX›        PLA›        RTS››; EXIT DEFERRED VERTICAL BLANK INTERRUPT ROUTINE FOLLOWS:››DONE    LDA     AUD             ; Get user AUDCTL setting›        STA     AUDCTL          ; Make sure POKEY remembers it›        JMP     XITVBV          ; Now let the O.S. take us out of the interrupt and back to main program››; VARIABLE STORAGE FOLLOWS:››NUMV    DB      $01›V0ADR   DB      $00,$00,$00,$00,$00,$00,$00,$00›DUR     DB      $01,$01,$01,$01›STATUS  DB      $00,$00,$00,$00›COUNT   DB      $00,$00,$00,$00›PAUSE   DB      $00,$00,$00,$00›AUD     DB      $00››; RELOCATABLE VBI INSERTION ROUTINE FOLLOWS:››        ORG     $6000›        PLA                     ; Required when accessing from BASIC›        LDY     #$00            ; Lobyte of VBI routine start address goes in Y-register›        LDX     #$06            ; Hibyte of same goes in X-register›        LDA     #07             ; 7=Deferred VBI, 6=Immediate VBI›        JSR     SETVBV          ; Let the O.S. insert the routine›        RTS                     ; All done, so back to BASIC››; RELOCATABLE VBI RESET ROUTINE FOLLOWS:››        ORG     $6100›        PLA                     ; This reverses the above routine by storing the›        LDY     #$62            ;   address XITVBV in the deferred VBI vector›        LDX     #$E4            ; (actually, it lets the O.S. do it again)›        LDA     #07›        JSR     SETVBV›        RTS››        END›