diff --git a/src/Tools/psxfileconv/src/audio/my_xa/mod.rs b/src/Tools/psxfileconv/src/audio/my_xa/mod.rs index 40fecb92..69abae74 100644 --- a/src/Tools/psxfileconv/src/audio/my_xa/mod.rs +++ b/src/Tools/psxfileconv/src/audio/my_xa/mod.rs @@ -4,6 +4,7 @@ mod xa_audio; use clap::{Args, ValueEnum}; use std::io::Write; use tool_helper::{Error, Input}; +use xa_audio::{LOW_FREQUENCY, HIGH_FREQUENCY}; #[derive(Args, Clone)] pub struct Arguments { @@ -26,7 +27,14 @@ pub enum SampleDepth { } pub fn convert(args: Arguments, input: Input, output: &mut dyn Write) -> Result<(), Error> { - let prepared_xa_audio = raw_audio::load_as_i16_audio(input, args.frequency)?; + let prepared_xa_audio = raw_audio::load_as_i16_audio(input, frequency_to_value(args.frequency))?; xa_audio::encode(prepared_xa_audio, output, &args) +} + +fn frequency_to_value(requested_freq: Frequency) -> u32 { + match requested_freq { + Frequency::High => HIGH_FREQUENCY, + Frequency::Low => LOW_FREQUENCY, + } } \ No newline at end of file diff --git a/src/Tools/psxfileconv/src/audio/my_xa/raw_audio/mod.rs b/src/Tools/psxfileconv/src/audio/my_xa/raw_audio/mod.rs index a3def9f1..9aed537a 100644 --- a/src/Tools/psxfileconv/src/audio/my_xa/raw_audio/mod.rs +++ b/src/Tools/psxfileconv/src/audio/my_xa/raw_audio/mod.rs @@ -1,15 +1,14 @@ mod error; -use super::Frequency as RequestedFrequencyType; use rubato::{FftFixedInOut, Resampler}; use symphonia::core::{ - audio::{Layout, SampleBuffer}, + audio::{AudioBuffer, Layout, SampleBuffer, Signal, SignalSpec}, codecs::{Decoder, DecoderOptions, CODEC_TYPE_NULL}, errors::Error as SymError, formats::{FormatOptions, FormatReader}, io::MediaSourceStream, meta::MetadataOptions, - probe::Hint, sample + probe::Hint }; use tool_helper::{Error, Input}; @@ -19,30 +18,21 @@ pub enum Orality { Mono, } -impl Orality { - fn as_channels(&self) -> usize { - match self { - Orality::Mono => 1, - Orality::Stereo => 2, - } - } -} - -pub struct PreparedAudioSamples { +pub struct CDAudioSamples { samples: Vec::, orality: Orality, frequency: u32, } -impl PreparedAudioSamples { - pub fn new(samples: Vec, channels: usize, frequency: u32) -> Result { +impl CDAudioSamples { + pub fn new(samples: Vec, channels: usize, frequency: u32) -> Result { let orality = match channels { 0 => return Err(Error::from_str("Input file has no audio channels")), 1 => Orality::Mono, 2 => Orality::Stereo, _ => return Err(Error::from_str("Only Mono and Stereo input are supported")), }; - Ok(PreparedAudioSamples{samples, orality, frequency}) + Ok(CDAudioSamples{samples, orality, frequency}) } pub fn samples(&self) -> &Vec:: { @@ -61,9 +51,8 @@ struct InternalAudioSamples { impl InternalAudioSamples { pub fn new(planar_samples: Vec>, frequency: u32) -> Result { - if planar_samples.len() < 1 { - // TODO: Make better text - Err(Error::from_str("Audio samples can not be empty")) + if planar_samples.len() < 1 || planar_samples.len() > 2{ + Err(Error::from_str("Audio samples need to be either mono or stereo")) } else { @@ -71,6 +60,20 @@ impl InternalAudioSamples { } } + pub fn into_audio_buffer(self) -> AudioBuffer { + let duration = self.sample_len() as u64; + let mut new_audio_buffer = AudioBuffer::new(duration, SignalSpec::new_with_layout(self.frequency, if self.planar_samples.len() == 1 {Layout::Mono} else {Layout::Stereo})); + + new_audio_buffer.render_silence(None); + for (channel_idx, channel) in self.planar_samples.into_iter().enumerate() { + let dst_channel = new_audio_buffer.chan_mut(channel_idx); + for (sample_idx, sample) in channel.into_iter().enumerate() { + dst_channel[sample_idx] = sample; + } + } + new_audio_buffer + } + pub fn sample_len(&self) -> usize { self.planar_samples[0].len() } @@ -89,18 +92,20 @@ impl InternalAudioSamples { } } -pub fn load_as_i16_audio(input: Input, freq_type: RequestedFrequencyType) -> Result { +pub fn load_as_i16_audio(input: Input, target_frequency: u32) -> Result { let raw_audio = load_raw_audio(input)?; - let raw_audio = resample(raw_audio, 37_800)?; + let raw_audio = resample(raw_audio, target_frequency)?; - test_write_wav(down_sample_interleave(raw_audio)?)?; - Err(Error::not_implemented("Resampling not implemented")) + down_sample_interleave(raw_audio) } -fn test_write_wav(audio_samples: PreparedAudioSamples) -> Result<(), Error> { +fn _test_write_wav(audio_samples: CDAudioSamples) -> Result<(), Error> { let spec = hound::WavSpec { - channels: 2, - sample_rate: 37_800, + channels: match audio_samples.orality { + Orality::Mono => 1, + Orality::Stereo => 2, + }, + sample_rate: audio_samples.frequency, bits_per_sample: 16, sample_format: hound::SampleFormat::Int, }; @@ -251,8 +256,14 @@ fn resample(input: InternalAudioSamples, target_frequency: u32) -> Result Result { - Err(Error::not_implemented("down_sample_interleave")) +fn down_sample_interleave(input: InternalAudioSamples) -> Result { + let channels = input.channels(); + let frequency = input.frequency; + let audio_buffer = input.into_audio_buffer(); + let mut sample_buffer = SampleBuffer::::new(audio_buffer.capacity() as u64, audio_buffer.spec().clone()); + + sample_buffer.copy_interleaved_typed::(&audio_buffer); + CDAudioSamples::new(sample_buffer.samples().to_vec(), channels, frequency) } fn load_to_ram(mut input: Input) -> Result>, Error> { diff --git a/src/Tools/psxfileconv/src/audio/my_xa/xa_audio/mod.rs b/src/Tools/psxfileconv/src/audio/my_xa/xa_audio/mod.rs index d6d54a6f..f940bd9f 100644 --- a/src/Tools/psxfileconv/src/audio/my_xa/xa_audio/mod.rs +++ b/src/Tools/psxfileconv/src/audio/my_xa/xa_audio/mod.rs @@ -1,24 +1,18 @@ mod xapcm; use super::Arguments; -use super::raw_audio::PreparedAudioSamples; +use super::raw_audio::CDAudioSamples; use std::io::Write; use tool_helper::Error; -const HIGH_FREQUENCY:u32 = 37_800; -const LOW_FREQUENCY:u32 = 18_900; +pub const HIGH_FREQUENCY:u32 = 37_800; +pub const LOW_FREQUENCY:u32 = 18_900; -pub fn encode(input: PreparedAudioSamples, output: &mut dyn Write, arguments: &Arguments) -> Result<(), Error> { - let mut encoder = xapcm::Encoder::new(&input.samples(), arguments.clone(), input.orality()); - let mut sector_count = 0; +pub fn encode(input: CDAudioSamples, output: &mut dyn Write, arguments: &Arguments) -> Result<(), Error> { + let mut encoder = xapcm::Encoder::new(&input.samples(), arguments.clone(), input.orality()); while let Some(xa_sector) = encoder.encode_next_xa_sector()? { output.write(&xa_sector)?; - - sector_count += 1; - print!("\rSector: {} written", sector_count); } - println!(); - //Err(Error::not_implemented("XA conversion")) Ok(()) } \ No newline at end of file diff --git a/src/Tools/psxfileconv/src/audio/my_xa/xa_audio/xapcm.rs b/src/Tools/psxfileconv/src/audio/my_xa/xa_audio/xapcm.rs index fe4e0e34..0943d56a 100644 --- a/src/Tools/psxfileconv/src/audio/my_xa/xa_audio/xapcm.rs +++ b/src/Tools/psxfileconv/src/audio/my_xa/xa_audio/xapcm.rs @@ -13,7 +13,7 @@ pub struct Encoder<'a> { impl<'a> Encoder<'a> { const BLOCKS_PER_SECTOR:usize = 18; - const XA_ADPCM_FILTER_COUNT: i32 = 4; + const XA_ADPCM_FILTER_COUNT: i32 = 3; const FILTER_K1: [i16; 5] = [0, 60, 115, 98, 122]; const FILTER_K2: [i16; 5] = [0, 0, -52, -55, -60];