xSFX Engine

https://atariage.com/forums/topic/320982-sfx-engine/

LEVEL1: wersja minimum, jedna komenda plus pętle
LEVEL2: brak sampli, brak funkcji, brak pluginów, brak syntezy mowy
LEVEL3: pełna wersja

                opt l+
SFXZP           equ $80     ; ZPAGE
VPOKEY          equ $D200

                org $2000
runme
                LDA #$00
                STA $D208
                LDA #$03
                STA $D20F

loop            lda $D40B
                cmp #4
                bcs loop

@               lda $D40B
                cmp #$10
                bcc @-

                lda #$0f
                sta $D01A

                jsr xSFX_ENGINE

                lda #$00
                sta $D01A

                lda $2FC
                cmp #$1f  ; klawisz "1" play      1e=2  1a=3  18=4 1d=5 1b=6 33=7 35=8 30=9  32=0
                beq insert
                cmp #$1e  ; klawisz "2" stop
                bne loop

                ldx #0
                jsr xSFX_ENGINE+6
                ldx #1
                jsr xSFX_ENGINE+6
                ldx #2
                jsr xSFX_ENGINE+6
                ldx #3
                jsr xSFX_ENGINE+6

@               lda #255
                sta $2FC
                jmp loop

insert          lda #5          ; sfx5
                ldx #0          ; ch1
                sec             ; force
                jsr xSFX_ENGINE+3

                jmp @-



; ================================================ LEVEL 2
; === SFX ENGINE ====
;xSFX_ENGINE - jump here 1 per frame at least
;
;xSFX_ENGINE+3  in:  A=sfx, X=channel, C=1 (force)
;                    A=sfx, C=0 (find free channel)
;               out: C=1 no free channel
;                    C=0 ok
;
;xSFX_ENGINE+6  in:  X=channel - will immediately terminate SFX on the specified channel
; ===
;
; Command:
;
;1. TIME,AUDF,AUDC          ; graj TIME ilość ramek, zapisz rejestry AUDF, AUDC
;2. REPF,TIME,COUNT,AUDC    ; powtórz COUNT razy: graj TIME ilosc ramek, zainicjuj AUDC, wpisuj AUDF COUNT razy
;3. REPC,TIME,COUNT,AUDF    ; powtórz COUNT razy: graj TIME ilosc ramek, zainicjuj AUDF, wpisuj AUDC COUNT razy
;4. LOOP                    ; powtórz ten sam dźwięk od komendy na pozycji loop
;5. RTS                     ; koniec opisu dźwięku
;6. JSR nnnnn               ; wywołaj SFX nr. nn i po jego zakończeniu wróć kontynuuj odtwarzanie obecnego
;7. JMP nnnnn               ; skocz do SFX nr.
 

xSFX_ENGINE     jmp xSFX_PROCEED         ; xSFX_ENGINE
xSFX_START      jmp SFX_INSERT           ; xSFX_ENGINE+3
xSFX_STOP       jmp SFX_CHANNEL_OFF      ; xSFX_ENGINE+6


SFX_ENDRTS      iny
                lda (SFXZP),Y
                tay
                dey                    
                cmp #$ff
                beq SFX_RTSEND
                jmp SFX_RELOAD

SFX_RTSEND      lda SFX_RTS,x          
                bne SFX_DORTS
                jsr SFX_CHANNEL_OFF
                jmp SFX_NXTCH          

SFX_DORTS       pha                    
                lda #$00
                sta SFX_RTS,x
                lda SFX_RCNT,x
                sta SFX_CNT,x
                jmp SFX_DORTSF         

SFX_REP         dec SFX_REPEAT,x       
                lda SFX_RTIME,x
                sta SFX_TIME,x         
                lda #$00
                lda SFX_FLAG,x         
                asl @                  
                bcs SFX_DF
                bcc SFX_DC


