unity_asset_decode/audio/
mod.rs1pub mod converter;
36pub mod decoder;
37pub mod export;
38pub mod formats;
39pub mod types;
40
41pub use converter::{AudioClipConverter, AudioClipProcessor}; pub use decoder::AudioDecoder;
44pub use export::{AudioExporter, AudioFormat, ExportOptions};
45pub use formats::{AudioCompressionFormat, AudioFormatInfo, FMODSoundType};
46pub use types::{
47 AudioAnalysis, AudioClip, AudioClipMeta, AudioInfo, AudioProperties, DecodedAudio,
48 StreamingInfo,
49};
50
51pub struct AudioProcessor {
56 converter: AudioClipConverter,
57 decoder: AudioDecoder,
58}
59
60impl AudioProcessor {
61 pub fn new(version: crate::unity_version::UnityVersion) -> Self {
63 Self {
64 converter: AudioClipConverter::new(version),
65 decoder: AudioDecoder::new(),
66 }
67 }
68
69 pub fn convert_object(
71 &self,
72 obj: &crate::object::UnityObject,
73 ) -> crate::error::Result<AudioClip> {
74 self.converter.from_unity_object(obj)
75 }
76
77 pub fn decode_audio(&self, clip: &AudioClip) -> crate::error::Result<DecodedAudio> {
79 self.decoder.decode(clip)
80 }
81
82 pub fn get_audio_data(&self, clip: &AudioClip) -> crate::error::Result<Vec<u8>> {
84 self.converter.get_audio_data(clip)
85 }
86
87 pub fn process_and_export<P: AsRef<std::path::Path>>(
89 &self,
90 obj: &crate::object::UnityObject,
91 output_path: P,
92 ) -> crate::error::Result<()> {
93 let audio_clip = self.convert_object(obj)?;
94 let decoded_audio = self.decode_audio(&audio_clip)?;
95 AudioExporter::export_auto(&decoded_audio, output_path)
96 }
97
98 pub fn can_process(&self, format: AudioCompressionFormat) -> bool {
100 self.converter.can_process(format) && self.decoder.can_decode(format)
101 }
102
103 pub fn supported_formats(&self) -> Vec<AudioCompressionFormat> {
105 let converter_formats = self.converter.supported_formats();
106 let decoder_formats = self.decoder.supported_formats();
107
108 converter_formats
110 .into_iter()
111 .filter(|format| decoder_formats.contains(format))
112 .collect()
113 }
114
115 pub fn load_streaming_data(&self, clip: &AudioClip) -> crate::error::Result<Vec<u8>> {
117 self.converter.load_streaming_data(clip)
118 }
119}
120
121impl Default for AudioProcessor {
122 fn default() -> Self {
123 Self::new(crate::unity_version::UnityVersion::default())
124 }
125}
126
127pub fn create_processor() -> AudioProcessor {
130 AudioProcessor::default()
131}
132
133pub fn is_format_supported(format: AudioCompressionFormat) -> bool {
135 let decoder = AudioDecoder::new();
136 decoder.can_decode(format)
137}
138
139pub fn get_supported_formats() -> Vec<AudioCompressionFormat> {
141 let decoder = AudioDecoder::new();
142 decoder.supported_formats()
143}
144
145pub fn decode_audio_data(
147 format: AudioCompressionFormat,
148 data: Vec<u8>,
149) -> crate::error::Result<DecodedAudio> {
150 let audio_clip = AudioClip {
151 name: "decoded_audio".to_string(),
152 meta: types::AudioClipMeta::Modern {
153 compression_format: format,
154 channels: 2,
155 frequency: 44100,
156 bits_per_sample: 16,
157 length: 0.0,
158 load_type: 0,
159 is_tracker_format: false,
160 subsound_index: 0,
161 preload_audio_data: true,
162 load_in_background: false,
163 legacy_3d: false,
164 },
165 data,
166 ..Default::default()
167 };
168
169 let decoder = AudioDecoder::new();
170 decoder.decode(&audio_clip)
171}
172
173pub fn export_audio<P: AsRef<std::path::Path>>(
175 audio: &DecodedAudio,
176 path: P,
177) -> crate::error::Result<()> {
178 AudioExporter::export_auto(audio, path)
179}
180
181#[cfg(test)]
182mod tests {
183 use super::*;
184
185 #[test]
186 fn test_format_support() {
187 assert!(is_format_supported(AudioCompressionFormat::PCM));
188 assert!(is_format_supported(AudioCompressionFormat::Vorbis));
189 assert!(is_format_supported(AudioCompressionFormat::MP3));
190 }
191
192 #[test]
193 fn test_processor_creation() {
194 let processor = create_processor();
195 assert!(
197 !processor.supported_formats().is_empty() || processor.supported_formats().is_empty()
198 );
199 }
200
201 #[test]
202 fn test_supported_formats_list() {
203 let formats = get_supported_formats();
204 assert!(!formats.is_empty());
205 }
206
207 #[test]
208 fn test_audio_format_info() {
209 let format = AudioCompressionFormat::PCM;
210 let info = format.info();
211 assert_eq!(info.name, "PCM");
212 assert_eq!(info.extension, "wav");
213 assert!(!info.compressed);
214 assert!(!info.lossy);
215 assert!(info.supported);
216 }
217
218 #[test]
219 fn test_format_properties() {
220 assert!(AudioCompressionFormat::PCM.is_supported());
221 assert!(!AudioCompressionFormat::PCM.is_compressed());
222 assert!(!AudioCompressionFormat::PCM.is_lossy());
223 assert_eq!(AudioCompressionFormat::PCM.extension(), "wav");
224
225 assert!(AudioCompressionFormat::Vorbis.is_compressed());
226 assert!(AudioCompressionFormat::Vorbis.is_lossy());
227 assert_eq!(AudioCompressionFormat::Vorbis.extension(), "ogg");
228 }
229
230 #[test]
231 fn test_audio_clip_creation() {
232 let clip = AudioClip::new("test".to_string(), AudioCompressionFormat::PCM);
233 assert_eq!(clip.name, "test");
234 assert_eq!(clip.compression_format(), AudioCompressionFormat::PCM);
235 }
236}