Full file transfer, no mem loading yet
This commit is contained in:
+31
-8
@@ -1,6 +1,7 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import os
|
||||||
import argparse
|
import argparse
|
||||||
import math
|
import math
|
||||||
import struct
|
import struct
|
||||||
@@ -8,7 +9,7 @@ import wave
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
class FSKWriter:
|
class FSKWriter:
|
||||||
def __init__(self, sample_rate: int, c_low: int, c_high: int, f_low: float, f_high: float, amplitude: float):
|
def __init__(self, sample_rate: int, c_low: int, c_high: int, f_low: float, f_high: float, amplitude: float, block_spacing: float):
|
||||||
self.sample_rate = sample_rate
|
self.sample_rate = sample_rate
|
||||||
self.c_low = c_low
|
self.c_low = c_low
|
||||||
self.c_high = c_high
|
self.c_high = c_high
|
||||||
@@ -18,12 +19,16 @@ class FSKWriter:
|
|||||||
self.samples_per_low = (sample_rate * c_low) // f_low
|
self.samples_per_low = (sample_rate * c_low) // f_low
|
||||||
self.samples_per_high = (sample_rate * c_high) // f_high
|
self.samples_per_high = (sample_rate * c_high) // f_high
|
||||||
self.phase = 0.0
|
self.phase = 0.0
|
||||||
|
self.block_spacing = block_spacing
|
||||||
self.samples = bytearray()
|
self.samples = bytearray()
|
||||||
|
|
||||||
self.samples.extend(b'\0'*int(1.0*self.sample_rate))
|
self.space(1.0)
|
||||||
|
|
||||||
def finalize(self):
|
def finalize(self):
|
||||||
self.samples.extend(b'\0'*int(1.0*self.sample_rate))
|
self.space(1.0)
|
||||||
|
|
||||||
|
def space(self, time:float = 0.03):
|
||||||
|
self.samples.extend(b'\0'*int(time*self.sample_rate))
|
||||||
|
|
||||||
def _tone(self, frequency: float, sample_count: int) -> None:
|
def _tone(self, frequency: float, sample_count: int) -> None:
|
||||||
phase_step = 2.0 * math.pi * frequency / self.sample_rate
|
phase_step = 2.0 * math.pi * frequency / self.sample_rate
|
||||||
@@ -64,14 +69,16 @@ class FSKWriter:
|
|||||||
self.byte(value)
|
self.byte(value)
|
||||||
|
|
||||||
def block(self, nr: int, data: bytes) -> None:
|
def block(self, nr: int, data: bytes) -> None:
|
||||||
|
print(f'> {data}')
|
||||||
self.leader()
|
self.leader()
|
||||||
self.byte(nr)
|
self.byte(nr)
|
||||||
l = len(data)
|
l = len(data)
|
||||||
self.byte(l>>8)
|
self.byte(l>>8)
|
||||||
self.byte(l&0xff)
|
self.byte(l&0xff)
|
||||||
|
self.samples.extend(b'\0'*int(self.samples_per_low*8))
|
||||||
self.bytes(data)
|
self.bytes(data)
|
||||||
self.byte(self.chsum(data))
|
self.byte(self.chsum(data))
|
||||||
self.samples.extend(b'\0'*int(0.3*self.sample_rate))
|
self.space(self.block_spacing)
|
||||||
|
|
||||||
def chsum(self, data: bytes) -> int:
|
def chsum(self, data: bytes) -> int:
|
||||||
cs = 0
|
cs = 0
|
||||||
@@ -83,21 +90,37 @@ class FSKWriter:
|
|||||||
def main() -> None:
|
def main() -> None:
|
||||||
parser = argparse.ArgumentParser(description="Encode a binary file as two tone FSK WAV")
|
parser = argparse.ArgumentParser(description="Encode a binary file as two tone FSK WAV")
|
||||||
parser.add_argument("input", type=Path, help="Binary input file")
|
parser.add_argument("input", type=Path, help="Binary input file")
|
||||||
parser.add_argument("output", type=Path, help="output WAVl default <input>.wav")
|
parser.add_argument("output", type=Path, help="output WAV; default <input>.wav")
|
||||||
parser.add_argument("--sample-rate", type=int, default=48000)
|
parser.add_argument("--sample-rate", type=int, default=48000)
|
||||||
parser.add_argument("--low", type=float, default=2000.0, help="low tone in Hz")
|
parser.add_argument("--low", type=float, default=2000.0, help="low tone in Hz")
|
||||||
parser.add_argument("--high", type=float, default=4000.0, help="high tone in Hz")
|
parser.add_argument("--high", type=float, default=4000.0, help="high tone in Hz")
|
||||||
parser.add_argument("--low-cycles", type=int, default=2, help="low tone cycle count for a 0")
|
parser.add_argument("--low-cycles", type=int, default=2, help="low tone cycle count for a 0")
|
||||||
parser.add_argument("--high-cycles", type=int, default=4, help="high tone cycle count for a 1")
|
parser.add_argument("--high-cycles", type=int, default=4, help="high tone cycle count for a 1")
|
||||||
parser.add_argument("--amplitude", type=float, default=0.75)
|
parser.add_argument("--amplitude", type=float, default=0.75)
|
||||||
parser.add_argument("--block-size", type=int, default=64)
|
parser.add_argument("--block-size", type=int, default=128)
|
||||||
|
parser.add_argument("--block-spacing", type=float, default=1.0)
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
output_path = args.output or args.input.with_name(args.input.stem + ".wav")
|
output_path = args.output or args.input.with_name(args.input.stem + ".wav")
|
||||||
|
|
||||||
tones = FSKWriter(args.sample_rate, args.low_cycles, args.high_cycles, args.low, args.high, args.amplitude)
|
tones = FSKWriter(args.sample_rate, args.low_cycles, args.high_cycles, args.low, args.high, args.amplitude, args.block_spacing)
|
||||||
tones.block(0, args.input.name.encode() + b'\0')
|
|
||||||
|
|
||||||
|
# Create header block
|
||||||
|
nrblocks = math.ceil(os.path.getsize(args.input)/args.block_size)
|
||||||
|
print(f"Number of blocks {nrblocks}*2")
|
||||||
|
|
||||||
|
tones.block(0, struct.pack('<H', nrblocks*2) + args.input.name.encode() + b'\0')
|
||||||
|
tones.space(1.0)
|
||||||
|
|
||||||
|
block = 1
|
||||||
|
with open(args.input, 'rb') as f:
|
||||||
|
while True:
|
||||||
|
data = f.read(args.block_size)
|
||||||
|
if not len(data):
|
||||||
|
break
|
||||||
|
tones.block(block, data)
|
||||||
|
tones.block(block, data)
|
||||||
|
block += 1
|
||||||
|
|
||||||
tones.finalize()
|
tones.finalize()
|
||||||
with wave.open(str(output_path), "wb") as wav:
|
with wave.open(str(output_path), "wb") as wav:
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
TAPE_PORT = 0x18
|
TAPE_PORT = 0x18
|
||||||
MAX_CYCLE_COUNT = 20
|
MAX_CYCLE_COUNT = 20
|
||||||
MAX_BLOCK_SIZE = 0x100
|
MAX_BLOCK_SIZE = 0x200
|
||||||
|
|
||||||
STACK_TOP = 0xBFFF
|
STACK_TOP = 0xBFFF
|
||||||
WORK_BASE = 0xB000
|
WORK_BASE = 0xB000
|
||||||
@@ -19,6 +19,7 @@ SHORT_COUNT = WORK_BASE + 0x06 ; byte
|
|||||||
LONG_COUNT = WORK_BASE + 0x07 ; byte
|
LONG_COUNT = WORK_BASE + 0x07 ; byte
|
||||||
BLOCK_LENGTH = WORK_BASE + 0x08 ; word
|
BLOCK_LENGTH = WORK_BASE + 0x08 ; word
|
||||||
BLOCK_NUMBER = WORK_BASE + 0x0a ; byte
|
BLOCK_NUMBER = WORK_BASE + 0x0a ; byte
|
||||||
|
NR_OF_BLOCKS = WORK_BASE + 0x0b ; word
|
||||||
|
|
||||||
BLOCK_BUFFER = WORK_BASE + 0x100 ; MAX_BLOCK_SIZE
|
BLOCK_BUFFER = WORK_BASE + 0x100 ; MAX_BLOCK_SIZE
|
||||||
|
|
||||||
@@ -54,13 +55,66 @@ save_iff:
|
|||||||
di
|
di
|
||||||
jp exit
|
jp exit
|
||||||
1$:
|
1$:
|
||||||
; Filename stored in buffer
|
; nr of blocks and filename stored in buffer
|
||||||
|
ld hl,(BLOCK_BUFFER)
|
||||||
|
ld (NR_OF_BLOCKS),hl
|
||||||
|
|
||||||
|
; Print info of blocks
|
||||||
ei
|
ei
|
||||||
ld hl,#msg_filename
|
ld hl,#msg_filename
|
||||||
call print_string
|
call print_string
|
||||||
ld hl,#BLOCK_BUFFER
|
ld hl,#BLOCK_BUFFER
|
||||||
|
inc hl
|
||||||
|
inc hl
|
||||||
call print_string
|
call print_string
|
||||||
call print_crlf
|
call print_crlf
|
||||||
|
ld hl,#msg_nr_of_blocks
|
||||||
|
call print_string
|
||||||
|
ld hl,(NR_OF_BLOCKS)
|
||||||
|
call print_hex16
|
||||||
|
call print_crlf
|
||||||
|
|
||||||
|
call BIOS_FLUSH
|
||||||
|
di
|
||||||
|
|
||||||
|
; #################################################3
|
||||||
|
; Read a consecutive list of blocks
|
||||||
|
; #################################################3
|
||||||
|
read_consecutive_blocks:
|
||||||
|
ld bc,(NR_OF_BLOCKS)
|
||||||
|
push bc
|
||||||
|
1$:
|
||||||
|
call read_block
|
||||||
|
jr z,2$
|
||||||
|
ei
|
||||||
|
ld a,#'x'
|
||||||
|
call BIOS_PUTC
|
||||||
|
call BIOS_FLUSH
|
||||||
|
di
|
||||||
|
jr 3$
|
||||||
|
2$:
|
||||||
|
ei
|
||||||
|
ld a,#'*'
|
||||||
|
call BIOS_PUTC
|
||||||
|
call BIOS_FLUSH
|
||||||
|
di
|
||||||
|
|
||||||
|
3$:
|
||||||
|
pop bc
|
||||||
|
dec bc
|
||||||
|
push bc
|
||||||
|
; Check for zero
|
||||||
|
ld a,b
|
||||||
|
or a,c
|
||||||
|
jr nz,1$
|
||||||
|
pop bc
|
||||||
|
|
||||||
|
; All blocks are read
|
||||||
|
ei
|
||||||
|
ld a,#'V'
|
||||||
|
call BIOS_PUTC
|
||||||
|
call print_crlf
|
||||||
|
call BIOS_FLUSH
|
||||||
di
|
di
|
||||||
|
|
||||||
; #################################################3
|
; #################################################3
|
||||||
@@ -359,6 +413,12 @@ read_block:
|
|||||||
ld c,a
|
ld c,a
|
||||||
ld (BLOCK_LENGTH),bc
|
ld (BLOCK_LENGTH),bc
|
||||||
|
|
||||||
|
; Check block length against max length
|
||||||
|
ld hl,#MAX_BLOCK_SIZE
|
||||||
|
and a,a
|
||||||
|
sbc hl, bc
|
||||||
|
jp c,error_block_too_big
|
||||||
|
|
||||||
exx
|
exx
|
||||||
|
|
||||||
ld bc,(BLOCK_LENGTH)
|
ld bc,(BLOCK_LENGTH)
|
||||||
@@ -407,6 +467,14 @@ read_block:
|
|||||||
cp a,e
|
cp a,e
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
error_block_too_big:
|
||||||
|
ei
|
||||||
|
ld hl,#msg_error_block_too_big
|
||||||
|
call print_string
|
||||||
|
call print_crlf
|
||||||
|
di
|
||||||
|
jp exit
|
||||||
|
|
||||||
|
|
||||||
; #################################################3
|
; #################################################3
|
||||||
; IO Helper functions
|
; IO Helper functions
|
||||||
@@ -506,3 +574,11 @@ msg_filename:
|
|||||||
.ascii "Filename: "
|
.ascii "Filename: "
|
||||||
.db 0
|
.db 0
|
||||||
|
|
||||||
|
msg_nr_of_blocks:
|
||||||
|
.ascii "Blocks: "
|
||||||
|
.db 0
|
||||||
|
|
||||||
|
msg_error_block_too_big:
|
||||||
|
.ascii "Block too big"
|
||||||
|
.db 0
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user