aboutsummaryrefslogtreecommitdiff
path: root/src/classes/audio_clip.rs
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-03-23 20:18:10 +0100
committermetamuffin <metamuffin@disroot.org>2025-03-23 20:18:10 +0100
commitd5aa53fafed0dbf6d43943e3b88b99693821e5cd (patch)
tree1facf5a2e9d83fa018b03636f03c641ec1a1c46a /src/classes/audio_clip.rs
parent756664281e6f8c37653e8769890962e8bab933e9 (diff)
downloadunity-tools-d5aa53fafed0dbf6d43943e3b88b99693821e5cd.tar
unity-tools-d5aa53fafed0dbf6d43943e3b88b99693821e5cd.tar.bz2
unity-tools-d5aa53fafed0dbf6d43943e3b88b99693821e5cd.tar.zst
audio clips
Diffstat (limited to 'src/classes/audio_clip.rs')
-rw-r--r--src/classes/audio_clip.rs93
1 files changed, 93 insertions, 0 deletions
diff --git a/src/classes/audio_clip.rs b/src/classes/audio_clip.rs
new file mode 100644
index 0000000..18bd297
--- /dev/null
+++ b/src/classes/audio_clip.rs
@@ -0,0 +1,93 @@
+use super::streamed_resource::StreamedResource;
+use crate::{
+ object::{Value, parser::FromValue},
+ unityfs::UnityFS,
+};
+use anyhow::{Result, anyhow, bail};
+use log::info;
+use serde::Serialize;
+use std::io::{Cursor, Read, Seek};
+
+#[derive(Debug, Serialize)]
+pub struct AudioClip {
+ pub resource: StreamedResource,
+ pub channels: i32,
+ pub ambisonic: bool,
+ pub bits_per_sample: i32,
+ pub compression_format: AudioCompressionFormat,
+ pub frequency: i32,
+ pub is_tracker_format: bool,
+ pub legacy_3d: bool,
+ pub length: f32,
+ pub name: String,
+ pub subsound_index: i32,
+}
+
+impl FromValue for AudioClip {
+ fn from_value(v: Value) -> Result<Self> {
+ let mut fields = v.as_class("AudioClip")?;
+ Ok(AudioClip {
+ resource: fields.field("m_Resource")?,
+ ambisonic: fields.field("m_Ambisonic")?,
+ bits_per_sample: fields.field("m_BitsPerSample")?,
+ compression_format: fields.field("m_CompressionFormat")?,
+ channels: fields.field("m_Channels")?,
+ frequency: fields.field("m_Frequency")?,
+ is_tracker_format: fields.field("m_IsTrackerFormat")?,
+ legacy_3d: fields.field("m_Legacy3D")?,
+ length: fields.field("m_Length")?,
+ name: fields.field("m_Name")?,
+ subsound_index: fields.field("m_SubsoundIndex")?,
+ })
+ }
+}
+
+impl AudioClip {
+ pub fn read_ogg(&self, fs: &UnityFS<impl Read + Seek>) -> Result<Vec<u8>> {
+ let data = self.resource.read(&fs)?;
+ match self.compression_format {
+ AudioCompressionFormat::Vorbis => {
+ info!("reading vorbis FMOD sound bank");
+ let bank = fsbex::Bank::new(Cursor::new(data))?;
+ assert_eq!(bank.format(), fsbex::AudioFormat::Vorbis);
+ assert_eq!(u32::from(bank.num_streams()), 1);
+ let stream = bank.into_iter().next().unwrap();
+
+ let mut buf = Cursor::new(Vec::new());
+ stream.write(&mut buf)?;
+ Ok(buf.into_inner())
+ }
+ x => todo!("audio format {x:?}"),
+ }
+ }
+}
+
+impl FromValue for AudioCompressionFormat {
+ fn from_value(v: Value) -> Result<Self> {
+ let x = v
+ .as_i32()
+ .ok_or(anyhow!("expected i32 AudioCompressionFormat"))?;
+ if x < 10 {
+ Ok(unsafe { std::mem::transmute(x) })
+ } else {
+ bail!("AudioCompressionFormat out of range")
+ }
+ }
+}
+
+#[allow(non_camel_case_types)]
+#[repr(i32)]
+#[derive(Debug, Serialize, PartialEq, Clone, Copy)]
+
+pub enum AudioCompressionFormat {
+ PCM,
+ Vorbis,
+ ADPCM,
+ MP3,
+ PSMVAG,
+ HEVAG,
+ XMA,
+ AAC,
+ GCADPCM,
+ ATRAC9,
+}