diff options
author | metamuffin <metamuffin@disroot.org> | 2025-03-23 20:18:10 +0100 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2025-03-23 20:18:10 +0100 |
commit | d5aa53fafed0dbf6d43943e3b88b99693821e5cd (patch) | |
tree | 1facf5a2e9d83fa018b03636f03c641ec1a1c46a /src/classes/audio_clip.rs | |
parent | 756664281e6f8c37653e8769890962e8bab933e9 (diff) | |
download | unity-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.rs | 93 |
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, +} |