From 4e091086d6eb934f66cc8e4610f899e1806c1bac Mon Sep 17 00:00:00 2001 From: Yuval Adam <_@yuv.al> Date: Tue, 24 Jun 2025 09:59:01 +0200 Subject: Initial version --- src/main.rs | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 src/main.rs (limited to 'src/main.rs') diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..d288331 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,72 @@ +use anyhow::{bail, Result}; +use clap::Parser; +use hound::{SampleFormat, WavReader}; +use std::path::PathBuf; + +mod decoder; +use decoder::MorseDecoder; + +const TARGET_SAMPLE_RATE: u32 = 12000; // Same as ggmorse's kBaseSampleRate +const CHUNK_SIZE: usize = 4096; + +#[derive(Parser)] +#[command(author, version, about, long_about = None)] +struct Cli { + /// Path to the input WAV file + #[arg(value_name = "WAV_FILE")] + wav_file: PathBuf, +} + +fn main() -> Result<()> { + // Set up logging. Use `RUST_LOG=info` or `RUST_LOG=debug` to see output. + env_logger::init(); + let cli = Cli::parse(); + + log::info!("Opening WAV file: {:?}", cli.wav_file); + let mut reader = WavReader::open(cli.wav_file)?; + let spec = reader.spec(); + log::info!("WAV spec: {:?}", spec); + + if spec.sample_format != SampleFormat::Int && spec.sample_format != SampleFormat::Float { + bail!( + "Unsupported sample format: {:?}. Only 16-bit Int and 32-bit Float are supported.", + spec.sample_format + ); + } + + // --- Create the Morse Decoder --- + let mut decoder = MorseDecoder::new(spec.sample_rate, TARGET_SAMPLE_RATE)?; + + // --- Read and process the audio in chunks --- + let samples_f32: Vec = if spec.sample_format == SampleFormat::Int { + reader + .samples::() + .map(|s| s.unwrap() as f32 / 32768.0) + .collect() + } else { + reader.samples::().map(|s| s.unwrap()).collect() + }; + + // Convert to mono by averaging channels if necessary + let mono_samples: Vec = if spec.channels > 1 { + samples_f32 + .chunks_exact(spec.channels as usize) + .map(|chunk| chunk.iter().sum::() / spec.channels as f32) + .collect() + } else { + samples_f32 + }; + + // Process the entire audio buffer + for chunk in mono_samples.chunks(CHUNK_SIZE) { + decoder.process(chunk)?; + } + + // Finalize decoding after all audio is processed + let decoded_text = decoder.finalize()?; + + println!("\n--- Decoded Text ---"); + println!("{}", decoded_text); + + Ok(()) +} \ No newline at end of file -- cgit v1.3.1