use clap::Parser;
use eyre::{bail, Result};
use piper_rs::synth::SonataSpeechSynthesizer;
use rodio::buffer::SamplesBuffer;
use std::path::{Path, PathBuf};
#[derive(Parser, Debug)]
#[command(version, about, long_about = None)]
struct Args {
config: String,
text: String,
#[arg(short, long)]
out_path: Option<String>,
#[arg(short, long)]
model: Option<String>,
}
fn main() -> Result<()> {
let args = Args::parse();
let model = args
.model
.map(|m| PathBuf::from(m))
.unwrap_or_else(|| PathBuf::from(&args.config.replace(".onnx.json", ".onnx")));
if !model.exists() {
bail!("Model not found at {}", model.display())
}
let voice = piper_rs::from_config_path(Path::new(&args.config)).unwrap();
let synth = SonataSpeechSynthesizer::new(voice).unwrap();
if let Some(path) = args.out_path {
synth
.synthesize_to_file(&PathBuf::from(path), args.text, None)?;
} else {
let audio = synth.synthesize_parallel(args.text, None).unwrap();
let mut samples: Vec<f32> = Vec::new();
for result in audio {
samples.append(&mut result.unwrap().into_vec());
}
let (_stream, handle) = rodio::OutputStream::try_default().unwrap();
let sink = rodio::Sink::try_new(&handle).unwrap();
let buf = SamplesBuffer::new(1, 22050, samples);
sink.append(buf);
sink.sleep_until_end();
}
Ok(())
}