1pub mod adpcm;
38pub mod pcm;
39mod reader;
40mod writer;
41
42pub use reader::{read_wav, read_wav_from_bytes};
43pub use writer::{
44 write_wav, write_wav_to_vec, write_wav_to_vec_with_options, write_wav_with_options,
45};
46
47use num_enum::{IntoPrimitive, TryFromPrimitive};
48use thiserror::Error;
49
50use crate::binary::{self, DecodeBinary, EncodeBinary};
51
52pub(super) const RIFF_MAGIC: [u8; 4] = *b"RIFF";
53pub(super) const WAVE_MAGIC: [u8; 4] = *b"WAVE";
54pub(super) const FMT_CHUNK_ID: [u8; 4] = *b"fmt ";
55pub(super) const DATA_CHUNK_ID: [u8; 4] = *b"data";
56pub(super) const SFX_MAGIC: [u8; 4] = [0xFF, 0xF3, 0x60, 0xC4];
57pub(super) const SFX_HEADER_SIZE: usize = 470;
58pub(super) const VO_HEADER_SIZE: usize = 20;
59pub(super) const MP3_IN_WAV_RIFF_SIZE: u32 = 50;
60pub(super) const MP3_IN_WAV_HEADER_SIZE: usize = 58;
61pub(super) const DEFAULT_MP3_CHANNELS: u16 = 2;
62pub(super) const DEFAULT_MP3_SAMPLE_RATE: u32 = 44_100;
63pub(super) const DEFAULT_MP3_BITS_PER_SAMPLE: u16 = 16;
64
65#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
67pub enum WavWrapperKind {
68 Standard,
70 SfxHeader,
72 VoHeader,
74 Mp3InWav,
76}
77
78#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
80pub enum WavType {
81 Standard,
83 Vo,
85 Sfx,
87}
88
89#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
91pub enum WavAudioFormat {
92 Wave,
94 Mp3,
96}
97
98#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, IntoPrimitive, TryFromPrimitive)]
100#[repr(u16)]
101pub enum WavEncoding {
102 Pcm = 0x0001,
104 MsAdpcm = 0x0002,
106 ALaw = 0x0006,
108 MuLaw = 0x0007,
110 ImaAdpcm = 0x0011,
112 Mp3 = 0x0055,
114}
115
116#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
118pub struct WavEncodingCode(u16);
119
120impl WavEncodingCode {
121 pub const fn from_raw(raw: u16) -> Self {
123 Self(raw)
124 }
125
126 pub const fn raw(self) -> u16 {
128 self.0
129 }
130
131 pub fn known(self) -> Option<WavEncoding> {
133 WavEncoding::try_from(self.0).ok()
134 }
135}
136
137impl From<WavEncoding> for WavEncodingCode {
138 fn from(value: WavEncoding) -> Self {
139 Self(u16::from(value))
140 }
141}
142
143#[derive(Debug, Clone, PartialEq, Eq)]
145pub struct Wav {
146 pub wav_type: WavType,
148 pub audio_format: WavAudioFormat,
150 pub encoding: WavEncodingCode,
152 pub channels: u16,
154 pub sample_rate: u32,
156 pub bytes_per_sec: u32,
158 pub block_align: u16,
160 pub bits_per_sample: u16,
162 pub data: Vec<u8>,
164}
165
166#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
168pub struct WavWaveMetadata {
169 pub encoding: WavEncodingCode,
171 pub channels: u16,
173 pub sample_rate: u32,
175 pub bytes_per_sec: u32,
177 pub block_align: u16,
179 pub bits_per_sample: u16,
181}
182
183impl Wav {
184 pub fn new_wave(wav_type: WavType, metadata: WavWaveMetadata, data: Vec<u8>) -> Self {
186 Self {
187 wav_type,
188 audio_format: WavAudioFormat::Wave,
189 encoding: metadata.encoding,
190 channels: metadata.channels,
191 sample_rate: metadata.sample_rate,
192 bytes_per_sec: metadata.bytes_per_sec,
193 block_align: metadata.block_align,
194 bits_per_sample: metadata.bits_per_sample,
195 data,
196 }
197 }
198
199 pub fn new_mp3(wav_type: WavType, data: Vec<u8>) -> Self {
201 Self {
202 wav_type,
203 audio_format: WavAudioFormat::Mp3,
204 encoding: WavEncodingCode::from(WavEncoding::Mp3),
205 channels: DEFAULT_MP3_CHANNELS,
206 sample_rate: DEFAULT_MP3_SAMPLE_RATE,
207 bytes_per_sec: 0,
208 block_align: 0,
209 bits_per_sample: DEFAULT_MP3_BITS_PER_SAMPLE,
210 data,
211 }
212 }
213}
214
215impl DecodeBinary for Wav {
216 type Error = WavError;
217
218 fn decode_binary(bytes: &[u8]) -> Result<Self, Self::Error> {
219 read_wav_from_bytes(bytes)
220 }
221}
222
223impl EncodeBinary for Wav {
224 type Error = WavError;
225
226 fn encode_binary(&self) -> Result<Vec<u8>, Self::Error> {
227 write_wav_to_vec(self)
228 }
229}
230
231#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
233pub enum WavWriteMode {
234 #[default]
236 Game,
237 Clean,
239}
240
241#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
243pub struct WavWriteOptions {
244 pub mode: WavWriteMode,
246}
247
248#[derive(Debug, Error)]
250pub enum WavError {
251 #[error(transparent)]
253 Io(#[from] std::io::Error),
254 #[error("invalid WAV header: {0}")]
256 InvalidHeader(String),
257 #[error("invalid WAV chunk: {0}")]
259 InvalidChunk(String),
260}