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 { 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) -> Result> { 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 { 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, }