symphonia-codec-adpcm-0.5.4/.cargo_vcs_info.json0000644000000001630000000000100152060ustar { "git": { "sha1": "d3b7742fa73674b70d9ab80cc5f8384cc653df3a" }, "path_in_vcs": "symphonia-codec-adpcm" }symphonia-codec-adpcm-0.5.4/Cargo.toml0000644000000021650000000000100132100ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" rust-version = "1.53" name = "symphonia-codec-adpcm" version = "0.5.4" authors = [ "Philip Deljanov ", "Johannes Hackel ", ] description = "Pure Rust ADPCM audio decoder (a part of project Symphonia)." homepage = "https://github.com/pdeljanov/Symphonia" readme = "README.md" keywords = [ "audio", "codec", "decoder", "adpcm", ] categories = [ "multimedia", "multimedia::audio", "multimedia::encoding", ] license = "MPL-2.0" repository = "https://github.com/pdeljanov/Symphonia" [dependencies.log] version = "0.4" [dependencies.symphonia-core] version = "0.5.4" symphonia-codec-adpcm-0.5.4/Cargo.toml.orig000064400000000000000000000011761046102023000166720ustar 00000000000000[package] name = "symphonia-codec-adpcm" version = "0.5.4" description = "Pure Rust ADPCM audio decoder (a part of project Symphonia)." homepage = "https://github.com/pdeljanov/Symphonia" repository = "https://github.com/pdeljanov/Symphonia" authors = ["Philip Deljanov ", "Johannes Hackel "] license = "MPL-2.0" readme = "README.md" categories = ["multimedia", "multimedia::audio", "multimedia::encoding"] keywords = ["audio", "codec", "decoder", "adpcm"] edition = "2018" rust-version = "1.53" [dependencies] log = "0.4" symphonia-core = { version = "0.5.4", path = "../symphonia-core" }symphonia-codec-adpcm-0.5.4/README.md000064400000000000000000000014531046102023000152600ustar 00000000000000# Symphonia ADPCM Codec [![Docs](https://docs.rs/symphonia-codec-adpcm/badge.svg)](https://docs.rs/symphonia-codec-adpcm) ADPCM audio decoders for Project Symphonia. **Note:** This crate is part of Symphonia. Please use the [`symphonia`](https://crates.io/crates/symphonia) crate instead of this one directly. ## Support The following ADPCM encodings are supported: * Microsoft ADPCM * ADPCM IMA WAV Only 4 bits per sample and only mono and stereo channels are supported. ## License Symphonia is provided under the MPL v2.0 license. Please refer to the LICENSE file for more details. ## Contributing Symphonia is a free and open-source project that welcomes contributions! To get started, please read our [Contribution Guidelines](https://github.com/pdeljanov/Symphonia/tree/master/CONTRIBUTING.md). symphonia-codec-adpcm-0.5.4/src/codec_ima.rs000064400000000000000000000073121046102023000170410ustar 00000000000000// Symphonia // Copyright (c) 2019-2022 The Project Symphonia Developers. // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. use symphonia_core::errors::{decode_error, Result}; use symphonia_core::io::ReadBytes; use symphonia_core::util::clamp::clamp_i16; use crate::common::{from_i16_shift, u16_to_i32, Nibble}; #[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: i32, } impl AdpcmImaBlockStatus { fn read_preamble(stream: &mut B) -> Result { let predictor = u16_to_i32!(stream.read_u16()?); let step_index = stream.read_byte()? as i32; if step_index > 88 { return decode_error("adpcm (ima): invalid step index"); } //reserved byte let _ = stream.read_byte()?; 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 as usize]; 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 + IMA_INDEX_TABLE[nibble as usize]).clamp(0, 88); from_i16_shift!(self.predictor) } } pub(crate) fn decode_mono( stream: &mut B, buffer: &mut [i32], frames_per_block: usize, ) -> Result<()> { let data_bytes_per_channel = (frames_per_block - 1) / 2; let mut status = AdpcmImaBlockStatus::read_preamble(stream)?; buffer[0] = from_i16_shift!(status.predictor); for byte in 0..data_bytes_per_channel { let nibbles = stream.read_u8()?; buffer[1 + byte * 2] = status.expand_nibble(nibbles, Nibble::Lower); buffer[1 + byte * 2 + 1] = status.expand_nibble(nibbles, Nibble::Upper); } Ok(()) } pub(crate) fn decode_stereo( stream: &mut B, buffers: [&mut [i32]; 2], frames_per_block: usize, ) -> Result<()> { let data_bytes_per_channel = frames_per_block - 1; let mut status = [AdpcmImaBlockStatus::read_preamble(stream)?, AdpcmImaBlockStatus::read_preamble(stream)?]; buffers[0][0] = from_i16_shift!(status[0].predictor); buffers[1][0] = from_i16_shift!(status[1].predictor); for index in 0..data_bytes_per_channel { let channel = (index / 4) & 1; let offset = (index / 8) * 8; let byte = index % 4; let nibbles = stream.read_u8()?; buffers[channel][1 + offset + byte * 2] = status[channel].expand_nibble(nibbles, Nibble::Lower); buffers[channel][1 + offset + byte * 2 + 1] = status[channel].expand_nibble(nibbles, Nibble::Upper); } Ok(()) } symphonia-codec-adpcm-0.5.4/src/codec_ms.rs000064400000000000000000000116171046102023000167150ustar 00000000000000// Symphonia // Copyright (c) 2019-2022 The Project Symphonia Developers. // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. use symphonia_core::errors::{unsupported_error, Result}; use symphonia_core::io::ReadBytes; use symphonia_core::util::clamp::clamp_i16; use crate::common::{from_i16_shift, u16_to_i32, Nibble}; #[rustfmt::skip] const MS_ADAPTATION_TABLE: [i32; 16] = [ 230, 230, 230, 230, 307, 409, 512, 614, 768, 614, 512, 409, 307, 230, 230, 230, ]; const MS_ADAPT_COEFFS1: [i32; 7] = [256, 512, 0, 192, 240, 460, 392]; const MS_ADAPT_COEFFS2: [i32; 7] = [0, -256, 0, 64, 0, -208, -232]; const DELTA_MIN: i32 = 16; macro_rules! check_block_predictor { ($block_predictor:ident, $max:expr) => { if $block_predictor > $max { return unsupported_error("adpcm: block predictor exceeds range"); } }; } pub fn signed_nibble(nibble: u8) -> i8 { if (nibble & 0x08) != 0 { nibble as i8 - 0x10 } else { nibble as i8 } } /// `AdpcmMsBlockStatus` contains values to decode a block struct AdpcmMsBlockStatus { coeff1: i32, coeff2: i32, delta: i32, sample1: i32, sample2: i32, } impl AdpcmMsBlockStatus { fn read_mono_preamble(stream: &mut B) -> Result { let block_predictor = stream.read_byte()? as usize; check_block_predictor!(block_predictor, 6); let status = Self { coeff1: MS_ADAPT_COEFFS1[block_predictor], coeff2: MS_ADAPT_COEFFS2[block_predictor], delta: u16_to_i32!(stream.read_u16()?), sample1: u16_to_i32!(stream.read_u16()?), sample2: u16_to_i32!(stream.read_u16()?), }; Ok(status) } fn read_stereo_preamble(stream: &mut B) -> Result<(Self, Self)> { let left_block_predictor = stream.read_byte()? as usize; check_block_predictor!(left_block_predictor, 6); let right_block_predictor = stream.read_byte()? as usize; check_block_predictor!(right_block_predictor, 6); let left_delta = u16_to_i32!(stream.read_u16()?); let right_delta = u16_to_i32!(stream.read_u16()?); let left_sample1 = u16_to_i32!(stream.read_u16()?); let right_sample1 = u16_to_i32!(stream.read_u16()?); let left_sample2 = u16_to_i32!(stream.read_u16()?); let right_sample2 = u16_to_i32!(stream.read_u16()?); Ok(( Self { coeff1: MS_ADAPT_COEFFS1[left_block_predictor], coeff2: MS_ADAPT_COEFFS2[left_block_predictor], delta: left_delta, sample1: left_sample1, sample2: left_sample2, }, Self { coeff1: MS_ADAPT_COEFFS1[right_block_predictor], coeff2: MS_ADAPT_COEFFS2[right_block_predictor], delta: right_delta, sample1: right_sample1, sample2: right_sample2, }, )) } fn expand_nibble(&mut self, byte: u8, nibble: Nibble) -> i32 { let nibble = nibble.get_nibble(byte); let signed_nibble = signed_nibble(nibble) as i32; let predictor = ((self.sample1 * self.coeff1) + (self.sample2 * self.coeff2)) / 256 + signed_nibble * self.delta; self.sample2 = self.sample1; self.sample1 = clamp_i16(predictor) as i32; self.delta = (MS_ADAPTATION_TABLE[nibble as usize] * self.delta) / 256; self.delta = self.delta.max(DELTA_MIN); from_i16_shift!(self.sample1) } } pub(crate) fn decode_mono( stream: &mut B, buffer: &mut [i32], frames_per_block: usize, ) -> Result<()> { let mut status = AdpcmMsBlockStatus::read_mono_preamble(stream)?; buffer[0] = from_i16_shift!(status.sample2); buffer[1] = from_i16_shift!(status.sample1); for byte in 1..(frames_per_block / 2) { let nibbles = stream.read_u8()?; buffer[byte * 2] = status.expand_nibble(nibbles, Nibble::Upper); buffer[byte * 2 + 1] = status.expand_nibble(nibbles, Nibble::Lower); } Ok(()) } pub(crate) fn decode_stereo( stream: &mut B, buffers: [&mut [i32]; 2], frames_per_block: usize, ) -> Result<()> { let (mut left_status, mut right_status) = AdpcmMsBlockStatus::read_stereo_preamble(stream)?; buffers[0][0] = from_i16_shift!(left_status.sample2); buffers[0][1] = from_i16_shift!(left_status.sample1); buffers[1][0] = from_i16_shift!(right_status.sample2); buffers[1][1] = from_i16_shift!(right_status.sample1); for frame in 2..frames_per_block { let nibbles = stream.read_u8()?; buffers[0][frame] = left_status.expand_nibble(nibbles, Nibble::Upper); buffers[1][frame] = right_status.expand_nibble(nibbles, Nibble::Lower); } Ok(()) } symphonia-codec-adpcm-0.5.4/src/common.rs000064400000000000000000000014551046102023000164300ustar 00000000000000// Symphonia // Copyright (c) 2019-2022 The Project Symphonia Developers. // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. /// `Nibble` represents the lower or upper 4 bits of a byte pub(crate) enum Nibble { Upper, Lower, } impl Nibble { pub fn get_nibble(&self, byte: u8) -> u8 { match self { Nibble::Upper => byte >> 4, Nibble::Lower => byte & 0x0F, } } } macro_rules! u16_to_i32 { ($input:expr) => { $input as i16 as i32 }; } macro_rules! from_i16_shift { ($input:expr) => { ($input as i32) << 16 }; } pub(crate) use from_i16_shift; pub(crate) use u16_to_i32; symphonia-codec-adpcm-0.5.4/src/lib.rs000064400000000000000000000140261046102023000157040ustar 00000000000000// Symphonia // Copyright (c) 2019-2022 The Project Symphonia Developers. // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. #![warn(rust_2018_idioms)] #![forbid(unsafe_code)] // The following lints are allowed in all Symphonia crates. Please see clippy.toml for their // justification. #![allow(clippy::comparison_chain)] #![allow(clippy::excessive_precision)] #![allow(clippy::identity_op)] #![allow(clippy::manual_range_contains)] use symphonia_core::support_codec; use symphonia_core::audio::{AsAudioBufferRef, AudioBuffer, AudioBufferRef, Signal, SignalSpec}; use symphonia_core::codecs::{CodecDescriptor, CodecParameters, CodecType}; use symphonia_core::codecs::{Decoder, DecoderOptions, FinalizeResult}; use symphonia_core::codecs::{CODEC_TYPE_ADPCM_IMA_WAV, CODEC_TYPE_ADPCM_MS}; use symphonia_core::errors::{unsupported_error, Result}; use symphonia_core::formats::Packet; use symphonia_core::io::ReadBytes; mod codec_ima; mod codec_ms; mod common; fn is_supported_adpcm_codec(codec_type: CodecType) -> bool { matches!(codec_type, CODEC_TYPE_ADPCM_MS | CODEC_TYPE_ADPCM_IMA_WAV) } enum InnerDecoder { AdpcmMs, AdpcmIma, } impl InnerDecoder { fn decode_mono_fn(&self) -> impl Fn(&mut B, &mut [i32], usize) -> Result<()> { match *self { InnerDecoder::AdpcmMs => codec_ms::decode_mono, InnerDecoder::AdpcmIma => codec_ima::decode_mono, } } fn decode_stereo_fn( &self, ) -> impl Fn(&mut B, [&mut [i32]; 2], usize) -> Result<()> { match *self { InnerDecoder::AdpcmMs => codec_ms::decode_stereo, InnerDecoder::AdpcmIma => codec_ima::decode_stereo, } } } /// Adaptive Differential Pulse Code Modulation (ADPCM) decoder. pub struct AdpcmDecoder { params: CodecParameters, inner_decoder: InnerDecoder, buf: AudioBuffer, } impl AdpcmDecoder { fn decode_inner(&mut self, packet: &Packet) -> Result<()> { let mut stream = packet.as_buf_reader(); let frames_per_block = self.params.frames_per_block.unwrap() as usize; let block_count = packet.block_dur() as usize / frames_per_block; self.buf.clear(); self.buf.render_reserved(Some(block_count * frames_per_block)); let channel_count = self.buf.spec().channels.count(); match channel_count { 1 => { let buffer = self.buf.chan_mut(0); let decode_mono = self.inner_decoder.decode_mono_fn(); for block_id in 0..block_count { let offset = frames_per_block * block_id; let buffer_range = offset..(offset + frames_per_block); let buffer = &mut buffer[buffer_range]; decode_mono(&mut stream, buffer, frames_per_block)?; } } 2 => { let buffers = self.buf.chan_pair_mut(0, 1); let decode_stereo = self.inner_decoder.decode_stereo_fn(); for block_id in 0..block_count { let offset = frames_per_block * block_id; let buffer_range = offset..(offset + frames_per_block); let buffers = [&mut buffers.0[buffer_range.clone()], &mut buffers.1[buffer_range]]; decode_stereo(&mut stream, buffers, frames_per_block)?; } } _ => unreachable!(), } Ok(()) } } impl Decoder for AdpcmDecoder { fn try_new(params: &CodecParameters, _options: &DecoderOptions) -> Result { // This decoder only supports certain ADPCM codecs. if !is_supported_adpcm_codec(params.codec) { return unsupported_error("adpcm: invalid codec type"); } let frames = match params.max_frames_per_packet { Some(frames) => frames, _ => return unsupported_error("adpcm: maximum frames per packet is required"), }; if params.frames_per_block.is_none() || params.frames_per_block.unwrap() == 0 { return unsupported_error("adpcm: valid frames per block is required"); } let rate = match params.sample_rate { Some(rate) => rate, _ => return unsupported_error("adpcm: sample rate is required"), }; let spec = if let Some(channels) = params.channels { SignalSpec::new(rate, channels) } else if let Some(layout) = params.channel_layout { SignalSpec::new_with_layout(rate, layout) } else { return unsupported_error("adpcm: channels or channel_layout is required"); }; let inner_decoder = match params.codec { CODEC_TYPE_ADPCM_MS => InnerDecoder::AdpcmMs, CODEC_TYPE_ADPCM_IMA_WAV => InnerDecoder::AdpcmIma, _ => return unsupported_error("adpcm: codec is unsupported"), }; Ok(AdpcmDecoder { params: params.clone(), inner_decoder, buf: AudioBuffer::new(frames, spec), }) } fn supported_codecs() -> &'static [CodecDescriptor] { &[ support_codec!(CODEC_TYPE_ADPCM_MS, "adpcm_ms", "Microsoft ADPCM"), support_codec!(CODEC_TYPE_ADPCM_IMA_WAV, "adpcm_ima_wav", "ADPCM IMA WAV"), ] } fn reset(&mut self) { // No state is stored between packets, therefore do nothing. } fn codec_params(&self) -> &CodecParameters { &self.params } fn decode(&mut self, packet: &Packet) -> Result> { if let Err(e) = self.decode_inner(packet) { self.buf.clear(); Err(e) } else { Ok(self.buf.as_audio_buffer_ref()) } } fn finalize(&mut self) -> FinalizeResult { Default::default() } fn last_decoded(&self) -> AudioBufferRef<'_> { self.buf.as_audio_buffer_ref() } }