diff --git a/apps/casette/encode.py b/apps/casette/encode.py index 690cd60..d1b518e 100644 --- a/apps/casette/encode.py +++ b/apps/casette/encode.py @@ -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 .wav") + parser.add_argument("output", type=Path, help="output WAV; default .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('