; 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›