1use crate::codecs::tables::{ADPCM_PRED_DIFF_TABLE, ADPCM_STEP_SIZE_ADJ, ADPCM_STEP_SIZES};
2use std::fmt;
3
4#[derive(Debug, Clone, Copy, PartialEq)]
5pub enum AdpcmError {
6 InvalidMagic,
7 BufferTooSmall { expected: u16, actual: u16 },
8 ChecksumMismatch { expected: u8, actual: u8 },
9 ChannelMismatch { expected: u16, actual: u16 },
10 UnsupportedSampleType(u8),
11}
12
13impl fmt::Display for AdpcmError {
14 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
15 match self {
16 AdpcmError::InvalidMagic => write!(f, "Invalid ADP magic numbers"),
17 AdpcmError::BufferTooSmall { expected, actual } => {
18 write!(
19 f,
20 "Input buffer too small. Expected {expected}, got {actual}",
21 )
22 }
23 AdpcmError::ChecksumMismatch { expected, actual } => {
24 write!(
25 f,
26 "ADP header checksum mismatch. Expected {expected}, got {actual}",
27 )
28 }
29 AdpcmError::ChannelMismatch { expected, actual } => {
30 write!(
31 f,
32 "ADP channel mismatch. Header reports {actual}, state expects {expected}",
33 )
34 }
35 AdpcmError::UnsupportedSampleType(t) => write!(f, "Unsupported ADP sample type: {t}"),
36 }
37 }
38}
39
40impl std::error::Error for AdpcmError {}
41
42#[repr(u8)]
44#[derive(Debug, Clone, Copy, PartialEq, Eq)]
45pub enum SampleType {
46 None = 0,
48 PcmMono8 = 1,
51 PcmMono16 = 2,
54 PcmStereo8 = 3,
57 PcmStereo16 = 4,
60 AdpcmMono = 5,
64 AdpcmStereo = 6,
68}
69
70impl From<u8> for SampleType {
71 fn from(v: u8) -> Self {
72 match v {
73 1 => SampleType::PcmMono8,
74 2 => SampleType::PcmMono16,
75 3 => SampleType::PcmStereo8,
76 4 => SampleType::PcmStereo16,
77 5 => SampleType::AdpcmMono,
78 6 => SampleType::AdpcmStereo,
79 _ => SampleType::None,
80 }
81 }
82}
83
84#[derive(Debug, Clone, Copy, PartialEq, Default)]
86pub struct AdpcmChannelState {
87 pub pred_value: i32,
89 pub step_size_index: i32,
91}
92
93use crate::types::Channels;
94
95pub struct AdpcmState {
101 pub channel_layout: Channels,
102 pub frame_length: usize,
103 pub channels: Vec<AdpcmChannelState>,
104 pub frame_bytes: usize,
105 pub header_bytes: usize,
106 pub header_size: usize,
107 pub encoding_type: SampleType,
108 pub sample_rate: u32,
109 pub current_header: Option<Vec<u8>>,
112 pub low_nibble: bool,
113 pub pending_byte: u8,
114 pub current_channel: usize,
115}
116
117impl AdpcmState {
118 #[must_use]
119 pub fn new(channel_layout: Channels, frame_length: usize) -> Self {
120 let channels = vec![AdpcmChannelState::default(); channel_layout.count()];
121 let encoding_type = match channel_layout {
122 Channels::Stereo => SampleType::AdpcmStereo,
123 Channels::Mono => SampleType::AdpcmMono,
124 };
125 Self {
126 channel_layout,
127 frame_length,
128 channels,
129 frame_bytes: 0,
130 header_bytes: 0,
131 header_size: 0,
132 current_header: None,
133 low_nibble: false,
134 pending_byte: 0,
135 current_channel: 0,
136 encoding_type,
137 sample_rate: 22050,
138 }
139 }
140
141 #[must_use]
142 pub fn with_type(
143 channel_layout: Channels,
144 frame_length: usize,
145 encoding_type: SampleType,
146 sample_rate: u32,
147 ) -> Self {
148 let channels: Vec<AdpcmChannelState> =
149 vec![AdpcmChannelState::default(); channel_layout.count()];
150 Self {
151 channel_layout,
152 frame_length,
153 channels,
154 frame_bytes: 0,
155 header_bytes: 0,
156 header_size: 0,
157 current_header: None,
158 low_nibble: false,
159 pending_byte: 0,
160 current_channel: 0,
161 encoding_type,
162 sample_rate,
163 }
164 }
165
166 #[must_use]
167 pub fn get_header_size(channel_layout: Channels) -> usize {
168 6 + channel_layout.count() * 3
169 }
170
171 pub fn encode(&mut self, input: &[i16], output: &mut [u8]) -> (usize, usize) {
172 let mut input_used = 0;
173 let mut output_written = 0;
174 let mut input_idx = 0;
175 let mut output_idx = 0;
176
177 while output_idx < output.len() && input_idx < input.len() {
178 if self.frame_bytes == 0 {
180 if self.current_header.is_none() {
181 let mut header = Vec::new();
183 header.push(0x17);
184 header.push(0x42);
185 header.extend_from_slice(&(self.frame_length as u16).to_le_bytes());
186 header.push(0); header.push(self.encoding_type as u8); for i in 0..self.channel_layout.count() {
191 header
192 .extend_from_slice(&(self.channels[i].pred_value as i16).to_le_bytes());
193 header.push(self.channels[i].step_size_index as u8);
194 }
195
196 let mut sum: u8 = 0;
198 for (i, b) in header.iter().enumerate() {
199 if i != 4 {
200 sum = sum.wrapping_add(*b);
201 }
202 }
203 header[4] = sum;
204
205 self.current_header = Some(header);
206 self.header_bytes = self.current_header.as_ref().unwrap().len();
207 }
208
209 if let Some(ref header) = self.current_header {
211 let offset = header.len() - self.header_bytes;
212 let available = output.len() - output_idx;
213 let to_write = std::cmp::min(self.header_bytes, available);
214
215 output[output_idx..output_idx + to_write]
216 .copy_from_slice(&header[offset..offset + to_write]);
217
218 output_idx += to_write;
219 output_written += to_write;
220 self.header_bytes -= to_write;
221
222 if self.header_bytes == 0 {
223 self.current_header = None;
224 self.frame_bytes =
225 self.frame_length - Self::get_header_size(self.channel_layout);
226 self.low_nibble = false;
227 self.pending_byte = 0;
228 self.current_channel = 0;
229 }
230 }
231
232 if output_idx >= output.len() {
233 break;
234 }
235 }
236
237 let ch = self.current_channel;
239 let sample = input[input_idx];
240
241 let can_fit = match self.encoding_type {
243 SampleType::AdpcmMono | SampleType::AdpcmStereo => {
244 self.low_nibble || output_idx < output.len()
245 }
246 SampleType::PcmMono16 | SampleType::PcmStereo16 => output_idx + 1 < output.len(),
247 SampleType::PcmMono8 | SampleType::PcmStereo8 => output_idx < output.len(),
248 _ => true,
249 };
250
251 if !can_fit {
252 break;
253 }
254
255 input_idx += 1;
257 input_used += 2;
258
259 match self.encoding_type {
260 SampleType::AdpcmMono | SampleType::AdpcmStereo => {
261 let chan = &mut self.channels[ch];
262
263 let mut diff = i32::from(sample) - chan.pred_value;
264 let mut qdiff = 0;
265
266 if diff < 0 {
267 qdiff = 8;
268 diff = -diff;
269 }
270
271 let mut step_size = ADPCM_STEP_SIZES[chan.step_size_index as usize];
272 let mut pred_diff = step_size / 8;
273
274 if diff >= step_size {
275 qdiff |= 4;
276 diff -= step_size;
277 pred_diff += step_size;
278 }
279 step_size /= 2;
280 if diff >= step_size {
281 qdiff |= 2;
282 diff -= step_size;
283 pred_diff += step_size;
284 }
285 step_size /= 2;
286 if diff >= step_size {
287 qdiff |= 1;
288 pred_diff += step_size;
289 }
290
291 if (qdiff & 8) != 0 {
292 chan.pred_value -= pred_diff;
293 } else {
294 chan.pred_value += pred_diff;
295 }
296
297 chan.pred_value = chan.pred_value.clamp(-32768, 32767);
299
300 chan.step_size_index += ADPCM_STEP_SIZE_ADJ[(qdiff & 7) as usize];
301 chan.step_size_index = chan.step_size_index.clamp(0, 88);
302
303 if self.low_nibble {
304 output[output_idx] = self.pending_byte | (qdiff as u8);
305 output_idx += 1;
306 output_written += 1;
307 self.frame_bytes -= 1;
308 self.low_nibble = false;
309 } else {
310 self.pending_byte = (qdiff as u8) << 4;
311 self.low_nibble = true;
312 }
313 }
314 SampleType::PcmMono16 | SampleType::PcmStereo16 => {
315 let bytes = sample.to_le_bytes();
316 output[output_idx] = bytes[0];
317 output[output_idx + 1] = bytes[1];
318 output_idx += 2;
319 output_written += 2;
320 self.frame_bytes -= 2;
321 }
322 SampleType::PcmMono8 | SampleType::PcmStereo8 => {
323 let unsigned = ((i32::from(sample) + 32768) >> 8) as u8;
325 output[output_idx] = unsigned;
326 output_idx += 1;
327 output_written += 1;
328 self.frame_bytes -= 1;
329 }
330 _ => {}
331 }
332
333 self.current_channel += 1;
335 if self.current_channel >= self.channel_layout.count() {
336 self.current_channel = 0;
337 }
338 }
339
340 (input_used, output_written)
341 }
342
343 pub fn decode(
344 &mut self,
345 input: &[u8],
346 output: &mut [i16],
347 ) -> Result<(usize, usize), AdpcmError> {
348 let mut input_used = 0;
349 let mut output_written = 0;
350 let mut input_idx = 0;
351 let mut output_idx = 0;
352
353 while input_idx < input.len() && output_idx < output.len() {
354 if self.frame_bytes == 0 {
355 let h_size = Self::get_header_size(self.channel_layout);
356 if input.len() - input_idx < h_size {
357 break;
358 }
359
360 if input[input_idx] != 0x17 || input[input_idx + 1] != 0x42 {
362 if input_used > 0 {
363 let mut found = false;
365 let mut search_idx = input_idx + 1;
366 while search_idx + 1 < input.len() {
367 if input[search_idx] == 0x17 && input[search_idx + 1] == 0x42 {
368 input_idx = search_idx;
369 found = true;
370 break;
371 }
372 search_idx += 1;
373 }
374 if !found {
375 break;
376 }
377 } else {
378 return Err(AdpcmError::InvalidMagic);
379 }
380 }
381
382 let frame_len =
384 u16::from_le_bytes([input[input_idx + 2], input[input_idx + 3]]) as usize;
385 let read_sum = input[input_idx + 4];
386 let header_type = input[input_idx + 5];
387
388 let mut calc_sum: u8 = 0;
390 for i in 0..h_size {
391 if i != 4 {
392 calc_sum = calc_sum.wrapping_add(input[input_idx + i]);
393 }
394 }
395
396 if calc_sum != read_sum {
397 return Err(AdpcmError::ChecksumMismatch {
398 expected: calc_sum,
399 actual: read_sum,
400 });
401 }
402
403 let encoding_type = SampleType::from(header_type);
404 if encoding_type == SampleType::None {
405 return Err(AdpcmError::UnsupportedSampleType(header_type));
406 }
407
408 self.frame_length = frame_len;
409 self.encoding_type = encoding_type;
410 let expected_channels = self.channel_layout.count();
413 let actual_channels = match encoding_type {
414 SampleType::PcmMono8 | SampleType::PcmMono16 | SampleType::AdpcmMono => 1,
415 SampleType::PcmStereo8 | SampleType::PcmStereo16 | SampleType::AdpcmStereo => 2,
416 _ => 0,
417 };
418
419 if actual_channels != expected_channels {
420 return Err(AdpcmError::ChannelMismatch {
421 expected: expected_channels as u16,
422 actual: actual_channels as u16,
423 });
424 }
425
426 let mut ptr = input_idx + 6;
428 for i in 0..self.channel_layout.count() {
429 let pred = i32::from(i16::from_le_bytes([input[ptr], input[ptr + 1]]));
430 let step = i32::from(input[ptr + 2]);
431 self.channels[i].pred_value = pred;
432 self.channels[i].step_size_index = step.clamp(0, 88);
433 ptr += 3;
434 }
435
436 input_idx += h_size;
437 input_used += h_size;
438 self.frame_bytes = self.frame_length - h_size;
439 self.low_nibble = false;
440 self.current_channel = 0;
441 }
442
443 let ch = self.current_channel;
444 if output_idx >= output.len() || self.frame_bytes == 0 {
445 break;
446 }
447
448 match self.encoding_type {
449 SampleType::AdpcmMono | SampleType::AdpcmStereo => {
450 let byte = input[input_idx];
451
452 let qdiff = if self.low_nibble {
453 let val = byte & 0x0F;
454 input_idx += 1;
455 input_used += 1;
456 self.frame_bytes -= 1;
457 val
458 } else {
459 (byte >> 4) & 0x0F
460 };
461 self.low_nibble = !self.low_nibble;
462
463 let chan = &mut self.channels[ch];
464 let pred_diff = ADPCM_PRED_DIFF_TABLE[(usize::try_from(chan.step_size_index)
465 .unwrap_or(0)
466 * 16)
467 + usize::from(qdiff)];
468
469 chan.pred_value += pred_diff;
470 chan.pred_value = chan.pred_value.clamp(-32768, 32767);
471
472 output[output_idx] = i16::try_from(chan.pred_value).unwrap_or(0);
473 output_idx += 1;
474 output_written += 2; chan.step_size_index += ADPCM_STEP_SIZE_ADJ[(qdiff & 7) as usize];
477 chan.step_size_index = chan.step_size_index.clamp(0, 88);
478 }
479 SampleType::PcmMono16 | SampleType::PcmStereo16 => {
480 if input_idx + 1 < input.len() {
481 let val = i16::from_le_bytes([input[input_idx], input[input_idx + 1]]);
482 output[output_idx] = val;
483 output_idx += 1;
484 output_written += 2;
485 input_idx += 2;
486 input_used += 2;
487 self.frame_bytes -= 2;
488 } else {
489 break;
490 }
491 }
492 SampleType::PcmMono8 | SampleType::PcmStereo8 => {
493 if input_idx < input.len() {
494 let b = input[input_idx];
495 let val = i16::try_from((i32::from(b) - 128) << 8).unwrap_or(0);
497 output[output_idx] = val;
498 output_idx += 1;
499 output_written += 2;
500 input_idx += 1;
501 input_used += 1;
502 self.frame_bytes -= 1;
503 } else {
504 break;
505 }
506 }
507 _ => {}
508 }
509
510 self.current_channel += 1;
512 if self.current_channel >= self.channel_layout.count() {
513 self.current_channel = 0;
514 }
515 }
516
517 Ok((input_used, output_written))
518 }
519}