Prepare XA-Audio interleaving

This commit is contained in:
Jaby 2024-05-22 20:22:07 +02:00
parent 28416fc624
commit 4b56c5c5d4
9 changed files with 100 additions and 41 deletions

View File

@ -39,6 +39,15 @@ pub fn force_convert_ascii_to_str(bytes: &[u8]) -> &str {
}
}
pub const fn xa_audio_interleave_count(files: usize) -> usize {
match files {
0..=4 => 4,
5..=8 => 8,
9..=16 => 16,
_ => 32
}
}
pub const fn sector_count_audio(audio_samples: usize) -> usize {
multiple_of_round_up(audio_samples, sector::Audio::SAMPLE_SIZE)
}

View File

@ -31,7 +31,8 @@ pub struct CommonProperties {
pub enum FileKind {
Regular,
Main(PathBuf),
Overlay(PathBuf)
Overlay(PathBuf),
XA_Audio(Vec<PathBuf>),
}
pub struct File {

View File

@ -78,15 +78,28 @@ fn parse_track(track: roxmltree::Node, config: &mut Configuration) -> Result<(),
}
fn parse_overlay_file(file: roxmltree::Node, is_hidden: bool) -> Result<File, Error> {
// v they will be compressed automatically
// v They will be compressed automatically
let common = read_common_properties(&file, is_hidden, Some(LZ4State::AlreadyCompressed))?;
let path = path_from_node(&file, &common.name)?;
Ok(File{common, path, kind: FileKind::Overlay(PathBuf::from(file.attribute(attribute_names::LBA_SOURCE).unwrap_or_default()))})
}
fn parse_xa_audio(_file: roxmltree::Node, _is_hidden: bool) -> Result<File, Error> {
Err(Error::not_implemented("XA-Audio not supported yet"))
fn parse_xa_audio(file: roxmltree::Node, is_hidden: bool) -> Result<File, Error> {
// v Never compress XA-Audio
let common = read_common_properties(&file, is_hidden, Some(LZ4State::None))?;
let channel = {
let mut channel = Vec::new();
for node in file.children() {
if node.is_element() && node.tag_name().name() == "Channel" {
channel.push(path_from_node(&node, "Channel")?);
}
}
channel
};
Ok(File{common, path: PathBuf::new(), kind: FileKind::XA_Audio(channel)})
}
fn parse_file_system(cur_node: roxmltree::Node, root: &mut Directory, mut is_hidden: bool) -> Result<(), Error> {

View File

@ -1,3 +1,4 @@
use crate::types::RawData;
use cdtypes::types::{helper::*, sector::*};
pub struct SubModeBuilder {
@ -62,7 +63,7 @@ pub fn create_xa_data_for<T>(sub_mode: SubMode, data: &T) -> Mode2Form1 {
create_xa_data_for_raw(sub_mode, unsafe {std::mem::transmute::<&T, &[u8; Mode2Form1::DATA_SIZE]>(data)})
}
pub fn create_xa_data_for_vec(sub_mode: Option<SubMode>, data: &Vec<u8>) -> Vec<Mode2Form1> {
pub fn create_xa_data_for_vec(sub_mode: Option<SubMode>, data: &RawData) -> Vec<Mode2Form1> {
let sectors_to_parse = sector_count_mode2_form1(data.len());
let mut data = &data[0..data.len()];
let mut sectors = vec![Mode2Form1::new(); sectors_to_parse];

View File

@ -325,33 +325,38 @@ fn process_directory_record(dir: &Directory, sec_writer: &mut dyn SectorWriter)
}
fn process_file(file: &File, sec_writer: &mut dyn SectorWriter) -> Result<(), Error> {
fn process_regular_file(content: &RawData, sec_writer: &mut dyn SectorWriter, padded_size: usize) -> Result<(), Error> {
let content_sectors = builder::create_xa_data_for_vec(None, content);
let content_sector_count = content_sectors.len();
for sector in content_sectors {
sec_writer.write_cd_xa_data(sector)?;
}
let extended_sector_count = sector_count_mode2_form1(padded_size) - content_sector_count;
for _ in 0..extended_sector_count {
sec_writer.write_cd_xa_data(builder::create_xa_data_zero())?;
}
Ok(())
}
fn process_cd_xa_file(_content: &Vec<RawData>, _sec_writer: &mut dyn SectorWriter) -> Result<(), Error> {
Err(Error::not_implemented("Encoding XA Audio"))
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
if !file.properties.is_size_valid() {
return Err(create_wrong_padding_error("File", file.name.to_string(), file.properties.get_padded_size(), file.properties.get_real_size()));
}
let content_sectors = {
match &file.content {
FileType::Regular(raw) => builder::create_xa_data_for_vec(None, raw),
FileType::Main(_, _) => {
return Err(Error::from_str("Trying to encode an unprocssed main file"));
},
FileType::Overlay(_, _) => {
return Err(Error::from_str("Trying to encode an unprocessed overlay file"));
},
}
};
let content_sector_count = content_sectors.len();
for sector in content_sectors {
sec_writer.write_cd_xa_data(sector)?;
match &file.content {
FileType::Regular(raw) => process_regular_file(raw, sec_writer, file.properties.get_padded_size()),
FileType::XA_Audio(raw) => process_cd_xa_file(raw, sec_writer),
FileType::Main(_, _) => Err(Error::from_str("Trying to encode an unprocssed main file")),
FileType::Overlay(_, _) => Err(Error::from_str("Trying to encode an unprocessed overlay file")),
}
let extended_sector_count = sector_count_mode2_form1(file.properties.get_padded_size()) - content_sector_count;
for _ in 0..extended_sector_count {
sec_writer.write_cd_xa_data(builder::create_xa_data_zero())?;
}
Ok(())
}
fn process_end_dummy_section(padding: usize, sec_writer: &mut dyn SectorWriter) -> Result<(), Error> {

View File

@ -5,6 +5,7 @@ pub mod encoder;
pub mod file_writer;
pub mod types;
use crate::types::RawData;
use cdtypes::types::sector::AudioSample;
use config_reader::LZ4State;
use encoder::{LbaCalculatorFunction, LengthCalculatorFunction};
@ -161,7 +162,7 @@ fn parse_configuration(config: config_reader::Configuration) -> Result<(CDDesc,
config_reader::DirMember::File(file) => {
let lz4_state = file.common.lz4_state;
let (mut desc_file, needs_treatment) = {
fn handle_file_load(file_path: &PathBuf, lz4_state: &LZ4State) -> Result<Vec<u8>, Error> {
fn handle_file_load(file_path: &PathBuf, lz4_state: &LZ4State) -> Result<RawData, Error> {
let file_content = read_file(file_path)?;
if matches!(lz4_state, LZ4State::Compress) {
@ -173,10 +174,20 @@ fn parse_configuration(config: config_reader::Configuration) -> Result<(CDDesc,
}
}
fn handle_multiple_file_load(file_paths: Vec<PathBuf>, lz4_state: &LZ4State) -> Result<Vec<RawData>, Error> {
let mut files = Vec::new();
for file_path in file_paths {
files.push(handle_file_load(&file_path, &lz4_state)?);
}
Ok(files)
}
match file.kind {
config_reader::FileKind::Regular => (types::File::new_regular(file.common.name.as_str(), handle_file_load(&file.path, &lz4_state)?)?, false),
config_reader::FileKind::Main(lba_source) => (types::overlay::load_for_main(file.common.name.as_str(), handle_file_load(&file.path, &lz4_state)?, lba_source)?, true),
config_reader::FileKind::Overlay(lba_source) => (types::overlay::load_from(file.common.name.as_str(), &file.path, lba_source)?, true),
config_reader::FileKind::XA_Audio(channels) => (types::File::new_xa_audio(file.common.name.as_str(), handle_multiple_file_load(channels, &lz4_state)?)?, false),
}
};

View File

@ -3,12 +3,13 @@ pub mod layout;
pub mod file_map;
pub mod overlay;
use cdtypes::types::{cdstring::DString, dir_record::DirectoryRecord, path_table::PathTableL, sector::AudioSample};
use cdtypes::types::{cdstring::DString, dir_record::DirectoryRecord, helper::xa_audio_interleave_count, path_table::PathTableL, sector::AudioSample};
use std::{cell::RefCell, path::PathBuf, rc::Rc};
pub use file_map::FileSystemMap;
pub use tool_helper::Error;
pub type SharedPtr<T> = Rc<RefCell<T>>;
pub type RawData = Vec<u8>;
pub fn new_shared_ptr<T>(value: T) -> SharedPtr<T> {
Rc::new(RefCell::new(value))
@ -216,9 +217,10 @@ impl std::fmt::Display for Directory {
}
pub(super) enum FileType {
Regular(Vec<u8>),
Main(Vec<u8>, overlay::LBANameVec),
Overlay(Vec<u8>, overlay::LBANameVec),
Regular(RawData),
Main(RawData, overlay::LBANameVec),
Overlay(RawData, overlay::LBANameVec),
XA_Audio(Vec<RawData>),
}
pub struct File {
@ -229,22 +231,36 @@ pub struct File {
}
impl File {
pub fn new_regular(file_name: &str, content: Vec<u8>) -> Result<File, Error> {
pub fn new_regular(file_name: &str, content: RawData) -> Result<File, Error> {
let content_size = content.len();
Self::new_from_content(file_name, FileType::Regular(content), content_size)
}
pub fn new_main(file_name: &str, content: Vec<u8>, lba_names: overlay::LBANameVec) -> Result<File, Error> {
pub fn new_main(file_name: &str, content: RawData, lba_names: overlay::LBANameVec) -> Result<File, Error> {
let content_size = content.len();
Self::new_from_content(file_name, FileType::Main(content, lba_names), content_size)
}
pub fn new_overlay(file_name: &str, content: Vec<u8>, lba_names: overlay::LBANameVec, content_size: usize) -> Result<File, Error> {
pub fn new_overlay(file_name: &str, content: RawData, lba_names: overlay::LBANameVec, content_size: usize) -> Result<File, Error> {
Self::new_from_content(file_name, FileType::Overlay(content, lba_names), content_size)
}
pub fn new_xa_audio(file_name: &str, content: Vec<RawData>) -> Result<File, Error> {
let channel_count = content.len();
let highest_size = {
let mut size = 0;
for channel in &content {
if channel.len() > size {
size = channel.len();
}
}
size
};
Self::new_from_content(file_name, FileType::XA_Audio(content), highest_size*xa_audio_interleave_count(channel_count))
}
pub fn get_track_rel_lba(&self) -> usize {
self.properties.lba.get_track_relative()
}
@ -257,7 +273,7 @@ impl File {
self.properties.get_padded_size()
}
pub(super) fn make_regular(&mut self, content: Vec<u8>) {
pub(super) fn make_regular(&mut self, content: RawData) {
self.properties.size_bytes = content.len();
self.content = FileType::Regular(content);
}

View File

@ -1,4 +1,6 @@
pub fn skip_to_lba_area(content: &mut Vec<u8>) -> &mut [u8] {
use crate::types::RawData;
pub fn skip_to_lba_area(content: &mut RawData) -> &mut [u8] {
const PSX_HEADER_SIZE:usize = 2048;
&mut content[PSX_HEADER_SIZE..]

View File

@ -1,3 +1,4 @@
use super::RawData;
use super::{layout::Layout, File, FileSystemMap};
use super::super::encoder::LengthCalculatorFunction;
use std::path::PathBuf;
@ -52,11 +53,11 @@ pub fn load_from(file_name: &str, file_path: &PathBuf, lba_source: PathBuf) -> R
Ok(File::new_overlay(file_name, content, lba_names, content_size)?)
}
pub fn load_for_main(file_name: &str, content: Vec<u8>, lba_source: PathBuf) -> Result<File, Error> {
pub fn load_for_main(file_name: &str, content: RawData, lba_source: PathBuf) -> Result<File, Error> {
File::new_main(file_name, content, load_lba_names(lba_source)?)
}
pub fn update_content(content: &mut Vec<u8>, lba_names: &LBANameVec, file_map: &FileSystemMap, length_func: LengthCalculatorFunction) -> Result<Vec<u8>, Error> {
pub fn update_content(content: &mut RawData, lba_names: &LBANameVec, file_map: &FileSystemMap, length_func: LengthCalculatorFunction) -> Result<RawData, Error> {
let lba_header = skip_to_lba_header(content);
let lba_header = unsafe{std::slice::from_raw_parts_mut(lba_header.as_mut_ptr() as *mut LBAEntry, lba_names.len())};
@ -67,7 +68,7 @@ pub fn update_content(content: &mut Vec<u8>, lba_names: &LBANameVec, file_map: &
Ok(tool_helper::compress::psx_default::lz4(content)?)
}
pub fn update_content_for_main(content: &mut Vec<u8>, lba_names: &LBANameVec, file_map: &FileSystemMap, length_func: LengthCalculatorFunction) -> Result<Vec<u8>, Error> {
pub fn update_content_for_main(content: &mut RawData, lba_names: &LBANameVec, file_map: &FileSystemMap, length_func: LengthCalculatorFunction) -> Result<RawData, Error> {
let lba_header = unsafe{std::slice::from_raw_parts_mut(main::skip_to_lba_area(content).as_mut_ptr() as *mut LBAEntry, lba_names.len())};
for_each_lba_name(lba_names, file_map, length_func, |idx, (lba, bytes), is_lz4| {
@ -97,7 +98,7 @@ fn for_each_lba_name<F: FnMut(usize, (usize, usize), bool) -> Result<(), Error>>
Ok(())
}
fn skip_to_lba_header(content: &mut Vec<u8>) -> &mut [u8] {
fn skip_to_lba_header(content: &mut RawData) -> &mut [u8] {
let overlay_header_size = 0;
&mut content[overlay_header_size..]