; 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
Back to previous page