diff --git a/src/Tools/fileconv/Cargo.toml b/src/Tools/fileconv/Cargo.toml index 11040700..3d64a806 100644 --- a/src/Tools/fileconv/Cargo.toml +++ b/src/Tools/fileconv/Cargo.toml @@ -9,6 +9,7 @@ panic = "abort" [dependencies] clap = {version = "4.4.11", features = ["derive"]} image = "0.24.7" +hound = "3.5.1" paste = "1.0.14" png = "0.17.10" tool_helper = {path = "../tool_helper"} \ No newline at end of file diff --git a/src/Tools/fileconv/src/audio/my_vag/mod.rs b/src/Tools/fileconv/src/audio/my_vag/mod.rs index 27b5b69f..c735bc14 100644 --- a/src/Tools/fileconv/src/audio/my_vag/mod.rs +++ b/src/Tools/fileconv/src/audio/my_vag/mod.rs @@ -1,6 +1,35 @@ +pub mod types; + use std::io::Write; use tool_helper::{Error, Input}; +use types::MonoADPCMIterator; -pub fn convert(_input: Input, _output: &mut dyn Write) -> Result<(), Error> { +pub fn convert(input: Input, _output: &mut dyn Write) -> Result<(), Error> { + let mut wav_file = hound::WavReader::new(input)?; + let wav_header = wav_file.spec(); + + validate(&wav_header)?; + let mut sample_count = 0; + for _adpcm_samples in MonoADPCMIterator::create(wav_file.samples::()) { + sample_count += 1; + } + + println!("Parsed {} vag samples", sample_count); Err(Error::not_implemented("my vag convert")) +} + +fn validate(wav_header: &hound::WavSpec) -> Result<(), Error> { + if wav_header.sample_format != hound::SampleFormat::Int { + return Err(Error::from_str("VAG: Only integer samples are supported as input.")); + } + + if wav_header.bits_per_sample != 16 { + return Err(Error::from_str("VAG: Only 16bits samples are currently supported as input.")); + } + + if wav_header.channels != 1 { + return Err(Error::from_str("VAG: Only mono samples are currently supported")); + } + + Ok(()) } \ No newline at end of file diff --git a/src/Tools/fileconv/src/audio/my_vag/types.rs b/src/Tools/fileconv/src/audio/my_vag/types.rs new file mode 100644 index 00000000..a61d5660 --- /dev/null +++ b/src/Tools/fileconv/src/audio/my_vag/types.rs @@ -0,0 +1,45 @@ +use tool_helper::Error; + +pub struct VAGADPCM { + data: [u32; 4] +} + +impl VAGADPCM { + const ADPCM_SAMPLES_PER_VAGADPCM:usize = 28; + + pub fn create() -> VAGADPCM { + VAGADPCM{data: [0; 4]} + } +} + +pub struct MonoADPCMIterator>> { + iter: I +} + +impl>> MonoADPCMIterator{ + pub fn create(iter: I) -> MonoADPCMIterator { + MonoADPCMIterator{iter} + } +} + +impl>> std::iter::Iterator for MonoADPCMIterator { + type Item = Result<[i16; VAGADPCM::ADPCM_SAMPLES_PER_VAGADPCM], Error>; + + fn next(&mut self) -> Option { + const STREAM_GONE_ERROR: &'static str = "Reading ADPCM sample failed"; + + if let Some(next_sample) = self.iter.next() { + let Ok(next_sample) = next_sample else {return Some(Err(Error::from_str(STREAM_GONE_ERROR)));}; + + let mut sample = [0;VAGADPCM::ADPCM_SAMPLES_PER_VAGADPCM]; + sample[0] = next_sample; + + for idx in 1..VAGADPCM::ADPCM_SAMPLES_PER_VAGADPCM { + let Ok(next_sample) = self.iter.next().unwrap_or(Ok(0)) else {return Some(Err(Error::from_str(STREAM_GONE_ERROR)));}; + sample[idx] = next_sample; + } + return Some(Ok(sample)); + } + None + } +} \ No newline at end of file