From a356f6a3a7685d5df58d6af9e0fc8257e10cff08 Mon Sep 17 00:00:00 2001 From: kris Date: Mon, 4 Jul 2022 11:03:19 +0100 Subject: [PATCH] It works! --- encode_audio.py | 41 +++- generate_player.py | 11 +- player/Makefile | 2 +- player/make/apple2-asm-system.cfg | 1 + player/player.dsk | Bin 143360 -> 143360 bytes player/player.s | 372 +++-------------------------- player/player_stage2_3_generated.s | 10 +- 7 files changed, 71 insertions(+), 366 deletions(-) diff --git a/encode_audio.py b/encode_audio.py index 4a4492e..c826710 100755 --- a/encode_audio.py +++ b/encode_audio.py @@ -118,7 +118,7 @@ def audio_bytestream(data: numpy.ndarray, step: int, lookahead_steps: int, clicks = 0 min_lookahead_steps = lookahead_steps - while i < dlen // 10: + while i < dlen // 1: if i >= next_tick: eta.print_status() next_tick = int(eta.i * dlen / 1000) @@ -164,12 +164,12 @@ def audio_bytestream(data: numpy.ndarray, step: int, lookahead_steps: int, numpy.mean(data[i:i + opcode_length])) # print(frame_offset, i / sample_rate, opcode) - for v in all_positions[0]: - yield (v * sp.scale).astype(numpy.float32) + # for v in all_positions[0]: + # yield # # print(v * sp.scale) # if frame_offset == 2047: # print(opcode) - # yield opcode + yield opcode, (all_positions * sp.scale).astype(numpy.float32) i += opcode_length frame_offset = (frame_offset + 1) % 2048 @@ -244,6 +244,7 @@ def main(): parser.add_argument("--norm_percentile", default=100, help="Normalize to specified percentile value of input " "audio") + parser.add_argument("--wav_output", type=str, help="output audio file") parser.add_argument("--noise_output", type=str, help="output audio file") parser.add_argument("input", type=str, help="input audio file to convert") parser.add_argument("output", type=str, help="output audio file") @@ -262,8 +263,13 @@ def main(): output_buffer = [] input_offset = 0 - output_context = sf.SoundFile( - args.output, "w", output_rate, channels=1, format='WAV') + opcode_context = open(args.output, "wb+") + + if args.wav_output: + wav_context = sf.SoundFile( + args.wav_output, "w", output_rate, channels=1, format='WAV') + else: + wav_context = contextlib.nullcontext if args.noise_output: noise_context = sf.SoundFile( @@ -273,12 +279,19 @@ def main(): # We're not creating a file but still need a context noise_context = contextlib.nullcontext - with output_context as output_f, noise_context as noise_f: - for idx, sample in enumerate(audio_bytestream( + with wav_context as wav_f, noise_context as noise_f, opcode_context\ + as opcode_f: + for idx, sample_data in enumerate(audio_bytestream( input_audio, args.step_size, args.lookahead_cycles, sample_rate)): - output_buffer.append(sample) - input_offset += 1 + opcode, samples = sample_data + # print(hex(idx), opcode, hex(opcode.byte)) + opcode_f.write(bytes([opcode.byte])) + + output_buffer.extend(samples) + input_offset += len(samples) + + # TODO: don't bother computing if we're not writing wavs # Keep accumulating as long as we have <10MB in the buffer, or are # within 10MB from the end. This ensures we have enough samples to @@ -291,7 +304,8 @@ def main(): output_buffer, input_audio[input_offset - len(output_buffer):], sample_rate, output_rate, bool(args.noise_output) ) - output_f.write(resampled_output_buffer) + if args.wav_output: + wav_f.write(resampled_output_buffer) if args.noise_output: noise_f.write(resampled_noise_buffer) @@ -302,11 +316,12 @@ def main(): output_buffer, input_audio[input_offset - len(output_buffer):], sample_rate, output_rate, bool(args.noise_output) ) - output_f.write(resampled_output_buffer) + if args.wav_output: + wav_f.write(resampled_output_buffer) if args.noise_output: noise_f.write(resampled_noise_buffer) - # with open(args.output, "wb+") as f: + # with as f: # for opcode in audio_bytestream( # preprocess(args.input, sample_rate, args.normalization, # args.norm_percentile), args.step_size, diff --git a/generate_player.py b/generate_player.py index ad0b33a..561d168 100644 --- a/generate_player.py +++ b/generate_player.py @@ -83,12 +83,12 @@ def eof_trampoline_stage2(cycles) -> List[opcodes_6502.Opcode]: ops = [ opcodes_6502.Opcode(4, 3, "LDA WDATA"), opcodes_6502.Opcode(4, 3, "STA @0+1"), - opcodes_6502.Literal("@0:", indent=0), opcodes_6502.Opcode( 6, 3, "JMP (eof_trampoline_%d_stage3_page)" % cycles) ] if cycles < 7 or cycles == 8: - return label + ops + return label + ops[:-1] + [opcodes_6502.Literal("@0:", indent=0)] + [ + ops[-1]] # For cycles == 7 or > 8 we need to interleave a STA $C030 into stage 2 # because we couldn't fit it in stage 1 @@ -97,7 +97,12 @@ def eof_trampoline_stage2(cycles) -> List[opcodes_6502.Opcode]: opcodes_6502.STA_C030, opcodes_6502.padding(100) ] - return label + list(opcodes_6502.interleave_opcodes(interleave_ops, ops)) + res = label + list(opcodes_6502.interleave_opcodes(interleave_ops, ops)) + # We can't insert the label before interleaving because we might have + # NOP/STA inserted after it + # TODO: this is a bit of a hack - add support for binding the literal to + # the following opcode so it can't be split + return res[:-1] + [opcodes_6502.Literal("@0:", indent=0)] + [res[-1]] EOF_TRAMPOLINE_STAGE2 = { diff --git a/player/Makefile b/player/Makefile index 2ea43d4..dcb89a5 100644 --- a/player/Makefile +++ b/player/Makefile @@ -8,7 +8,7 @@ objects = $(patsubst %.s,%.o,$(src_files)) all: $(DISKIMAGE) %.o : %.s - ca65 -t apple2 --cpu 6502 -o $@ $< + ca65 -t apple2 --cpu 6502 -o $@ -l player.lst $< %.system : %.o cl65 -t apple2 -C make/apple2-asm-system.cfg -u __EXEHDR__ --start-addr 0x2000 -o $@ $< diff --git a/player/make/apple2-asm-system.cfg b/player/make/apple2-asm-system.cfg index 40156a9..abe1ffa 100644 --- a/player/make/apple2-asm-system.cfg +++ b/player/make/apple2-asm-system.cfg @@ -18,5 +18,6 @@ SEGMENTS { CODE: load = MAIN, type = rw; RODATA: load = MAIN, type = ro, optional = yes; DATA: load = MAIN, type = rw, optional = yes; + DATA256: load = MAIN, type = rw, optional = yes, align = $100; BSS: load = BSS, type = bss, optional = yes, define = yes; } diff --git a/player/player.dsk b/player/player.dsk index ac69447ef6fda68d8a926597a4cf8cf369f6bf8f..a0844ef48822206e74f8bc6c016db2fa709704a7 100644 GIT binary patch delta 19540 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 I*3gds13J|7N&o-= delta 18528 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 diff --git a/player/player.s b/player/player.s index b121eb9..78b81a1 100644 --- a/player/player.s +++ b/player/player.s @@ -36,8 +36,6 @@ ; speaker is in a known trajectory. We can compensate for this in the audio encoder. .proc main -.org $2000 - init: JMP bootstrap @@ -53,10 +51,10 @@ MAC: .byte $00,$08,$DC,$01,$02,$03 ; W5100 MAC ADDRESS ; TODO: make slot I/O addresses customizable at runtime - would probably require somehow ; compiling a list of all of the binary offsets at which we reference $C09x and patching ; them in memory or on-disk. -WMODE = $C094 -WADRH = $C095 -WADRL = $C096 -WDATA = $C097 +WMODE = $C0b4 +WADRH = $C0b5 +WADRL = $C0b6 +WDATA = $C0b7 ; W5100 LOCATIONS MACADDR = $0009 ; MAC ADDRESS @@ -271,12 +269,23 @@ setup: lda #$00 sta RXRD - ; to restore after checkrecv - LDY #>RXBASE LDX #>S0RXRSR STX WADRH LDX #RXBASE + STX WADRH + LDX #$00 + STX WADRL + JMP (WDATA) ; Start playing! real_exit: INC RESET_VECTOR+2 ; Invalidate power-up byte @@ -291,10 +300,13 @@ exit_parmtable: .BYTE 0 ; Byte reserved for future use .WORD 0000 ; Pointer reserved for future use -; The actual player code, which will be copied to $3xx for execution -; -; opcode cycle counts are for 65c02, for 6502 they are 1 less because JMP (indirect) is 5 cycles instead of 6. +RXRD: + .byte 00 +; Stage 2 and 3 player code +.include "player_stage2_3_generated.s" + +; Stage 1 player code, which will be copied to $3xx for execution begin_copy_page1: ; generated audio playback code .include "player_generated.s" @@ -302,339 +314,11 @@ begin_copy_page1: ; Quit to ProDOS exit: JMP real_exit - -; Manage W5100 socket buffer and ACK TCP stream. -; -; In order to simplify the buffer management we expect this ACK opcode to consume the last 4 bytes in a 2K "TCP frame". -; i.e. we can assume that we need to consume exactly 2K from the W5100 socket buffer. -; -; While during this we need to keep ticking the speaker at a regular cadence to maintain the same net position of the -; speaker cone. We choose to tick every 14 cycles, which requires adding in minimal NOP padding. -; -; We end up ticking 8 times with 10 cycles left over, assuming we don't stall waiting for the socket buffer to refill. -; -; From the point of view of speaker voltages this slowpath is equivalent to the following opcode sequence: -; TICK_6 (TICK_14 * 7) with 4 cycles left over, adding 4 to the effective n of the next TICK_n we jump to (as chosen by -; the encoder). XXX timing -; -; If we do stall waiting for data then there is no need to worry about maintaining an even cadence, because audio -; will already be disrupted (since the encoder won't have predicted it, so will be tracking wrong). The speaker will -; resynchronize within a few hundred microseconds though. -end_of_frame_10_10: - STA TICK ; 4 - JMP _end_of_frame_10_10 ; 3 rest of end_of_frame doesn't fit in page 3 - -end_of_frame_20_4: - STA TICK ; 4 - JMP _end_of_frame_10_10 ; 3 rest of end_of_frame doesn't fit in page 3 - end_copy_page1: -; -;_end_of_frame: -; STA zpdummy ; 3 -; ; Save the W5100 address pointer so we can come back here later -; ; We know the low-order byte is 0 because Socket RX memory is page-aligned and so is 2K frame. -; ; IMPORTANT - from now on until we restore this below, we can't trash the Y register! -; STA TICK ; 4 [10] -; LDY WADRH ; 4 -; -; ; Read Received Read pointer -; LDA #>S0RXRD ; 2 -; STA TICK ; 4 [10] -; STA WADRH ; 4 -; -; LDX # 133 with tick padding -; + 7 from dispatcher = 140 total -_end_of_frame_10_10: - ; Save the W5100 address pointer so we can come back here later - ; We know the low-order byte is 0 because Socket RX memory is page-aligned and so is 2K frame. - ; IMPORTANT - from now on until we restore this below, we can't trash the Y register! - STA zpdummy ; 3 - STA TICK ; 4 - LDY WADRH ; 4 - - ; Update new Received Read pointer - ; We know we have received an additional 2KB, so we don't need to read the current value from the hardware. We can - ; track it ourselves instead. - LDA #>S0RXRD ; 2 - STA TICK ; [10] - STA WADRH ; 4 - LDX #S0RXRD ; 2 - STA WADRH ; 4 - LDA #S0RXRD ; 2 - STA WADRH ; 4 - STA TICK ; 4 [20] - STA TICK ; 4 [4] - LDA #S0RXRD ; 2 - STA WADRH ; 4 - LDA #