#![deny(clippy::all)]
#![deny(clippy::pedantic)]
#![allow(clippy::cast_possible_truncation)]
use std::fs::File;
use std::io::{self, BufWriter, Read};
use std::process;
use arrayvec::ArrayVec;
use byteorder::{ByteOrder, NativeEndian};
use colored::Colorize;
use riff_wave::{WaveWriter, WriteError};
use thiserror::Error;
use sonant::{errors::iter_sources, Error as SonantError, Song, Synth};
#[derive(Debug, Error)]
pub enum Error {
#[error("Missing snt-file argument\nUsage: player <snt-file> <wav-file>")]
MissingSntFilename,
#[error("Missing wav-file argument\nUsage: player <snt-file> <wav-file>")]
MissingWavFilename,
#[error("Sonant error")]
Sonant(#[from] SonantError),
#[error("I/O error")]
IO(#[from] io::Error),
#[error("Wave writer error")]
Writer(#[from] WriteError),
}
fn main() {
handle_errors(writer());
}
fn writer() -> Result<(), Error> {
let mut args = std::env::args().skip(1);
let snt_filename = args.next().ok_or(Error::MissingSntFilename)?;
let wav_filename = args.next().ok_or(Error::MissingWavFilename)?;
let mut file = File::open(snt_filename)?;
let mut data = Vec::new();
file.read_to_end(&mut data)?;
let mut seed = [0_u8; 16];
getrandom::getrandom(&mut seed).expect("failed to getrandom");
let seed = (
NativeEndian::read_u64(&seed[0..8]),
NativeEndian::read_u64(&seed[8..16]),
);
let song = Song::from_slice(&data)?;
let synth = Synth::new(&song, seed, 44100.0 as f32)
.flat_map(ArrayVec::from)
.peekable();
let file = File::create(wav_filename)?;
let writer = BufWriter::new(file);
let mut wave_writer = WaveWriter::new(2, 44100, 16, writer)?;
for sample in synth {
let sample = (sample * f32::from(i16::max_value())).round() as i16;
wave_writer.write_sample_i16(sample)?;
}
Ok(())
}
pub fn handle_errors<E>(result: Result<(), E>)
where
E: std::error::Error + 'static,
{
match result {
Err(e) => {
eprintln!("{} {}", "error:".red(), e);
for cause in iter_sources(&e) {
eprintln!("{} {}", "caused by:".bright_red(), cause);
}
process::exit(1);
}
Ok(()) => (),
};
}