Classic Computer Magazine Archive PROGRAM LISTING: 83-11/SNDEDTR.ASM


; 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