diff options
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, +} |