xSFX_PROCEED    ldx #3
SFX_CONTCH      lda SFX_NO,x
                bne SFX_PROCED
SFX_NXTCH       dex
                bpl SFX_CONTCH
                rts

SFX_PROCED      ldy SFX_TIME,x
                bne SFX_CONTTONE
SFX_CONTCHJ     tay
                lda SFX_ADR_TAB-2,y          
                sta SFXZP
                lda SFX_ADR_TAB-1,y
                sta SFXZP+1
                ldy SFX_CNT,x                
                lda SFX_REPEAT,x             
                bne SFX_REP
SFX_RELOAD      iny
                lda (SFXZP),Y                
                beq SFX_ENDRTS
SFX_TOKEN       asl @                        
                bcc SFX_TIM
                asl @                        
                ror SFX_FLAG,x
                asl @
                bcs SFX_JUMP                 
                iny
                lda (SFXZP),Y
                sta SFX_RTIME,x
                iny
                lda (SFXZP),Y
                sta SFX_REPEAT,x
                lda SFX_FLAG,x           
                asl @
                iny
                lda (SFXZP),Y
                bcs SFX_C0C
                sta SFX_AUDF,x           
                bcc SFX_REP              
SFX_C0C         sta SFX_AUDC,x
                bcs SFX_REP              

SFX_TIM         lsr @                    
                sta SFX_TIME,x           
SFX_DF          iny
                lda (SFXZP),Y
                sta SFX_AUDF,x           
                bcs SFX_N3
SFX_DC          iny
                lda (SFXZP),Y
                sta SFX_AUDC,x           
SFX_N3          tya
                sta SFX_CNT,x            
SFX_CONTTONE    txa                      
                asl @
                tay
                lda SFX_AUDF,x
                sta VPOKEY,y             
                lda SFX_AUDC,x           
                sta VPOKEY+1,y
                dec SFX_TIME,x           
                jmp SFX_NXTCH

SFX_JUMP        lsr @
                lsr @
                pha
                lda SFX_FLAG,x
                bmi SFX_JMP
                lda SFX_NO,x
                sta SFX_RTS,x
                tya
                sta SFX_RCNT,x
SFX_JMP         lda #$ff
                sta SFX_CNT,x
SFX_DORTSF      pla
                sta SFX_NO,x
                jmp SFX_CONTCHJ         


SFX_CHANNEL_OFF
                txa
                asl @
                tay
                lda #$ff
                sta SFX_CNT,x
                lda #$00
                sta SFX_NO,x
                sta SFX_TIME,x
                sta SFX_REPEAT,x
                sta SFX_RTS,x
                sta VPOKEY,y
                sta VPOKEY+1,y
                rts

SFX_INSERT      bcs SFX_FORCE
                ldx #$03
SFX_FIND        ldy SFX_NO,x
                beq SFX_SETNO
                dex
                bpl SFX_FIND
                sec                         
                rts
SFX_FORCE       pha
                jsr SFX_CHANNEL_OFF
                pla
SFX_SETNO       asl @
                sta SFX_NO,x
                clc                         
                rts

SFX_NO     .HE 00 00 00 00                  
SFX_CNT    .HE FF,FF,FF,FF                  
SFX_TIME   .HE 00 00 00 00                  
SFX_AUDC   .HE 00 00 00 00
SFX_AUDF   .HE 00 00 00 00
SFX_FLAG   .HE 00 00 00 00
SFX_REPEAT .HE 00 00 00 00
SFX_RTIME  .HE 00 00 00 00
SFX_RTS    .HE 00 00 00 00
SFX_RCNT   .HE 00 00 00 00

SFX_ADR_TAB .word sfx1,sfx2,sfx3,sfx4,sfx5



