]>
Commit | Line | Data |
---|---|---|
e781ccc3 KS |
1 | //! IMA ADPCM decoding functionality. |
2 | ||
3 | ///! IMA ADPCM step change table. | |
4 | pub const IMA_STEPS: [i8; 16] = [ | |
5 | -1, -1, -1, -1, 2, 4, 6, 8, | |
6 | -1, -1, -1, -1, 2, 4, 6, 8 | |
7 | ]; | |
8 | ||
9 | ///! IMA ADPCM step size table. | |
10 | pub const IMA_STEP_TABLE: [i32; 89] = [ | |
11 | 7, 8, 9, 10, 11, 12, 13, 14, | |
12 | 16, 17, 19, 21, 23, 25, 28, 31, | |
13 | 34, 37, 41, 45, 50, 55, 60, 66, | |
14 | 73, 80, 88, 97, 107, 118, 130, 143, | |
15 | 157, 173, 190, 209, 230, 253, 279, 307, | |
16 | 337, 371, 408, 449, 494, 544, 598, 658, | |
17 | 724, 796, 876, 963, 1060, 1166, 1282, 1411, | |
18 | 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, | |
19 | 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, | |
20 | 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, | |
21 | 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 | |
22 | ]; | |
23 | ||
24 | ///! Maximum step value for IMA ADPCM. | |
25 | pub const IMA_MAX_STEP: u8 = 88; | |
26 | ||
d6c81913 | 27 | #[derive(Clone,Copy,Debug)] |
e781ccc3 KS |
28 | ///! Decoder for IMA ADPCM. |
29 | pub struct IMAState { | |
30 | ///! Current sample value. | |
31 | pub predictor: i32, | |
32 | ///! Current step index. | |
33 | pub step: usize, | |
34 | } | |
35 | ||
36 | impl IMAState { | |
37 | ///! Constructs a new instance of `IMAState`. | |
38 | pub fn new() -> Self { | |
39 | Self { | |
40 | predictor: 0, | |
41 | step: 0, | |
42 | } | |
43 | } | |
44 | ///! Re-initialises decoder with new predictor and step values. | |
45 | pub fn reset(&mut self, predictor: i16, step: u8) { | |
46 | self.predictor = i32::from(predictor); | |
47 | self.step = step.min(IMA_MAX_STEP) as usize; | |
48 | } | |
49 | ///! Computes a new sample value from an input nibble. | |
50 | pub fn expand_sample(&mut self, nibble: u8) -> i16 { | |
51 | let istep = (self.step as isize) + (IMA_STEPS[(nibble & 0xF) as usize] as isize); | |
52 | let sign = (nibble & 8) != 0; | |
53 | let diff = (i32::from(2 * (nibble & 7) + 1) * IMA_STEP_TABLE[self.step]) >> 3; | |
54 | let sample = if !sign { self.predictor + diff } else { self.predictor - diff }; | |
55 | self.predictor = sample.max(i32::from(std::i16::MIN)).min(i32::from(std::i16::MAX)); | |
56 | self.step = istep.max(0).min(IMA_MAX_STEP as isize) as usize; | |
57 | self.predictor as i16 | |
58 | } | |
4ee6b98f KS |
59 | ///! Computes an encoded nibble from an input sample. |
60 | pub fn compress_sample(&self, sample: i16) -> u8 { | |
61 | let diff = i32::from(sample) - self.predictor; | |
62 | let sign = if diff >= 0 { 0 } else { 8 }; | |
63 | let nib = (diff.abs() * 4 / IMA_STEP_TABLE[self.step]).min(7) as u8; | |
64 | nib | sign | |
65 | } | |
e781ccc3 KS |
66 | } |
67 | ||
03011b99 KS |
68 | impl Default for IMAState { |
69 | fn default() -> Self { | |
70 | Self::new() | |
71 | } | |
72 | } |