use std::fs::File;
use std::io::prelude::*;
use std::path;
use crate::hound;
use crate::bitpacker::BitPacker;
use crate::encoder;
use crate::error;
use crate::x3;
use error::X3Error;
pub fn wav_to_x3a<P: AsRef<path::Path>>(wav_filename: P, x3a_filename: P) -> Result<(), X3Error> {
let mut reader = hound::WavReader::open(wav_filename).unwrap();
assert_eq!(reader.spec().bits_per_sample, 16);
assert_eq!(reader.spec().channels, 1);
let params = x3::Parameters::default();
let sample_rate = reader.spec().sample_rate;
let samples = reader.samples::<i16>().map(|x| x.unwrap()).collect::<Vec<i16>>();
let first_channel = x3::Channel::new(0, &samples[0..], sample_rate, params);
let num_samples = first_channel.wav.len();
let mut x3_out = vec![0u8; num_samples * 2];
let bp = &mut BitPacker::new(&mut x3_out);
create_archive_header(&first_channel, bp)?;
encoder::encode(&[&first_channel], bp)?;
let mut file = File::create(x3a_filename)?;
file.write_all(bp.as_bytes())?;
Ok(())
}
fn create_archive_header(ch: &x3::Channel, bp: &mut BitPacker) -> Result<(), X3Error> {
bp.write_bytes(x3::Archive::ID);
bp.bookmark();
bp.inc_counter_n_bytes(x3::FrameHeader::LENGTH)?;
let xml: &str = &[
"<X3ARCH PROG=\"x3new.m\" VERSION=\"2.0\" />",
"<CFG ID=\"0\" FTYPE=\"XML\" />",
"<CFG ID=\"1\" FTYPE=\"WAV\">",
&format!("<FS UNIT=\"Hz\">{}</FS>", ch.sample_rate),
"<SUFFIX>wav</SUFFIX>",
"<CODEC TYPE=\"X3\" VERS=\"2\">",
&format!("<BLKLEN>{}</BLKLEN>", ch.params.block_len),
&format!(
"<CODES N=\"4\">RICE{},RICE{},RICE{},BFP</CODES>",
ch.params.codes[0], ch.params.codes[1], ch.params.codes[2]
),
"<FILTER>DIFF</FILTER>",
"<NBITS>16</NBITS>",
&format!(
"<T N=\"3\">{},{},{}</T>",
ch.params.thresholds[0], ch.params.thresholds[1], ch.params.thresholds[2]
),
"</CODEC>",
"</CFG>",
]
.concat();
bp.write_bytes(xml.as_bytes());
if xml.len() % 2 == 1 {
bp.write_bits(0, 8);
}
encoder::write_frame_header(bp, 0, 0)?;
Ok(())
}