; =====================
sfx1                   ; upadek Preliminary Monte
 .HE C0 01 06 8A       ; C0 = REPF
                       ; 01 = zapisuj rejestr AUDF co 1 ramke
                       ; 06 = mamy 6 wartosci do pobrania
                       ; 8A = wartosc inicjujaca zapisywana do AUDC
 .HE C0 C0 01 C0 C0 01 ; 6 wartosci po kolei beda zapisywane co jedna ramke do AUDF
 .HE 00 FF             ; 00 FF = RTS w tym przypadku koniec odtwarzania
; =====================
sfx2                   ; local perfect w Gyruss
 .HE 80 01 03 00       ; 80 = REPC
 .HE 07 27 47
 .HE 80 01 03 00
 .HE 06 26 46
 .HE 80 01 03 00
 .HE 05 27 45
 .HE 80 01 03 00
 .HE 04 24 44
 .HE 80 01 03 00
 .HE 03 23 43
 .HE 80 01 03 00
 .HE 02 22 42
 .HE 80 01 03 00
 .HE 01 21 41
 .HE 00 FF
; =====================
sfx3                   ; Donkey Kong
 .HE 02 44 A7        ; zagraj 2 ramki wartosci AUDF i AUDC
 .HE 01 43 A7
 .HE 01 44 A7
 .HE 01 3C A7
 .HE 01 3D A7
 .HE 01 3C A7
 .HE 01 35 A7
 .HE 02 34 A7
 .HE 01 35 A7
 .HE 01 34 A7
 .HE 01 28 A7
 .HE 01 27 A7
 .HE 01 29 A7
 .HE 01 28 A6
 .HE 01 27 A6
 .HE 02 28 A5
 .HE 01 27 A5
 .HE 01 28 A5
 .HE 01 29 A4
 .HE 01 28 A3
 .HE 04 28 A0
 .HE 04 32 A7
 .HE 01 33 A7
 .HE 03 32 A7
 .HE 01 33 A7
 .HE 03 32 A7
 .HE 01 33 A7
 .HE 04 32 A7
 .HE 01 32 A7
 .HE 01 32 00
 .HE 00 FF
; =====================
sfx4
 .HE C0 01 03 84   ; chodzenie Preliminary Monty
 .HE C0 FE 01
 .HE 05 00 00      ; 05 = piec ramek
                   ; 00 do AUDF
                   ; 00 do AUDC = 5 ramek ciszy
 .HE 00 00         ; 00 00 = LOOP zagraj tego SFX jeszcze raz od pozycji 00
; =====================
sfx5               ; Pacman BG2
 .HE A3            ; A0 = JSR; E0 = JMP  starsze 3 bity %1110 0000
                   ; 03 = SFX nr. 03     mlodszy 5 bitow %0001 1111
 .HE C0 01 0A A5
 .HE 80 70 60 50 40 50 60 70 80 90
 .HE C0 01 0A A4                      ; loop
 .HE 80 70 60 50 40 50 60 70 80 90
 .HE C0 01 0A A3
 .HE 80 70 60 50 40 50 60 70 80 90
 .HE 00 0F         ; 00 0F = LOOP do pozycji 0F
 ; =====================

            run runme
            end

Wersja minimum LEVEL 1:


; ================================================ LEVEL 1
; === SFX ENGINE ====
;xSFX_PROCEED     - jump here 1 per frame at least
;
;xSFX_START  in:  A=sfx, X=channel, C=1 (force)
;                 A=sfx, C=0 (find free channel)
;            out: C=1 no free channel
;                 C=0 ok
;
;xSFX_STOP   in:  X=channel - will immediately terminate SFX on the specified channel
; ===
;
; Command:
;
;1. TIME,AUDF,AUDC          ; graj TIME ilość ramek, zapisz rejestry AUDF, AUDC
;4. LOOP                    ; powtórz ten sam dźwięk od komendy na pozycji loop
;5. RTS                     ; koniec opisu dźwięku


xSFX_ENGINE     jmp xSFX_PROCEED         ; xSFX_ENGINE
xSFX_START      jmp SFX_INSERT           ; xSFX_ENGINE+3
xSFX_STOP       jmp SFX_CHANNEL_OFF      ; xSFX_ENGINE+6


