aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock36
-rw-r--r--Cargo.toml1
-rw-r--r--src/classes/audio_clip.rs3
-rw-r--r--src/fmod.rs114
4 files changed, 128 insertions, 26 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 67645ec..a5b1bca 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -601,6 +601,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8"
[[package]]
+name = "lewton"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "777b48df9aaab155475a83a7df3070395ea1ac6902f5cd062b8f2b028075c030"
+dependencies = [
+ "byteorder 1.5.0",
+ "ogg",
+ "tinyvec",
+]
+
+[[package]]
name = "libc"
version = "0.2.171"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -770,6 +781,15 @@ dependencies = [
]
[[package]]
+name = "ogg"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6951b4e8bf21c8193da321bcce9c9dd2e13c858fe078bf9054a288b419ae5d6e"
+dependencies = [
+ "byteorder 1.5.0",
+]
+
+[[package]]
name = "once_cell"
version = "1.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1191,6 +1211,21 @@ dependencies = [
]
[[package]]
+name = "tinyvec"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71"
+dependencies = [
+ "tinyvec_macros",
+]
+
+[[package]]
+name = "tinyvec_macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
+
+[[package]]
name = "toml"
version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1249,6 +1284,7 @@ dependencies = [
"glam",
"humansize",
"image",
+ "lewton",
"log",
"lz4_flex",
"lzma",
diff --git a/Cargo.toml b/Cargo.toml
index 702632a..ebde4a3 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -21,3 +21,4 @@ glam = { version = "0.30.0", features = ["serde"] }
texpresso = "2.0.1"
image = "0.25.5"
texture2ddecoder = { git = "https://github.com/UniversalGameExtraction/texture2ddecoder", rev = "d2b4653fda298f1da39917da86bc509b17879808" }
+lewton = "0.10.2"
diff --git a/src/classes/audio_clip.rs b/src/classes/audio_clip.rs
index a3e8d22..8f027ad 100644
--- a/src/classes/audio_clip.rs
+++ b/src/classes/audio_clip.rs
@@ -52,7 +52,8 @@ impl AudioClip {
let mut bank = FmodSoundBank::open(Cursor::new(data))?;
// Ok(buf.into_inner())
for i in 0..bank.streams.len() {
- let data = bank.read_stream(i)?;
+ let data = bank.read_stream_raw(i)?;
+ // eprintln!("{data:?}")
}
Ok(Vec::new())
diff --git a/src/fmod.rs b/src/fmod.rs
index f0e7b4c..8713a56 100644
--- a/src/fmod.rs
+++ b/src/fmod.rs
@@ -1,7 +1,11 @@
use crate::helper::ReadExt;
-use anyhow::{Ok, Result, bail};
+use anyhow::{Result, bail};
+use lewton::{
+ audio::PreviousWindowRight,
+ header::{IdentHeader, SetupHeader, read_header_ident},
+};
use log::debug;
-use std::io::{Cursor, Read, Seek, SeekFrom};
+use std::io::{Cursor, Read, Seek, SeekFrom, Write};
pub struct FmodSoundBank<T> {
inner: T,
@@ -12,6 +16,7 @@ pub struct FmodSoundBank<T> {
pub struct StreamInfo {
header: StreamHeader,
+ channels: usize,
}
struct FsbHeader {
@@ -95,18 +100,22 @@ impl<T: Read + Seek> FmodSoundBank<T> {
for _ in 0..header.num_streams {
let header = StreamHeader::from_packed(file.read_u64_le()?)?;
- eprintln!("{header:?}");
let mut next = header.next_chunk;
+ let mut info = StreamInfo {
+ channels: header.channels as usize,
+ header,
+ };
while next {
let chunk = ChunkHeader::from_packed(file.read_u32_le()?)?;
-
match chunk.kind {
+ ChunkKind::Channels => {
+ info.channels = file.read_u64_le()? as usize;
+ }
k => todo!("chunk kind {k:?}"),
}
-
next = chunk.next_chunk;
}
- streams.push(StreamInfo { header });
+ streams.push(info);
}
if header.name_table_size != 0 {
@@ -132,22 +141,33 @@ impl<T: Read + Seek> FmodSoundBank<T> {
inner: file,
})
}
- pub fn read_stream(&mut self, n: usize) -> Result<()> {
+ fn stream_read_range(&self, n: usize) -> Result<(u64, u64)> {
let info = &self.streams[n];
-
- let start = info.header.data_offset;
+ let start = info.header.data_offset as u64;
let end = self
.streams
.get(n + 1)
- .map_or(self.header.data_size, |s| s.header.data_offset);
+ .map_or(self.header.data_size, |s| s.header.data_offset) as u64;
- let mut data = vec![0; (end - start) as usize];
- debug!("{} {}", start, end);
- self.inner
- .seek(SeekFrom::Start(start as u64 + self.data_base_offset))?;
+ Ok((start + self.data_base_offset, end - start))
+ }
+ pub fn read_stream_raw(&mut self, n: usize) -> Result<Vec<u8>> {
+ let (offset, size) = self.stream_read_range(n)?;
+ let mut data = vec![0; size as usize];
+ self.inner.seek(SeekFrom::Start(offset))?;
self.inner.read_exact(&mut data)?;
- Ok(())
+ Ok(data)
+ }
+ pub fn read_stream(&mut self, n: usize) -> Result<Vec<f32>> {
+ let (offset, size) = self.stream_read_range(n)?;
+
+ match self.header.format {
+ FsbFormat::Vorbis => {}
+ _ => todo!(),
+ }
+
+ Ok(Vec::new())
}
}
@@ -161,16 +181,17 @@ struct StreamHeader {
}
impl StreamHeader {
const MASKS: &[u64] = &[
- 0b1000000000000000000000000000000000000000000000000000000000000000,
- 0b0111100000000000000000000000000000000000000000000000000000000000,
- 0b0000011000000000000000000000000000000000000000000000000000000000,
- 0b0000000111111111111111111111111111000000000000000000000000000000,
- 0b0000000000000000000000000000000000111111111111111111111111111111,
+ 0b0000000000000000000000000000000000000000000000000000000000000001,
+ 0b0000000000000000000000000000000000000000000000000000000000011110,
+ 0b0000000000000000000000000000000000000000000000000000000001100000,
+ 0b0000000000000000000000000000001111111111111111111111111110000000,
+ 0b1111111111111111111111111111110000000000000000000000000000000000,
];
pub fn from_packed(x: u64) -> Result<Self> {
- let next_chunk = x & Self::MASKS[0] != 0;
+ eprintln!("{x:032b}");
+ let next_chunk = (x & Self::MASKS[0]) != 0;
let samplerate_raw = (x & Self::MASKS[1]) >> Self::MASKS[1].trailing_zeros();
- let channels_raw = x & Self::MASKS[2] >> Self::MASKS[2].trailing_zeros();
+ let channels_raw = (x & Self::MASKS[2]) >> Self::MASKS[2].trailing_zeros();
let data_offset = (x & Self::MASKS[3]) >> Self::MASKS[3].trailing_zeros();
let samples = x & Self::MASKS[4];
Ok(Self {
@@ -202,6 +223,7 @@ impl StreamHeader {
}
}
+#[derive(Debug)]
struct ChunkHeader {
next_chunk: bool,
size: u32,
@@ -209,9 +231,9 @@ struct ChunkHeader {
}
impl ChunkHeader {
const MASKS: &[u32] = &[
- 0b10000000000000000000000000000000,
- 0b01111111111111111111111110000000,
- 0b00000000000000000000000001111111,
+ 0b00000000000000000000000000000001,
+ 0b00000001111111111111111111111110,
+ 0b11111110000000000000000000000000,
];
pub fn from_packed(x: u32) -> Result<Self> {
let next_chunk = x & Self::MASKS[0] != 0;
@@ -250,3 +272,45 @@ impl ChunkKind {
}
}
}
+
+pub struct VorbisStreamReader<T> {
+ inner: T,
+ ident: IdentHeader,
+ setup: SetupHeader,
+ previous_window: PreviousWindowRight,
+}
+impl<T: Read> VorbisStreamReader<T> {
+ fn read_packet(&mut self) -> Result<Vec<u8>> {
+ let packet_size = self.inner.read_u16_le()?;
+ let mut buf = vec![0; packet_size as usize];
+ self.inner.read_exact(&mut buf)?;
+ Ok(buf)
+ }
+ fn decode_packet(&mut self) -> Result<Vec<Vec<f32>>> {
+ let packet = self.read_packet()?;
+ Ok(lewton::audio::read_audio_packet_generic(
+ &self.ident,
+ &self.setup,
+ &packet,
+ &mut self.previous_window,
+ )?)
+ }
+}
+
+fn make_vorbis_ident(channels: u8, sample_rate: u32) -> Result<IdentHeader> {
+ let mut packet = Vec::new();
+ packet.write_all(&[1])?;
+ packet.write_all(b"vorbis")?;
+ packet.write_all(&0u32.to_le_bytes())?;
+ packet.write_all(&[channels])?;
+ packet.write_all(&sample_rate.to_le_bytes())?;
+ packet.write_all(&0u32.to_le_bytes())?;
+ packet.write_all(&0u32.to_le_bytes())?;
+ packet.write_all(&0u32.to_le_bytes())?;
+ packet.write_all(&[(8 << 4) | 11])?;
+ packet.write_all(&1u8.to_le_bytes())?;
+ Ok(read_header_ident(&packet)?)
+}
+fn make_vorbis_setup() -> Result<SetupHeader> {
+ todo!()
+}