Full file transfer, no mem loading yet

This commit is contained in:
Joppe Blondel
2026-10-04 19:11:14 +02:00
parent a945dd32ab
commit d7150ef2eb
3 changed files with 109 additions and 10 deletions
+31 -8
View File
@@ -1,6 +1,7 @@
#!/usr/bin/env python3
from __future__ import annotations
import os
import argparse
import math
import struct
@@ -8,7 +9,7 @@ import wave
from pathlib import Path
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.c_low = c_low
self.c_high = c_high
@@ -18,12 +19,16 @@ class FSKWriter:
self.samples_per_low = (sample_rate * c_low) // f_low
self.samples_per_high = (sample_rate * c_high) // f_high
self.phase = 0.0
self.block_spacing = block_spacing
self.samples = bytearray()
self.samples.extend(b'\0'*int(1.0*self.sample_rate))
self.space(1.0)
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:
phase_step = 2.0 * math.pi * frequency / self.sample_rate
@@ -64,14 +69,16 @@ class FSKWriter:
self.byte(value)
def block(self, nr: int, data: bytes) -> None:
print(f'> {data}')
self.leader()
self.byte(nr)
l = len(data)
self.byte(l>>8)
self.byte(l&0xff)
self.samples.extend(b'\0'*int(self.samples_per_low*8))
self.bytes(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:
cs = 0
@@ -83,21 +90,37 @@ class FSKWriter:
def main() -> None:
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("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("--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("--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("--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()
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.block(0, args.input.name.encode() + b'\0')
tones = FSKWriter(args.sample_rate, args.low_cycles, args.high_cycles, args.low, args.high, args.amplitude, args.block_spacing)
# 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()
with wave.open(str(output_path), "wb") as wav: