warbler 0.0.1

procedural bird chirp synthesizer using sdl3
Documentation
use warbler::{ChirpParams, Synthesizer};

fn print_usage() {
    eprintln!("usage: warbler [preset]");
    eprintln!();
    eprintln!("presets:");
    eprintln!("  sparrow    - sharp, quick chirp (2.5-5kHz, 150ms)");
    eprintln!("  robin      - melodic warble with vibrato (2-3.5kHz, 300ms)");
    eprintln!("  warbler    - complex trill (3-6kHz, 180ms)");
    eprintln!("  finch      - high-pitched tweet (3.5-7kHz, 120ms)");
    eprintln!("  default    - basic chirp");
    eprintln!();
    eprintln!("or use flags for custom chirp:");
    eprintln!("  --start-freq <hz>      starting frequency");
    eprintln!("  --end-freq <hz>        ending frequency");
    eprintln!("  --duration <ms>        duration in milliseconds");
    eprintln!("  --volume <0.0-1.0>     volume");
}

fn parse_custom_params(args: &[String]) -> Result<ChirpParams, String> {
    let mut params = ChirpParams::new();
    let mut i = 1;

    while i < args.len() {
        match args[i].as_str() {
            "--start-freq" => {
                i += 1;
                if i >= args.len() {
                    return Err("--start-freq requires value".to_string());
                }
                params.start_freq_hz = args[i]
                    .parse()
                    .map_err(|_| "invalid start-freq".to_string())?;
            }
            "--end-freq" => {
                i += 1;
                if i >= args.len() {
                    return Err("--end-freq requires value".to_string());
                }
                params.end_freq_hz = args[i]
                    .parse()
                    .map_err(|_| "invalid end-freq".to_string())?;
            }
            "--duration" => {
                i += 1;
                if i >= args.len() {
                    return Err("--duration requires value".to_string());
                }
                params.duration_ms = args[i]
                    .parse()
                    .map_err(|_| "invalid duration".to_string())?;
            }
            "--volume" => {
                i += 1;
                if i >= args.len() {
                    return Err("--volume requires value".to_string());
                }
                let vol: f32 = args[i]
                    .parse()
                    .map_err(|_| "invalid volume".to_string())?;
                params.volume = vol.clamp(0.0, 1.0);
            }
            arg => return Err(format!("unknown flag: {}", arg)),
        }
        i += 1;
    }

    Ok(params)
}

fn main() {
    let args: Vec<String> = std::env::args().collect();

    if args.len() < 2 {
        eprintln!("playing default chirp...");
        let synth = Synthesizer::new().unwrap_or_else(|e| {
            eprintln!("failed to initialize audio: {}", e);
            std::process::exit(1);
        });

        if let Err(e) = synth.play_chirp(ChirpParams::new()) {
            eprintln!("error playing chirp: {}", e);
            std::process::exit(1);
        }
        return;
    }

    let preset = &args[1];

    if preset == "--help" || preset == "-h" {
        print_usage();
        return;
    }

    let params = if preset.starts_with("--") {
        match parse_custom_params(&args) {
            Ok(p) => {
                eprintln!(
                    "playing custom chirp: {:.0}Hz -> {:.0}Hz over {}ms",
                    p.start_freq_hz, p.end_freq_hz, p.duration_ms
                );
                p
            }
            Err(e) => {
                eprintln!("error: {}", e);
                print_usage();
                std::process::exit(1);
            }
        }
    } else {
        let p = match preset.as_str() {
            "sparrow" => {
                eprintln!("chirping like a sparrow...");
                warbler::sparrow()
            }
            "robin" => {
                eprintln!("warbling like a robin...");
                warbler::robin()
            }
            "warbler" => {
                eprintln!("trilling like a warbler...");
                warbler::warbler()
            }
            "finch" => {
                eprintln!("tweeting like a finch...");
                warbler::finch()
            }
            "default" => {
                eprintln!("playing default chirp...");
                ChirpParams::new()
            }
            _ => {
                eprintln!("unknown preset: {}", preset);
                print_usage();
                std::process::exit(1);
            }
        };
        p
    };

    let synth = Synthesizer::new().unwrap_or_else(|e| {
        eprintln!("failed to initialize audio: {}", e);
        std::process::exit(1);
    });

    if let Err(e) = synth.play_chirp(params) {
        eprintln!("error playing chirp: {}", e);
        std::process::exit(1);
    }
}