Skip to main content

embedded_audio/decode/
adpcm.rs

1/// IMA ADPCM step table (standard 89 values; we use first 89 indices).
2const STEP_TABLE: [i16; 89] = [
3    7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, 60, 66,
4    73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449,
5    494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 2272,
6    2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493,
7    10442, 11487, 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767,
8];
9
10const INDEX_TABLE: [i8; 16] = [-1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8];
11
12/// Stateful IMA ADPCM decoder.
13#[derive(Debug, Clone, Copy)]
14pub struct AdpcmDecoder {
15    predictor: i16,
16    index: u8,
17    nibble_high: bool,
18    current_byte: u8,
19}
20
21impl AdpcmDecoder {
22    pub fn new(predictor: i16, index: u8) -> Self {
23        Self {
24            predictor,
25            index: index.min(88),
26            nibble_high: true,
27            current_byte: 0,
28        }
29    }
30
31    pub fn decode_nibble(&mut self, nibble: u8) -> i8 {
32        let nibble = nibble & 0x0F;
33        let step = STEP_TABLE[self.index as usize];
34        let mut diff = step >> 3;
35        if nibble & 4 != 0 {
36            diff += step;
37        }
38        if nibble & 2 != 0 {
39            diff += step >> 1;
40        }
41        if nibble & 1 != 0 {
42            diff += step >> 2;
43        }
44        if nibble & 8 != 0 {
45            self.predictor = (self.predictor as i32 - diff as i32).clamp(-32768, 32767) as i16;
46        } else {
47            self.predictor = (self.predictor as i32 + diff as i32).clamp(-32768, 32767) as i16;
48        }
49        let idx = self.index as i32 + INDEX_TABLE[nibble as usize] as i32;
50        self.index = idx.clamp(0, 88) as u8;
51        (self.predictor >> 8).clamp(-128, 127) as i8
52    }
53
54    fn next_from_bytes(&mut self, bytes: &mut &[u8]) -> Option<i8> {
55        if self.nibble_high {
56            let b = *bytes.first()?;
57            self.current_byte = *bytes.first()?;
58            *bytes = &bytes[1..];
59            self.nibble_high = false;
60            Some(self.decode_nibble(b >> 4))
61        } else {
62            self.nibble_high = true;
63            Some(self.decode_nibble(self.current_byte))
64        }
65    }
66}
67
68/// Tier B ADPCM stream: 4-byte header (predictor le, index u8) + nibbles.
69#[derive(Debug, Clone, Copy)]
70pub struct AdpcmStream<'a> {
71    payload: &'a [u8],
72    bytes: &'a [u8],
73    decoder: AdpcmDecoder,
74    looped: bool,
75}
76
77impl<'a> AdpcmStream<'a> {
78    pub fn new(payload: &'a [u8], flags: u8) -> Option<Self> {
79        if payload.len() < 4 {
80            return None;
81        }
82        let predictor = i16::from_le_bytes([payload[0], payload[1]]);
83        let index = payload[2];
84        let decoder = AdpcmDecoder::new(predictor, index);
85        Some(Self {
86            payload,
87            bytes: &payload[4..],
88            decoder,
89            looped: flags & crate::tier::flags::LOOP != 0,
90        })
91    }
92
93    fn rewind(&mut self) {
94        if let Some(s) = Self::new(self.payload, crate::tier::flags::LOOP) {
95            *self = s;
96        }
97    }
98
99    pub fn is_done(&self) -> bool {
100        self.bytes.is_empty() && !self.looped
101    }
102}
103
104impl<'a> AdpcmStream<'a> {
105    pub fn next_sample(&mut self) -> Option<i8> {
106        if self.bytes.is_empty() {
107            if self.looped {
108                self.rewind();
109            } else {
110                return None;
111            }
112        }
113        let mut slice = self.bytes;
114        let sample = self.decoder.next_from_bytes(&mut slice)?;
115        self.bytes = slice;
116        Some(sample)
117    }
118}