summaryrefslogtreecommitdiff
path: root/src/main.rs
diff options
context:
space:
mode:
authorYuval Adam <_@yuv.al>2025-06-24 13:07:16 +0200
committerYuval Adam <_@yuv.al>2025-06-24 13:07:16 +0200
commitf26568cc73e2104e9c78e29ef385636538010e10 (patch)
treeb08c2649d8a13748533aa771637065e3d2b51ef7 /src/main.rs
parent06a4169d7bd188039f22bdb20172b6c0829aac6c (diff)
Update README and run fmt
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs167
1 files changed, 115 insertions, 52 deletions
diff --git a/src/main.rs b/src/main.rs
index c711d3d..98429ee 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -16,72 +16,97 @@ struct Cli {
/// Path to the input WAV file
#[arg(value_name = "FILE", help = "WAV file containing Morse code audio")]
wav_file: Option<PathBuf>,
-
+
/// Show detailed processing information
#[arg(short, long, help = "Enable verbose output")]
verbose: bool,
-
+
/// Show timing information
#[arg(short, long, help = "Show processing time")]
time: bool,
-
+
/// Generate a test WAV file instead of decoding
- #[arg(long, value_name = "TEXT", help = "Generate test WAV file with given text")]
+ #[arg(
+ long,
+ value_name = "TEXT",
+ help = "Generate test WAV file with given text"
+ )]
generate: Option<String>,
-
+
/// Output file for generation (default: output.wav)
- #[arg(short, long, value_name = "FILE", help = "Output file for generated WAV")]
+ #[arg(
+ short,
+ long,
+ value_name = "FILE",
+ help = "Output file for generated WAV"
+ )]
output: Option<PathBuf>,
-
+
/// Frequency for generated audio (default: 600 Hz)
- #[arg(long, value_name = "HZ", default_value = "600", help = "Frequency in Hz for generated audio")]
+ #[arg(
+ long,
+ value_name = "HZ",
+ default_value = "600",
+ help = "Frequency in Hz for generated audio"
+ )]
frequency: f32,
-
+
/// Words per minute for generated audio (default: 20 WPM)
- #[arg(long, value_name = "WPM", default_value = "20", help = "Words per minute for generated audio")]
+ #[arg(
+ long,
+ value_name = "WPM",
+ default_value = "20",
+ help = "Words per minute for generated audio"
+ )]
wpm: f32,
}
fn main() -> Result<()> {
let cli = Cli::parse();
-
+
// Set up logging - user can control with RUST_LOG environment variable
env_logger::try_init().ok();
-
+
// Handle generation mode
if let Some(text) = &cli.generate {
return generate_wav_file(&cli, text);
}
-
+
// Validate we have an input file for decoding
- let wav_file = cli.wav_file.as_ref()
- .ok_or_else(|| anyhow::anyhow!("No input file specified. Use --help for usage information."))?;
-
+ let wav_file = cli.wav_file.as_ref().ok_or_else(|| {
+ anyhow::anyhow!("No input file specified. Use --help for usage information.")
+ })?;
+
// Validate input file exists
if !wav_file.exists() {
bail!("File not found: {}", wav_file.display());
}
-
+
let start_time = Instant::now();
-
+
if cli.verbose {
println!("Processing: {}", wav_file.display());
}
-
+
// Use the new high-level API
- let decoded_text = ditdah::decode_wav_file(wav_file)
- .map_err(|e| {
- // Provide user-friendly error messages
- match e.to_string().as_str() {
- s if s.contains("No such file") => anyhow::anyhow!("File not found: {}", wav_file.display()),
- s if s.contains("Unsupported sample format") => anyhow::anyhow!("Unsupported audio format. Please use 16-bit or 32-bit WAV files."),
- s if s.contains("Could not find a dominant frequency") => anyhow::anyhow!("No Morse code signal detected. Check that the file contains clear Morse audio."),
- _ => e
+ let decoded_text = ditdah::decode_wav_file(wav_file).map_err(|e| {
+ // Provide user-friendly error messages
+ match e.to_string().as_str() {
+ s if s.contains("No such file") => {
+ anyhow::anyhow!("File not found: {}", wav_file.display())
+ }
+ s if s.contains("Unsupported sample format") => {
+ anyhow::anyhow!("Unsupported audio format. Please use 16-bit or 32-bit WAV files.")
}
- })?;
-
+ s if s.contains("Could not find a dominant frequency") => anyhow::anyhow!(
+ "No Morse code signal detected. Check that the file contains clear Morse audio."
+ ),
+ _ => e,
+ }
+ })?;
+
let duration = start_time.elapsed();
-
+
// Output results
if decoded_text.is_empty() {
println!("No Morse code detected");
@@ -90,11 +115,11 @@ fn main() -> Result<()> {
}
} else {
println!("Decoded: {}", decoded_text);
-
+
if cli.time {
println!("Processing time: {:.2?}", duration);
}
-
+
if cli.verbose {
println!("Length: {} characters", decoded_text.len());
if decoded_text.len() > 50 {
@@ -102,52 +127,90 @@ fn main() -> Result<()> {
}
}
}
-
+
Ok(())
}
fn generate_wav_file(cli: &Cli, text: &str) -> Result<()> {
use generator::MorseGenerator;
-
- let output_path = cli.output.as_ref()
+
+ let output_path = cli
+ .output
+ .as_ref()
.map(|p| p.clone())
.unwrap_or_else(|| PathBuf::from("output.wav"));
-
+
if cli.verbose {
- println!("Generating: '{}' at {} Hz, {} WPM", text, cli.frequency, cli.wpm);
+ println!(
+ "Generating: '{}' at {} Hz, {} WPM",
+ text, cli.frequency, cli.wpm
+ );
println!("Output: {}", output_path.display());
}
-
+
let generator = MorseGenerator::new(12000, cli.frequency, cli.wpm);
generator.generate_wav_file(text, &output_path)?;
-
+
println!("Generated: {}", output_path.display());
-
+
if cli.verbose {
- println!("Settings: {} Hz, {} WPM, 12kHz sample rate", cli.frequency, cli.wpm);
-
+ println!(
+ "Settings: {} Hz, {} WPM, 12kHz sample rate",
+ cli.frequency, cli.wpm
+ );
+
// Show what the Morse pattern looks like
let morse_pattern = text_to_morse_pattern(text);
if !morse_pattern.is_empty() {
println!("Morse: {}", morse_pattern);
}
}
-
+
Ok(())
}
fn text_to_morse_pattern(text: &str) -> String {
let morse_map = [
- ('A', ".-"), ('B', "-..."), ('C', "-.-."), ('D', "-.."), ('E', "."),
- ('F', "..-."), ('G', "--."), ('H', "...."), ('I', ".."), ('J', ".---"),
- ('K', "-.-"), ('L', ".-.."), ('M', "--"), ('N', "-."), ('O', "---"),
- ('P', ".--."), ('Q', "--.-"), ('R', ".-."), ('S', "..."), ('T', "-"),
- ('U', "..-"), ('V', "...-"), ('W', ".--"), ('X', "-..-"), ('Y', "-.--"),
- ('Z', "--.."), ('1', ".----"), ('2', "..---"), ('3', "...--"), ('4', "....-"),
- ('5', "....."), ('6', "-...."), ('7', "--..."), ('8', "---.."), ('9', "----."),
+ ('A', ".-"),
+ ('B', "-..."),
+ ('C', "-.-."),
+ ('D', "-.."),
+ ('E', "."),
+ ('F', "..-."),
+ ('G', "--."),
+ ('H', "...."),
+ ('I', ".."),
+ ('J', ".---"),
+ ('K', "-.-"),
+ ('L', ".-.."),
+ ('M', "--"),
+ ('N', "-."),
+ ('O', "---"),
+ ('P', ".--."),
+ ('Q', "--.-"),
+ ('R', ".-."),
+ ('S', "..."),
+ ('T', "-"),
+ ('U', "..-"),
+ ('V', "...-"),
+ ('W', ".--"),
+ ('X', "-..-"),
+ ('Y', "-.--"),
+ ('Z', "--.."),
+ ('1', ".----"),
+ ('2', "..---"),
+ ('3', "...--"),
+ ('4', "....-"),
+ ('5', "....."),
+ ('6', "-...."),
+ ('7', "--..."),
+ ('8', "---.."),
+ ('9', "----."),
('0', "-----"),
- ].into_iter().collect::<std::collections::HashMap<_, _>>();
-
+ ]
+ .into_iter()
+ .collect::<std::collections::HashMap<_, _>>();
+
text.to_uppercase()
.chars()
.filter_map(|c| {