Resampling and interleaving supported

This commit is contained in:
Jaby 2024-12-01 11:02:51 +00:00
parent c83e27a1c9
commit f905bf6013
4 changed files with 54 additions and 41 deletions

View File

@ -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,
}
}

View File

@ -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::<i16>,
orality: Orality,
frequency: u32,
}
impl PreparedAudioSamples {
pub fn new(samples: Vec<i16>, channels: usize, frequency: u32) -> Result<PreparedAudioSamples, Error> {
impl CDAudioSamples {
pub fn new(samples: Vec<i16>, channels: usize, frequency: u32) -> Result<CDAudioSamples, Error> {
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::<i16> {
@ -61,9 +51,8 @@ struct InternalAudioSamples {
impl InternalAudioSamples {
pub fn new(planar_samples: Vec<Vec<f32>>, frequency: u32) -> Result<InternalAudioSamples, Error> {
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<f32> {
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<PreparedAudioSamples, Error> {
pub fn load_as_i16_audio(input: Input, target_frequency: u32) -> Result<CDAudioSamples, Error> {
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<Intern
InternalAudioSamples::new(planar_output, target_frequency)
}
fn down_sample_interleave(input: InternalAudioSamples) -> Result<PreparedAudioSamples, Error> {
Err(Error::not_implemented("down_sample_interleave"))
fn down_sample_interleave(input: InternalAudioSamples) -> Result<CDAudioSamples, Error> {
let channels = input.channels();
let frequency = input.frequency;
let audio_buffer = input.into_audio_buffer();
let mut sample_buffer = SampleBuffer::<i16>::new(audio_buffer.capacity() as u64, audio_buffer.spec().clone());
sample_buffer.copy_interleaved_typed::<f32>(&audio_buffer);
CDAudioSamples::new(sample_buffer.samples().to_vec(), channels, frequency)
}
fn load_to_ram(mut input: Input) -> Result<std::io::Cursor<Vec<u8>>, Error> {

View File

@ -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(())
}

View File

@ -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];