From dc04dd1ab18aa5dff2b3b390b6e9ea66d01d2e3a Mon Sep 17 00:00:00 2001 From: lifegpc Date: Sun, 3 Aug 2025 19:41:44 +0800 Subject: [PATCH] Add circus pcm audio support --- Cargo.toml | 4 +- msg_tool_macro/src/lib.rs | 2 +- src/scripts/circus/audio/mod.rs | 1 + src/scripts/circus/audio/pcm.rs | 854 ++++++++++++++++++++++++++++++++ src/scripts/circus/mod.rs | 2 + src/scripts/mod.rs | 2 + src/types.rs | 3 + src/utils/mod.rs | 2 + src/utils/pcm.rs | 48 ++ src/utils/struct_pack.rs | 16 + 10 files changed, 932 insertions(+), 2 deletions(-) create mode 100644 src/scripts/circus/audio/mod.rs create mode 100644 src/scripts/circus/audio/pcm.rs create mode 100644 src/utils/pcm.rs diff --git a/Cargo.toml b/Cargo.toml index 437adcf..2baf13d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,7 @@ utf16string = "0.2" zstd = { version = "0.13", optional = true } [features] -default = ["artemis", "artemis-arc", "bgi", "bgi-arc", "bgi-img", "cat-system", "cat-system-arc", "cat-system-img", "circus", "circus-arc", "circus-img", "escude", "escude-arc", "hexen-haus", "kirikiri", "kirikiri-img", "will-plus", "yaneurao", "yaneurao-itufuru"] +default = ["artemis", "artemis-arc", "bgi", "bgi-arc", "bgi-img", "cat-system", "cat-system-arc", "cat-system-img", "circus", "circus-arc", "circus-audio", "circus-img", "escude", "escude-arc", "hexen-haus", "kirikiri", "kirikiri-img", "will-plus", "yaneurao", "yaneurao-itufuru"] artemis = ["utils-escape"] artemis-arc = ["artemis", "msg_tool_macro/artemis-arc", "sha1"] bgi = [] @@ -43,6 +43,7 @@ cat-system-arc = ["cat-system", "blowfish", "utils-crc32"] cat-system-img = ["cat-system", "flate2", "image", "utils-bit-stream"] circus = [] circus-arc = ["circus"] +circus-audio = ["circus", "flate2", "int-enum", "utils-pcm"] circus-img = ["circus", "image", "flate2", "zstd"] escude = ["int-enum"] escude-arc = ["escude", "rand", "utils-bit-stream"] @@ -58,6 +59,7 @@ image = ["png"] utils-bit-stream = [] utils-crc32 = [] utils-escape = ["fancy-regex"] +utils-pcm = [] utils-str = [] [target.'cfg(windows)'.dependencies] diff --git a/msg_tool_macro/src/lib.rs b/msg_tool_macro/src/lib.rs index 1c86fcc..b910ee8 100644 --- a/msg_tool_macro/src/lib.rs +++ b/msg_tool_macro/src/lib.rs @@ -613,7 +613,7 @@ pub fn struct_unpack_derive(input: TokenStream) -> TokenStream { } let p = cur.unwrap_or_else(|| { quote::quote! { - let #field_name = #field_type::unpack(&mut reader, big, encoding)?; + let #field_name = <#field_type>::unpack(&mut reader, big, encoding)?; } }); if let Some(skip_if) = skip_if { diff --git a/src/scripts/circus/audio/mod.rs b/src/scripts/circus/audio/mod.rs new file mode 100644 index 0000000..fac9bf7 --- /dev/null +++ b/src/scripts/circus/audio/mod.rs @@ -0,0 +1 @@ +pub mod pcm; diff --git a/src/scripts/circus/audio/pcm.rs b/src/scripts/circus/audio/pcm.rs new file mode 100644 index 0000000..0739be3 --- /dev/null +++ b/src/scripts/circus/audio/pcm.rs @@ -0,0 +1,854 @@ +use crate::ext::io::*; +use crate::ext::vec::*; +use crate::scripts::base::*; +use crate::types::*; +use crate::utils::pcm::*; +use crate::utils::struct_pack::*; +use anyhow::Result; +use int_enum::IntEnum; +use msg_tool_macro::*; +use overf::wrapping; +use std::io::{Read, Seek, Write}; + +#[derive(Debug)] +pub struct PcmBuilder {} + +impl PcmBuilder { + pub fn new() -> Self { + Self {} + } +} + +impl ScriptBuilder for PcmBuilder { + fn default_encoding(&self) -> Encoding { + Encoding::Utf8 + } + + fn build_script( + &self, + buf: Vec, + _filename: &str, + _encoding: Encoding, + _archive_encoding: Encoding, + config: &ExtraConfig, + _archive: Option<&Box>, + ) -> Result> { + Ok(Box::new(Pcm::new(MemReader::new(buf), config)?)) + } + + fn build_script_from_file( + &self, + filename: &str, + _encoding: Encoding, + _archive_encoding: Encoding, + config: &ExtraConfig, + _archive: Option<&Box>, + ) -> Result> { + let file = std::fs::File::open(filename)?; + let f = std::io::BufReader::new(file); + Ok(Box::new(Pcm::new(f, config)?)) + } + + fn build_script_from_reader( + &self, + reader: Box, + _filename: &str, + _encoding: Encoding, + _archive_encoding: Encoding, + config: &ExtraConfig, + _archive: Option<&Box>, + ) -> Result> { + Ok(Box::new(Pcm::new(reader, config)?)) + } + + fn extensions(&self) -> &'static [&'static str] { + &["pcm"] + } + + fn script_type(&self) -> &'static ScriptType { + &ScriptType::CircusPcm + } + + fn is_this_format(&self, _filename: &str, buf: &[u8], buf_len: usize) -> Option { + if buf_len >= 4 && buf.starts_with(b"XPCM") { + Some(10) + } else { + None + } + } +} + +#[derive(Debug, IntEnum)] +#[repr(u32)] +enum Mode { + Raw = 0, + Lzss = 1, + Zlib = 3, + Ogg = 5, +} + +#[derive(Debug, StructPack, StructUnpack)] +struct Header { + src_size: u32, + _mode: u32, + #[skip_pack_if(self.mode() != 5)] + #[skip_unpack_if((_mode & 0xFF) != 5)] + ogg_size: u32, + #[skip_pack_if(self.mode() == 5)] + #[skip_unpack_if((_mode & 0xFF) == 5)] + pcm: Option, +} + +impl Header { + pub fn mode(&self) -> u32 { + self._mode & 0xFF + } + + pub fn extra(&self) -> u32 { + (self._mode >> 8) & 0xFF + } +} + +#[derive(Debug)] +pub struct Pcm { + header: Header, + data: MemReader, +} + +impl Pcm { + pub fn new(mut reader: R, _config: &ExtraConfig) -> Result { + let mut magic = [0u8; 4]; + reader.read_exact(&mut magic)?; + if &magic != b"XPCM" { + return Err(anyhow::anyhow!("Invalid PCM header magic: {:?}", magic)); + } + let header = Header::unpack(&mut reader, false, Encoding::Utf8)?; + let mode = Mode::try_from(header.mode()) + .map_err(|_| anyhow::anyhow!("Unsupported PCM mode: {}", header.mode()))?; + let data = match mode { + Mode::Ogg => { + if header.ogg_size == 0 { + return Err(anyhow::anyhow!("Invalid OGG size in PCM header")); + } + let mut data = vec![0u8; header.ogg_size as usize]; + reader.read_exact(&mut data)?; + data + } + Mode::Raw => { + let mut data = vec![0u8; header.src_size as usize]; + reader.read_exact(&mut data)?; + data + } + _ => { + PcmDecoder::new(reader, header.src_size as usize, header.extra(), mode)?.unpack()? + } + }; + Ok(Self { + header, + data: MemReader::new(data), + }) + } +} + +impl Script for Pcm { + fn default_output_script_type(&self) -> OutputScriptType { + OutputScriptType::Custom + } + + fn default_format_type(&self) -> FormatOptions { + FormatOptions::None + } + + fn is_output_supported(&self, output: OutputScriptType) -> bool { + matches!(output, OutputScriptType::Custom) + } + + fn custom_output_extension<'a>(&'a self) -> &'a str { + if self.header.mode() == 5 { + "ogg" + } else { + "wav" + } + } + + fn custom_export(&self, filename: &std::path::Path, _encoding: Encoding) -> Result<()> { + let mut writer = std::fs::File::create(filename)?; + if self.header.mode() == 5 { + writer.write_all(&self.data.data)?; + } else { + let fmt = self + .header + .pcm + .as_ref() + .ok_or_else(|| anyhow::anyhow!("PCM format not found in header"))?; + write_pcm(fmt, self.data.to_ref(), writer)?; + } + Ok(()) + } +} + +const UNK_43A254: [u8; 256] = [ + 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, +]; +const DWORD_43A358: [i32; 2048] = [ + 0x1000, 0x0000, 0x0FFF, 0x0006, 0x0FFF, 0x000C, 0x0FFF, 0x0012, 0x0FFF, 0x0019, 0x0FFF, 0x001F, + 0x0FFF, 0x0025, 0x0FFF, 0x002B, 0x0FFF, 0x0032, 0x0FFF, 0x0038, 0x0FFF, 0x003E, 0x0FFF, 0x0045, + 0x0FFF, 0x004B, 0x0FFF, 0x0051, 0x0FFF, 0x0057, 0x0FFE, 0x005E, 0x0FFE, 0x0064, 0x0FFE, 0x006A, + 0x0FFE, 0x0071, 0x0FFE, 0x0077, 0x0FFE, 0x007D, 0x0FFD, 0x0083, 0x0FFD, 0x008A, 0x0FFD, 0x0090, + 0x0FFD, 0x0096, 0x0FFC, 0x009D, 0x0FFC, 0x00A3, 0x0FFC, 0x00A9, 0x0FFC, 0x00AF, 0x0FFB, 0x00B6, + 0x0FFB, 0x00BC, 0x0FFB, 0x00C2, 0x0FFB, 0x00C8, 0x0FFA, 0x00CF, 0x0FFA, 0x00D5, 0x0FFA, 0x00DB, + 0x0FF9, 0x00E2, 0x0FF9, 0x00E8, 0x0FF9, 0x00EE, 0x0FF8, 0x00F4, 0x0FF8, 0x00FB, 0x0FF7, 0x0101, + 0x0FF7, 0x0107, 0x0FF7, 0x010D, 0x0FF6, 0x0114, 0x0FF6, 0x011A, 0x0FF5, 0x0120, 0x0FF5, 0x0127, + 0x0FF4, 0x012D, 0x0FF4, 0x0133, 0x0FF3, 0x0139, 0x0FF3, 0x0140, 0x0FF2, 0x0146, 0x0FF2, 0x014C, + 0x0FF1, 0x0152, 0x0FF1, 0x0159, 0x0FF0, 0x015F, 0x0FF0, 0x0165, 0x0FEF, 0x016B, 0x0FEF, 0x0172, + 0x0FEE, 0x0178, 0x0FEE, 0x017E, 0x0FED, 0x0184, 0x0FEC, 0x018B, 0x0FEC, 0x0191, 0x0FEB, 0x0197, + 0x0FEB, 0x019D, 0x0FEA, 0x01A4, 0x0FE9, 0x01AA, 0x0FE9, 0x01B0, 0x0FE8, 0x01B6, 0x0FE7, 0x01BD, + 0x0FE7, 0x01C3, 0x0FE6, 0x01C9, 0x0FE5, 0x01CF, 0x0FE4, 0x01D6, 0x0FE4, 0x01DC, 0x0FE3, 0x01E2, + 0x0FE2, 0x01E8, 0x0FE1, 0x01EF, 0x0FE1, 0x01F5, 0x0FE0, 0x01FB, 0x0FDF, 0x0201, 0x0FDE, 0x0208, + 0x0FDE, 0x020E, 0x0FDD, 0x0214, 0x0FDC, 0x021A, 0x0FDB, 0x0221, 0x0FDA, 0x0227, 0x0FD9, 0x022D, + 0x0FD9, 0x0233, 0x0FD8, 0x0239, 0x0FD7, 0x0240, 0x0FD6, 0x0246, 0x0FD5, 0x024C, 0x0FD4, 0x0252, + 0x0FD3, 0x0259, 0x0FD2, 0x025F, 0x0FD1, 0x0265, 0x0FD0, 0x026B, 0x0FCF, 0x0271, 0x0FCE, 0x0278, + 0x0FCD, 0x027E, 0x0FCC, 0x0284, 0x0FCB, 0x028A, 0x0FCA, 0x0290, 0x0FC9, 0x0297, 0x0FC8, 0x029D, + 0x0FC7, 0x02A3, 0x0FC6, 0x02A9, 0x0FC5, 0x02AF, 0x0FC4, 0x02B6, 0x0FC3, 0x02BC, 0x0FC2, 0x02C2, + 0x0FC1, 0x02C8, 0x0FC0, 0x02CE, 0x0FBF, 0x02D5, 0x0FBE, 0x02DB, 0x0FBD, 0x02E1, 0x0FBB, 0x02E7, + 0x0FBA, 0x02ED, 0x0FB9, 0x02F3, 0x0FB8, 0x02FA, 0x0FB7, 0x0300, 0x0FB6, 0x0306, 0x0FB4, 0x030C, + 0x0FB3, 0x0312, 0x0FB2, 0x0318, 0x0FB1, 0x031F, 0x0FB0, 0x0325, 0x0FAE, 0x032B, 0x0FAD, 0x0331, + 0x0FAC, 0x0337, 0x0FAB, 0x033D, 0x0FA9, 0x0344, 0x0FA8, 0x034A, 0x0FA7, 0x0350, 0x0FA5, 0x0356, + 0x0FA4, 0x035C, 0x0FA3, 0x0362, 0x0FA1, 0x0368, 0x0FA0, 0x036F, 0x0F9F, 0x0375, 0x0F9D, 0x037B, + 0x0F9C, 0x0381, 0x0F9B, 0x0387, 0x0F99, 0x038D, 0x0F98, 0x0393, 0x0F96, 0x0399, 0x0F95, 0x03A0, + 0x0F94, 0x03A6, 0x0F92, 0x03AC, 0x0F91, 0x03B2, 0x0F8F, 0x03B8, 0x0F8E, 0x03BE, 0x0F8C, 0x03C4, + 0x0F8B, 0x03CA, 0x0F89, 0x03D0, 0x0F88, 0x03D7, 0x0F86, 0x03DD, 0x0F85, 0x03E3, 0x0F83, 0x03E9, + 0x0F82, 0x03EF, 0x0F80, 0x03F5, 0x0F7F, 0x03FB, 0x0F7D, 0x0401, 0x0F7B, 0x0407, 0x0F7A, 0x040D, + 0x0F78, 0x0413, 0x0F77, 0x041A, 0x0F75, 0x0420, 0x0F73, 0x0426, 0x0F72, 0x042C, 0x0F70, 0x0432, + 0x0F6E, 0x0438, 0x0F6D, 0x043E, 0x0F6B, 0x0444, 0x0F69, 0x044A, 0x0F68, 0x0450, 0x0F66, 0x0456, + 0x0F64, 0x045C, 0x0F63, 0x0462, 0x0F61, 0x0468, 0x0F5F, 0x046E, 0x0F5D, 0x0474, 0x0F5C, 0x047A, + 0x0F5A, 0x0480, 0x0F58, 0x0486, 0x0F56, 0x048C, 0x0F55, 0x0492, 0x0F53, 0x0498, 0x0F51, 0x049E, + 0x0F4F, 0x04A5, 0x0F4D, 0x04AB, 0x0F4B, 0x04B1, 0x0F4A, 0x04B7, 0x0F48, 0x04BD, 0x0F46, 0x04C3, + 0x0F44, 0x04C9, 0x0F42, 0x04CF, 0x0F40, 0x04D5, 0x0F3E, 0x04DB, 0x0F3C, 0x04E0, 0x0F3B, 0x04E6, + 0x0F39, 0x04EC, 0x0F37, 0x04F2, 0x0F35, 0x04F8, 0x0F33, 0x04FE, 0x0F31, 0x0504, 0x0F2F, 0x050A, + 0x0F2D, 0x0510, 0x0F2B, 0x0516, 0x0F29, 0x051C, 0x0F27, 0x0522, 0x0F25, 0x0528, 0x0F23, 0x052E, + 0x0F21, 0x0534, 0x0F1F, 0x053A, 0x0F1D, 0x0540, 0x0F1B, 0x0546, 0x0F18, 0x054C, 0x0F16, 0x0552, + 0x0F14, 0x0558, 0x0F12, 0x055D, 0x0F10, 0x0563, 0x0F0E, 0x0569, 0x0F0C, 0x056F, 0x0F0A, 0x0575, + 0x0F08, 0x057B, 0x0F05, 0x0581, 0x0F03, 0x0587, 0x0F01, 0x058D, 0x0EFF, 0x0593, 0x0EFD, 0x0599, + 0x0EFA, 0x059E, 0x0EF8, 0x05A4, 0x0EF6, 0x05AA, 0x0EF4, 0x05B0, 0x0EF2, 0x05B6, 0x0EEF, 0x05BC, + 0x0EED, 0x05C2, 0x0EEB, 0x05C7, 0x0EE8, 0x05CD, 0x0EE6, 0x05D3, 0x0EE4, 0x05D9, 0x0EE2, 0x05DF, + 0x0EDF, 0x05E5, 0x0EDD, 0x05EB, 0x0EDB, 0x05F0, 0x0ED8, 0x05F6, 0x0ED6, 0x05FC, 0x0ED4, 0x0602, + 0x0ED1, 0x0608, 0x0ECF, 0x060E, 0x0ECD, 0x0613, 0x0ECA, 0x0619, 0x0EC8, 0x061F, 0x0EC5, 0x0625, + 0x0EC3, 0x062B, 0x0EC0, 0x0630, 0x0EBE, 0x0636, 0x0EBC, 0x063C, 0x0EB9, 0x0642, 0x0EB7, 0x0648, + 0x0EB4, 0x064D, 0x0EB2, 0x0653, 0x0EAF, 0x0659, 0x0EAD, 0x065F, 0x0EAA, 0x0664, 0x0EA8, 0x066A, + 0x0EA5, 0x0670, 0x0EA3, 0x0676, 0x0EA0, 0x067B, 0x0E9E, 0x0681, 0x0E9B, 0x0687, 0x0E98, 0x068D, + 0x0E96, 0x0692, 0x0E93, 0x0698, 0x0E91, 0x069E, 0x0E8E, 0x06A3, 0x0E8B, 0x06A9, 0x0E89, 0x06AF, + 0x0E86, 0x06B5, 0x0E84, 0x06BA, 0x0E81, 0x06C0, 0x0E7E, 0x06C6, 0x0E7C, 0x06CB, 0x0E79, 0x06D1, + 0x0E76, 0x06D7, 0x0E74, 0x06DC, 0x0E71, 0x06E2, 0x0E6E, 0x06E8, 0x0E6B, 0x06ED, 0x0E69, 0x06F3, + 0x0E66, 0x06F9, 0x0E63, 0x06FE, 0x0E60, 0x0704, 0x0E5E, 0x070A, 0x0E5B, 0x070F, 0x0E58, 0x0715, + 0x0E55, 0x071B, 0x0E53, 0x0720, 0x0E50, 0x0726, 0x0E4D, 0x072B, 0x0E4A, 0x0731, 0x0E47, 0x0737, + 0x0E44, 0x073C, 0x0E42, 0x0742, 0x0E3F, 0x0748, 0x0E3C, 0x074D, 0x0E39, 0x0753, 0x0E36, 0x0758, + 0x0E33, 0x075E, 0x0E30, 0x0763, 0x0E2D, 0x0769, 0x0E2B, 0x076F, 0x0E28, 0x0774, 0x0E25, 0x077A, + 0x0E22, 0x077F, 0x0E1F, 0x0785, 0x0E1C, 0x078A, 0x0E19, 0x0790, 0x0E16, 0x0795, 0x0E13, 0x079B, + 0x0E10, 0x07A0, 0x0E0D, 0x07A6, 0x0E0A, 0x07AC, 0x0E07, 0x07B1, 0x0E04, 0x07B7, 0x0E01, 0x07BC, + 0x0DFE, 0x07C2, 0x0DFB, 0x07C7, 0x0DF8, 0x07CD, 0x0DF5, 0x07D2, 0x0DF2, 0x07D7, 0x0DEE, 0x07DD, + 0x0DEB, 0x07E2, 0x0DE8, 0x07E8, 0x0DE5, 0x07ED, 0x0DE2, 0x07F3, 0x0DDF, 0x07F8, 0x0DDC, 0x07FE, + 0x0DD9, 0x0803, 0x0DD5, 0x0809, 0x0DD2, 0x080E, 0x0DCF, 0x0813, 0x0DCC, 0x0819, 0x0DC9, 0x081E, + 0x0DC6, 0x0824, 0x0DC2, 0x0829, 0x0DBF, 0x082E, 0x0DBC, 0x0834, 0x0DB9, 0x0839, 0x0DB6, 0x083F, + 0x0DB2, 0x0844, 0x0DAF, 0x0849, 0x0DAC, 0x084F, 0x0DA9, 0x0854, 0x0DA5, 0x085A, 0x0DA2, 0x085F, + 0x0D9F, 0x0864, 0x0D9B, 0x086A, 0x0D98, 0x086F, 0x0D95, 0x0874, 0x0D91, 0x087A, 0x0D8E, 0x087F, + 0x0D8B, 0x0884, 0x0D87, 0x088A, 0x0D84, 0x088F, 0x0D81, 0x0894, 0x0D7D, 0x0899, 0x0D7A, 0x089F, + 0x0D77, 0x08A4, 0x0D73, 0x08A9, 0x0D70, 0x08AF, 0x0D6C, 0x08B4, 0x0D69, 0x08B9, 0x0D65, 0x08BE, + 0x0D62, 0x08C4, 0x0D5F, 0x08C9, 0x0D5B, 0x08CE, 0x0D58, 0x08D3, 0x0D54, 0x08D9, 0x0D51, 0x08DE, + 0x0D4D, 0x08E3, 0x0D4A, 0x08E8, 0x0D46, 0x08EE, 0x0D43, 0x08F3, 0x0D3F, 0x08F8, 0x0D3C, 0x08FD, + 0x0D38, 0x0902, 0x0D35, 0x0908, 0x0D31, 0x090D, 0x0D2D, 0x0912, 0x0D2A, 0x0917, 0x0D26, 0x091C, + 0x0D23, 0x0921, 0x0D1F, 0x0927, 0x0D1C, 0x092C, 0x0D18, 0x0931, 0x0D14, 0x0936, 0x0D11, 0x093B, + 0x0D0D, 0x0940, 0x0D09, 0x0945, 0x0D06, 0x094B, 0x0D02, 0x0950, 0x0CFE, 0x0955, 0x0CFB, 0x095A, + 0x0CF7, 0x095F, 0x0CF3, 0x0964, 0x0CF0, 0x0969, 0x0CEC, 0x096E, 0x0CE8, 0x0973, 0x0CE5, 0x0978, + 0x0CE1, 0x097D, 0x0CDD, 0x0982, 0x0CD9, 0x0987, 0x0CD6, 0x098D, 0x0CD2, 0x0992, 0x0CCE, 0x0997, + 0x0CCA, 0x099C, 0x0CC7, 0x09A1, 0x0CC3, 0x09A6, 0x0CBF, 0x09AB, 0x0CBB, 0x09B0, 0x0CB7, 0x09B5, + 0x0CB4, 0x09BA, 0x0CB0, 0x09BF, 0x0CAC, 0x09C4, 0x0CA8, 0x09C9, 0x0CA4, 0x09CE, 0x0CA0, 0x09D3, + 0x0C9D, 0x09D7, 0x0C99, 0x09DC, 0x0C95, 0x09E1, 0x0C91, 0x09E6, 0x0C8D, 0x09EB, 0x0C89, 0x09F0, + 0x0C85, 0x09F5, 0x0C81, 0x09FA, 0x0C7D, 0x09FF, 0x0C79, 0x0A04, 0x0C76, 0x0A09, 0x0C72, 0x0A0E, + 0x0C6E, 0x0A12, 0x0C6A, 0x0A17, 0x0C66, 0x0A1C, 0x0C62, 0x0A21, 0x0C5E, 0x0A26, 0x0C5A, 0x0A2B, + 0x0C56, 0x0A30, 0x0C52, 0x0A35, 0x0C4E, 0x0A39, 0x0C4A, 0x0A3E, 0x0C46, 0x0A43, 0x0C42, 0x0A48, + 0x0C3E, 0x0A4D, 0x0C3A, 0x0A51, 0x0C36, 0x0A56, 0x0C31, 0x0A5B, 0x0C2D, 0x0A60, 0x0C29, 0x0A65, + 0x0C25, 0x0A69, 0x0C21, 0x0A6E, 0x0C1D, 0x0A73, 0x0C19, 0x0A78, 0x0C15, 0x0A7C, 0x0C11, 0x0A81, + 0x0C0D, 0x0A86, 0x0C08, 0x0A8B, 0x0C04, 0x0A8F, 0x0C00, 0x0A94, 0x0BFC, 0x0A99, 0x0BF8, 0x0A9D, + 0x0BF4, 0x0AA2, 0x0BEF, 0x0AA7, 0x0BEB, 0x0AAC, 0x0BE7, 0x0AB0, 0x0BE3, 0x0AB5, 0x0BDF, 0x0ABA, + 0x0BDA, 0x0ABE, 0x0BD6, 0x0AC3, 0x0BD2, 0x0AC8, 0x0BCE, 0x0ACC, 0x0BCA, 0x0AD1, 0x0BC5, 0x0AD5, + 0x0BC1, 0x0ADA, 0x0BBD, 0x0ADF, 0x0BB8, 0x0AE3, 0x0BB4, 0x0AE8, 0x0BB0, 0x0AEC, 0x0BAC, 0x0AF1, + 0x0BA7, 0x0AF6, 0x0BA3, 0x0AFA, 0x0B9F, 0x0AFF, 0x0B9A, 0x0B03, 0x0B96, 0x0B08, 0x0B92, 0x0B0C, + 0x0B8D, 0x0B11, 0x0B89, 0x0B15, 0x0B85, 0x0B1A, 0x0B80, 0x0B1F, 0x0B7C, 0x0B23, 0x0B78, 0x0B28, + 0x0B73, 0x0B2C, 0x0B6F, 0x0B31, 0x0B6A, 0x0B35, 0x0B66, 0x0B3A, 0x0B62, 0x0B3E, 0x0B5D, 0x0B42, + 0x0B59, 0x0B47, 0x0B54, 0x0B4B, 0x0B50, 0x0B50, 0x0B4B, 0x0B54, 0x0B47, 0x0B59, 0x0B42, 0x0B5D, + 0x0B3E, 0x0B62, 0x0B3A, 0x0B66, 0x0B35, 0x0B6A, 0x0B31, 0x0B6F, 0x0B2C, 0x0B73, 0x0B28, 0x0B78, + 0x0B23, 0x0B7C, 0x0B1F, 0x0B80, 0x0B1A, 0x0B85, 0x0B15, 0x0B89, 0x0B11, 0x0B8D, 0x0B0C, 0x0B92, + 0x0B08, 0x0B96, 0x0B03, 0x0B9A, 0x0AFF, 0x0B9F, 0x0AFA, 0x0BA3, 0x0AF6, 0x0BA7, 0x0AF1, 0x0BAC, + 0x0AEC, 0x0BB0, 0x0AE8, 0x0BB4, 0x0AE3, 0x0BB8, 0x0ADF, 0x0BBD, 0x0ADA, 0x0BC1, 0x0AD5, 0x0BC5, + 0x0AD1, 0x0BCA, 0x0ACC, 0x0BCE, 0x0AC8, 0x0BD2, 0x0AC3, 0x0BD6, 0x0ABE, 0x0BDA, 0x0ABA, 0x0BDF, + 0x0AB5, 0x0BE3, 0x0AB0, 0x0BE7, 0x0AAC, 0x0BEB, 0x0AA7, 0x0BEF, 0x0AA2, 0x0BF4, 0x0A9D, 0x0BF8, + 0x0A99, 0x0BFC, 0x0A94, 0x0C00, 0x0A8F, 0x0C04, 0x0A8B, 0x0C08, 0x0A86, 0x0C0D, 0x0A81, 0x0C11, + 0x0A7C, 0x0C15, 0x0A78, 0x0C19, 0x0A73, 0x0C1D, 0x0A6E, 0x0C21, 0x0A69, 0x0C25, 0x0A65, 0x0C29, + 0x0A60, 0x0C2D, 0x0A5B, 0x0C31, 0x0A56, 0x0C36, 0x0A51, 0x0C3A, 0x0A4D, 0x0C3E, 0x0A48, 0x0C42, + 0x0A43, 0x0C46, 0x0A3E, 0x0C4A, 0x0A39, 0x0C4E, 0x0A35, 0x0C52, 0x0A30, 0x0C56, 0x0A2B, 0x0C5A, + 0x0A26, 0x0C5E, 0x0A21, 0x0C62, 0x0A1C, 0x0C66, 0x0A17, 0x0C6A, 0x0A12, 0x0C6E, 0x0A0E, 0x0C72, + 0x0A09, 0x0C76, 0x0A04, 0x0C79, 0x09FF, 0x0C7D, 0x09FA, 0x0C81, 0x09F5, 0x0C85, 0x09F0, 0x0C89, + 0x09EB, 0x0C8D, 0x09E6, 0x0C91, 0x09E1, 0x0C95, 0x09DC, 0x0C99, 0x09D7, 0x0C9D, 0x09D3, 0x0CA0, + 0x09CE, 0x0CA4, 0x09C9, 0x0CA8, 0x09C4, 0x0CAC, 0x09BF, 0x0CB0, 0x09BA, 0x0CB4, 0x09B5, 0x0CB7, + 0x09B0, 0x0CBB, 0x09AB, 0x0CBF, 0x09A6, 0x0CC3, 0x09A1, 0x0CC7, 0x099C, 0x0CCA, 0x0997, 0x0CCE, + 0x0992, 0x0CD2, 0x098D, 0x0CD6, 0x0987, 0x0CD9, 0x0982, 0x0CDD, 0x097D, 0x0CE1, 0x0978, 0x0CE5, + 0x0973, 0x0CE8, 0x096E, 0x0CEC, 0x0969, 0x0CF0, 0x0964, 0x0CF3, 0x095F, 0x0CF7, 0x095A, 0x0CFB, + 0x0955, 0x0CFE, 0x0950, 0x0D02, 0x094B, 0x0D06, 0x0945, 0x0D09, 0x0940, 0x0D0D, 0x093B, 0x0D11, + 0x0936, 0x0D14, 0x0931, 0x0D18, 0x092C, 0x0D1C, 0x0927, 0x0D1F, 0x0921, 0x0D23, 0x091C, 0x0D26, + 0x0917, 0x0D2A, 0x0912, 0x0D2D, 0x090D, 0x0D31, 0x0908, 0x0D35, 0x0902, 0x0D38, 0x08FD, 0x0D3C, + 0x08F8, 0x0D3F, 0x08F3, 0x0D43, 0x08EE, 0x0D46, 0x08E8, 0x0D4A, 0x08E3, 0x0D4D, 0x08DE, 0x0D51, + 0x08D9, 0x0D54, 0x08D3, 0x0D58, 0x08CE, 0x0D5B, 0x08C9, 0x0D5F, 0x08C4, 0x0D62, 0x08BE, 0x0D65, + 0x08B9, 0x0D69, 0x08B4, 0x0D6C, 0x08AF, 0x0D70, 0x08A9, 0x0D73, 0x08A4, 0x0D77, 0x089F, 0x0D7A, + 0x0899, 0x0D7D, 0x0894, 0x0D81, 0x088F, 0x0D84, 0x088A, 0x0D87, 0x0884, 0x0D8B, 0x087F, 0x0D8E, + 0x087A, 0x0D91, 0x0874, 0x0D95, 0x086F, 0x0D98, 0x086A, 0x0D9B, 0x0864, 0x0D9F, 0x085F, 0x0DA2, + 0x085A, 0x0DA5, 0x0854, 0x0DA9, 0x084F, 0x0DAC, 0x0849, 0x0DAF, 0x0844, 0x0DB2, 0x083F, 0x0DB6, + 0x0839, 0x0DB9, 0x0834, 0x0DBC, 0x082E, 0x0DBF, 0x0829, 0x0DC2, 0x0824, 0x0DC6, 0x081E, 0x0DC9, + 0x0819, 0x0DCC, 0x0813, 0x0DCF, 0x080E, 0x0DD2, 0x0809, 0x0DD5, 0x0803, 0x0DD9, 0x07FE, 0x0DDC, + 0x07F8, 0x0DDF, 0x07F3, 0x0DE2, 0x07ED, 0x0DE5, 0x07E8, 0x0DE8, 0x07E2, 0x0DEB, 0x07DD, 0x0DEE, + 0x07D7, 0x0DF2, 0x07D2, 0x0DF5, 0x07CD, 0x0DF8, 0x07C7, 0x0DFB, 0x07C2, 0x0DFE, 0x07BC, 0x0E01, + 0x07B7, 0x0E04, 0x07B1, 0x0E07, 0x07AC, 0x0E0A, 0x07A6, 0x0E0D, 0x07A0, 0x0E10, 0x079B, 0x0E13, + 0x0795, 0x0E16, 0x0790, 0x0E19, 0x078A, 0x0E1C, 0x0785, 0x0E1F, 0x077F, 0x0E22, 0x077A, 0x0E25, + 0x0774, 0x0E28, 0x076F, 0x0E2B, 0x0769, 0x0E2D, 0x0763, 0x0E30, 0x075E, 0x0E33, 0x0758, 0x0E36, + 0x0753, 0x0E39, 0x074D, 0x0E3C, 0x0748, 0x0E3F, 0x0742, 0x0E42, 0x073C, 0x0E44, 0x0737, 0x0E47, + 0x0731, 0x0E4A, 0x072B, 0x0E4D, 0x0726, 0x0E50, 0x0720, 0x0E53, 0x071B, 0x0E55, 0x0715, 0x0E58, + 0x070F, 0x0E5B, 0x070A, 0x0E5E, 0x0704, 0x0E60, 0x06FE, 0x0E63, 0x06F9, 0x0E66, 0x06F3, 0x0E69, + 0x06ED, 0x0E6B, 0x06E8, 0x0E6E, 0x06E2, 0x0E71, 0x06DC, 0x0E74, 0x06D7, 0x0E76, 0x06D1, 0x0E79, + 0x06CB, 0x0E7C, 0x06C6, 0x0E7E, 0x06C0, 0x0E81, 0x06BA, 0x0E84, 0x06B5, 0x0E86, 0x06AF, 0x0E89, + 0x06A9, 0x0E8B, 0x06A3, 0x0E8E, 0x069E, 0x0E91, 0x0698, 0x0E93, 0x0692, 0x0E96, 0x068D, 0x0E98, + 0x0687, 0x0E9B, 0x0681, 0x0E9E, 0x067B, 0x0EA0, 0x0676, 0x0EA3, 0x0670, 0x0EA5, 0x066A, 0x0EA8, + 0x0664, 0x0EAA, 0x065F, 0x0EAD, 0x0659, 0x0EAF, 0x0653, 0x0EB2, 0x064D, 0x0EB4, 0x0648, 0x0EB7, + 0x0642, 0x0EB9, 0x063C, 0x0EBC, 0x0636, 0x0EBE, 0x0630, 0x0EC0, 0x062B, 0x0EC3, 0x0625, 0x0EC5, + 0x061F, 0x0EC8, 0x0619, 0x0ECA, 0x0613, 0x0ECD, 0x060E, 0x0ECF, 0x0608, 0x0ED1, 0x0602, 0x0ED4, + 0x05FC, 0x0ED6, 0x05F6, 0x0ED8, 0x05F0, 0x0EDB, 0x05EB, 0x0EDD, 0x05E5, 0x0EDF, 0x05DF, 0x0EE2, + 0x05D9, 0x0EE4, 0x05D3, 0x0EE6, 0x05CD, 0x0EE8, 0x05C7, 0x0EEB, 0x05C2, 0x0EED, 0x05BC, 0x0EEF, + 0x05B6, 0x0EF2, 0x05B0, 0x0EF4, 0x05AA, 0x0EF6, 0x05A4, 0x0EF8, 0x059E, 0x0EFA, 0x0599, 0x0EFD, + 0x0593, 0x0EFF, 0x058D, 0x0F01, 0x0587, 0x0F03, 0x0581, 0x0F05, 0x057B, 0x0F08, 0x0575, 0x0F0A, + 0x056F, 0x0F0C, 0x0569, 0x0F0E, 0x0563, 0x0F10, 0x055D, 0x0F12, 0x0558, 0x0F14, 0x0552, 0x0F16, + 0x054C, 0x0F18, 0x0546, 0x0F1B, 0x0540, 0x0F1D, 0x053A, 0x0F1F, 0x0534, 0x0F21, 0x052E, 0x0F23, + 0x0528, 0x0F25, 0x0522, 0x0F27, 0x051C, 0x0F29, 0x0516, 0x0F2B, 0x0510, 0x0F2D, 0x050A, 0x0F2F, + 0x0504, 0x0F31, 0x04FE, 0x0F33, 0x04F8, 0x0F35, 0x04F2, 0x0F37, 0x04EC, 0x0F39, 0x04E6, 0x0F3B, + 0x04E0, 0x0F3C, 0x04DB, 0x0F3E, 0x04D5, 0x0F40, 0x04CF, 0x0F42, 0x04C9, 0x0F44, 0x04C3, 0x0F46, + 0x04BD, 0x0F48, 0x04B7, 0x0F4A, 0x04B1, 0x0F4B, 0x04AB, 0x0F4D, 0x04A5, 0x0F4F, 0x049E, 0x0F51, + 0x0498, 0x0F53, 0x0492, 0x0F55, 0x048C, 0x0F56, 0x0486, 0x0F58, 0x0480, 0x0F5A, 0x047A, 0x0F5C, + 0x0474, 0x0F5D, 0x046E, 0x0F5F, 0x0468, 0x0F61, 0x0462, 0x0F63, 0x045C, 0x0F64, 0x0456, 0x0F66, + 0x0450, 0x0F68, 0x044A, 0x0F69, 0x0444, 0x0F6B, 0x043E, 0x0F6D, 0x0438, 0x0F6E, 0x0432, 0x0F70, + 0x042C, 0x0F72, 0x0426, 0x0F73, 0x0420, 0x0F75, 0x041A, 0x0F77, 0x0413, 0x0F78, 0x040D, 0x0F7A, + 0x0407, 0x0F7B, 0x0401, 0x0F7D, 0x03FB, 0x0F7F, 0x03F5, 0x0F80, 0x03EF, 0x0F82, 0x03E9, 0x0F83, + 0x03E3, 0x0F85, 0x03DD, 0x0F86, 0x03D7, 0x0F88, 0x03D0, 0x0F89, 0x03CA, 0x0F8B, 0x03C4, 0x0F8C, + 0x03BE, 0x0F8E, 0x03B8, 0x0F8F, 0x03B2, 0x0F91, 0x03AC, 0x0F92, 0x03A6, 0x0F94, 0x03A0, 0x0F95, + 0x0399, 0x0F96, 0x0393, 0x0F98, 0x038D, 0x0F99, 0x0387, 0x0F9B, 0x0381, 0x0F9C, 0x037B, 0x0F9D, + 0x0375, 0x0F9F, 0x036F, 0x0FA0, 0x0368, 0x0FA1, 0x0362, 0x0FA3, 0x035C, 0x0FA4, 0x0356, 0x0FA5, + 0x0350, 0x0FA7, 0x034A, 0x0FA8, 0x0344, 0x0FA9, 0x033D, 0x0FAB, 0x0337, 0x0FAC, 0x0331, 0x0FAD, + 0x032B, 0x0FAE, 0x0325, 0x0FB0, 0x031F, 0x0FB1, 0x0318, 0x0FB2, 0x0312, 0x0FB3, 0x030C, 0x0FB4, + 0x0306, 0x0FB6, 0x0300, 0x0FB7, 0x02FA, 0x0FB8, 0x02F3, 0x0FB9, 0x02ED, 0x0FBA, 0x02E7, 0x0FBB, + 0x02E1, 0x0FBD, 0x02DB, 0x0FBE, 0x02D5, 0x0FBF, 0x02CE, 0x0FC0, 0x02C8, 0x0FC1, 0x02C2, 0x0FC2, + 0x02BC, 0x0FC3, 0x02B6, 0x0FC4, 0x02AF, 0x0FC5, 0x02A9, 0x0FC6, 0x02A3, 0x0FC7, 0x029D, 0x0FC8, + 0x0297, 0x0FC9, 0x0290, 0x0FCA, 0x028A, 0x0FCB, 0x0284, 0x0FCC, 0x027E, 0x0FCD, 0x0278, 0x0FCE, + 0x0271, 0x0FCF, 0x026B, 0x0FD0, 0x0265, 0x0FD1, 0x025F, 0x0FD2, 0x0259, 0x0FD3, 0x0252, 0x0FD4, + 0x024C, 0x0FD5, 0x0246, 0x0FD6, 0x0240, 0x0FD7, 0x0239, 0x0FD8, 0x0233, 0x0FD9, 0x022D, 0x0FD9, + 0x0227, 0x0FDA, 0x0221, 0x0FDB, 0x021A, 0x0FDC, 0x0214, 0x0FDD, 0x020E, 0x0FDE, 0x0208, 0x0FDE, + 0x0201, 0x0FDF, 0x01FB, 0x0FE0, 0x01F5, 0x0FE1, 0x01EF, 0x0FE1, 0x01E8, 0x0FE2, 0x01E2, 0x0FE3, + 0x01DC, 0x0FE4, 0x01D6, 0x0FE4, 0x01CF, 0x0FE5, 0x01C9, 0x0FE6, 0x01C3, 0x0FE7, 0x01BD, 0x0FE7, + 0x01B6, 0x0FE8, 0x01B0, 0x0FE9, 0x01AA, 0x0FE9, 0x01A4, 0x0FEA, 0x019D, 0x0FEB, 0x0197, 0x0FEB, + 0x0191, 0x0FEC, 0x018B, 0x0FEC, 0x0184, 0x0FED, 0x017E, 0x0FEE, 0x0178, 0x0FEE, 0x0172, 0x0FEF, + 0x016B, 0x0FEF, 0x0165, 0x0FF0, 0x015F, 0x0FF0, 0x0159, 0x0FF1, 0x0152, 0x0FF1, 0x014C, 0x0FF2, + 0x0146, 0x0FF2, 0x0140, 0x0FF3, 0x0139, 0x0FF3, 0x0133, 0x0FF4, 0x012D, 0x0FF4, 0x0127, 0x0FF5, + 0x0120, 0x0FF5, 0x011A, 0x0FF6, 0x0114, 0x0FF6, 0x010D, 0x0FF7, 0x0107, 0x0FF7, 0x0101, 0x0FF7, + 0x00FB, 0x0FF8, 0x00F4, 0x0FF8, 0x00EE, 0x0FF9, 0x00E8, 0x0FF9, 0x00E2, 0x0FF9, 0x00DB, 0x0FFA, + 0x00D5, 0x0FFA, 0x00CF, 0x0FFA, 0x00C8, 0x0FFB, 0x00C2, 0x0FFB, 0x00BC, 0x0FFB, 0x00B6, 0x0FFB, + 0x00AF, 0x0FFC, 0x00A9, 0x0FFC, 0x00A3, 0x0FFC, 0x009D, 0x0FFC, 0x0096, 0x0FFD, 0x0090, 0x0FFD, + 0x008A, 0x0FFD, 0x0083, 0x0FFD, 0x007D, 0x0FFE, 0x0077, 0x0FFE, 0x0071, 0x0FFE, 0x006A, 0x0FFE, + 0x0064, 0x0FFE, 0x005E, 0x0FFE, 0x0057, 0x0FFF, 0x0051, 0x0FFF, 0x004B, 0x0FFF, 0x0045, 0x0FFF, + 0x003E, 0x0FFF, 0x0038, 0x0FFF, 0x0032, 0x0FFF, 0x002B, 0x0FFF, 0x0025, 0x0FFF, 0x001F, 0x0FFF, + 0x0019, 0x0FFF, 0x0012, 0x0FFF, 0x000C, 0x0FFF, 0x0006, 0x0FFF, +]; + +lazy_static::lazy_static! { + static ref WORD_6A56C8: Vec = init_table(); +} + +fn init_table() -> Vec { + let mut table = Vec::with_capacity(0x10000); + let mut cx: i16 = 0; + let mut dx: i16 = 0; + for _ in 0..0x8000 { + table.push(dx); + wrapping! { + dx -= 1; + cx += 1; + } + table.push(cx); + } + table +} + +struct PcmDecoder { + pcm_data: Vec, + encoded: MemReader, + pcm_size: usize, + extra: u32, + dword_43a214: Vec, + unk_6a16c8: Vec, + /// dword_6996C8 + a2: Vec, + /// dword_69D6C8 + a3: Vec, +} + +impl PcmDecoder { + pub fn new( + mut input: R, + pcm_size: usize, + extra: u32, + mode: Mode, + ) -> Result { + if extra > 3 { + return Err(anyhow::anyhow!("Unsupported PCM extra: {}", extra)); + } + let packed_size = input.read_u32()?; + let pcm_data = vec![0u8; pcm_size + 8192]; + let encoded = match mode { + Mode::Lzss => { + let mut data = vec![0u8; packed_size as usize]; + input.read_exact(&mut data)?; + Self::unpack_v1(&data)? + } + Mode::Zlib => { + let mut decoder = flate2::read::ZlibDecoder::new(input); + let mut data = Vec::new(); + decoder.read_to_end(&mut data)?; + data + } + _ => return Err(anyhow::anyhow!("Unsupported PCM mode: {:?}", mode)), + }; + Ok(Self { + pcm_data, + encoded: MemReader::new(encoded), + pcm_size, + extra, + dword_43a214: vec![0; 0x10], + unk_6a16c8: vec![0; 0x2000], + a2: vec![0; 0x1000], + a3: vec![0; 0x1000], + }) + } + + pub fn unpack(mut self) -> Result> { + let mut reader = MemReaderRef::new(&UNK_43A254); + reader.pos = self.extra as usize * 0x40; + for i in 0..0x10 { + self.dword_43a214[i] = reader.read_i32()?; + } + self.decode_v1()?; + Ok(self.pcm_data) + } + + /// #TODO: FIXME + fn decode_v1(&mut self) -> Result<()> { + let v14 = self.pcm_size as i32 / 2; + let mut v5 = 0; + let mut decoded = 0; + let mut dst_sizea = 0; + while dst_sizea < v14 { + self.sub_4121c0(v5)?; + v5 += 8192; + self.sub_411ab0(12); + let mut v6 = decoded; + let mut v7 = 0; + let mut v8 = 0; + let mut v9 = 32; + while v9 > -4064 { + if v7 + dst_sizea < v14 { + let mut v11; + if v9 > 0 && 0 != dst_sizea { + let v10 = (v7 as u32 * self.a2[v8 as usize] as u32) as i64 + + (v9 as i32 + * (i16::from_le_bytes([ + self.pcm_data[v6 as usize], + self.pcm_data[v6 as usize + 1], + ]) as i32)) as i64; + v11 = (((v10 >> 32) & 0x1F) as i32 + v10 as i32) >> 5; + } else { + v11 = self.a2[v8 as usize]; + } + if v11 > 32767 { + v11 = 32767; + } else if v11 < -32768 { + v11 = -32768; + } + let data = (v11 as i16).to_le_bytes(); + self.pcm_data[v6 as usize] = data[0]; + self.pcm_data[v6 as usize + 1] = data[1]; + } + v7 += 1; + v6 += 2; + v8 += 1; + v9 -= 1; + } + decoded += 8128; + dst_sizea += 4064; + } + Ok(()) + } + + fn sub_4121c0(&mut self, a1: i32) -> Result<()> { + let mut v1 = a1; + let mut v5 = 1; + let mut v3 = 0; + while v3 < 0x1000 { + self.unk_6a16c8[v5 as usize] = self.encoded.cpeek_u8_at(v1 as usize)?; + v1 += 1; + v5 += 2; + v3 += 1; + } + v5 = 0; + let mut v6 = 0; + while v6 < 0x800 { + let v7 = self.encoded.cpeek_u8_at(v1 as usize + 0x800)?; + let v8 = self.encoded.cpeek_u8_at(v1 as usize)?; + self.unk_6a16c8[v5 as usize] = (v7 >> 4) | (v8 & 0xF0); + self.unk_6a16c8[v5 as usize + 2] = (v8 << 4) | (v7 & 0x0F); + v5 += 4; + v6 += 1; + } + let mut v9 = 0; + v5 = 0; + let mut v11 = 0; + while v11 < 32768 { + let result = self.dword_43a214[v11 as usize / 0x1000]; + let i1 = u16::from_le_bytes([ + self.unk_6a16c8[v5 as usize], + self.unk_6a16c8[v5 as usize + 1], + ]) as i32; + let i2 = u16::from_le_bytes([ + self.unk_6a16c8[v5 as usize + 2], + self.unk_6a16c8[v5 as usize + 3], + ]) as i32; + self.a2[v9 as usize] = result * WORD_6A56C8[i1 as usize] as i32; + self.a3[v9 as usize] = result * WORD_6A56C8[i2 as usize] as i32; + v9 += 1; + v5 += 4; + v11 += 16; + } + let mut i = v9; + while i < 4096 { + self.a2[i] = 0; + self.a3[i] = 0; + i += 1; + } + Ok(()) + } + + fn sub_411ab0(&mut self, a1: i32) { + let mut v4 = 1 << a1; + let mut v5 = 1; + let mut v68 = 1; + let mut v6 = 1 << a1; + let v79 = 1 << a1; + if a1 >= 3 { + let mut v7 = v4 >> 1; + let mut v59 = a1 - 2; + loop { + let v63 = v4; + let v82 = DWORD_43A358[v5 as usize * 2]; + let v66 = v7; + let mut v8 = v7 >> 1; + let v62 = v7 >> 1; + let v80 = DWORD_43A358[1 + 2 * v5 as usize]; + let mut v77 = 0; + if v6 > 0 { + let mut v73 = 0; + let mut v69 = v8; + let mut v75 = v7; + let v9 = v8 + 1; + let v10 = v7 + v8; + let mut v64 = v9; + let mut v11 = 1; + let mut v12 = v10 + 1; + let mut v71 = v10; + let mut v13 = v7 + 1; + loop { + let v14 = self.a2[v75 as usize]; + let v15 = self.a2[v73 as usize]; + let v16 = self.a3[v11 as usize - 1] - self.a3[v13 as usize - 1]; + self.a2[v73 as usize] += self.a2[v75 as usize]; + self.a3[v11 as usize - 1] += self.a3[v13 as usize - 1]; + self.a2[v75 as usize] = v15 - v14; + self.a3[v13 as usize - 1] = v16; + let v17 = self.a2[v13 as usize]; + let v18 = self.a2[v11 as usize] - v17; + let v19 = self.a3[v11 as usize] - self.a3[v13 as usize]; + self.a2[v11 as usize] += v17; + self.a3[v11 as usize] += self.a3[v13 as usize]; + self.a2[v13 as usize] = (((v18 as i64 * v82 as i64) as u64 >> 12) + + ((v19 as i64 * v80 as i64) as u64 >> 12)) + as i32; + self.a3[v13 as usize] = (((v19 as i64 * v82 as i64) as u64 >> 12) + - ((v18 as i64 * v80 as i64) as u64 >> 12)) + as i32; + let v20 = self.a2[v69 as usize] - self.a2[v71 as usize]; + let v21 = v64; + let v22 = self.a3[v64 as usize - 1] - self.a3[v12 as usize - 1]; + self.a2[v69 as usize] += self.a2[v71 as usize]; + self.a3[v21 as usize - 1] += self.a3[v12 as usize - 1]; + self.a2[v71 as usize] = v22; + self.a3[v12 as usize - 1] = -v20; + let v23 = self.a2[v12 as usize]; + let v24 = self.a2[v64 as usize] - v23; + let v25 = self.a3[v64 as usize] - self.a3[v12 as usize]; + self.a2[v21 as usize] += v23; + self.a3[v21 as usize] += self.a3[v12 as usize]; + self.a2[v12 as usize] = (((v25 as i64 * v82 as i64) as u64 >> 12) + - ((v24 as i64 * v80 as i64) as u64 >> 12)) + as i32; + self.a3[v12 as usize] = (-((((v24 as i64 * v82 as i64) as u64 >> 12) + + ((v25 as i64 * v80 as i64) as u64 >> 12)) + as i64)) as i32; + v13 += v63; + v75 += v63; + v11 += v63; + v73 += v63; + v12 += v63; + v71 += v63; + v77 += v63; + v69 += v63; + v64 += v63; + if v77 >= v79 { + break; + } + } + v8 = v62; + v5 = v68; + v7 = v66; + v6 = 1 << a1; + } + if v8 > 2 { + let mut v70 = 2; + let mut v72 = v7 + 2; + let mut v74 = v8 + 2; + let mut v27 = 1 + 4 * v5; + let mut v60 = v8 - 2; + let mut v76 = v8 + 2 + v7; + loop { + let v83 = DWORD_43A358[v27 as usize - 1]; + let v81 = DWORD_43A358[v27 as usize]; + let mut v78 = 0; + if v6 > 0 { + let mut v28 = v70; + let mut v29 = v72; + let mut v65 = v74; + let mut v85 = v76; + loop { + let v31 = self.a2[v29 as usize]; + let v32 = self.a2[v28 as usize] - v31; + let v33 = self.a3[v28 as usize] - self.a3[v29 as usize]; + self.a2[v28 as usize] += v31; + self.a3[v28 as usize] += self.a3[v29 as usize]; + self.a2[v29 as usize] = (((v32 as i64 * v83 as i64) as u64 >> 12) + + ((v33 as i64 * v81 as i64) as u64 >> 12)) + as i32; + self.a3[v29 as usize] = (((v33 as i64 * v83 as i64) as u64 >> 12) + - ((v32 as i64 * v81 as i64) as u64 >> 12)) + as i32; + let v34 = self.a2[v65 as usize] - self.a2[v85 as usize]; + let v35 = self.a3[v65 as usize] - self.a3[v85 as usize]; + self.a2[v65 as usize] += self.a2[v85 as usize]; + self.a3[v65 as usize] += self.a3[v85 as usize]; + self.a2[v85 as usize] = (((v35 as i64 * v83 as i64) as u64 >> 12) + - ((v34 as i64 * v81 as i64) as u64 >> 12)) + as i32; + self.a3[v85 as usize] = + (-((((v34 as i64 * v83 as i64) as u64 >> 12) + + ((v35 as i64 * v81 as i64) as u64 >> 12)) + as i64)) as i32; + v29 += v63; + v85 += v63; + v28 += v63; + v65 += v63; + v78 += v63; + if v78 >= v79 { + break; + } + } + v5 = v68; + v6 = 1 << a1; + } + v27 += 2 * v5; + v70 += 1; + v72 += 1; + v74 += 1; + v76 += 1; + v60 -= 1; + if v60 == 0 { + break; + } + } + } + v68 = 2 * v5; + v59 -= 1; + if v59 == 0 { + break; + } + v7 = v62; + v5 *= 2; + v4 = v66; + } + } + if !(a1 < 2 || v6 <= 0) { + let mut v37 = 1; + let mut v38 = 3; + let mut v88 = (v6 as u32 + 3) >> 2; + loop { + let v39 = self.a2[v37 as usize - 1]; + let v40 = self.a2[v37 as usize + 1]; + let v41 = self.a3[v38 as usize - 3] - self.a3[v38 as usize - 1]; + self.a2[v37 as usize - 1] = v40 + v39; + v37 += 4; + self.a3[v38 as usize - 3] += self.a3[v38 as usize - 1]; + self.a2[v37 as usize - 3] = v39 - v40; + self.a3[v38 as usize - 1] = v41; + let v42 = self.a2[v38 as usize]; + let v43 = self.a3[v38 as usize - 2] - self.a3[v38 as usize]; + v38 += 4; + let v44 = self.a2[v37 as usize - 4] - v42; + self.a2[v37 as usize - 4] += v42; + self.a3[v38 as usize - 6] += self.a3[v38 as usize - 4]; + self.a2[v38 as usize - 4] = v43; + self.a3[v38 as usize - 4] = -v44; + v88 -= 1; + if v88 == 0 { + break; + } + } + v6 = v79; + } + let mut v45 = 0; + if v6 > 0 { + let mut v47 = 1; + let mut v89 = (v79 as u32 + 1) >> 1; + loop { + let v48 = self.a2[v47 as usize]; + let v49 = self.a3[v47 as usize - 1] - self.a3[v47 as usize]; + let v50 = self.a2[v45 as usize] - v48; + v47 += 2; + self.a2[v45 as usize] += v48; + v45 += 2; + self.a3[v47 as usize - 3] += self.a3[v47 as usize - 2]; + self.a2[v47 as usize - 2] = v50; + self.a3[v47 as usize - 2] = v49; + v89 -= 1; + if v89 == 0 { + break; + } + } + v45 = 0; + v6 = v79; + } + let mut v51 = 0; + let mut result = v6 / 2; + let v67 = v6 / 2; + let mut v90 = 1; + if v6 - 1 > 1 { + let mut v54 = 1; + loop { + while result <= v51 { + v51 -= result; + result /= 2; + } + v51 += result; + if v90 < v51 { + let v55 = self.a2[(v45 + v51) as usize]; + self.a2[(v45 + v51) as usize] = self.a2[v54 as usize]; + self.a2[v54 as usize] = v55; + let v56 = self.a3[v51 as usize]; + self.a3[v51 as usize] = self.a3[v54 as usize]; + self.a3[v54 as usize] = v56; + } + v54 += 1; + // result = v79 - 1; + v90 += 1; + if v90 >= v79 - 1 { + break; + } + result = v67; + } + v6 = v79; + } + while v6 > 0 { + let mut eax = self.a2[v45 as usize] << 4; + let edx = (((eax as i64) >> 32) & 0x3FFF) as i32; + eax += edx; + self.a2[v45 as usize] = eax >> 14; + v45 += 1; + v6 -= 1; + } + } + + fn unpack_v1(input: &[u8]) -> Result> { + let packed_size = input.len(); + let mut flag = 0; + let mut src = 0; + let mut output = vec![0u8]; + while src < packed_size { + flag >>= 1; + if (flag & 0x100) == 0 { + flag = input[src] as i32 | 0xFF00; + src += 1; + } + if (flag & 1) != 0 { + output.push(input[src]); + src += 1; + } else { + if src >= packed_size { + break; + } + let mut offset; + let count; + let ctl = input[src] as i32; + src += 1; + if ctl >= 0xc0 { + offset = input[src] as i32 | ((ctl & 3) << 8); + src += 1; + count = 4 + ((ctl >> 2) & 0xF); + } else if ctl & 0x80 != 0 { + offset = ctl & 0x1F; + count = 2 + ((ctl >> 5) & 3); + if offset == 0 { + offset = input[src] as i32; + src += 1; + } + } else if ctl == 0x7F { + count = 2 + u16::from_le_bytes([input[src], input[src + 1]]) as i32; + src += 2; + offset = u16::from_le_bytes([input[src], input[src + 1]]) as i32; + src += 2; + } else { + offset = u16::from_le_bytes([input[src], input[src + 1]]) as i32; + src += 2; + count = ctl + 4; + } + let dst = output.len(); + offset = dst as i32 - offset; + output.resize(dst + count as usize, 0); + output.copy_overlapped(offset as usize, dst, count as usize); + } + } + Ok(output) + } +} diff --git a/src/scripts/circus/mod.rs b/src/scripts/circus/mod.rs index 0ea7903..98c00ff 100644 --- a/src/scripts/circus/mod.rs +++ b/src/scripts/circus/mod.rs @@ -1,5 +1,7 @@ #[cfg(feature = "circus-arc")] pub mod archive; +#[cfg(feature = "circus-audio")] +pub mod audio; #[cfg(feature = "circus-img")] pub mod image; mod info; diff --git a/src/scripts/mod.rs b/src/scripts/mod.rs index ed02228..4e4a033 100644 --- a/src/scripts/mod.rs +++ b/src/scripts/mod.rs @@ -86,6 +86,8 @@ lazy_static::lazy_static! { Box::new(cat_system::cstl::CstlScriptBuilder::new()), #[cfg(feature = "circus-arc")] Box::new(circus::archive::pck::PckArchiveBuilder::new()), + #[cfg(feature = "circus-audio")] + Box::new(circus::audio::pcm::PcmBuilder::new()), ]; pub static ref ALL_EXTS: Vec = BUILDER.iter().flat_map(|b| b.extensions()).map(|s| s.to_string()).collect(); diff --git a/src/types.rs b/src/types.rs index c745ea6..a13374b 100644 --- a/src/types.rs +++ b/src/types.rs @@ -312,6 +312,9 @@ pub enum ScriptType { #[cfg(feature = "circus-arc")] /// Circus PCK archive CircusPck, + #[cfg(feature = "circus-audio")] + /// Circus PCM audio + CircusPcm, #[cfg(feature = "circus-img")] /// Circus CRX Image CircusCrx, diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 54fb52e..22a0e6b 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -13,6 +13,8 @@ pub mod files; pub mod img; pub mod macros; pub mod name_replacement; +#[cfg(feature = "utils-pcm")] +pub mod pcm; #[cfg(feature = "utils-str")] pub mod str; pub mod struct_pack; diff --git a/src/utils/pcm.rs b/src/utils/pcm.rs new file mode 100644 index 0000000..1b142fd --- /dev/null +++ b/src/utils/pcm.rs @@ -0,0 +1,48 @@ +use crate::ext::io::*; +use crate::types::*; +use crate::utils::struct_pack::*; +use anyhow::Result; +use msg_tool_macro::*; +use std::io::{Read, Seek, Write}; + +#[derive(Debug, StructPack, StructUnpack)] +pub struct PcmFormat { + format_tag: u16, + channels: u16, + sample_rate: u32, + average_bytes_per_second: u32, + block_align: u16, + bits_per_sample: u16, +} + +pub fn write_pcm( + format: &PcmFormat, + mut reader: R, + mut writer: W, +) -> Result<()> { + writer.write_all(b"RIFF")?; + let mut total_size = 0x24u32; + writer.write_u32(0)?; // Placeholder for total size + writer.write_all(b"WAVE")?; + writer.write_all(b"fmt ")?; + writer.write_u32(16)?; // Size of fmt chunk + format.pack(&mut writer, false, Encoding::Utf8)?; + writer.write_all(b"data")?; + let mut data_size = 0u32; + writer.write_u32(0)?; // Placeholder for data size + let mut buffer = [0u8; 4096]; + loop { + let bytes_read = reader.read(&mut buffer)?; + if bytes_read == 0 { + break; + } + writer.write_all(&buffer[..bytes_read])?; + data_size += bytes_read as u32; + } + total_size += data_size; + writer.seek(std::io::SeekFrom::Start(4))?; + writer.write_u32(total_size)?; + writer.seek(std::io::SeekFrom::Start(40))?; + writer.write_u32(data_size)?; + Ok(()) +} diff --git a/src/utils/struct_pack.rs b/src/utils/struct_pack.rs index 2e1d0c4..765ccd1 100644 --- a/src/utils/struct_pack.rs +++ b/src/utils/struct_pack.rs @@ -47,3 +47,19 @@ impl StructPack for bool { Ok(()) } } + +impl StructPack for Option { + fn pack(&self, writer: &mut W, big: bool, encoding: Encoding) -> Result<()> { + if let Some(value) = self { + value.pack(writer, big, encoding)?; + } + Ok(()) + } +} + +impl StructUnpack for Option { + fn unpack(reader: R, big: bool, encoding: Encoding) -> Result { + let value = T::unpack(reader, big, encoding)?; + Ok(Some(value)) + } +}