From b74c2cb578cc586ce90efe3c0236a61c2e19a405 Mon Sep 17 00:00:00 2001 From: Jaby Date: Sat, 9 Nov 2024 22:21:32 +0000 Subject: [PATCH] Prepare for XA encoding --- src/Tools/psxfileconv/src/audio/my_xa/mod.rs | 36 ++++++++++++-- .../src/audio/my_xa/raw_audio/mod.rs | 47 ++++++++++++------- .../src/audio/my_xa/xa_audio/mod.rs | 25 ++++++++++ src/Tools/psxfileconv/src/main.rs | 6 +-- 4 files changed, 90 insertions(+), 24 deletions(-) create mode 100644 src/Tools/psxfileconv/src/audio/my_xa/xa_audio/mod.rs diff --git a/src/Tools/psxfileconv/src/audio/my_xa/mod.rs b/src/Tools/psxfileconv/src/audio/my_xa/mod.rs index 82d57f46..84f5ba75 100644 --- a/src/Tools/psxfileconv/src/audio/my_xa/mod.rs +++ b/src/Tools/psxfileconv/src/audio/my_xa/mod.rs @@ -1,9 +1,39 @@ mod raw_audio; +mod xa_audio; +use clap::{Args, ValueEnum}; use std::io::Write; use tool_helper::{Error, Input}; -pub fn convert(input: Input, _output: &mut dyn Write) -> Result<(), Error> { - let _prepared_xa_audio = raw_audio::load_for_xa_audio(input)?; - Err(Error::not_implemented("XA conversion")) +#[derive(Args)] +pub struct Arguments { + #[clap(value_enum, value_parser, default_value_t=Frequency::High)] + frequency: Frequency, + #[clap(value_enum, value_parser, default_value_t=Channels::Stereo)] + channels: Channels, + #[clap(value_enum, value_parser, default_value_t=SampleDepth::Normal)] + sample_depth: SampleDepth, +} + +#[derive(Copy, Clone, ValueEnum)] +pub enum Frequency { + High, + Low, +} + +#[derive(Copy, Clone, ValueEnum)] +pub enum Channels { + Stereo, + Mono, +} + +#[derive(Copy, Clone, ValueEnum)] +pub enum SampleDepth { + Normal, + High +} + +pub fn convert(args: Arguments, input: Input, output: &mut dyn Write) -> Result<(), Error> { + let prepared_xa_audio = raw_audio::load_as_i16_audio(input, xa_audio::audio_conversion_settings(&args))?; + xa_audio::convert(prepared_xa_audio, output, &args) } \ 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 9f164ef3..a83d0343 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,17 +1,28 @@ mod error; - -use symphonia::core::audio::{RawSampleBuffer, SignalSpec}; -use symphonia::core::codecs::{Decoder, DecoderOptions, CODEC_TYPE_NULL}; -use symphonia::core::errors::Error as SymError; -use symphonia::core::formats::{FormatReader, FormatOptions}; -use symphonia::core::io::MediaSourceStream; -use symphonia::core::meta::MetadataOptions; -use symphonia::core::probe::Hint; +use symphonia::core::{ + audio::{Layout, SampleBuffer, SignalSpec}, + codecs::{Decoder, DecoderOptions, CODEC_TYPE_NULL}, + errors::Error as SymError, + formats::{FormatReader, FormatOptions}, + io::MediaSourceStream, + meta::MetadataOptions, + probe::Hint +}; use tool_helper::{Error, Input}; -type XASamples = RawSampleBuffer::; +pub type I16Samples = SampleBuffer::; +pub struct Settings { + frequency: u32, + layout: Layout +} -pub fn load_for_xa_audio(input: Input) -> Result { +impl Settings { + pub fn new(frequency: u32, layout: Layout) -> Settings { + Settings{frequency, layout} + } +} + +pub fn load_as_i16_audio(input: Input, settings: Settings) -> Result { let media_stream = MediaSourceStream::new(Box::new(load_to_ram(input)?), Default::default()); let format = symphonia::default::get_probe().format(&Hint::new(), media_stream, &FormatOptions::default(), &MetadataOptions::default()).map_err(error::probe)?.format; let track = format.tracks().iter().find(|t| t.codec_params.codec != CODEC_TYPE_NULL).ok_or_else(error::find_track)?; @@ -20,11 +31,11 @@ pub fn load_for_xa_audio(input: Input) -> Result { let decoder = symphonia::default::get_codecs().make(&track.codec_params, &DecoderOptions::default()).map_err(error::decoder)?; let track_id = track.id; - decode(format, decoder, track_id) + decode(format, decoder, settings, track_id) } -fn decode(mut format: Box, mut decoder: Box, track_id: u32) -> Result { - let mut xa_audio = None; +fn decode(mut format: Box, mut decoder: Box, settings: Settings, track_id: u32) -> Result { + let mut i16_audio = None; loop { // Get the next packet from the media format. @@ -33,7 +44,7 @@ fn decode(mut format: Box, mut decoder: Box, trac Err(err) => { if let SymError::IoError(io_err) = &err { if io_err.kind() == std::io::ErrorKind::UnexpectedEof { - return xa_audio.ok_or_else(error::no_buffer_created); + return i16_audio.ok_or_else(error::no_buffer_created); } } return Err(error::next_packet(err)); @@ -50,14 +61,14 @@ fn decode(mut format: Box, mut decoder: Box, trac // Decode the packet into audio samples. let packet = decoder.decode(&packet).map_err(error::decode)?; - if xa_audio.is_none() { + if i16_audio.is_none() { let duration = packet.capacity() as u64; - xa_audio = Some(XASamples::new(duration, SignalSpec::new_with_layout(44_100, symphonia::core::audio::Layout::Stereo))); + i16_audio = Some(I16Samples::new(duration, SignalSpec::new_with_layout(settings.frequency, settings.layout))); } - if let Some(xa_audio) = &mut xa_audio { - xa_audio.copy_interleaved_ref(packet); + if let Some(i16_audio) = &mut i16_audio { + i16_audio.copy_interleaved_ref(packet); } } } 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 new file mode 100644 index 00000000..7822fe78 --- /dev/null +++ b/src/Tools/psxfileconv/src/audio/my_xa/xa_audio/mod.rs @@ -0,0 +1,25 @@ +use super::Arguments; +use super::raw_audio::{I16Samples, Settings}; +use std::io::Write; +use symphonia::core::audio::Layout; +use tool_helper::Error; + +const HIGH_FREQUENCY:u32 = 37_800; +const LOW_FREQUENCY:u32 = 18_900; + +pub fn audio_conversion_settings(arguments: &Arguments) -> Settings { + let frequency = match arguments.frequency { + super::Frequency::High => HIGH_FREQUENCY, + super::Frequency::Low => LOW_FREQUENCY, + }; + let layout = match arguments.channels { + super::Channels::Stereo => Layout::Stereo, + super::Channels::Mono => Layout::Mono, + }; + + Settings::new(frequency, layout) +} + +pub fn convert(_input: I16Samples, _output: &mut dyn Write, _arguments: &Arguments) -> Result<(), Error> { + Err(Error::not_implemented("XA conversion")) +} \ No newline at end of file diff --git a/src/Tools/psxfileconv/src/main.rs b/src/Tools/psxfileconv/src/main.rs index 9ac92376..da407a47 100644 --- a/src/Tools/psxfileconv/src/main.rs +++ b/src/Tools/psxfileconv/src/main.rs @@ -25,7 +25,7 @@ enum SubCommands { Nothing, SimpleTIM(reduced_tim::Arguments), VAG(vag::Arguments), - MyXA, + MyXA(my_xa::Arguments), // === External Commands === XA(xa::Arguments), @@ -37,7 +37,7 @@ impl SubCommands { SubCommands::Nothing => false, SubCommands::SimpleTIM(_) => false, SubCommands::VAG(_) => false, - SubCommands::MyXA => false, + SubCommands::MyXA(_) => false, SubCommands::XA(_) => true } @@ -63,7 +63,7 @@ fn run_internal_conversion(cmd: CommandLine) -> Result<(), Error> { SubCommands::Nothing => nothing::copy(&mut input, dst_buffer), SubCommands::SimpleTIM(args) => reduced_tim::convert(args, input, dst_buffer), SubCommands::VAG(args) => audio::vag::convert(args, &cmd.output_file, input, dst_buffer), - SubCommands::MyXA => audio::my_xa::convert(input, dst_buffer), + SubCommands::MyXA(args) => audio::my_xa::convert(args, input, dst_buffer), _ => Err(Error::from_str("External functions can not be called for internal conversion")) } };