Something playing!
This commit is contained in:
parent
c4a7fbe441
commit
c5537b6a60
|
@ -5,7 +5,7 @@ use clap::{Args, ValueEnum};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use tool_helper::{Error, Input};
|
use tool_helper::{Error, Input};
|
||||||
|
|
||||||
#[derive(Args)]
|
#[derive(Args, Clone)]
|
||||||
pub struct Arguments {
|
pub struct Arguments {
|
||||||
#[clap(value_enum, value_parser, default_value_t=Frequency::High)]
|
#[clap(value_enum, value_parser, default_value_t=Frequency::High)]
|
||||||
frequency: Frequency,
|
frequency: Frequency,
|
||||||
|
|
|
@ -1,14 +1,11 @@
|
||||||
mod xapcm;
|
mod xapcm;
|
||||||
|
|
||||||
use crate::audio::my_xa::Orality;
|
|
||||||
|
|
||||||
use super::Arguments;
|
use super::Arguments;
|
||||||
use super::raw_audio::{I16Samples, Settings};
|
use super::raw_audio::{I16Samples, Settings};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use symphonia::core::audio::Layout;
|
use symphonia::core::audio::Layout;
|
||||||
use tool_helper::Error;
|
use tool_helper::Error;
|
||||||
|
|
||||||
const BLOCKS_PER_SECTOR:usize = 18;
|
|
||||||
const HIGH_FREQUENCY:u32 = 37_800;
|
const HIGH_FREQUENCY:u32 = 37_800;
|
||||||
const LOW_FREQUENCY:u32 = 18_900;
|
const LOW_FREQUENCY:u32 = 18_900;
|
||||||
|
|
||||||
|
@ -26,31 +23,16 @@ pub fn audio_conversion_settings(arguments: &Arguments) -> Settings {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn encode(input: I16Samples, output: &mut dyn Write, arguments: &Arguments) -> Result<(), Error> {
|
pub fn encode(input: I16Samples, output: &mut dyn Write, arguments: &Arguments) -> Result<(), Error> {
|
||||||
let mut encoder = xapcm::Encoder::default();
|
let mut encoder = xapcm::Encoder::new(&input, arguments.clone());
|
||||||
let (samples_per_block, sample_count) = init_values(&input, arguments);
|
let mut sector_count = 0;
|
||||||
|
|
||||||
for (sector, iteration) in (0..sample_count).step_by(samples_per_block).enumerate() {
|
while let Some(xa_sector) = encoder.encode_next_xa_sector()? {
|
||||||
let mut block = [0u8; 0x914];
|
output.write(&xa_sector)?;
|
||||||
let slice = &input[sector..(sector + samples_per_block)];
|
|
||||||
|
|
||||||
encoder.encode_xa(slice, (sample_count - sector) as i32, &mut block, arguments)?;
|
sector_count += 1;
|
||||||
|
print!("\rSector: {} written", sector_count);
|
||||||
print!("\rSector: {}; Sample_id: {}", sector, iteration);
|
|
||||||
}
|
}
|
||||||
println!();
|
println!();
|
||||||
Err(Error::not_implemented("XA conversion"))
|
//Err(Error::not_implemented("XA conversion"))
|
||||||
}
|
Ok(())
|
||||||
|
|
||||||
fn init_values(input: &I16Samples, arguments: &Arguments) -> (usize, usize) {
|
|
||||||
let samples_per_block = match arguments.sample_depth {
|
|
||||||
super::SampleDepth::Normal => 224,
|
|
||||||
super::SampleDepth::High => 112,
|
|
||||||
};
|
|
||||||
|
|
||||||
let sample_count = match arguments.orality {
|
|
||||||
super::Orality::Stereo => input.len()/2,
|
|
||||||
super::Orality::Mono => input.len(),
|
|
||||||
};
|
|
||||||
|
|
||||||
(samples_per_block as usize, sample_count)
|
|
||||||
}
|
}
|
|
@ -1,24 +1,59 @@
|
||||||
use crate::audio::my_xa::{Arguments, Orality, SampleDepth};
|
use crate::audio::my_xa::{Arguments, Orality, SampleDepth};
|
||||||
use tool_helper::Error;
|
use tool_helper::Error;
|
||||||
|
|
||||||
pub struct Encoder {
|
pub struct Encoder<'a> {
|
||||||
left: ChannelState,
|
left: ChannelState,
|
||||||
right: ChannelState
|
right: ChannelState,
|
||||||
|
source: &'a[i16],
|
||||||
|
arguments: Arguments,
|
||||||
|
samples_per_block: i32,
|
||||||
|
sample_limit: i32
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encoder {
|
impl<'a> Encoder<'a> {
|
||||||
|
const BLOCKS_PER_SECTOR:usize = 18;
|
||||||
const XA_ADPCM_FILTER_COUNT: i32 = 4;
|
const XA_ADPCM_FILTER_COUNT: i32 = 4;
|
||||||
const FILTER_K1: [i16; 5] = [0, 60, 115, 98, 122];
|
const FILTER_K1: [i16; 5] = [0, 60, 115, 98, 122];
|
||||||
const FILTER_K2: [i16; 5] = [0, 0, -52, -55, -60];
|
const FILTER_K2: [i16; 5] = [0, 0, -52, -55, -60];
|
||||||
|
|
||||||
pub fn encode_xa(&mut self, samples: &[i16], sample_limit: i32, data: &mut [u8], args: &Arguments) -> Result<(), Error> {
|
pub fn new(source: &[i16], arguments: Arguments) -> Encoder {
|
||||||
|
let (samples_per_block, sample_limit) = Self::samples_per_block_and_limit(&source, &arguments);
|
||||||
|
Encoder{left: ChannelState::default(), right: ChannelState::default(), source, arguments, samples_per_block, sample_limit}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn encode_next_xa_sector(&mut self) -> Result<Option<[u8; 0x930]>, Error> {
|
||||||
|
if self.source.is_empty() {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut sector = [0u8; 0x930];
|
||||||
|
sector[0x12] = 0x24 | 0x40;
|
||||||
|
sector[0x13] = 1 | 0 | 0;
|
||||||
|
|
||||||
|
let mut dst = &mut sector[0x18..];
|
||||||
|
for _ in 0..Self::BLOCKS_PER_SECTOR {
|
||||||
|
if self.source.len() < self.samples_per_block as usize {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.encode_xa(&self.source[0..], self.sample_limit, dst)?;
|
||||||
|
|
||||||
|
self.sample_limit -= self.samples_per_block;
|
||||||
|
self.source = &self.source[self.samples_per_block as usize..];
|
||||||
|
dst = &mut dst[0x80..];
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Some(sector))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encode_xa(&mut self, samples: &[i16], sample_limit: i32, data: &mut [u8]) -> Result<(), Error> {
|
||||||
const SHIFT_RANGE_4BPS: i32 = 12;
|
const SHIFT_RANGE_4BPS: i32 = 12;
|
||||||
const SHIFT_RANGE_8BPS: i32 = 8;
|
const SHIFT_RANGE_8BPS: i32 = 8;
|
||||||
|
|
||||||
let channels = [&mut self.left, &mut self.right];
|
let channels = [&mut self.left, &mut self.right];
|
||||||
match args.sample_depth {
|
match self.arguments.sample_depth {
|
||||||
SampleDepth::Normal => {
|
SampleDepth::Normal => {
|
||||||
let (modulo, offset) = if args.orality == Orality::Stereo {(2, &STEREO_4BIT)} else {(1, &MONO_4BIT)};
|
let (modulo, offset) = if self.arguments.orality == Orality::Stereo {(2, &STEREO_4BIT)} else {(1, &MONO_4BIT)};
|
||||||
let (first_offset, second_offset) = offset;
|
let (first_offset, second_offset) = offset;
|
||||||
|
|
||||||
for (offset_idx, offset_set) in [first_offset, second_offset].iter().enumerate() {
|
for (offset_idx, offset_set) in [first_offset, second_offset].iter().enumerate() {
|
||||||
|
@ -30,7 +65,7 @@ impl Encoder {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
SampleDepth::High => {
|
SampleDepth::High => {
|
||||||
let (modulo, offset_set) = if args.orality == Orality::Stereo {(2, &STEREO_8BIT)} else {(1, &MONO_8BIT)};
|
let (modulo, offset_set) = if self.arguments.orality == Orality::Stereo {(2, &STEREO_8BIT)} else {(1, &MONO_8BIT)};
|
||||||
for (idx, offset) in offset_set.iter().enumerate() {
|
for (idx, offset) in offset_set.iter().enumerate() {
|
||||||
let byte = Self::encode(channels[idx%modulo], &samples[offset.sample..], sample_limit + offset.sample_limit, offset.pitch, &mut data[offset.data..], offset.data_shift, offset.data_pitch, Self::XA_ADPCM_FILTER_COUNT, SHIFT_RANGE_8BPS)?;
|
let byte = Self::encode(channels[idx%modulo], &samples[offset.sample..], sample_limit + offset.sample_limit, offset.pitch, &mut data[offset.data..], offset.data_shift, offset.data_pitch, Self::XA_ADPCM_FILTER_COUNT, SHIFT_RANGE_8BPS)?;
|
||||||
data[idx] = byte;
|
data[idx] = byte;
|
||||||
|
@ -170,11 +205,19 @@ impl Encoder {
|
||||||
Err(Error::from_text(format!("0 <= {} && {} <= {} was not satisfied with min_shift: {}", min_shift, min_shift, shift_range, min_shift)))
|
Err(Error::from_text(format!("0 <= {} && {} <= {} was not satisfied with min_shift: {}", min_shift, min_shift, shift_range, min_shift)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl std::default::Default for Encoder {
|
fn samples_per_block_and_limit(input: &[i16], arguments: &Arguments) -> (i32, i32) {
|
||||||
fn default() -> Self {
|
let samples_per_block = match arguments.sample_depth {
|
||||||
Encoder{left: ChannelState::default(), right: ChannelState::default()}
|
SampleDepth::Normal => 224,
|
||||||
|
SampleDepth::High => 112,
|
||||||
|
};
|
||||||
|
|
||||||
|
let sample_limit = match arguments.orality {
|
||||||
|
Orality::Stereo => input.len()*2,
|
||||||
|
Orality::Mono => input.len(),
|
||||||
|
};
|
||||||
|
|
||||||
|
(samples_per_block, sample_limit as i32)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue