unity_asset_decode/audio/
formats.rs

1//! Audio format definitions
2//!
3//! This module defines Unity audio formats and their capabilities.
4//! Inspired by UnityPy audio format handling and unity-rs simplicity.
5
6use serde::{Deserialize, Serialize};
7
8/// Unity audio compression formats
9///
10/// This enum represents all audio compression formats supported by Unity.
11/// Values match Unity's internal AudioCompressionFormat enum.
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
13#[repr(i32)]
14pub enum AudioCompressionFormat {
15    /// Uncompressed PCM audio
16    PCM = 0,
17    /// Ogg Vorbis compression
18    Vorbis = 1,
19    /// ADPCM compression
20    ADPCM = 2,
21    /// MP3 compression
22    MP3 = 3,
23    /// PlayStation VAG format
24    VAG = 4,
25    /// PlayStation HEVAG format
26    HEVAG = 5,
27    /// Xbox XMA format
28    XMA = 6,
29    /// AAC compression
30    AAC = 7,
31    /// GameCube ADPCM
32    GCADPCM = 8,
33    /// PlayStation ATRAC9
34    ATRAC9 = 9,
35    /// Unknown format
36    #[default]
37    Unknown = -1,
38}
39
40impl From<i32> for AudioCompressionFormat {
41    fn from(value: i32) -> Self {
42        match value {
43            0 => AudioCompressionFormat::PCM,
44            1 => AudioCompressionFormat::Vorbis,
45            2 => AudioCompressionFormat::ADPCM,
46            3 => AudioCompressionFormat::MP3,
47            4 => AudioCompressionFormat::VAG,
48            5 => AudioCompressionFormat::HEVAG,
49            6 => AudioCompressionFormat::XMA,
50            7 => AudioCompressionFormat::AAC,
51            8 => AudioCompressionFormat::GCADPCM,
52            9 => AudioCompressionFormat::ATRAC9,
53            _ => AudioCompressionFormat::Unknown,
54        }
55    }
56}
57
58/// FMOD sound type enumeration
59///
60/// Used for identifying audio format types in FMOD-based Unity versions.
61#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
62#[repr(i32)]
63pub enum FMODSoundType {
64    #[default]
65    Unknown = 0,
66    ACC = 1,
67    AIFF = 2,
68    ASF = 3,
69    DLS = 4,
70    FLAC = 5,
71    FSB = 6,
72    IT = 7,
73    MIDI = 8,
74    MOD = 9,
75    MPEG = 10,
76    OGG = 11,
77    PLAYLIST = 12,
78    RAW = 13,
79    S3M = 14,
80    USER = 15,
81    WAV = 16,
82    XM = 17,
83    XMA = 18,
84    AUDIOQUEUE = 19,
85    AT9 = 20,
86    VORBIS = 21,
87    MediaFoundation = 22,
88    MediaCodec = 23,
89    FADPCM = 24,
90    OPUS = 25,
91}
92
93impl From<i32> for FMODSoundType {
94    fn from(value: i32) -> Self {
95        match value {
96            1 => FMODSoundType::ACC,
97            2 => FMODSoundType::AIFF,
98            3 => FMODSoundType::ASF,
99            4 => FMODSoundType::DLS,
100            5 => FMODSoundType::FLAC,
101            6 => FMODSoundType::FSB,
102            7 => FMODSoundType::IT,
103            8 => FMODSoundType::MIDI,
104            9 => FMODSoundType::MOD,
105            10 => FMODSoundType::MPEG,
106            11 => FMODSoundType::OGG,
107            12 => FMODSoundType::PLAYLIST,
108            13 => FMODSoundType::RAW,
109            14 => FMODSoundType::S3M,
110            15 => FMODSoundType::USER,
111            16 => FMODSoundType::WAV,
112            17 => FMODSoundType::XM,
113            18 => FMODSoundType::XMA,
114            19 => FMODSoundType::AUDIOQUEUE,
115            20 => FMODSoundType::AT9,
116            21 => FMODSoundType::VORBIS,
117            22 => FMODSoundType::MediaFoundation,
118            23 => FMODSoundType::MediaCodec,
119            24 => FMODSoundType::FADPCM,
120            25 => FMODSoundType::OPUS,
121            _ => FMODSoundType::Unknown,
122        }
123    }
124}
125
126/// Audio format information and capabilities
127#[derive(Debug, Clone, Serialize, Deserialize)]
128pub struct AudioFormatInfo {
129    pub name: String,
130    pub extension: String,
131    pub compressed: bool,
132    pub lossy: bool,
133    pub supported: bool,
134}
135
136impl Default for AudioFormatInfo {
137    fn default() -> Self {
138        Self {
139            name: "Unknown".to_string(),
140            extension: "bin".to_string(),
141            compressed: false,
142            lossy: false,
143            supported: false,
144        }
145    }
146}
147
148impl AudioCompressionFormat {
149    /// Get format information
150    pub fn info(&self) -> AudioFormatInfo {
151        match self {
152            AudioCompressionFormat::PCM => AudioFormatInfo {
153                name: "PCM".to_string(),
154                extension: "wav".to_string(),
155                compressed: false,
156                lossy: false,
157                supported: true,
158            },
159            AudioCompressionFormat::Vorbis => AudioFormatInfo {
160                name: "Ogg Vorbis".to_string(),
161                extension: "ogg".to_string(),
162                compressed: true,
163                lossy: true,
164                supported: true,
165            },
166            AudioCompressionFormat::ADPCM => AudioFormatInfo {
167                name: "ADPCM".to_string(),
168                extension: "wav".to_string(),
169                compressed: true,
170                lossy: true,
171                supported: true,
172            },
173            AudioCompressionFormat::MP3 => AudioFormatInfo {
174                name: "MP3".to_string(),
175                extension: "mp3".to_string(),
176                compressed: true,
177                lossy: true,
178                supported: true,
179            },
180            AudioCompressionFormat::AAC => AudioFormatInfo {
181                name: "AAC".to_string(),
182                extension: "aac".to_string(),
183                compressed: true,
184                lossy: true,
185                supported: true,
186            },
187            AudioCompressionFormat::VAG => AudioFormatInfo {
188                name: "PlayStation VAG".to_string(),
189                extension: "vag".to_string(),
190                compressed: true,
191                lossy: true,
192                supported: false, // Requires specialized decoder
193            },
194            AudioCompressionFormat::HEVAG => AudioFormatInfo {
195                name: "PlayStation HEVAG".to_string(),
196                extension: "vag".to_string(),
197                compressed: true,
198                lossy: true,
199                supported: false, // Requires specialized decoder
200            },
201            AudioCompressionFormat::XMA => AudioFormatInfo {
202                name: "Xbox XMA".to_string(),
203                extension: "xma".to_string(),
204                compressed: true,
205                lossy: true,
206                supported: false, // Requires specialized decoder
207            },
208            AudioCompressionFormat::GCADPCM => AudioFormatInfo {
209                name: "GameCube ADPCM".to_string(),
210                extension: "adp".to_string(),
211                compressed: true,
212                lossy: true,
213                supported: false, // Requires specialized decoder
214            },
215            AudioCompressionFormat::ATRAC9 => AudioFormatInfo {
216                name: "PlayStation ATRAC9".to_string(),
217                extension: "at9".to_string(),
218                compressed: true,
219                lossy: true,
220                supported: false, // Requires specialized decoder
221            },
222            AudioCompressionFormat::Unknown => AudioFormatInfo::default(),
223        }
224    }
225
226    /// Check if format is supported for decoding
227    pub fn is_supported(&self) -> bool {
228        self.info().supported
229    }
230
231    /// Check if format is compressed
232    pub fn is_compressed(&self) -> bool {
233        self.info().compressed
234    }
235
236    /// Check if format is lossy
237    pub fn is_lossy(&self) -> bool {
238        self.info().lossy
239    }
240
241    /// Get recommended file extension
242    pub fn extension(&self) -> &str {
243        match self {
244            AudioCompressionFormat::PCM | AudioCompressionFormat::ADPCM => "wav",
245            AudioCompressionFormat::Vorbis => "ogg",
246            AudioCompressionFormat::MP3 => "mp3",
247            AudioCompressionFormat::AAC => "aac",
248            AudioCompressionFormat::VAG | AudioCompressionFormat::HEVAG => "vag",
249            AudioCompressionFormat::XMA => "xma",
250            AudioCompressionFormat::GCADPCM => "adp",
251            AudioCompressionFormat::ATRAC9 => "at9",
252            AudioCompressionFormat::Unknown => "bin",
253        }
254    }
255
256    /// Get MIME type for the format
257    pub fn mime_type(&self) -> &str {
258        match self {
259            AudioCompressionFormat::PCM | AudioCompressionFormat::ADPCM => "audio/wav",
260            AudioCompressionFormat::Vorbis => "audio/ogg",
261            AudioCompressionFormat::MP3 => "audio/mpeg",
262            AudioCompressionFormat::AAC => "audio/aac",
263            _ => "application/octet-stream",
264        }
265    }
266}