From 73d9b710c779b129f610dce302fd4ae934507fbb Mon Sep 17 00:00:00 2001 From: Vince Weaver Date: Fri, 7 Jun 2019 15:18:51 -0400 Subject: [PATCH] pt3_lib: add directory with just the pt3 player This will be less optimized than pt3_player but possibly easier for other programs to use. --- pt3_lib/Makefile | 29 + pt3_lib/OPTIMIZATION.txt | 47 + pt3_lib/README.pt3_lib | 17 + pt3_lib/empty.dsk | Bin 0 -> 143360 bytes pt3_lib/hello.bas | 2 + pt3_lib/interrupt_handler.s | 157 +++ pt3_lib/mockingboard_a.s | 241 ++++ pt3_lib/pt3_lib.dsk | Bin 0 -> 143360 bytes pt3_lib/pt3_lib.s | 2329 +++++++++++++++++++++++++++++++++++ pt3_lib/pt3_test.s | 184 +++ pt3_lib/zp.inc | 263 ++++ 11 files changed, 3269 insertions(+) create mode 100644 pt3_lib/Makefile create mode 100644 pt3_lib/OPTIMIZATION.txt create mode 100644 pt3_lib/README.pt3_lib create mode 100644 pt3_lib/empty.dsk create mode 100644 pt3_lib/hello.bas create mode 100644 pt3_lib/interrupt_handler.s create mode 100644 pt3_lib/mockingboard_a.s create mode 100644 pt3_lib/pt3_lib.dsk create mode 100644 pt3_lib/pt3_lib.s create mode 100644 pt3_lib/pt3_test.s create mode 100644 pt3_lib/zp.inc diff --git a/pt3_lib/Makefile b/pt3_lib/Makefile new file mode 100644 index 00000000..ac2b44dd --- /dev/null +++ b/pt3_lib/Makefile @@ -0,0 +1,29 @@ +include ../Makefile.inc + +DOS33 = ../dos33fs-utils/dos33 +PNG2GR = ../gr-utils/png2gr + +all: pt3_lib.dsk + +$(DOS33): + cd ../dos33fs-utils && make + +pt3_lib.dsk: PT3_TEST HELLO + cp empty.dsk pt3_lib.dsk + $(DOS33) -y pt3_lib.dsk SAVE A HELLO + $(DOS33) -y pt3_lib.dsk BSAVE -a 0x1000 PT3_TEST + +HELLO: hello.bas + ../asoft_basic-utils/tokenize_asoft < hello.bas > HELLO + +# + +PT3_TEST: pt3_test.o + ld65 -o PT3_TEST pt3_test.o -C ../linker_scripts/apple2_1000.inc + +pt3_test.o: pt3_test.s pt3_lib.s interrupt_handler.s zp.inc + ca65 -o pt3_test.o pt3_test.s -l pt3_test.lst +# + +clean: + rm -f *~ *.o *.lst PT3_TEST HELLO diff --git a/pt3_lib/OPTIMIZATION.txt b/pt3_lib/OPTIMIZATION.txt new file mode 100644 index 00000000..8c40f6b7 --- /dev/null +++ b/pt3_lib/OPTIMIZATION.txt @@ -0,0 +1,47 @@ +Code Optimization +~~~~~~~~~~~~~~~~~ + + The original working code is about 4k (not counting the pt3 file) + and has an overhead of roughly 20% when playing a song interrupt-driven + at 50Hz. + + I'm keeping some stats here as I try to optimize the size and speed. + + Song: "Summer of Rain" SR.PT3 + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + lz4 compressed + pt3 size: raw size: ym5 size: pt3.lz4: + 3871 137015 7637 1793 + + + Size=pt3lib_end - note_a + + Decoder Type size ZP use raw decode total CPU overhead + ------------------------------------------------------------- + Original 3407 22B 1F.22 31s 171s 18% + VolTableGen 3302 22B 20.0E 32s 171s 19% + SizeOpts 3262 22B 20.0A 32s 171s 19% + MoreSizeOpt 3203 22B 1F.1D 31s 171s 18% + Qkumba#1 2937 ?? 1D.18 29s 171s 17% + Qkumba#2 2879 ?? 1C.18 28s 171s 16% + Qkumba#3+vmw 2816 ?? 1C.22 28s 171s 16% + +Times: Validated + BH.PT3: 10.0B 16 1:33 93 17.2% + CH.PT3: 1D.12 29 2:49 169 17.2% + CR.PT3: 0F.25 15 1:30 90 16.7% Yes + DF.PT3: 19.1C 25 2:27 147 17.0% + EA.PT3: 1E.13 30 2:53 173 17.3% Yes + F4.PT3: 18.1D 24 2:16 136 17.6% + FC.PT3: 20.24 32 3:12 192 16.7% + FR.PT3: 0B.0A 11 1:01 61 18.0% + HI.PT3: 11.19 17 1:34 94 18.0% + I2.PT3: 1E.0C 30 2:59 179 16.8% + IT.PT3: 16.19 22 2:11 131 16.8% Yes + MB.PT3: 14.08 20 1:59 119 16.8% + ND.PT3: 14.1C 20 1:52 112 17.9% + OS.PT3: 13.24 19 1:48 108 17.6% + RI.PT3: 0F.03 15 1:26 86 17.4% + SD.PT3: 11.16 17 1:40 100 17.0% + SR.PT3: 1F.22 31 2:51 171 18.1% + VC.PT3: 1B.20 27 2:40 160 16.9% diff --git a/pt3_lib/README.pt3_lib b/pt3_lib/README.pt3_lib new file mode 100644 index 00000000..3cecaed9 --- /dev/null +++ b/pt3_lib/README.pt3_lib @@ -0,0 +1,17 @@ +The PT3_player Library +~~~~~~~~~~~~~~~~~~~~~~ + + by Vince "Deater" Weaver + 7 June 2019 + http://www.deater.net/weave/vmwprod/pt3_player/ + + Plays Vortex Tracker II .pt3 files on the Apple II + + +This code is meant as a relatively simple, reasonably optimized version +of the PT3 Vortex-Tracker player for use in other programs. + +The orignal player code can be found in ../pt3_player/ +That codebase is being *extremely* optimized to the point it's no longer +very straightforward to reuse the code. + diff --git a/pt3_lib/empty.dsk b/pt3_lib/empty.dsk new file mode 100644 index 0000000000000000000000000000000000000000..0a2af35ebf17f3a74836447b291be4abc4648fef GIT binary patch literal 143360 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
    m%EBRFq&ZLMzxK$i(0M7IL@7 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ĊV~1$$o2m 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 MYsSKYvj!plFB<`3(EtDd literal 0 HcmV?d00001 diff --git a/pt3_lib/hello.bas b/pt3_lib/hello.bas new file mode 100644 index 00000000..94d3e6b9 --- /dev/null +++ b/pt3_lib/hello.bas @@ -0,0 +1,2 @@ + 10 PRINT "PT3 LIB TEST V0.1" + 100 PRINT CHR$ (4)"BRUN PT3_TEST" diff --git a/pt3_lib/interrupt_handler.s b/pt3_lib/interrupt_handler.s new file mode 100644 index 00000000..25dc329d --- /dev/null +++ b/pt3_lib/interrupt_handler.s @@ -0,0 +1,157 @@ + ;================================ + ;================================ + ; mockingboard interrupt handler + ;================================ + ;================================ + ; On Apple II/6502 the interrupt handler jumps to address in 0xfffe + ; This is in the ROM, which saves the registers + ; on older IIe it saved A to $45 (which could mess with DISK II) + ; newer IIe doesn't do that. + ; It then calculates if it is a BRK or not (which trashes A) + ; Then it sets up the stack like an interrupt and calls 0x3fe + +TIME_OFFSET EQU 13 + +interrupt_handler: +; pha ; save A ; 3 + ; A is saved in $45 by firmware + txa + pha ; save X + tya + pha ; save Y + + + +; inc $0404 ; debug (flashes char onscreen) + + bit $C404 ; clear 6522 interrupt by reading T1C-L ; 4 + + lda DONE_PLAYING ; 3 + beq pt3_play_music ; if song done, don't play music ; 3/2nt + jmp exit_interrupt ; 3 + ;============ + ; 13 + +pt3_play_music: + + ; decode a frame of music + + jsr pt3_make_frame + + ; handle song over condition + lda DONE_SONG + beq mb_write_frame ; if not done, continue + + lda LOOP ; see if looping + beq move_to_next + +pt3_loop_smc: + lda #0 ; looping, move to loop location + sta current_pattern + lda #$0 + sta current_line + sta current_subframe + sta DONE_SONG ; undo the next song + + beq done_interrupt ; branch always + +move_to_next: + ; same as "press right" + ldx #$20 + jmp quiet_exit + + ;====================================== + ; Write frames to Mockingboard + ;====================================== + ; for speed could merge this into + ; the decode code + +mb_write_frame: + + + tax ; set up reg count ; 2 + ;============ + ; 2 + + ;================================== + ; loop through the 14 registers + ; reading the value, then write out + ;================================== + +mb_write_loop: + lda AY_REGISTERS,X ; load register value ; 4 + + ; special case R13. If it is 0xff, then don't update + ; otherwise might spuriously reset the envelope settings + + cpx #13 ; 2 + bne mb_not_13 ; 3/2nt + cmp #$ff ; 2 + beq mb_skip_13 ; 3/2nt + ;============ + ; typ 5 +mb_not_13: + + + ; address + stx MOCK_6522_ORA1 ; put address on PA1 ; 4 + stx MOCK_6522_ORA2 ; put address on PA2 ; 4 + lda #MOCK_AY_LATCH_ADDR ; latch_address for PB1 ; 2 + sta MOCK_6522_ORB1 ; latch_address on PB1 ; 4 + sta MOCK_6522_ORB2 ; latch_address on PB2 ; 4 + ldy #MOCK_AY_INACTIVE ; go inactive ; 2 + sty MOCK_6522_ORB1 ; 4 + sty MOCK_6522_ORB2 ; 4 + + ; value + lda AY_REGISTERS,X ; load register value ; 4 + sta MOCK_6522_ORA1 ; put value on PA1 ; 4 + sta MOCK_6522_ORA2 ; put value on PA2 ; 4 + lda #MOCK_AY_WRITE ; ; 2 + sta MOCK_6522_ORB1 ; write on PB1 ; 4 + sta MOCK_6522_ORB2 ; write on PB2 ; 4 + sty MOCK_6522_ORB1 ; 4 + sty MOCK_6522_ORB2 ; 4 + ;=========== + ; 60 +mb_no_write: + inx ; point to next register ; 2 + cpx #14 ; if 14 we're done ; 2 + bmi mb_write_loop ; otherwise, loop ; 3/2nt + ;============ + ; 7 +mb_skip_13: + + + jmp exit_interrupt + + ;================================= + ; Finally done with this interrupt + ;================================= + +done_interrupt: + +quiet_exit: + stx DONE_PLAYING + jsr clear_ay_both + + ;ldx #$ff ; also mute the channel + stx AY_REGISTERS+7 ; just in case + +done_key: +exit_interrupt: + + pla + tay ; restore Y + pla + tax ; restore X + lda $45 ; restore A +; pla ; restore a ; 4 + + rti ; return from interrupt ; 6 + + ;============ + ; typical + ; ???? cycles + + diff --git a/pt3_lib/mockingboard_a.s b/pt3_lib/mockingboard_a.s new file mode 100644 index 00000000..bf8b7cdd --- /dev/null +++ b/pt3_lib/mockingboard_a.s @@ -0,0 +1,241 @@ +; Mockingboad programming: +; + Has two 6522 I/O chips connected to two AY-3-8910 chips +; + Optionally has some speech chips controlled via the outport on the AY +; + Often in slot 4 +; TODO: how to auto-detect? +; References used: +; http://macgui.com/usenet/?group=2&id=8366 +; 6522 Data Sheet +; AY-3-8910 Data Sheet + +;======================== +; Mockingboard card +; Essentially two 6522s hooked to the Apple II bus +; Connected to AY-3-8910 chips +; PA0-PA7 on 6522 connected to DA0-DA7 on AY +; PB0 on 6522 connected to BC1 +; PB1 on 6522 connected to BDIR +; PB2 on 6522 connected to RESET + + +; left speaker +MOCK_6522_ORB1 EQU $C400 ; 6522 #1 port b data +MOCK_6522_ORA1 EQU $C401 ; 6522 #1 port a data +MOCK_6522_DDRB1 EQU $C402 ; 6522 #1 data direction port B +MOCK_6522_DDRA1 EQU $C403 ; 6522 #1 data direction port A + +; right speaker +MOCK_6522_ORB2 EQU $C480 ; 6522 #2 port b data +MOCK_6522_ORA2 EQU $C481 ; 6522 #2 port a data +MOCK_6522_DDRB2 EQU $C482 ; 6522 #2 data direction port B +MOCK_6522_DDRA2 EQU $C483 ; 6522 #2 data direction port A + +; AY-3-8910 commands on port B +; RESET BDIR BC1 +MOCK_AY_RESET EQU $0 ; 0 0 0 +MOCK_AY_INACTIVE EQU $4 ; 1 0 0 +MOCK_AY_READ EQU $5 ; 1 0 1 +MOCK_AY_WRITE EQU $6 ; 1 1 0 +MOCK_AY_LATCH_ADDR EQU $7 ; 1 1 1 + + + ;======================== + ; Mockingboard Init + ;======================== + ; Initialize the 6522s + ; set the data direction for all pins of PortA/PortB to be output + +mockingboard_init: + lda #$ff ; all output (1) + sta MOCK_6522_DDRB1 + sta MOCK_6522_DDRA1 + sta MOCK_6522_DDRB2 + sta MOCK_6522_DDRA2 + rts + + ;====================== + ; Reset Left AY-3-8910 + ;====================== +reset_ay_both: + lda #MOCK_AY_RESET + sta MOCK_6522_ORB1 + lda #MOCK_AY_INACTIVE + sta MOCK_6522_ORB1 + + ;====================== + ; Reset Right AY-3-8910 + ;====================== +;reset_ay_right: +;could be merged with both + lda #MOCK_AY_RESET + sta MOCK_6522_ORB2 + lda #MOCK_AY_INACTIVE + sta MOCK_6522_ORB2 + rts + + +; Write sequence +; Inactive -> Latch Address -> Inactive -> Write Data -> Inactive + + ;========================================= + ; Write Right/Left to save value AY-3-8910 + ;========================================= + ; register in X + ; value in MB_VALUE + +write_ay_both: + ; address + stx MOCK_6522_ORA1 ; put address on PA1 ; 3 + stx MOCK_6522_ORA2 ; put address on PA2 ; 3 + lda #MOCK_AY_LATCH_ADDR ; latch_address on PB1 ; 2 + sta MOCK_6522_ORB1 ; latch_address on PB1 ; 3 + sta MOCK_6522_ORB2 ; latch_address on PB2 ; 3 + ldy #MOCK_AY_INACTIVE ; go inactive ; 2 + sty MOCK_6522_ORB1 ; 3 + sty MOCK_6522_ORB2 ; 3 + + ; value + lda MB_VALUE ; 3 + sta MOCK_6522_ORA1 ; put value on PA1 ; 3 + sta MOCK_6522_ORA2 ; put value on PA2 ; 3 + lda #MOCK_AY_WRITE ; ; 2 + sta MOCK_6522_ORB1 ; write on PB1 ; 3 + sta MOCK_6522_ORB2 ; write on PB2 ; 3 + sty MOCK_6522_ORB1 ; 3 + sty MOCK_6522_ORB2 ; 3 + + rts ; 6 + ;=========== + ; 51 + ;======================================= + ; clear ay -- clear all 14 AY registers + ; should silence the card + ;======================================= +clear_ay_both: + ldx #14 + lda #0 + sta MB_VALUE +clear_ay_left_loop: + jsr write_ay_both + dex + bpl clear_ay_left_loop + rts + + ;======================================= + ; Detect a Mockingboard card + ;======================================= + ; Based on code from the French Touch "Pure Noise" Demo + ; Attempts to time an instruction sequence with a 6522 + ; + ; If found, puts in bMB + ; MB_ADDRL:MB_ADDRH has address of Mockingboard + ; returns X=0 if not found, X=1 if found + +mockingboard_detect: + lda #0 + sta MB_ADDRL + +mb_detect_loop: ; self-modifying + lda #$07 ; we start in slot 7 ($C7) and go down to 0 ($C0) + ora #$C0 ; make it start with C + sta MB_ADDRH + ldy #04 ; $CX04 + ldx #02 ; 2 tries? +mb_check_cycle_loop: + lda (MB_ADDRL),Y ; timer 6522 (Low Order Counter) + ; count down + sta TEMP ; 3 cycles + lda (MB_ADDRL),Y ; + 5 cycles = 8 cycles + ; between the two accesses to the timer + sec + sbc TEMP ; subtract to see if we had 8 cycles + cmp #$f8 ; -8 + bne mb_not_in_this_slot + dex ; decrement, try one more time + bne mb_check_cycle_loop ; loop detection + inx ; Mockingboard found (X=1) +done_mb_detect: + ;stx bMB ; store result to bMB + rts ; return + +mb_not_in_this_slot: + dec mb_detect_loop+1 ; decrement the "slot" (self_modify) + bne mb_detect_loop ; loop down to one + ldx #00 + beq done_mb_detect + +;alternative MB detection from Nox Archaist +; lda #$04 +; sta MB_ADDRL +; ldx #$c7 +; +;find_mb: +; stx MB_ADDRH +; +; ;detect sound I +; +; sec +; ldy #$00 +; lda (MB_ADDRL), y +; sbc (MB_ADDRL), y +; cmp #$05 +; beq found_mb +; dex +; cpx #$c0 +; bne find_mb +; ldx #$00 ;no mockingboard found +; rts +; +;found_mb: +; ldx #$01 ;mockingboard found +; rts +; +; ;optionally detect sound II +; +; sec +; ldy #$80 +; lda (MB_ADDRL), y +; sbc (MB_ADDRL), y +; cmp #$05 +; beq found_mb + + + ;======================================= + ; Detect a Mockingboard card in Slot4 + ;======================================= + ; Based on code from the French Touch "Pure Noise" Demo + ; Attempts to time an instruction sequence with a 6522 + ; + ; MB_ADDRL:MB_ADDRH has address of Mockingboard + ; returns X=0 if not found, X=1 if found + +mockingboard_detect_slot4: + lda #0 + sta MB_ADDRL + +mb4_detect_loop: ; self-modifying + lda #$04 ; we're only looking in Slot 4 + ora #$C0 ; make it start with C + sta MB_ADDRH + ldy #04 ; $CX04 + ldx #02 ; 2 tries? +mb4_check_cycle_loop: + lda (MB_ADDRL),Y ; timer 6522 (Low Order Counter) + ; count down + sta TEMP ; 3 cycles + lda (MB_ADDRL),Y ; + 5 cycles = 8 cycles + ; between the two accesses to the timer + sec + sbc TEMP ; subtract to see if we had 8 cycles + cmp #$f8 ; -8 + bne mb4_not_in_this_slot + dex ; decrement, try one more time + bne mb4_check_cycle_loop ; loop detection + inx ; Mockingboard found (X=1) +done_mb4_detect: + rts ; return + +mb4_not_in_this_slot: + ldx #00 + beq done_mb4_detect + diff --git a/pt3_lib/pt3_lib.dsk b/pt3_lib/pt3_lib.dsk new file mode 100644 index 0000000000000000000000000000000000000000..238aab37aebaf74b9de250c0267e129929373cb2 GIT binary patch literal 143360 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 J + +; Roughly based on the Formats.pas Pascal code from Ay_Emul + +; Size Optimization -- Mem+Code (pt3_lib_end-note_a) +; + 3407 bytes -- original working implementation +; + 3302 bytes -- autogenerate the volume tables +; + 3297 bytes -- remove some un-needed bytes from struct +; + 3262 bytes -- combine some duplicated code in $1X/$BX env setting +; + 3253 bytes -- remove unnecessary variable +; + 3203 bytes -- combine common code in note decoder +; + 2937 bytes -- qkumba first pass +; + 2879 bytes -- qkumba second pass +; + 2839 bytes -- mask note command in common code +; + 2832 bytes -- combine $D0 and $E0 decode +; + 2816 bytes -- eliminate "decode_done" variable (2.75k) +; + 2817 bytes -- eliminate pt3_version. Slighly faster but also bigger + +; TODO +; move some of these flags to be bits rather than bytes? +; enabled could be bit 6 or 7 for fast checking +; NOTE_ENABLED,ENVELOPE_ENABLED,SIMPLE_GLISS,ENV_SLIDING,AMP_SLIDING? + +; Header offsets + +PT3_VERSION = $0D +PT3_HEADER_FREQUENCY = $63 +PT3_SPEED = $64 +PT3_LOOP = $66 +PT3_PATTERN_LOC_L = $67 +PT3_PATTERN_LOC_H = $68 +PT3_SAMPLE_LOC_L = $69 +PT3_SAMPLE_LOC_H = $6A +PT3_ORNAMENT_LOC_L = $A9 +PT3_ORNAMENT_LOC_H = $AA +PT3_PATTERN_TABLE = $C9 + +; Use memset to set things to 0? + +NOTE_VOLUME =0 +NOTE_TONE_SLIDING_L =1 +NOTE_TONE_SLIDING_H =2 +NOTE_ENABLED =3 +NOTE_ENVELOPE_ENABLED =4 +NOTE_SAMPLE_POINTER_L =5 +NOTE_SAMPLE_POINTER_H =6 +NOTE_SAMPLE_LOOP =7 +NOTE_SAMPLE_LENGTH =8 +NOTE_TONE_L =9 +NOTE_TONE_H =10 +NOTE_AMPLITUDE =11 +NOTE_NOTE =12 +NOTE_LEN =13 +NOTE_LEN_COUNT =14 +NOTE_ADDR_L =15 +NOTE_ADDR_H =16 +NOTE_ORNAMENT_POINTER_L =17 +NOTE_ORNAMENT_POINTER_H =18 +NOTE_ORNAMENT_LOOP =19 +NOTE_ORNAMENT_LENGTH =20 +NOTE_ONOFF =21 +NOTE_TONE_ACCUMULATOR_L =22 +NOTE_TONE_ACCUMULATOR_H =23 +NOTE_TONE_SLIDE_COUNT =24 +NOTE_ORNAMENT_POSITION =25 +NOTE_SAMPLE_POSITION =26 +NOTE_ENVELOPE_SLIDING =27 +NOTE_NOISE_SLIDING =28 +NOTE_AMPLITUDE_SLIDING =29 +NOTE_ONOFF_DELAY =30 ;ordering of DELAYs is hard-coded now +NOTE_OFFON_DELAY =31 ;ordering of DELAYs is hard-coded now +NOTE_TONE_SLIDE_STEP_L =32 +NOTE_TONE_SLIDE_STEP_H =33 +NOTE_TONE_SLIDE_DELAY =34 +NOTE_SIMPLE_GLISS =35 +NOTE_SLIDE_TO_NOTE =36 +NOTE_TONE_DELTA_L =37 +NOTE_TONE_DELTA_H =38 +NOTE_TONE_SLIDE_TO_STEP =39 + +NOTE_STRUCT_SIZE=40 + +note_a: + .byte $0 ; NOTE_VOLUME ; 0 + .byte $0 ; NOTE_TONE_SLIDING_L ; 1 + .byte $0 ; NOTE_TONE_SLIDING_H ; 2 + .byte $0 ; NOTE_ENABLED ; 3 + .byte $0 ; NOTE_ENVELOPE_ENABLED ; 4 + .byte $0 ; NOTE_SAMPLE_POINTER_L ; 5 + .byte $0 ; NOTE_SAMPLE_POINTER_H ; 6 + .byte $0 ; NOTE_SAMPLE_LOOP ; 7 + .byte $0 ; NOTE_SAMPLE_LENGTH ; 8 + .byte $0 ; NOTE_TONE_L ; 9 + .byte $0 ; NOTE_TONE_H ; 10 + .byte $0 ; NOTE_AMPLITUDE ; 11 + .byte $0 ; NOTE_NOTE ; 12 + .byte $0 ; NOTE_LEN ; 13 + .byte $0 ; NOTE_LEN_COUNT ; 14 + .byte $0 ; NOTE_ADDR_L ; 15 + .byte $0 ; NOTE_ADDR_H ; 16 + .byte $0 ; NOTE_ORNAMENT_POINTER_L ; 17 + .byte $0 ; NOTE_ORNAMENT_POINTER_H ; 18 + .byte $0 ; NOTE_ORNAMENT_LOOP ; 19 + .byte $0 ; NOTE_ORNAMENT_LENGTH ; 20 + .byte $0 ; NOTE_ONOFF ; 21 + .byte $0 ; NOTE_TONE_ACCUMULATOR_L ; 22 + .byte $0 ; NOTE_TONE_ACCUMULATOR_H ; 23 + .byte $0 ; NOTE_TONE_SLIDE_COUNT ; 24 + .byte $0 ; NOTE_ORNAMENT_POSITION ; 25 + .byte $0 ; NOTE_SAMPLE_POSITION ; 26 + .byte $0 ; NOTE_ENVELOPE_SLIDING ; 27 + .byte $0 ; NOTE_NOISE_SLIDING ; 28 + .byte $0 ; NOTE_AMPLITUDE_SLIDING ; 29 + .byte $0 ; NOTE_ONOFF_DELAY ; 30 + .byte $0 ; NOTE_OFFON_DELAY ; 31 + .byte $0 ; NOTE_TONE_SLIDE_STEP_L ; 32 + .byte $0 ; NOTE_TONE_SLIDE_STEP_H ; 33 + .byte $0 ; NOTE_TONE_SLIDE_DELAY ; 34 + .byte $0 ; NOTE_SIMPLE_GLISS ; 35 + .byte $0 ; NOTE_SLIDE_TO_NOTE ; 36 + .byte $0 ; NOTE_TONE_DELTA_L ; 37 + .byte $0 ; NOTE_TONE_DELTA_H ; 38 + .byte $0 ; NOTE_TONE_SLIDE_TO_STEP ; 39 + +note_b: + .byte $0 ; NOTE_VOLUME + .byte $0 ; NOTE_TONE_SLIDING_L + .byte $0 ; NOTE_TONE_SLIDING_H + .byte $0 ; NOTE_ENABLED + .byte $0 ; NOTE_ENVELOPE_ENABLED + .byte $0 ; NOTE_SAMPLE_POINTER_L + .byte $0 ; NOTE_SAMPLE_POINTER_H + .byte $0 ; NOTE_SAMPLE_LOOP + .byte $0 ; NOTE_SAMPLE_LENGTH + .byte $0 ; NOTE_TONE_L + .byte $0 ; NOTE_TONE_H + .byte $0 ; NOTE_AMPLITUDE + .byte $0 ; NOTE_NOTE + .byte $0 ; NOTE_LEN + .byte $0 ; NOTE_LEN_COUNT + .byte $0 ; NOTE_ADDR_L + .byte $0 ; NOTE_ADDR_H + .byte $0 ; NOTE_ORNAMENT_POINTER_L + .byte $0 ; NOTE_ORNAMENT_POINTER_H + .byte $0 ; NOTE_ORNAMENT_LOOP + .byte $0 ; NOTE_ORNAMENT_LENGTH + .byte $0 ; NOTE_ONOFF + .byte $0 ; NOTE_TONE_ACCUMULATOR_L + .byte $0 ; NOTE_TONE_ACCUMULATOR_H + .byte $0 ; NOTE_TONE_SLIDE_COUNT + .byte $0 ; NOTE_ORNAMENT_POSITION + .byte $0 ; NOTE_SAMPLE_POSITION + .byte $0 ; NOTE_ENVELOPE_SLIDING + .byte $0 ; NOTE_NOISE_SLIDING + .byte $0 ; NOTE_AMPLITUDE_SLIDING + .byte $0 ; NOTE_ONOFF_DELAY + .byte $0 ; NOTE_OFFON_DELAY + .byte $0 ; NOTE_TONE_SLIDE_STEP_L + .byte $0 ; NOTE_TONE_SLIDE_STEP_H + .byte $0 ; NOTE_TONE_SLIDE_DELAY + .byte $0 ; NOTE_SIMPLE_GLISS + .byte $0 ; NOTE_SLIDE_TO_NOTE + .byte $0 ; NOTE_TONE_DELTA_L + .byte $0 ; NOTE_TONE_DELTA_H + .byte $0 ; NOTE_TONE_SLIDE_TO_STEP + +note_c: + .byte $0 ; NOTE_VOLUME + .byte $0 ; NOTE_TONE_SLIDING_L + .byte $0 ; NOTE_TONE_SLIDING_H + .byte $0 ; NOTE_ENABLED + .byte $0 ; NOTE_ENVELOPE_ENABLED + .byte $0 ; NOTE_SAMPLE_POINTER_L + .byte $0 ; NOTE_SAMPLE_POINTER_H + .byte $0 ; NOTE_SAMPLE_LOOP + .byte $0 ; NOTE_SAMPLE_LENGTH + .byte $0 ; NOTE_TONE_L + .byte $0 ; NOTE_TONE_H + .byte $0 ; NOTE_AMPLITUDE + .byte $0 ; NOTE_NOTE + .byte $0 ; NOTE_LEN + .byte $0 ; NOTE_LEN_COUNT + .byte $0 ; NOTE_ADDR_L + .byte $0 ; NOTE_ADDR_H + .byte $0 ; NOTE_ORNAMENT_POINTER_L + .byte $0 ; NOTE_ORNAMENT_POINTER_H + .byte $0 ; NOTE_ORNAMENT_LOOP + .byte $0 ; NOTE_ORNAMENT_LENGTH + .byte $0 ; NOTE_ONOFF + .byte $0 ; NOTE_TONE_ACCUMULATOR_L + .byte $0 ; NOTE_TONE_ACCUMULATOR_H + .byte $0 ; NOTE_TONE_SLIDE_COUNT + .byte $0 ; NOTE_ORNAMENT_POSITION + .byte $0 ; NOTE_SAMPLE_POSITION + .byte $0 ; NOTE_ENVELOPE_SLIDING + .byte $0 ; NOTE_NOISE_SLIDING + .byte $0 ; NOTE_AMPLITUDE_SLIDING + .byte $0 ; NOTE_ONOFF_DELAY + .byte $0 ; NOTE_OFFON_DELAY + .byte $0 ; NOTE_TONE_SLIDE_STEP_L + .byte $0 ; NOTE_TONE_SLIDE_STEP_H + .byte $0 ; NOTE_TONE_SLIDE_DELAY + .byte $0 ; NOTE_SIMPLE_GLISS + .byte $0 ; NOTE_SLIDE_TO_NOTE + .byte $0 ; NOTE_TONE_DELTA_L + .byte $0 ; NOTE_TONE_DELTA_H + .byte $0 ; NOTE_TONE_SLIDE_TO_STEP + + +;==================================== +; Global vars that must be preserved + +current_subframe: .byte $0 +current_line: .byte $0 +current_pattern: .byte $0 +pt3_pattern_done: .byte $0 + +pt3_noise_period: .byte $0 +pt3_noise_add: .byte $0 + +pt3_envelope_period_l: .byte $0 +pt3_envelope_period_h: .byte $0 +pt3_envelope_slide_l: .byte $0 +pt3_envelope_slide_h: .byte $0 +pt3_envelope_slide_add_l:.byte $0 +pt3_envelope_slide_add_h:.byte $0 +pt3_envelope_add: .byte $0 +pt3_envelope_type: .byte $0 +pt3_envelope_type_old: .byte $0 +pt3_envelope_delay: .byte $0 +pt3_envelope_delay_orig:.byte $0 + +pt3_mixer_value: .byte $0 + + +;========================== +; local variables + +note_command: ; shared space with sample_b0 +sample_b0: .byte $0 +note_command_bottom: ; shared space with sample_b1 +sample_b1: .byte $0 + +temp_word_l: .byte $0 +temp_word_h: .byte $0 + +spec_command: .byte $0 + +freq_l: .byte $00 +freq_h: .byte $00 + +e_slide_amount: .byte $0 + +prev_note: .byte $0 +prev_sliding_l: .byte $0 +prev_sliding_h: .byte $0 + +z80_h: .byte $0 +z80_l: .byte $0 +z80_d: .byte $0 +z80_e: .byte $0 + + + + + ;=========================== + ; Load Ornament + ;=========================== + ; ornament value in A + ; note offset in X + + ; Ornament table pointers are 16-bits little endian + ; There are 16 of these pointers starting at $aa:$a9 + ; Our ornament starts at address (A*2)+that pointer + ; We point ORNAMENT_H:ORNAMENT_L to this + ; then we load the length/data values + ; and then leave ORNAMENT_H:ORNAMENT_L pointing to begnning of + ; the ornament data + + ; Optimization: + ; Loop and length only used once, can be located negative + ; from the pointer, but 6502 doesn't make addressing like that + ; easy. Can't self modify as channels A/B/C have own copies + ; of the var. + +load_ornament0: + lda #0 ; 2 + +load_ornament: + + sty TEMP ; save Y value ; 3 + + ;pt3->ornament_patterns[i]= + ; (pt3->data[0xaa+(i*2)]<<8)|pt3->data[0xa9+(i*2)]; + + asl ; A*2 ; 2 + tay ; 2 + + ; a->ornament_pointer=pt3->ornament_patterns[a->ornament]; + + lda PT3_LOC+PT3_ORNAMENT_LOC_L,Y ; 4+ + sta ORNAMENT_L ; 3 + + lda PT3_LOC+PT3_ORNAMENT_LOC_L+1,Y ; 4+ + + ; we're assuming PT3 is loaded to a page boundary + + adc #>PT3_LOC ; 2 + sta ORNAMENT_H ; 3 + + lda #0 ; 2 + sta note_a+NOTE_ORNAMENT_POSITION,X ; 5 + + tay ; 2 + + ; Set the loop value + ; a->ornament_loop=pt3->data[a->ornament_pointer]; + lda (ORNAMENT_L),Y ; 5+ + sta note_a+NOTE_ORNAMENT_LOOP,X ; 5 + + ; Set the length value + ; a->ornament_length=pt3->data[a->ornament_pointer]; + iny ; 2 + lda (ORNAMENT_L),Y ; 5+ + sta note_a+NOTE_ORNAMENT_LENGTH,X ; 5 + + ; Set the pointer to the value past the length + + lda ORNAMENT_L ; 3 + adc #$2 ; 2 + sta note_a+NOTE_ORNAMENT_POINTER_L,X ; 5 + lda ORNAMENT_H ; 3 + adc #$0 ; 2 + sta note_a+NOTE_ORNAMENT_POINTER_H,X ; 5 + + ldy TEMP ; restore Y value ; 3 + + rts ; 6 + + ;============ + ; 83 + + ;=========================== + ; Load Sample + ;=========================== + ; sample in A + ; which note offset in X + + ; Sample table pointers are 16-bits little endian + ; There are 32 of these pointers starting at $6a:$69 + ; Our sample starts at address (A*2)+that pointer + ; We point SAMPLE_H:SAMPLE_L to this + ; then we load the length/data values + ; and then leave SAMPLE_H:SAMPLE_L pointing to begnning of + ; the sample data + + ; Optimization: + ; see comments on ornament setting + +load_sample1: + lda #1 ; 2 + +load_sample: + + sty TEMP ; 3 + + ;pt3->ornament_patterns[i]= + ; (pt3->data[0x6a+(i*2)]<<8)|pt3->data[0x69+(i*2)]; + + asl ; A*2 ; 2 + tay ; 2 + + ; Set the initial sample pointer + ; a->sample_pointer=pt3->sample_patterns[a->sample]; + + lda PT3_LOC+PT3_SAMPLE_LOC_L,Y ; 4+ + sta SAMPLE_L ; 3 + + lda PT3_LOC+PT3_SAMPLE_LOC_L+1,Y ; 4+ + + ; assume pt3 file is at page boundary + adc #>PT3_LOC ; 2 + sta SAMPLE_H ; 3 + + ; Set the loop value + ; a->sample_loop=pt3->data[a->sample_pointer]; + + ldy #0 ; 2 + lda (SAMPLE_L),Y ; 5+ + sta note_a+NOTE_SAMPLE_LOOP,X ; 5 + + ; Set the length value + ; a->sample_length=pt3->data[a->sample_pointer]; + + iny ; 2 + lda (SAMPLE_L),Y ; 5+ + sta note_a+NOTE_SAMPLE_LENGTH,X ; 5 + + ; Set pointer to beginning of samples + + lda SAMPLE_L ; 3 + adc #$2 ; 2 + sta note_a+NOTE_SAMPLE_POINTER_L,X ; 5 + lda SAMPLE_H ; 3 + adc #$0 ; 2 + sta note_a+NOTE_SAMPLE_POINTER_H,X ; 5 + + ldy TEMP ; 3 + + rts ; 6 + ;============ + ; 76 + + ;==================================== + ; pt3_init_song + ;==================================== + ; + ; TODO: change to a memset type instruction? + ; it will save bytes only if the labels are adjacent + ; it will add a lot more cycles, though +pt3_init_song: + lda #$f ; 2 + sta note_a+NOTE_VOLUME ; 4 + sta note_b+NOTE_VOLUME ; 4 + sta note_c+NOTE_VOLUME ; 4 + + lda #$0 ; 2 + sta DONE_SONG ; 3 + sta note_a+NOTE_TONE_SLIDING_L ; 4 + sta note_b+NOTE_TONE_SLIDING_L ; 4 + sta note_c+NOTE_TONE_SLIDING_L ; 4 + sta note_a+NOTE_TONE_SLIDING_H ; 4 + sta note_b+NOTE_TONE_SLIDING_H ; 4 + sta note_c+NOTE_TONE_SLIDING_H ; 4 + sta note_a+NOTE_ENABLED ; 4 + sta note_b+NOTE_ENABLED ; 4 + sta note_c+NOTE_ENABLED ; 4 + sta note_a+NOTE_ENVELOPE_ENABLED ; 4 + sta note_b+NOTE_ENVELOPE_ENABLED ; 4 + sta note_c+NOTE_ENVELOPE_ENABLED ; 4 + + sta pt3_noise_period ; 4 + sta pt3_noise_add ; 4 + sta pt3_envelope_period_l ; 4 + sta pt3_envelope_period_h ; 4 + sta pt3_envelope_type ; 4 + + ; default ornament/sample in A + ldx #(NOTE_STRUCT_SIZE*0) ; 2 + jsr load_ornament ; 6+93 + jsr load_sample1 ; 6+86 + + ; default ornament/sample in B + ldx #(NOTE_STRUCT_SIZE*1) ; 2 + jsr load_ornament0 ; 6+93 + jsr load_sample1 ; 6+86 + + ; default ornament/sample in C + ldx #(NOTE_STRUCT_SIZE*2) ; 2 + jsr load_ornament0 ; 6+93 + jsr load_sample1 ; 6+86 + + ;======================= + ; load default speed + + lda PT3_LOC+PT3_SPEED ; 4 + sta pt3_speed_smc+1 ; 4 + + ;======================= + ; load loop + + lda PT3_LOC+PT3_LOOP ; 4 + sta pt3_loop_smc+1 ; 4 + + + ;====================== + ; calculate version + ldx #6 ; 2 + lda PT3_LOC+PT3_VERSION ; 4 + sec ; 2 + sbc #'0' ; 2 + cmp #9 ; 2 + bcs not_ascii_number ; bge ; 2/3 + tax ; 2 + +not_ascii_number: + + ; adjust version<6 SMC code in the slide code + + ; FIXME: I am sure there's a more clever way to do this + + lda #$2C ; BIT ; 2 + cpx #$6 ; 2 + bcc version_less_than_6 ; blt ; 3 + ; carry is set + adc #$1F ; BIT->JMP 2C->4C ; 2 +version_less_than_6: + sta version_smc ; 4 + +pick_volume_table: + + ;======================= + ; Pick which volume number, based on version + + ; if (PlParams.PT3.PT3_Version <= 4) + + cpx #5 ; 2 + + ; carry clear = 3.3/3.4 table + ; carry set = 3.5 table + + ;========================== + ; VolTableCreator + ;========================== + ; Creates the appropriate volume table + ; based on z80 code by Ivan Roshin ZXAYHOBETA/VTII10bG.asm + ; + + ; Called with carry==0 for 3.3/3.4 table + ; Called with carry==1 for 3.5 table + + ; 177f-1932 = 435 bytes, not that much better than 512 of lookup + + +VolTableCreator: + + ; Init initial variables + lda #$0 + sta z80_d + ldy #$11 + + ; Set up self modify + + ldx #$2A ; ROL for self-modify + bcs vol_type_35 + +vol_type_33: + + ; For older table, we set initial conditions a bit + ; different + + dey + tya + + ldx #$ea ; NOP for self modify + +vol_type_35: + sty z80_l ; l=16 or 17 + sta z80_e ; e=16 or 0 + stx vol_smc ; set the self-modify code + + ldy #16 ; skip first row, all zeros + ldx #16 ; c=16 +vol_outer: + clc ; add HL,DE + lda z80_l + adc z80_e + sta z80_e + lda #0 + adc z80_d + sta z80_d ; carry is important + + ; sbc hl,hl + lda #0 + adc #$ff + eor #$ff + +vol_write: + sta z80_h + pha + +vol_inner: + pla + pha + +vol_smc: + nop ; nop or ROL depending + + lda z80_h + + adc #$0 ; a=a+carry; + + sta VolumeTable,Y + iny + + pla ; add HL,DE + adc z80_e + pha + lda z80_h + adc z80_d + sta z80_h + + inx ; inc C + txa ; a=c + and #$f + bne vol_inner + + + pla + + lda z80_e ; a=e + cmp #$77 + bne vol_m3 + + inc z80_e + +vol_m3: + txa ; a=c + bne vol_outer + +vol_done: + rts + + + + + + + + + + + ;===================================== + ; Calculate Note + ;===================================== + ; note offset in X + +calculate_note: + + lda note_a+NOTE_ENABLED,X ; 4+ + bne note_enabled ; 2/3 + + sta note_a+NOTE_AMPLITUDE,X ; 5 + jmp done_note ; 3 + +note_enabled: + + lda note_a+NOTE_SAMPLE_POINTER_H,X ; 4+ + sta SAMPLE_H ; 3 + lda note_a+NOTE_SAMPLE_POINTER_L,X ; 4+ + sta SAMPLE_L ; 3 + + lda note_a+NOTE_ORNAMENT_POINTER_H,X ; 4+ + sta ORNAMENT_H ; 3 + lda note_a+NOTE_ORNAMENT_POINTER_L,X ; 4+ + sta ORNAMENT_L ; 3 + + + lda note_a+NOTE_SAMPLE_POSITION,X ; 4+ + asl ; 2 + asl ; 2 + tay ; 2 + + ; b0 = pt3->data[a->sample_pointer + a->sample_position * 4]; + lda (SAMPLE_L),Y ; 5+ + sta sample_b0 ; 4 + + ; b1 = pt3->data[a->sample_pointer + a->sample_position * 4 + 1]; + iny ; 2 + lda (SAMPLE_L),Y ; 5+ + sta sample_b1 ; 4 + + ; a->tone = pt3->data[a->sample_pointer + a->sample_position*4+2]; + ; a->tone+=(pt3->data[a->sample_pointer + a->sample_position*4+3])<<8; + ; a->tone += a->tone_accumulator; + iny ; 2 + lda (SAMPLE_L),Y ; 5+ + adc note_a+NOTE_TONE_ACCUMULATOR_L,X ; 4+ + sta note_a+NOTE_TONE_L,X ; 4 + + iny ; 2 + lda (SAMPLE_L),Y ; 5+ + adc note_a+NOTE_TONE_ACCUMULATOR_H,X ; 4+ + sta note_a+NOTE_TONE_H,X ; 4 + + ;============================= + ; Accumulate tone if set + ; (if sample_b1 & $40) + + bit sample_b1 + bvc no_accum ; (so, if b1&0x40 is zero, skip it) + + sta note_a+NOTE_TONE_ACCUMULATOR_H,X + lda note_a+NOTE_TONE_L,X ; tone_accumulator=tone + sta note_a+NOTE_TONE_ACCUMULATOR_L,X + +no_accum: + + ;============================ + ; Calculate tone + ; j = a->note + (pt3->data[a->ornament_pointer + a->ornament_position] + clc ;;can be removed if ADC ACCUMULATOR_H cannot overflow + ldy note_a+NOTE_ORNAMENT_POSITION,X + lda (ORNAMENT_L),Y + adc note_a+NOTE_NOTE,X + + ; if (j < 0) j = 0; + bpl note_not_negative + lda #0 + + ; if (j > 95) j = 95; +note_not_negative: + cmp #96 + bcc note_not_too_high ; blt + + lda #95 + +note_not_too_high: + + ; w = GetNoteFreq(j,pt3->frequency_table); + + jsr GetNoteFreq + + ; a->tone = (a->tone + a->tone_sliding + w) & 0xfff; + + clc + ldy note_a+NOTE_TONE_SLIDING_L,X + tya + adc note_a+NOTE_TONE_L,X + sta note_a+NOTE_TONE_L,X + lda note_a+NOTE_TONE_H,X + adc note_a+NOTE_TONE_SLIDING_H,X + sta note_a+NOTE_TONE_H,X + + clc ;;can be removed if ADC SLIDING_H cannot overflow + lda note_a+NOTE_TONE_L,X + adc freq_l + sta note_a+NOTE_TONE_L,X + lda note_a+NOTE_TONE_H,X + adc freq_h + and #$0f + sta note_a+NOTE_TONE_H,X + + ;===================== + ; handle tone sliding + + lda note_a+NOTE_TONE_SLIDE_COUNT,X + bmi no_tone_sliding ; if (a->tone_slide_count > 0) { + beq no_tone_sliding + + dec note_a+NOTE_TONE_SLIDE_COUNT,X ; a->tone_slide_count--; + bne no_tone_sliding ; if (a->tone_slide_count==0) { + + + ; a->tone_sliding+=a->tone_slide_step + clc ;;can be removed if ADC freq_h cannot overflow + tya + adc note_a+NOTE_TONE_SLIDE_STEP_L,X + sta note_a+NOTE_TONE_SLIDING_L,X + tay + lda note_a+NOTE_TONE_SLIDING_H,X + adc note_a+NOTE_TONE_SLIDE_STEP_H,X + sta note_a+NOTE_TONE_SLIDING_H,X + + ; a->tone_slide_count = a->tone_slide_delay; + lda note_a+NOTE_TONE_SLIDE_DELAY,X + sta note_a+NOTE_TONE_SLIDE_COUNT,X + + lda note_a+NOTE_SIMPLE_GLISS,X + bne no_tone_sliding ; if (!a->simplegliss) { + + ; FIXME: do these need to be signed compares? + +check1: + lda note_a+NOTE_TONE_SLIDE_STEP_H,X + bpl check2 ; if ( ((a->tone_slide_step < 0) && + + ; (a->tone_sliding <= a->tone_delta) || + + ; 16 bit signed compare + tya ; NUM1-NUM2 + cmp note_a+NOTE_TONE_DELTA_L,X ; + lda note_a+NOTE_TONE_SLIDING_H,X + sbc note_a+NOTE_TONE_DELTA_H,X + bvc sc_loser1 ; N eor V + eor #$80 +sc_loser1: + bmi slide_to_note ; then A (signed) < NUM (signed) and BMI will branch + + ; equals case + tya + cmp note_a+NOTE_TONE_DELTA_L,X + bne check2 + lda note_a+NOTE_TONE_SLIDING_H,X + cmp note_a+NOTE_TONE_DELTA_H,X + beq slide_to_note + +check2: + lda note_a+NOTE_TONE_SLIDE_STEP_H,X + bmi no_tone_sliding ; ((a->tone_slide_step >= 0) && + + ; (a->tone_sliding >= a->tone_delta) + + ; 16 bit signed compare + tya ; NUM1-NUM2 + cmp note_a+NOTE_TONE_DELTA_L,X ; + lda note_a+NOTE_TONE_SLIDING_H,X + sbc note_a+NOTE_TONE_DELTA_H,X + bvc sc_loser2 ; N eor V + eor #$80 +sc_loser2: + bmi no_tone_sliding ; then A (signed) < NUM (signed) and BMI will branch + +slide_to_note: + ; a->note = a->slide_to_note; + lda note_a+NOTE_SLIDE_TO_NOTE,X + sta note_a+NOTE_NOTE,X + lda #0 + sta note_a+NOTE_TONE_SLIDE_COUNT,X + sta note_a+NOTE_TONE_SLIDING_L,X + sta note_a+NOTE_TONE_SLIDING_H,X + + +no_tone_sliding: + + ;========================= + ; Calculate the amplitude + ;========================= +calc_amplitude: + ; get base value from the sample (bottom 4 bits of sample_b1) + + lda sample_b1 ; a->amplitude= (b1 & 0xf); + and #$f + + ;======================================== + ; if b0 top bit is set, it means sliding + + ; adjust amplitude sliding + + bit sample_b0 ; if ((b0 & 0x80)!=0) { + bpl done_amp_sliding ; so if top bit not set, skip + tay + + ;================================ + ; if top bits 0b11 then slide up + ; if top bits 0b10 then slide down + + ; if ((b0 & 0x40)!=0) { + lda note_a+NOTE_AMPLITUDE_SLIDING,X + sec + bvc amp_slide_down + +amp_slide_up: + ; if (a->amplitude_sliding < 15) { + ; a pain to do signed compares + sbc #15 + bvc asu_signed + eor #$80 +asu_signed: + bpl done_amp_sliding ; skip if A>=15 + inc note_a+NOTE_AMPLITUDE_SLIDING,X ; a->amplitude_sliding++; + bne done_amp_sliding_y + +amp_slide_down: + ; if (a->amplitude_sliding > -15) { + ; a pain to do signed compares + sbc #$f1 ; -15 + bvc asd_signed + eor #$80 +asd_signed: + bmi done_amp_sliding ; if A < -15, skip subtract + + dec note_a+NOTE_AMPLITUDE_SLIDING,X ; a->amplitude_sliding--; + +done_amp_sliding_y: + tya + +done_amp_sliding: + + ; a->amplitude+=a->amplitude_sliding; + clc + adc note_a+NOTE_AMPLITUDE_SLIDING,X + + ; clamp amplitude to 0 - 15 + +check_amp_lo: + bmi write_clamp_amplitude + +check_amp_hi: + cmp #16 + bcc write_amplitude ; blt + lda #15 + .byte $2C +write_clamp_amplitude: + lda #0 +write_amplitude: + sta note_amp_smc+1 + +done_clamp_amplitude: + + ; We generate the proper table at runtime now + ; so always in Volume Table + ; a->amplitude = PT3VolumeTable_33_34[a->volume][a->amplitude]; + ; a->amplitude = PT3VolumeTable_35[a->volume][a->amplitude]; + + lda note_a+NOTE_VOLUME,X ; 4+ + asl ; 2 + asl ; 2 + asl ; 2 + asl ; 2 +note_amp_smc: + ora #0 ; 4+ + + tay ; 2 + lda VolumeTable,Y ; 4+ + sta note_a+NOTE_AMPLITUDE,X ; 5 + +done_table: + + +check_envelope_enable: + ; Bottom bit of b0 indicates our sample has envelope + ; Also make sure envelopes are enabled + + + ; if (((b0 & 0x1) == 0) && ( a->envelope_enabled)) { + lda sample_b0 + lsr + tay + bcs envelope_slide + + lda note_a+NOTE_ENVELOPE_ENABLED,X + beq envelope_slide + + + ; Bit 4 of the per-channel AY-3-8910 amplitude specifies + ; envelope enabled + + lda note_a+NOTE_AMPLITUDE,X ; a->amplitude |= 16; + ora #$10 + sta note_a+NOTE_AMPLITUDE,X + + +envelope_slide: + + ; Envelope slide + ; If b1 top bits are 10 or 11 + + lda sample_b0 + asl + asl + asl ; b0 bit 5 to carry flag + lda #$20 + bit sample_b1 ; b1 bit 7 to sign flag, bit 5 to zero flag + php + bpl else_noise_slide ; if ((b1 & 0x80) != 0) { + tya + ora #$f0 + bcs envelope_slide_down ; if ((b0 & 0x20) == 0) { + +envelope_slide_up: + ; j = ((b0>>1)&0xF) + a->envelope_sliding; + and #$0f + clc + +envelope_slide_down: + + ; j = ((b0>>1)|0xF0) + a->envelope_sliding + adc note_a+NOTE_ENVELOPE_SLIDING,X + sta e_slide_amount ; j + +envelope_slide_done: + + plp + beq last_envelope ; if (( b1 & 0x20) != 0) { + + ; a->envelope_sliding = j; + sta note_a+NOTE_ENVELOPE_SLIDING,X + +last_envelope: + + ; pt3->envelope_add+=j; + + clc + lda e_slide_amount + adc pt3_envelope_add + sta pt3_envelope_add + + jmp noise_slide_done ; skip else + +else_noise_slide: + ; Noise slide + ; else { + + ; pt3->noise_add = (b0>>1) + a->noise_sliding; + tya + clc + adc note_a+NOTE_NOISE_SLIDING,X + sta pt3_noise_add + + plp + beq noise_slide_done ; if ((b1 & 0x20) != 0) { + + ; noise_sliding = pt3_noise_add + sta note_a+NOTE_NOISE_SLIDING,X + +noise_slide_done: + ;====================== + ; set mixer + + lda sample_b1 ; pt3->mixer_value = ((b1 >>1) & 0x48) | pt3->mixer_value; + lsr + and #$48 + ora pt3_mixer_value + sta pt3_mixer_value + + + ;======================== + ; increment sample position + + inc note_a+NOTE_SAMPLE_POSITION,X ; a->sample_position++; + + lda note_a+NOTE_SAMPLE_POSITION,X + cmp note_a+NOTE_SAMPLE_LENGTH,X + + bcc sample_pos_ok ; blt + + lda note_a+NOTE_SAMPLE_LOOP,X + sta note_a+NOTE_SAMPLE_POSITION,X + +sample_pos_ok: + + ;======================== + ; increment ornament position + + inc note_a+NOTE_ORNAMENT_POSITION,X ; a->ornament_position++; + lda note_a+NOTE_ORNAMENT_POSITION,X + cmp note_a+NOTE_ORNAMENT_LENGTH,X + + bcc ornament_pos_ok ; blt + + lda note_a+NOTE_ORNAMENT_LOOP,X + sta note_a+NOTE_ORNAMENT_POSITION,X +ornament_pos_ok: + + +done_note: + ; set mixer value + ; this is a bit complex (from original code) + ; after 3 calls it is set up properly + lsr pt3_mixer_value + +handle_onoff: + lda note_a+NOTE_ONOFF,X ;if (a->onoff>0) { + beq done_onoff + + dec note_a+NOTE_ONOFF,X ; a->onoff--; + + bne done_onoff ; if (a->onoff==0) { + lda note_a+NOTE_ENABLED,X + eor #$1 ; toggle + sta note_a+NOTE_ENABLED,X + + .byte $a9 ;mask do_onoff +do_onoff: + dex ; select ONOFF + ;lda note_a+NOTE_ONOFF_DELAY,X ; if (a->enabled) a->onoff=a->onoff_delay; +do_offon: + lda note_a+NOTE_OFFON_DELAY,X ; else a->onoff=a->offon_delay; +put_offon: + sta note_a+NOTE_ONOFF,X + +done_onoff: + + rts ; 6 + + + + + + + ;===================================== + ; Decode Note + ;===================================== + ; X points to the note offset + + ; Note! These timings are out of date (FIXME) + ; Timings (from ===>) + ; 00: 14+30 + ; 0X: 14+15 + ; 10: 14+5 +124 + ; 1X: 14+5 +193 + ; 2X/3X: 14+5 +17 + ; 4X: 14+5+5 + 111 + ; 5X-BX: 14+5+5+ 102 + ; CX: + ; DX/EX: + ; FX: + +stop_decoding: + + ; we are still running, decrement and early return + dec note_a+NOTE_LEN_COUNT,X ; 7 + rts ; 6 + + ;===================================== + ; Decode Line + ;===================================== + +pt3_decode_line: + ; decode_note(&pt3->a,&(pt3->a_addr),pt3); + ldx #(NOTE_STRUCT_SIZE*0) + jsr decode_note + + ; decode_note(&pt3->b,&(pt3->b_addr),pt3); + ldx #(NOTE_STRUCT_SIZE*1) + jsr decode_note + + ; decode_note(&pt3->c,&(pt3->c_addr),pt3); + ldx #(NOTE_STRUCT_SIZE*2) + ;;jsr decode_note ; fall through + +; if (pt3->a.all_done && pt3->b.all_done && pt3->c.all_done) { +; return 1; +; } + +decode_note: + + ; Init vars + + ldy #0 ; 2 + sty spec_command ; 4 + + ; Skip decode if note still running + lda note_a+NOTE_LEN_COUNT,X ; 4+ + cmp #2 ; 2 + bcs stop_decoding ; blt, assume not negative ; 2/3 + +keep_decoding: + + lda note_a+NOTE_NOTE,X ; store prev note ; 4+ + sta prev_note ; 4 + + lda note_a+NOTE_TONE_SLIDING_H,X ; store prev sliding ; 4+ + sta prev_sliding_h ; 4 + lda note_a+NOTE_TONE_SLIDING_L,X ; 4+ + sta prev_sliding_l ; 4 + + + ;============ + ; 24 + +note_decode_loop: + lda note_a+NOTE_LEN,X ; re-up length count ; 4+ + sta note_a+NOTE_LEN_COUNT,X ; 5 + + lda note_a+NOTE_ADDR_L,X ; 4+ + sta PATTERN_L ; 3 + lda note_a+NOTE_ADDR_H,X ; 4+ + sta PATTERN_H ; 3 +;===> + ; get next value + lda (PATTERN_L),Y ; 5+ + sta note_command ; save termporarily ; 4 + and #$0f ; 2 + sta note_command_bottom ; 4 + lda note_command ; 4 + + ; FIXME: use a jump table?? + ; further reflection, that would require 32-bytes of addresses + ; in addition to needing X or Y to index the jump table. hmmm + + and #$f0 ; 2 + + ; cmp #$00 + bne decode_case_1X ; 2/3 + ;============= + ; 14 + +decode_case_0X: + ;============================== + ; $0X set special effect + ;============================== + ; -1 + lda note_command_bottom ; 4 + + ; we can always store spec as 0 means no spec + + ; FIXME: what if multiple spec commands? + ; Doesn't seem to happen in practice + ; But AY_emul has code to handle it + + sta spec_command ; 4 + + bne decode_case_0X_not_zero ; 2/3 + ;============= + ; 12 + ; 00 case + ; means end of pattern + ; -1 + sta note_a+NOTE_LEN_COUNT,X ; len_count=0; ; 5 + + dec pt3_pattern_done ; 6 + + jmp note_done_decoding ; 3 + +decode_case_0X_not_zero: + + jmp done_decode_loop ; 3 + + +decode_case_1X: + ;============================== + ; $1X -- Set Envelope Type + ;============================== + + cmp #$10 ; 2 + bne decode_case_2X ; 2/3 + ;============ + ; 5 + + ; -1 + lda note_command_bottom ; 4 + bne decode_case_not_10 ; 3 + +decode_case_10: + ; 10 case - disable ; -1 + sta note_a+NOTE_ENVELOPE_ENABLED,X ; A is 0 ; 5 + beq decode_case_1x_common ; branch always ; 3 + +decode_case_not_10: + ; -1 + jsr set_envelope ; 6+64 + +decode_case_1x_common: + + iny ; 2 + lda (PATTERN_L),Y ; 5+ + lsr ; 2 + jsr load_sample ; 6+86 + + lda #0 ; 2 + sta note_a+NOTE_ORNAMENT_POSITION,X ; ornament_position=0 ; 5 + + jmp done_decode_loop ; 3 + +decode_case_2X: +decode_case_3X: + ;============================== + ; $2X/$3X set noise period + ;============================== + + cmp #$40 ; 2 + bcs decode_case_4X ; branch greater/equal ; 3 + ; -1 + lda note_command ; 3 + adc #$e0 ; same as subtract $20 ; 2 + sta pt3_noise_period ; 3 + + jmp done_decode_loop ; 3 + ;=========== + ; 15 + +decode_case_4X: + ;============================== + ; $4X -- set ornament + ;============================== +; cmp #$40 ; already set ; + bne decode_case_5X ; 3 + ; -1 + lda note_command_bottom ; set ornament to bottom nibble ; 4 + jsr load_ornament ; 6+93 + + jmp done_decode_loop ; 3 + ;============ + ; 110 + +decode_case_5X: + ;============================== + ; $5X-$AX set note + ;============================== + cmp #$B0 ; 2 + bcs decode_case_bX ; branch greater/equal ; 3 + + ; -1 + lda note_command ; 4 + adc #$b0 ; 2 + sta note_a+NOTE_NOTE,X ; note=(current_val-0x50); ; 5 + + jsr reset_note ; 6+69 + + lda #1 ; 2 + sta note_a+NOTE_ENABLED,X ; enabled=1 ; 5 + + + bne note_done_decoding ; 3 + +decode_case_bX: + ;============================================ + ; $BX -- note length or envelope manipulation + ;============================================ +; cmp #$b0 ; already set from before + bne decode_case_cX ; 3 + ; -1 + lda note_command_bottom ; 4 + beq decode_case_b0 ; 3 + ; -1 + sbc #1 ; envelope_type=(current_val&0xf)-1; ; 2 + bne decode_case_bx_higher ; 3 + +decode_case_b1: + ; Set Length + + ; get next byte + iny ; 2 + lda (PATTERN_L),Y ; 5 + + sta note_a+NOTE_LEN,X ; 5 + sta note_a+NOTE_LEN_COUNT,X ; 5 + bcs done_decode_loop ; branch always ; 3 + +decode_case_b0: + ; Disable envelope + sta note_a+NOTE_ENVELOPE_ENABLED,X ; 5 + sta note_a+NOTE_ORNAMENT_POSITION,X ; 5 + beq done_decode_loop ; 3 + + +decode_case_bx_higher: + + jsr set_envelope ; 6+64 + + bcs done_decode_loop ; branch always ; 3 + +decode_case_cX: + ;============================== + ; $CX -- set volume + ;============================== + cmp #$c0 ; check top nibble $C ; 2 + bne decode_case_dX ; 3 + ; -1 + lda note_command_bottom ; 4 + bne decode_case_cx_not_c0 ; 3 + ; -1 +decode_case_c0: + ; special case $C0 means shut down the note + + sta note_a+NOTE_ENABLED,X ; enabled=0 ; 5 + + jsr reset_note ; 6+69 + + beq note_done_decoding ; branch always ; 3 + +decode_case_cx_not_c0: + sta note_a+NOTE_VOLUME,X ; volume=current_val&0xf; 5 + bne done_decode_loop ; branch always ; 3 + +decode_case_dX: + ;============================== + ; $DX/$EX -- change sample + ;============================== + ; D0 = special case (end note) + ; D1-EF = set sample to (value - $D0) + + cmp #$f0 ; check top nibble $D/$E ; 2 + beq decode_case_fX ; 3 + ; -1 + + lda note_command ; 4 + sec ; 2 + sbc #$d0 ; 2 + beq note_done_decoding ; 3 + +decode_case_not_d0: + ; -1 + + jsr load_sample ; load sample in bottom nybble ; 6+?? + + bcc done_decode_loop; branch always ; 3 + + ;======================== + ; d0 case means end note +;decode_case_d0: +; jmp note_done_decoding + + + ;============================== + ; $FX - change ornament/sample + ;============================== +decode_case_fX: + ; disable envelope + lda #0 ; 2 + sta note_a+NOTE_ENVELOPE_ENABLED,X ; 5 + + ; Set ornament to low byte of command + lda note_command_bottom ; 4 + jsr load_ornament ; ornament to load in A ; 6+? + + ; Get next byte + iny ; point to next byte ; 2 + lda (PATTERN_L),Y ; 5 + + ; Set sample to value/2 + lsr ; divide by two ; 2 + jsr load_sample ; sample to load in A ; 6+? + + ; fallthrough + +done_decode_loop: + + iny ; point to next byte ; 2 + + jmp note_decode_loop ; 3 + +note_done_decoding: + + iny ; point to next byte ; 2 + + ;================================= + ; handle effects + ;================================= + ; Note, the AYemul code has code to make sure these are applied + ; In the same order they appear. We don't bother? +handle_effects: + + lda spec_command ; 4 + + ;============================== + ; Effect #1 -- Tone Down + ;============================== +effect_1: + cmp #$1 ; 2 + bne effect_2 ; 3 + ; -1 + sta note_a+NOTE_SIMPLE_GLISS,X ; 5 + lsr ; 2 + sta note_a+NOTE_ONOFF,X ; 5 + + lda (PATTERN_L),Y ; load byte, set as slide delay ; 5 + iny ; 2 + + sta note_a+NOTE_TONE_SLIDE_DELAY,X ; 5 + sta note_a+NOTE_TONE_SLIDE_COUNT,X ; 5 + + lda (PATTERN_L),Y ; load byte, set as slide step low ; 5 + iny ; 2 + sta note_a+NOTE_TONE_SLIDE_STEP_L,X ; 5 + + lda (PATTERN_L),Y ; load byte, set as slide step high ; 5 + iny ; 2 + sta note_a+NOTE_TONE_SLIDE_STEP_H,X ; 5 + + jmp no_effect ; 3 + + ;============================== + ; Effect #2 -- Portamento + ;============================== +effect_2: + cmp #$2 ; 2 + beq effect_2_small ; 3 + ; -1 + jmp effect_3 ; 3 +effect_2_small: ; FIXME: make smaller + lda #0 ; 2 + sta note_a+NOTE_SIMPLE_GLISS,X ; 5 + sta note_a+NOTE_ONOFF,X ; 5 + + lda (PATTERN_L),Y ; load byte, set as delay ; 5 + iny ; 2 + + sta note_a+NOTE_TONE_SLIDE_DELAY,X ; 5 + sta note_a+NOTE_TONE_SLIDE_COUNT,X ; 5 + + iny ; 2 + iny ; 2 + iny ; 2 + + lda (PATTERN_L),Y ; load byte, set as slide_step high ; 5 + php ; 3 + + ; 16-bit absolute value + bpl slide_step_positive1 ; 3 + ;-1 + eor #$ff ; 2 + +slide_step_positive1: + sta note_a+NOTE_TONE_SLIDE_STEP_H,X ; 5 + dey ; 2 + lda (PATTERN_L),Y ; load byte, set as slide_step low ; 5 + plp ; 4 + bpl slide_step_positive2 ; 3 + ;-1 + eor #$ff ; 2 + adc #$0 ;+carry set by earlier CMP ; 2 + +slide_step_positive2: + sta note_a+NOTE_TONE_SLIDE_STEP_L,X ; 5 + bcc skip_step_inc1 ; 3 + inc note_a+NOTE_TONE_SLIDE_STEP_H,X ; 7 +skip_step_inc1: + + + iny ; moved here as it messed with flags ; 2 + iny ; 2 + + +; a->tone_delta=GetNoteFreq(a->note,pt3)- +; GetNoteFreq(prev_note,pt3); + + lda note_a+NOTE_NOTE,X + jsr GetNoteFreq + lda freq_l + sta temp_word_l + lda freq_h + sta temp_word_h + + lda prev_note + jsr GetNoteFreq + + sec + lda temp_word_l + sbc freq_l + sta note_a+NOTE_TONE_DELTA_L,X + lda temp_word_h + sbc freq_h + sta note_a+NOTE_TONE_DELTA_H,X + + ; a->slide_to_note=a->note; + lda note_a+NOTE_NOTE,X + sta note_a+NOTE_SLIDE_TO_NOTE,X + + ; a->note=prev_note; + lda prev_note + sta note_a+NOTE_NOTE,X + + ; implement file version 6 and above slide behavior + ; this is done by SMC at song init time +version_smc: + jmp weird_version ; (JMP to BIT via smc) ; 3 + + lda prev_sliding_l + sta note_a+NOTE_TONE_SLIDING_L,X + lda prev_sliding_h + sta note_a+NOTE_TONE_SLIDING_H,X + +weird_version: + + ; annoying 16-bit subtract, only care if negative + ; if ((a->tone_delta - a->tone_sliding) < 0) { + sec + lda note_a+NOTE_TONE_DELTA_L,X + sbc note_a+NOTE_TONE_SLIDING_L,X + lda note_a+NOTE_TONE_DELTA_H,X + sbc note_a+NOTE_TONE_SLIDING_H,X + bpl no_need + + ; a->tone_slide_step = -a->tone_slide_step; + + lda note_a+NOTE_TONE_SLIDE_STEP_L,X + eor #$ff + clc + adc #$1 + sta note_a+NOTE_TONE_SLIDE_STEP_L,X + lda note_a+NOTE_TONE_SLIDE_STEP_H,X + eor #$ff + adc #$0 + sta note_a+NOTE_TONE_SLIDE_STEP_H,X + +no_need: + + jmp no_effect + + ;============================== + ; Effect #3 -- Sample Position + ;============================== +effect_3: + cmp #$3 + bne effect_4 + + lda (PATTERN_L),Y ; load byte, set as sample position + iny + sta note_a+NOTE_SAMPLE_POSITION,X + + bne no_effect ; branch always + + ;============================== + ; Effect #4 -- Ornament Position + ;============================== +effect_4: + cmp #$4 + bne effect_5 + + lda (PATTERN_L),Y ; load byte, set as ornament position + iny + sta note_a+NOTE_ORNAMENT_POSITION,X + + bne no_effect ; branch always + + ;============================== + ; Effect #5 -- Vibrato + ;============================== +effect_5: + cmp #$5 + bne effect_8 + + lda (PATTERN_L),Y ; load byte, set as onoff delay + iny + sta note_a+NOTE_ONOFF_DELAY,X + sta note_a+NOTE_ONOFF,X + + lda (PATTERN_L),Y ; load byte, set as offon delay + iny + sta note_a+NOTE_OFFON_DELAY,X + + lda #0 + sta note_a+NOTE_TONE_SLIDE_COUNT,X + sta note_a+NOTE_TONE_SLIDING_L,X + sta note_a+NOTE_TONE_SLIDING_H,X + + beq no_effect ; branch always + + ;============================== + ; Effect #8 -- Envelope Down + ;============================== +effect_8: + cmp #$8 + bne effect_9 + + ; delay + lda (PATTERN_L),Y ; load byte, set as speed + iny + sta pt3_envelope_delay + sta pt3_envelope_delay_orig + + ; low value + lda (PATTERN_L),Y ; load byte, set as low + iny + sta pt3_envelope_slide_add_l + + ; high value + lda (PATTERN_L),Y ; load byte, set as high + iny + sta pt3_envelope_slide_add_h + + bne no_effect ; branch always + + ;============================== + ; Effect #9 -- Set Speed + ;============================== +effect_9: + cmp #$9 + bne no_effect + + lda (PATTERN_L),Y ; load byte, set as speed + iny + sta pt3_speed_smc+1 + +no_effect: + + ;================================ + ; add y into the address pointer + + clc + tya + adc note_a+NOTE_ADDR_L,X + sta note_a+NOTE_ADDR_L,X + lda #0 + adc note_a+NOTE_ADDR_H,X + sta note_a+NOTE_ADDR_H,X + sta PATTERN_H + + rts + + + ;======================================= + ; Set Envelope + ;======================================= + ; pulls out common code from $1X and $BX + ; commands + + ; A = new envelope type + +set_envelope: + + sta pt3_envelope_type ; 4 + +; give fake old to force update? maybe only needed if printing? +; pt3->envelope_type_old=0x78; + + lda #$78 ; 2 + sta pt3_envelope_type_old ; 4 + + ; get next byte + iny ; 2 + lda (PATTERN_L),Y ; 5+ + sta pt3_envelope_period_h ; 4 + + iny ; 2 + lda (PATTERN_L),Y ; 5+ + sta pt3_envelope_period_l ; 4 + + lda #1 ; 2 + sta note_a+NOTE_ENVELOPE_ENABLED,X ; envelope_enabled=1 ; 5 + lsr ; 2 + sta note_a+NOTE_ORNAMENT_POSITION,X ; ornament_position=0 ; 5 + sta pt3_envelope_delay ; envelope_delay=0 ; 4 + sta pt3_envelope_slide_l ; envelope_slide=0 ; 4 + sta pt3_envelope_slide_h ; 4 + + rts ; 6 + ;=========== + ; 64 + + ;======================== + ; reset note + ;======================== + ; common code from the decode note code + +reset_note: + lda #0 ; 2 + sta note_a+NOTE_SAMPLE_POSITION,X ; sample_position=0 ; 5 + sta note_a+NOTE_AMPLITUDE_SLIDING,X ; amplitude_sliding=0 ; 5 + sta note_a+NOTE_NOISE_SLIDING,X ; noise_sliding=0 ; 5 + sta note_a+NOTE_ENVELOPE_SLIDING,X ; envelope_sliding=0 ; 5 + sta note_a+NOTE_ORNAMENT_POSITION,X ; ornament_position=0 ; 5 + sta note_a+NOTE_TONE_SLIDE_COUNT,X ; tone_slide_count=0 ; 5 + sta note_a+NOTE_TONE_SLIDING_L,X ; tone_sliding=0 ; 5 + sta note_a+NOTE_TONE_SLIDING_H,X ; 5 + sta note_a+NOTE_TONE_ACCUMULATOR_L,X ; tone_accumulator=0 ; 5 + sta note_a+NOTE_TONE_ACCUMULATOR_H,X ; 5 + sta note_a+NOTE_ONOFF,X ; onoff=0; ; 5 + + rts ; 6 + ;============ + ; 69 + + + + + + + ;===================================== + ; Set Pattern + ;===================================== + ; FIXME: inline this? we do call it from outside + ; in the player note length code + +is_done: + ; done with song, set it to non-zero + sta DONE_SONG ; 3 + rts ; 6 + +pt3_set_pattern: + + ; Lookup current pattern in pattern table + ldy current_pattern ; 4 + lda PT3_LOC+PT3_PATTERN_TABLE,Y ; 4+ + + ; if value is $FF we are at the end of the song + cmp #$ff ; 2 + beq is_done ; 2/3 + + ;============ + ; 22 if end + +not_done: + + ; set up the three pattern address pointers + + asl ; mul pattern offset by two, as word sized ; 2 + tay ; 2 + + ; point PATTERN_H/PATTERN_L to the pattern address table + + clc ; 2 + lda PT3_LOC+PT3_PATTERN_LOC_L ; 4 + sta PATTERN_L ; 3 + lda PT3_LOC+PT3_PATTERN_LOC_H ; 4 + adc #>PT3_LOC ; assume page boundary ; 2 + sta PATTERN_H ; 3 + + ; First 16-bits points to the Channel A address + lda (PATTERN_L),Y ; 5+ + sta note_a+NOTE_ADDR_L ; 4 + iny ; 2 + lda (PATTERN_L),Y ; 5+ + adc #>PT3_LOC ; assume page boundary ; 2 + sta note_a+NOTE_ADDR_H ; 4 + iny ; 2 + + ; Next 16-bits points to the Channel B address + lda (PATTERN_L),Y ; 5+ + sta note_b+NOTE_ADDR_L ; 4 + iny ; 2 + lda (PATTERN_L),Y ; 5+ + adc #>PT3_LOC ; assume page boundary ; 2 + sta note_b+NOTE_ADDR_H ; 4 + iny ; 2 + + ; Next 16-bits points to the Channel C address + lda (PATTERN_L),Y ; 5+ + sta note_c+NOTE_ADDR_L ; 4 + iny ; 2 + lda (PATTERN_L),Y ; 5+ + adc #>PT3_LOC ; assume page boundary ; 2 + sta note_c+NOTE_ADDR_H ; 4 + + ; clear out the noise channel + lda #0 ; 2 + sta pt3_noise_period ; 4 + + ; Set all three channels as active + ; FIXME: num_channels, may need to be 6 if doing 6-channel pt3? + lda #3 ; 2 + sta pt3_pattern_done ; 4 + + rts ; 6 + + + + ;===================================== + ; pt3 make frame + ;===================================== + ; update pattern or line if necessary + ; then calculate the values for the next frame + + ;========================== + ; pattern done early! + +early_end: + inc current_pattern ; increment pattern ; 6 + sta current_line ; 4 + sta current_subframe ; 4 + +check_subframe: + lda current_subframe ; 4 + bne pattern_good ; 2/3 + + ; load a new pattern in + jsr pt3_set_pattern ;6+? + + lda DONE_SONG ; 3 + beq pattern_good ; 2/3 + rts ; 6 + +pt3_make_frame: + + ; see if we need a new pattern + ; we do if line==0 and subframe==0 + ; allow fallthrough where possible + lda current_line ; 4 + beq check_subframe ; 2/3 + +pattern_good: + + ; see if we need a new line + + lda current_subframe ; 4 + bne line_good ; 2/3 + + ; decode a new line + jsr pt3_decode_line ; 6+? + + ; check if pattern done early + lda pt3_pattern_done ; 4 + beq early_end ; 2/3 + +line_good: + + ; Increment everything + + inc current_subframe ; subframe++ ; 6 + lda current_subframe ; 4 + + ; if we hit pt3_speed, move to next +pt3_speed_smc: + eor #0 ; 2 + bne do_frame ; 2/3 + +next_line: + sta current_subframe ; reset subframe to 0 ; 4 + + inc current_line ; and increment line ; 6 + lda current_line ; 4 + + eor #64 ; always end at 64. ; 2 + bne do_frame ; is this always needed? ; 2/3 + +next_pattern: + sta current_line ; reset line to 0 ; 4 + + inc current_pattern ; increment pattern ; 6 + +do_frame: + ; AY-3-8910 register summary + ; + ; R0/R1 = A period low/high + ; R2/R3 = B period low/high + ; R4/R5 = C period low/high + ; R6 = Noise period + ; R7 = Enable XX Noise=!CBA Tone=!CBA + ; R8/R9/R10 = Channel A/B/C amplitude M3210, M=envelope enable + ; R11/R12 = Envelope Period low/high + ; R13 = Envelope Shape, 0xff means don't write + ; R14/R15 = I/O (ignored) + + lda #0 ; needed ; 2 + sta pt3_mixer_value ; 4 + sta pt3_envelope_add ; 4 + + ldx #(NOTE_STRUCT_SIZE*0) ; Note A ; 2 + jsr calculate_note ; 6+? + ldx #(NOTE_STRUCT_SIZE*1) ; Note B ; 2 + jsr calculate_note ; 6+? + ldx #(NOTE_STRUCT_SIZE*2) ; Note C ; 2 + jsr calculate_note ; 6+? + +convert_177_smc1: + sec ; 2 + + ; Load up the Frequency Registers + + lda note_a+NOTE_TONE_L ; Note A Period L ; 4 + sta AY_REGISTERS+0 ; into R0 ; 3 + + lda note_a+NOTE_TONE_H ; Note A Period H ; 4 + sta AY_REGISTERS+1 ; into R1 ; 3 + lda note_a+NOTE_TONE_L ; Note A Period L ; 4 + bcc no_scale_a ; 2/3 + + ; Convert from 1.77MHz to 1MHz by multiplying by 9/16 + + ; conversion costs 100 cycles! + + ; first multiply by 8 + asl ; 2 + rol AY_REGISTERS+1 ; 5 + asl ; 2 + rol AY_REGISTERS+1 ; 5 + asl ; 2 + rol AY_REGISTERS+1 ; 5 + + ; add in original to get 9 + clc ; 2 + adc note_a+NOTE_TONE_L ; 4 + sta AY_REGISTERS+0 ; 3 + lda note_a+NOTE_TONE_H ; 4 + adc AY_REGISTERS+1 ; 3 + + ; divide by 16 to get proper value + ror ; 2 + ror AY_REGISTERS+0 ; 5 + ror ; 2 + ror AY_REGISTERS+0 ; 5 + ror ; 2 + ror AY_REGISTERS+0 ; 5 + ror ; 2 + ror AY_REGISTERS+0 ; 5 + and #$0f ; 2 + sta AY_REGISTERS+1 ; 3 + +no_scale_a: + +convert_177_smc2: + sec ; 2 + + lda note_b+NOTE_TONE_L ; Note B Period L ; 4 + sta AY_REGISTERS+2 ; into R2 ; 3 + + lda note_b+NOTE_TONE_H ; Note B Period H ; 4 + sta AY_REGISTERS+3 ; into R3 ; 3 + lda note_b+NOTE_TONE_L ; Note B Period L ; 4 + bcc no_scale_b ; 2/3 + + ; Convert from 1.77MHz to 1MHz by multiplying by 9/16 + + ; first multiply by 8 + asl ; 2 + rol AY_REGISTERS+3 ; 5 + asl ; 2 + rol AY_REGISTERS+3 ; 5 + asl ; 2 + rol AY_REGISTERS+3 ; 5 + + ; add in original to get 9 + clc ; 2 + adc note_b+NOTE_TONE_L ; 4 + sta AY_REGISTERS+2 ; 3 + lda note_b+NOTE_TONE_H ; 4 + adc AY_REGISTERS+3 ; 3 + + ; divide by 16 to get proper value + ror ; 2 + ror AY_REGISTERS+2 ; 5 + ror ; 2 + ror AY_REGISTERS+2 ; 5 + ror ; 2 + ror AY_REGISTERS+2 ; 5 + ror ; 2 + ror AY_REGISTERS+2 ; 5 + and #$0f ; 2 + sta AY_REGISTERS+3 ; 3 + +no_scale_b: + +convert_177_smc3: + sec ; 2 + + lda note_c+NOTE_TONE_L ; Note C Period L ; 4 + sta AY_REGISTERS+4 ; into R4 ; 3 + lda note_c+NOTE_TONE_H ; Note C Period H ; 4 + sta AY_REGISTERS+5 ; into R5 ; 3 + lda note_c+NOTE_TONE_L ; Note C Period L ; 4 + bcc no_scale_c ; 2/3 + + ; Convert from 1.77MHz to 1MHz by multiplying by 9/16 + + ; first multiply by 8 + asl ; 2 + rol AY_REGISTERS+5 ; 5 + asl ; 2 + rol AY_REGISTERS+5 ; 5 + asl ; 2 + rol AY_REGISTERS+5 ; 5 + + ; add in original to get 9 + clc ; 2 + adc note_c+NOTE_TONE_L ; 4 + sta AY_REGISTERS+4 ; 3 + lda note_c+NOTE_TONE_H ; 4 + adc AY_REGISTERS+5 ; 3 + + ; divide by 16 to get proper value + ror ; 2 + ror AY_REGISTERS+4 ; 5 + ror ; 2 + ror AY_REGISTERS+4 ; 5 + ror ; 2 + ror AY_REGISTERS+4 ; 5 + ror ; 2 + ror AY_REGISTERS+4 ; 5 + and #$0f ; 2 + sta AY_REGISTERS+5 ; 3 + +no_scale_c: + + + ; Noise + ; frame[6]= (pt3->noise_period+pt3->noise_add)&0x1f; + clc ; 2 + lda pt3_noise_period ; 4 + adc pt3_noise_add ; 4 + and #$1f ; 2 + sta AY_REGISTERS+6 ; 3 + +convert_177_smc4: + sec ; 2 + bcc no_scale_n ; 2/3 + + ; Convert from 1.77MHz to 1MHz by multiplying by 9/16 + + ; first multiply by 8 + asl ; 2 + asl ; 2 + asl ; 2 + + ; add in original to get 9 + adc AY_REGISTERS+6 ; 3 + + ; divide by 16 to get proper value + ror ; 2 + ror ; 2 + ror ; 2 + ror ; 2 + and #$1f ; 2 + +no_scale_n: + sta AY_REGISTERS+6 ; 3 + + ;======================= + ; Mixer + + lda pt3_mixer_value ; 4 + sta AY_REGISTERS+7 ; 3 + + ;======================= + ; Amplitudes + + lda note_a+NOTE_AMPLITUDE ; 4 + sta AY_REGISTERS+8 ; 3 + lda note_b+NOTE_AMPLITUDE ; 4 + sta AY_REGISTERS+9 ; 3 + lda note_c+NOTE_AMPLITUDE ; 4 + sta AY_REGISTERS+10 ; 3 + + ;====================================== + ; Envelope period + ; result=period+add+slide (16-bits) + clc ; 2 + lda pt3_envelope_period_l ; 4 + adc pt3_envelope_add ; 4 + tay ; 2 + lda pt3_envelope_period_h ; 4 + adc #0 ; 2 + sta temp_word_h ; 4 + + clc ; 2 + tya ; 2 + adc pt3_envelope_slide_l ; 4 + sta AY_REGISTERS+11 ; 3 + lda temp_word_h ; 4 + adc pt3_envelope_slide_h ; 4 + sta AY_REGISTERS+12 ; 3 + +convert_177_smc5: + sec + bcc no_scale_e ; 2/3 + + ; Convert from 1.77MHz to 1MHz by multiplying by 9/16 + + tay ; 2 + ; first multiply by 8 + lda AY_REGISTERS+11 ; 3 + asl ; 2 + rol AY_REGISTERS+12 ; 5 + asl ; 2 + rol AY_REGISTERS+12 ; 5 + asl ; 2 + rol AY_REGISTERS+12 ; 5 + + ; add in original to get 9 + clc ; 2 + adc AY_REGISTERS+11 ; 3 + sta AY_REGISTERS+11 ; 3 + tya ; 2 + adc AY_REGISTERS+12 ; 3 + + ; divide by 16 to get proper value + ror ; 2 + ror AY_REGISTERS+11 ; 5 + ror ; 2 + ror AY_REGISTERS+11 ; 5 + ror ; 2 + ror AY_REGISTERS+11 ; 5 + ror ; 2 + ror AY_REGISTERS+11 ; 5 + and #$0f ; 2 + sta AY_REGISTERS+12 ; 3 + +no_scale_e: + + ;======================== + ; Envelope shape + + lda pt3_envelope_type ; 4 + cmp pt3_envelope_type_old ; 4 + sta pt3_envelope_type_old ; copy old to new ; 4 + bne envelope_diff ; 2/3 +envelope_same: + lda #$ff ; if same, store $ff ; 2 +envelope_diff: + sta AY_REGISTERS+13 ; 3 + + + + ;============================== + ; end-of-frame envelope update + ;============================== + + lda pt3_envelope_delay ; 4 + beq done_do_frame ; assume can't be negative? ; 2/3 + ; do this if envelope_delay>0 + dec pt3_envelope_delay ; 6 + bne done_do_frame ; 2/3 + ; only do if we hit 0 + lda pt3_envelope_delay_orig ; reset envelope delay ; 4 + sta pt3_envelope_delay ; 4 + + clc ; 16-bit add ; 2 + lda pt3_envelope_slide_l ; 4 + adc pt3_envelope_slide_add_l ; 4 + sta pt3_envelope_slide_l ; 4 + lda pt3_envelope_slide_h ; 4 + adc pt3_envelope_slide_add_h ; 4 + sta pt3_envelope_slide_h ; 4 + +done_do_frame: + + rts ; 6 + + ;====================================== + ; GetNoteFreq + ;====================================== + ; Return frequency from lookup table + ; Which note is in A + ; return in freq_l/freq_h + + ; FIXME: self modify code +GetNoteFreq: + + sty TEMP ; 3 + + tay ; 2 + lda PT3_LOC+PT3_HEADER_FREQUENCY ; 4 + cmp #1 ; 2 + bne freq_table_2 ; 2/3 + + lda PT3NoteTable_ST_high,Y ; 4+ + sta freq_h ; 4 + lda PT3NoteTable_ST_low,Y ; 4+ + sta freq_l ; 4 + + ldy TEMP ; 3 + rts ; 6 + ;=========== + ; 40 + + +freq_table_2: + lda PT3NoteTable_ASM_34_35_high,Y ; 4+ + sta freq_h ; 4 + lda PT3NoteTable_ASM_34_35_low,Y ; 4+ + sta freq_l ; 4 + + ldy TEMP ; 3 + rts ; 6 + ;=========== + ; 41 + + +; Table #1 of Pro Tracker 3.3x - 3.5x +PT3NoteTable_ST_high: +.byte $0E,$0E,$0D,$0C,$0B,$0B,$0A,$09 +.byte $09,$08,$08,$07,$07,$07,$06,$06 +.byte $05,$05,$05,$04,$04,$04,$04,$03 +.byte $03,$03,$03,$03,$02,$02,$02,$02 +.byte $02,$02,$02,$01,$01,$01,$01,$01 +.byte $01,$01,$01,$01,$01,$01,$01,$00 +.byte $00,$00,$00,$00,$00,$00,$00,$00 +.byte $00,$00,$00,$00,$00,$00,$00,$00 +.byte $00,$00,$00,$00,$00,$00,$00,$00 +.byte $00,$00,$00,$00,$00,$00,$00,$00 +.byte $00,$00,$00,$00,$00,$00,$00,$00 +.byte $00,$00,$00,$00,$00,$00,$00,$00 + +PT3NoteTable_ST_low: +.byte $F8,$10,$60,$80,$D8,$28,$88,$F0 +.byte $60,$E0,$58,$E0,$7C,$08,$B0,$40 +.byte $EC,$94,$44,$F8,$B0,$70,$2C,$FD +.byte $BE,$84,$58,$20,$F6,$CA,$A2,$7C +.byte $58,$38,$16,$F8,$DF,$C2,$AC,$90 +.byte $7B,$65,$51,$3E,$2C,$1C,$0A,$FC +.byte $EF,$E1,$D6,$C8,$BD,$B2,$A8,$9F +.byte $96,$8E,$85,$7E,$77,$70,$6B,$64 +.byte $5E,$59,$54,$4F,$4B,$47,$42,$3F +.byte $3B,$38,$35,$32,$2F,$2C,$2A,$27 +.byte $25,$23,$21,$1F,$1D,$1C,$1A,$19 +.byte $17,$16,$15,$13,$12,$11,$10,$0F + + +; Table #2 of Pro Tracker 3.4x - 3.5x +PT3NoteTable_ASM_34_35_high: +.byte $0D,$0C,$0B,$0A,$0A,$09,$09,$08 +.byte $08,$07,$07,$06,$06,$06,$05,$05 +.byte $05,$04,$04,$04,$04,$03,$03,$03 +.byte $03,$03,$02,$02,$02,$02,$02,$02 +.byte $02,$01,$01,$01,$01,$01,$01,$01 +.byte $01,$01,$01,$01,$01,$00,$00,$00 +.byte $00,$00,$00,$00,$00,$00,$00,$00 +.byte $00,$00,$00,$00,$00,$00,$00,$00 +.byte $00,$00,$00,$00,$00,$00,$00,$00 +.byte $00,$00,$00,$00,$00,$00,$00,$00 +.byte $00,$00,$00,$00,$00,$00,$00,$00 +.byte $00,$00,$00,$00,$00,$00,$00,$00 + +PT3NoteTable_ASM_34_35_low: +.byte $10,$55,$A4,$FC,$5F,$CA,$3D,$B8 +.byte $3B,$C5,$55,$EC,$88,$2A,$D2,$7E +.byte $2F,$E5,$9E,$5C,$1D,$E2,$AB,$76 +.byte $44,$15,$E9,$BF,$98,$72,$4F,$2E +.byte $0F,$F1,$D5,$BB,$A2,$8B,$74,$60 +.byte $4C,$39,$28,$17,$07,$F9,$EB,$DD +.byte $D1,$C5,$BA,$B0,$A6,$9D,$94,$8C +.byte $84,$7C,$75,$6F,$69,$63,$5D,$58 +.byte $53,$4E,$4A,$46,$42,$3E,$3B,$37 +.byte $34,$31,$2F,$2C,$29,$27,$25,$23 +.byte $21,$1F,$1D,$1C,$1A,$19,$17,$16 +.byte $15,$14,$12,$11,$10,$0F,$0E,$0D + + +;PT3VolumeTable_33_34: +;.byte $0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0 +;.byte $0,$0,$0,$0,$0,$0,$0,$0,$1,$1,$1,$1,$1,$1,$1,$1 +;.byte $0,$0,$0,$0,$0,$0,$1,$1,$1,$1,$1,$2,$2,$2,$2,$2 +;.byte $0,$0,$0,$0,$1,$1,$1,$1,$2,$2,$2,$2,$3,$3,$3,$3 +;.byte $0,$0,$0,$0,$1,$1,$1,$2,$2,$2,$3,$3,$3,$4,$4,$4 +;.byte $0,$0,$0,$1,$1,$1,$2,$2,$3,$3,$3,$4,$4,$4,$5,$5 +;.byte $0,$0,$0,$1,$1,$2,$2,$3,$3,$3,$4,$4,$5,$5,$6,$6 +;.byte $0,$0,$1,$1,$2,$2,$3,$3,$4,$4,$5,$5,$6,$6,$7,$7 +;.byte $0,$0,$1,$1,$2,$2,$3,$3,$4,$5,$5,$6,$6,$7,$7,$8 +;.byte $0,$0,$1,$1,$2,$3,$3,$4,$5,$5,$6,$6,$7,$8,$8,$9 +;.byte $0,$0,$1,$2,$2,$3,$4,$4,$5,$6,$6,$7,$8,$8,$9,$A +;.byte $0,$0,$1,$2,$3,$3,$4,$5,$6,$6,$7,$8,$9,$9,$A,$B +;.byte $0,$0,$1,$2,$3,$4,$4,$5,$6,$7,$8,$8,$9,$A,$B,$C +;.byte $0,$0,$1,$2,$3,$4,$5,$6,$7,$7,$8,$9,$A,$B,$C,$D +;.byte $0,$0,$1,$2,$3,$4,$5,$6,$7,$8,$9,$A,$B,$C,$D,$E +;.byte $0,$1,$2,$3,$4,$5,$6,$7,$8,$9,$A,$B,$C,$D,$E,$F + +;PT3VolumeTable_35: +;.byte $0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0 +;.byte $0,$0,$0,$0,$0,$0,$0,$0,$1,$1,$1,$1,$1,$1,$1,$1 +;.byte $0,$0,$0,$0,$1,$1,$1,$1,$1,$1,$1,$1,$2,$2,$2,$2 +;.byte $0,$0,$0,$1,$1,$1,$1,$1,$2,$2,$2,$2,$2,$3,$3,$3 +;.byte $0,$0,$1,$1,$1,$1,$2,$2,$2,$2,$3,$3,$3,$3,$4,$4 +;.byte $0,$0,$1,$1,$1,$2,$2,$2,$3,$3,$3,$4,$4,$4,$5,$5 +;.byte $0,$0,$1,$1,$2,$2,$2,$3,$3,$4,$4,$4,$5,$5,$6,$6 +;.byte $0,$0,$1,$1,$2,$2,$3,$3,$4,$4,$5,$5,$6,$6,$7,$7 +;.byte $0,$1,$1,$2,$2,$3,$3,$4,$4,$5,$5,$6,$6,$7,$7,$8 +;.byte $0,$1,$1,$2,$2,$3,$4,$4,$5,$5,$6,$7,$7,$8,$8,$9 +;.byte $0,$1,$1,$2,$3,$3,$4,$5,$5,$6,$7,$7,$8,$9,$9,$A +;.byte $0,$1,$1,$2,$3,$4,$4,$5,$6,$7,$7,$8,$9,$A,$A,$B +;.byte $0,$1,$2,$2,$3,$4,$5,$6,$6,$7,$8,$9,$A,$A,$B,$C +;.byte $0,$1,$2,$3,$3,$4,$5,$6,$7,$8,$9,$A,$A,$B,$C,$D +;.byte $0,$1,$2,$3,$4,$5,$6,$7,$7,$8,$9,$A,$B,$C,$D,$E +;.byte $0,$1,$2,$3,$4,$5,$6,$7,$8,$9,$A,$B,$C,$D,$E,$F + + + + + +VolumeTable: + .res 256,0 + + +pt3_lib_end: diff --git a/pt3_lib/pt3_test.s b/pt3_lib/pt3_test.s new file mode 100644 index 00000000..479510b6 --- /dev/null +++ b/pt3_lib/pt3_test.s @@ -0,0 +1,184 @@ +;================= +; VMW PT3_LIB test +;================= +; template for using the pt3_lib + + +; zero page definitions +.include "zp.inc" + +; Location the files load at. +; If you change this, you need to update the Makefile + +PT3_LOC = song + + + ;============================= + ; Setup + ;============================= +pt3_setup: + jsr HOME + jsr TEXT + + ;=========================== + ; Check for Apple II/II+/IIc + ;=========================== + ; this is used to see if we have lowecase support + + lda $FBB3 ; IIe and newer is $06 + cmp #6 + beq apple_iie + + lda #1 ; set if older than a IIe + sta apple_ii +apple_iie: + + ;=============== + ; init variables + ;=============== + + lda #0 + sta DONE_PLAYING + sta LOOP + + ;======================= + ; Detect mockingboard + ;======================== + + ; Note, we do this, but then ignore it, as sometimes + ; the test fails and then you don't get music. + ; In theory this could do bad things if you had something + ; easily confused in slot4, but that's probably not an issue. + + ; print detection message + +; lda #mocking_message +; sta OUTH +; jsr move_and_print ; print it + + jsr mockingboard_detect_slot4 ; call detection routine + cpx #$1 + beq mockingboard_found + +; lda #not_message +; sta OUTH +; inc CV +; jsr move_and_print + +; jmp forever_loop ; and wait forever + +mockingboard_found: +; lda #found_message +; sta OUTH +; inc CV +; jsr move_and_print + + ;============================ + ; Init the Mockingboard + ;============================ + + jsr mockingboard_init + jsr reset_ay_both + jsr clear_ay_both + + ;========================= + ; Setup Interrupt Handler + ;========================= + ; Vector address goes to 0x3fe/0x3ff + ; FIXME: should chain any existing handler + + lda #interrupt_handler + sta $03ff + + ;============================ + ; Enable 50Hz clock on 6522 + ;============================ + + sei ; disable interrupts just in case + + lda #$40 ; Continuous interrupts, don't touch PB7 + sta $C40B ; ACR register + lda #$7F ; clear all interrupt flags + sta $C40E ; IER register (interrupt enable) + + lda #$C0 + sta $C40D ; IFR: 1100, enable interrupt on timer one oflow + sta $C40E ; IER: 1100, enable timer one interrupt + + lda #$E7 + sta $C404 ; write into low-order latch + lda #$4f + sta $C405 ; write into high-order latch, + ; load both values into counter + ; clear interrupt and start counting + + ; 4fe7 / 1e6 = .020s, 50Hz + + + ;================== + ; init song + ;================== + + jsr pt3_init_song + + ;============================ + ; Enable 6502 interrupts + ;============================ +start_interrupts: + cli ; clear interrupt mask + + + ;============================ + ; Loop forever + ;============================ +main_loop: + + jmp main_loop + + +;==============================-========= +;======================================== + +; Helper routines below + +;======================================== +;======================================== + +;========= +; vars +;========= + +time_frame: .byte $0 +apple_ii: .byte $0 + +;========= +;routines +;========= +.include "mockingboard_a.s" +.include "interrupt_handler.s" +.include "pt3_lib.s" + +;========= +; strings +;========= +;mocking_message: .asciiz "LOOKING FOR MOCKINGBOARD IN SLOT #4" +not_message: .byte "NOT " +found_message: .asciiz "FOUND" +;done_message: .asciiz "DONE PLAYING" + +;============= +; include song +;============= +.align 256 ; must be on page boundary + ; this can be fixed but some changes would have + ; to be made throughout the player code +song: +.incbin "../pt3_player/music/EA.PT3" diff --git a/pt3_lib/zp.inc b/pt3_lib/zp.inc new file mode 100644 index 00000000..4a58cfd6 --- /dev/null +++ b/pt3_lib/zp.inc @@ -0,0 +1,263 @@ +.define EQU = + +LZ4_SRC EQU $00 +LZ4_DST EQU $02 +LZ4_END EQU $04 +COUNT EQU $06 +DELTA EQU $08 + +;; Zero page monitor routines addresses + +WNDLFT EQU $20 +WNDWDTH EQU $21 +WNDTOP EQU $22 +WNDBTM EQU $23 +CH EQU $24 +CV EQU $25 +GBASL EQU $26 +GBASH EQU $27 +BASL EQU $28 +BASH EQU $29 +BAS2L EQU $2A +BAS2H EQU $2B +H2 EQU $2C +V2 EQU $2D +MASK EQU $2E +LASTIN EQU $3F +COLOR EQU $30 +MODE EQU $31 +INVFLG EQU $32 +PROMPT EQU $33 +YSAV EQU $34 +YSAV1 EQU $35 +CSWL EQU $36 ; address of COUT1 routine +CSWH EQU $37 +KSWL EQU $38 ; key in routine +KSWH EQU $39 + +SEEDL EQU $4E +SEEDH EQU $4F + + +; dos33 zero page = 26-2f, 35-38, 3e 3f 40-4d +; overlap applesoft 67-6a,6f,70,af,b0,ca-cd,d8 + + +; DOS33: Confirmed kills $68 + +RWTSL EQU $60 +RWTSH EQU $61 +DOSBUFL EQU $62 +DOSBUFH EQU $63 +FILEML EQU $64 +FILEMH EQU $65 + ;TURNING EQU $60 + ;SCREEN_X EQU $61 ; not used? + ;SCREEN_Y EQU $62 + + + ;ANGLE EQU $63 + ;HORIZ_SCALE_I EQU $64 + ;HORIZ_SCALE_F EQU $65 + ;FACTOR_I EQU $66 + ;FACTOR_F EQU $67 + ;DX_I EQU $68 + ;DX_F EQU $69 + ;SPACEX_I EQU $6A + ;SPACEX_F EQU $6B + ;CX_I EQU $6C + ;CX_F EQU $6D + ;DY_I EQU $6E + ;DY_F EQU $6F + +AY_REGISTERS EQU $70 +A_FINE_TONE EQU $70 +A_COARSE_TONE EQU $71 +B_FINE_TONE EQU $72 +B_COARSE_TONE EQU $73 +C_FINE_TONE EQU $74 +C_COARSE_TONE EQU $75 +NOISE EQU $76 +ENABLE EQU $77 +A_VOLUME EQU $78 +B_VOLUME EQU $79 +C_VOLUME EQU $7A +ENVELOPE_FINE EQU $7B +ENVELOPE_COARSE EQU $7C +ENVELOPE_SHAPE EQU $7D +COPY_OFFSET EQU $7E +DECODER_STATE EQU $7F + +PATTERN_L EQU $80 +PATTERN_H EQU $81 +ORNAMENT_L EQU $82 +ORNAMENT_H EQU $83 +SAMPLE_L EQU $84 +SAMPLE_H EQU $85 + + + + +DECODE_ERROR EQU $90 +A_COLOR EQU $91 +B_COLOR EQU $92 +C_COLOR EQU $93 +COPY_TIME EQU $94 +DECOMPRESS_TIME EQU $95 +TIME_TAKEN EQU $96 +SCREEN_Y EQU $97 +WHICH_FILE EQU $98 +COLOR_MASK EQU $99 +RASTERBARS_ON EQU $9A +RANDOM_POINTER EQU $9B +LOOP EQU $9C +MB_VALUE EQU $9D +;MB_CHUNK EQU $9E +MB_ADDRL EQU $9F +MB_ADDRH EQU $A0 +DONE_PLAYING EQU $A1 +MB_CHUNK_OFFSET EQU $A2 +DONE_SONG EQU $A3 +FIRE_FB_L EQU $A4 +FIRE_FB_H EQU $A5 +FIRE_FB2_L EQU $A6 +FIRE_FB2_H EQU $A7 +FIRE_FB_LINE EQU $A8 +FIRE_Q EQU $A9 +FIRE_Y EQU $AA +FIRE_X EQU $AB + +; More zero-page addresses +; we try not to conflict with anything DOS, MONITOR or BASIC related + + ;COLOR1 EQU $E0 +COLOR2 EQU $E1 + ;MATCH EQU $E2 +XX EQU $E3 + ;YY EQU $E4 + ;SHIPY EQU $E4 + ;YADD EQU $E5 + ;LOOP EQU $E6 + ;MEMPTRL EQU $E7 + ;MEMPTRH EQU $E8 + ;NAMEL EQU $E9 + ;NAMEH EQU $EA + ;NAMEX EQU $EB + ;CHAR EQU $EC +DISP_PAGE EQU $ED +DRAW_PAGE EQU $EE + + ;FIRST EQU $F0 +LASTKEY EQU $F1 + ;PADDLE_STATUS EQU $F2 +XPOS EQU $F3 +YPOS EQU $F4 + + + namlo = $f6 + namhi = $f7 + step = $f8 ; state for stepper motor + tmptrk = $f9 ; temporary copy of current track + phase = $fa ; current phase for /seek + + + +TEMP EQU $FA + ;RUN EQU $FA + ;TEMP2 EQU $FB +TEMPY EQU $FB +INL EQU $FC +INH EQU $FD +OUTL EQU $FE +OUTH EQU $FF + + + +KEYPRESS EQU $C000 +KEYRESET EQU $C010 + +;; SOFT SWITCHES +CLR80COL EQU $C000 ; PAGE0/PAGE1 normal +SET80COL EQU $C001 ; PAGE0/PAGE1 switches PAGE0 in Aux instead +EIGHTYCOL EQU $C00D +SPEAKER EQU $C030 +SET_GR EQU $C050 +SET_TEXT EQU $C051 +FULLGR EQU $C052 +TEXTGR EQU $C053 +PAGE0 EQU $C054 +PAGE1 EQU $C055 +LORES EQU $C056 ; Enable LORES graphics +HIRES EQU $C057 ; Enable HIRES graphics +AN3 EQU $C05E ; Annunciator 3 + +PADDLE_BUTTON0 EQU $C061 +PADDL0 EQU $C064 +PTRIG EQU $C070 + +;; BASIC ROUTINES + +NORMAL EQU $F273 + +;; MONITOR ROUTINES + +HLINE EQU $F819 ;; HLINE Y,$2C at A +VLINE EQU $F828 ;; VLINE A,$2D at Y +CLRSCR EQU $F832 ;; Clear low-res screen +CLRTOP EQU $F836 ;; clear only top of low-res screen +SETCOL EQU $F864 ;; COLOR=A +TEXT EQU $FB36 +TABV EQU $FB5B ;; VTAB to A +BASCALC EQU $FBC1 ;; +VTAB EQU $FC22 ;; VTAB to CV +HOME EQU $FC58 ;; Clear the text screen +WAIT EQU $FCA8 ;; delay 1/2(26+27A+5A^2) us +SETINV EQU $FE80 ;; INVERSE +SETNORM EQU $FE84 ;; NORMAL +COUT EQU $FDED ;; output A to screen +COUT1 EQU $FDF0 ;; output A to screen +CROUT EQU $FD8E ;; send a RETURN +CROUT1 EQU $FD8B ;; send a RETURN and clear end of line +PRBYTE EQU $FDDA +PRHEX EQU $FDE3 + +;; Applesoft routines +HCLR EQU $F3F2 +;HGR_PAGE EQU $E6 + + + +COLOR_BLACK EQU 0 +COLOR_RED EQU 1 +COLOR_DARKBLUE EQU 2 +COLOR_PURPLE EQU 3 +COLOR_DARKGREEN EQU 4 +COLOR_GREY EQU 5 +COLOR_MEDIUMBLUE EQU 6 +COLOR_LIGHTBLUE EQU 7 +COLOR_BROWN EQU 8 +COLOR_ORANGE EQU 9 +COLOR_GREY2 EQU 10 +COLOR_PINK EQU 11 +COLOR_LIGHTGREEN EQU 12 +COLOR_YELLOW EQU 13 +COLOR_AQUA EQU 14 +COLOR_WHITE EQU 15 + +COLOR_BOTH_BLACK EQU $00 +COLOR_BOTH_RED EQU $11 +COLOR_BOTH_DARKBLUE EQU $22 +COLOR_BOTH_DARKGREEN EQU $44 +COLOR_BOTH_GREY EQU $55 +COLOR_BOTH_MEDIUMBLUE EQU $66 +COLOR_BOTH_LIGHTBLUE EQU $77 +COLOR_BOTH_BROWN EQU $88 +COLOR_BOTH_ORANGE EQU $99 +COLOR_BOTH_PINK EQU $BB +COLOR_BOTH_LIGHTGREEN EQU $CC +COLOR_BOTH_YELLOW EQU $DD +COLOR_BOTH_AQUA EQU $EE +COLOR_BOTH_WHITE EQU $FF + +AUX_BOTH_MEDIUMBLUE EQU $33 ; 0011 0011 +AUX_BOTH_GREY EQU $AA ; 1010 1010