SFX_ENDRTS      iny
                lda (SFXZP),Y
                tay
                dey
                cmp #$ff
                bne SFX_RELOAD
                jsr SFX_CHANNEL_OFF
                jmp SFX_NXTCH

xSFX_PROCEED    ldx #3
SFX_CONTCH      lda SFX_NO,x
                bne SFX_PROCED
SFX_NXTCH       dex
                bpl SFX_CONTCH
                rts

SFX_PROCED      ldy SFX_TIME,x
                bne SFX_CONTTONE
                tay
                lda SFX_ADR_TAB-2,y
                sta SFXZP
                lda SFX_ADR_TAB-1,y
                sta SFXZP+1
                ldy SFX_CNT,x
SFX_RELOAD      iny
                lda (SFXZP),Y
                beq SFX_ENDRTS
                sta SFX_TIME,x
                iny
                lda (SFXZP),Y
                sta SFX_AUDF,x
                iny
                lda (SFXZP),Y
                sta SFX_AUDC,x
                tya
                sta SFX_CNT,x
SFX_CONTTONE    txa
                asl @
                tay
                lda SFX_AUDF,x
                sta VPOKEY,y
                lda SFX_AUDC,x
                sta VPOKEY+1,y
                dec SFX_TIME,x
                jmp SFX_NXTCH

SFX_CHANNEL_OFF
                txa
                asl @
                tay
                lda #$ff
                sta SFX_CNT,x
                lda #$00
                sta SFX_NO,x
                sta SFX_TIME,x
                sta VPOKEY,y
                sta VPOKEY+1,y
                rts

SFX_INSERT      bcs SFX_FORCE
                ldx #$03
SFX_FIND        ldy SFX_NO,x
                beq SFX_SETNO
                dex
                bpl SFX_FIND
                sec
                rts
SFX_FORCE       pha
                jsr SFX_CHANNEL_OFF
                pla
SFX_SETNO       asl @
                sta SFX_NO,x
                clc
                rts

SFX_NO     .HE 00 00 00 00
SFX_CNT    .HE FF,FF,FF,FF
SFX_TIME   .HE 00 00 00 00
SFX_AUDC   .HE 00 00 00 00
SFX_AUDF   .HE 00 00 00 00

SFX_ADR_TAB .word sfx1,sfx2,sfx3


; =====================
sfx1                   ; Bruce Lee  death
 .HE 01 54 A2
 .HE 01 54 44
 .HE 01 54 A6
 .HE 01 54 48
 .HE 01 54 A8
 .HE 01 54 4A
 .HE 01 54 AA
 .HE 01 00 4A
 .HE 01 00 AA
 .HE 01 00 4A
 .HE 01 00 AA
 .HE 01 00 48
 .HE 01 00 A8
 .HE 01 00 46
 .HE 01 00 A4
 .HE 01 00 42
 .HE 01 00 A2
 .HE 01 00 42
 .HE 00 FF
; =====================
sfx2                   ; Bruce Lee  collecting
 .HE 01 24 C2
 .HE 01 20 C6
 .HE 01 2C C8
 .HE 01 38 CC
 .HE 01 20 C8
 .HE 01 44 C4
 .HE 01 58 C2
 .HE 01 00 00
 .HE 01 00 00
 .HE 01 00 00
 .HE 01 58 C2
 .HE 01 18 C4
 .HE 01 78 C6
 .HE 01 08 C8
 .HE 01 08 E2
 .HE 00 FF
; =====================
sfx3                 ; syrena loop
 .HE 01 50 A5
 .HE 01 48 A5
 .HE 01 40 A5
 .HE 01 38 A5
 .HE 01 30 A5
 .HE 01 28 A5
 .HE 01 20 A3
 .HE 01 18 A2
 .HE 00 00