-
Notifications
You must be signed in to change notification settings - Fork 167
Adpcm ima4 #384
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev-0.6
Are you sure you want to change the base?
Adpcm ima4 #384
Conversation
Co-authored-by: hikari_no_yume <[email protected]>
I am listed as a co-author here because the |
#[rustfmt::skip] | ||
const IMA_INDEX_TABLE: [i32; 16] = [ | ||
-1, -1, -1, -1, 2, 4, 6, 8, | ||
-1, -1, -1, -1, 2, 4, 6, 8, | ||
]; | ||
|
||
#[rustfmt::skip] | ||
const IMA_STEP_TABLE: [i32; 89] = [ | ||
7, 8, 9, 10, 11, 12, 13, 14, 16, 17, | ||
19, 21, 23, 25, 28, 31, 34, 37, 41, 45, | ||
50, 55, 60, 66, 73, 80, 88, 97, 107, 118, | ||
130, 143, 157, 173, 190, 209, 230, 253, 279, 307, | ||
337, 371, 408, 449, 494, 544, 598, 658, 724, 796, | ||
876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, | ||
2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, | ||
5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, | ||
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767, | ||
]; | ||
|
||
/// `AdpcmImaBlockStatus` contains values to decode a block | ||
struct AdpcmImaBlockStatus { | ||
predictor: i32, | ||
step_index: usize, | ||
} | ||
|
||
impl AdpcmImaBlockStatus { | ||
fn read_preamble<B: ReadBytes>(stream: &mut B) -> Result<Self> { | ||
let header = stream.read_be_u16()?; | ||
let predictor = u16_to_i32!(header & 0xFF80); | ||
let step_index = ((header & 0x7F) as usize).min(IMA_STEP_TABLE.len() - 1); | ||
|
||
let status = Self { predictor, step_index }; | ||
Ok(status) | ||
} | ||
|
||
fn expand_nibble(&mut self, byte: u8, nibble: Nibble) -> i32 { | ||
let nibble = nibble.get_nibble(byte); | ||
let step = IMA_STEP_TABLE[self.step_index]; | ||
let sign = (nibble & 0x08) != 0; | ||
let delta = (nibble & 0x07) as i32; | ||
let diff = ((2 * delta + 1) * step) >> 3; | ||
let predictor = if sign { self.predictor - diff } else { self.predictor + diff }; | ||
self.predictor = clamp_i16(predictor) as i32; | ||
self.step_index = self | ||
.step_index | ||
.saturating_add_signed(IMA_INDEX_TABLE[nibble as usize] as isize) | ||
.min(IMA_STEP_TABLE.len() - 1); | ||
from_i16_shift!(self.predictor) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couldn't all or most of this code be shared with codec_ima.rs
? The ima4
format is basically just another framing of IMA ADPCM.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the tables and the nibble expansion could be shared. The preamble read definitely can't. I could consolidate if that's preferred.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was the table and nibbles part I had in mind, yeah, because they're from the IMA ADPCM standard.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I refactored it a bit keeping the preamble and decoding separate with a shared expansion
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks nice, thank you!
Adds ima4 decoding support to adpcm. This seems to be working from my local testing. Please let me know if I missed anything or if I should make any changes!