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