From 6c2ef8d2ddd3f9c148e3da928bd1bebbca1a654a Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 21 Apr 2025 19:38:19 -0500 Subject: [PATCH] 6502 command stream player, part 16 incomplete vibrato/pitch implementation incomplete porta implementation prepare for arp impl --- src/asm/6502/nes/test.s | 7 +- src/asm/6502/seq.bin | Bin 3935 -> 3943 bytes src/asm/6502/stream.s | 196 ++++++++++++++++++++++++++++++++++------ 3 files changed, 173 insertions(+), 30 deletions(-) diff --git a/src/asm/6502/nes/test.s b/src/asm/6502/nes/test.s index 81613e06c..077aef5cb 100644 --- a/src/asm/6502/nes/test.s +++ b/src/asm/6502/nes/test.s @@ -45,9 +45,9 @@ initPPU: bpl - startPlayer: ; draw some text - lda #$21 + lda #$20 sta PPUADDR - lda #$02 + lda #$42 sta PPUADDR ldx #$00 @@ -123,7 +123,6 @@ irq: ; command stream player definition FCS_MAX_CHAN=8 -FCS_MAX_STACK=10 fcsAddrBase=$30 fcsZeroPage=$0e @@ -139,7 +138,7 @@ fcsCmdTableHigh=fcsCmdTableExample ; data helloWorld: - .db "Hello, World!" + .db "Furnace Test Player" .db 0 ppuPalette: diff --git a/src/asm/6502/seq.bin b/src/asm/6502/seq.bin index 5b0afe69e9d5a323f32733b683b0f623650903bd..76eda5e4406413bfd03dec3e18819d77e4fe5bbe 100644 GIT binary patch literal 3943 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 Snm*~*O~n(H>siPZ%6|YpxhKg0 literal 3935 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[x] || CARRY) + bcs + ; overflow check + lda chanVol+1,x ; comparison check + cmp fcsVolMax.w,x + bmi fcsChanSubmitVol + ; chanVol[x]=fcsVolMax[x] ++ lda fcsVolMax.w,x + sta chanVol+1,x + lda #0 + sta chanVol,x + fcsChanSubmitVol: + lda chanVol+1,x + sta fcsArg0 + ldy #$05 ; volume + jsr fcsDispatchCmd ;;; DO PITCH fcsChanDoPitch: + ; if (sendPitch || chanVibrato[x]!=0) + lda fcsSendPitch + bne + + lda chanVibrato,x + and #$0f ; depth only + beq fcsChanDoPorta + ; update vibrato + ; get vibrato ++ lda chanVibrato,x + lsr + lsr + lsr + lsr + clc + adc chanVibratoPos,x + and #$3f + sta chanVibratoPos,x + ; calculate vibrato pitch (TODO) + ; 1. calculate vibrato position + ; - we use 15 quarter sine tables, one for each vibrato depth + ; - 32-63 are negatives of 0-31 + ; - a&31: zero is zero. otherwise a-1 in the table unless a&16 + ; - if a&16 then invert a + tay + ; check for zero in a&31 + and #$1f + bne + + ; it is. load zero + lda #0 + jmp fcsPostVibratoCalc1 + ; it is not. check a&16 ++ and #$10 + bne + + ; 0-15 + dey + tya + and #$0f + jmp fcsPostVibratoCalc + ; 16-31 ++ tya + and #$0f + eor #$0f ; 0-15 -> 15-0 + + fcsPostVibratoCalc: + ; check for 32-63 + pha + tya + and #$20 + bne + + ; 0-31 + pla + tay + lda (fcsTempPtr),y + jmp fcsPostVibratoCalc1 + ; 32-63 (negate) ++ pla + tay + lda (fcsTempPtr),y + eor #$ff + clc + adc #1 + + ; at this point, a contains the vibrato pitch + fcsPostVibratoCalc1: + sta fcsArg0 + ; extend sign + bmi + + lda #0 + sta fcsArg0+1 + beq ++ ++ lda #$ff + sta fcsArg0+1 + ; extend pitch sign +++ lda chanPitch,x + sta fcsTempPtr + bmi + + lda #0 + sta fcsTempPtr+1 + beq ++ ++ lda #$ff + sta fcsTempPtr+1 + ; add pitch +++ lda fcsArg0 + clc + adc fcsTempPtr + sta fcsArg0 + lda fcsArg0+1 + adc fcsTempPtr+1 + sta fcsArg0+1 + ; dispatch command + ldy #9 + jsr fcsDispatchCmd ;;; DO PORTAMENTO fcsChanDoPorta: + ; if (chanPortaSpeed[x]) + lda chanPortaSpeed,x + beq fcsChanDoArp + ; do portamento + sta fcsArg0 + lda #0 + sta fcsArg0+1 + lda chanPortaTarget,x + sta fcsArg1 + ldy #8 ; NOTE_PORTA + jsr fcsDispatchCmd + ; get out (we can't do porta and arp simultaneously) + rts ;;; DO ARPEGGIO fcsChanDoArp: + ; if (chanArp[x] && !chanPortaSpeed[x]) + lda chanArp,x + beq + + ; do arpeggio (TODO) + nop ;;; END - rts ++ rts ; x: channel*2 fcsDoChannel: @@ -530,12 +679,7 @@ fcsDoChannel: sta fcsSendVolume sta fcsSendPitch - ; check whether this channel is halted (PC = 0) - lda chanPC,x - ora chanPC+1,x - bne + - rts - ; channel not halted... begin processing + ; begin processing ; chanTicks-- + lda chanTicks,x sec @@ -619,14 +763,17 @@ fcsInit: ; initialize channel stacks lda #0 ldx #0 + ldy #0 - sta chanStackPtr,x clc - adc #FCS_MAX_STACK + adc fcsStackSize.w,y + clc + adc fcsStackSize.w,y inx inx + iny cpx #(FCS_MAX_CHAN*2) bne - - ; set volumes ; TODO @@ -637,10 +784,7 @@ fcsInit: ; floor(127*sin((x/64)*(2*pi))) fcsVibTable: - .db 0, 12, 24, 36, 48, 59, 70, 80, 89, 98, 105, 112, 117, 121, 124, 126 - .db 127, 126, 124, 121, 117, 112, 105, 98, 89, 80, 70, 59, 48, 36, 24, 12 - .db 0, -12, -24, -36, -48, -59, -70, -80, -89, -98, -105, -112, -117, -121, -124, -126 - .db -126, -126, -124, -121, -117, -112, -105, -98, -89, -80, -70, -59, -48, -36, -24, -12 + .db 12, 24, 36, 48, 59, 70, 80, 89, 98, 105, 112, 117, 121, 124, 126, 127 ; COMMAND TABLE ; $b4 fcsNoArgDispatch, @@ -957,14 +1101,14 @@ fcsDummyFunc: rts fcsVolMaxExample: - .dw $7f00 - .dw $7f00 - .dw $7f00 - .dw $7f00 - .dw $7f00 - .dw $7f00 - .dw $7f00 - .dw $7f00 + .db $7f, $00 + .db $7f, $00 + .db $7f, $00 + .db $7f, $00 + .db $7f, $00 + .db $7f, $00 + .db $7f, $00 + .db $7f, $00 ; first 64 commands fcsCmdTableExample: