symphonia-codec-adpcm-0.5.2/.cargo_vcs_info.json0000644000000001630000000000100152040ustar { "git": { "sha1": "412f44daab39920beeb81d78b0e4271b263d33e9" }, "path_in_vcs": "symphonia-codec-adpcm" }symphonia-codec-adpcm-0.5.2/Cargo.toml0000644000000021650000000000100132060ustar # 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.2" 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.2" symphonia-codec-adpcm-0.5.2/Cargo.toml.orig000064400000000000000000000011761046102023000166700ustar 00000000000000[package] name = "symphonia-codec-adpcm" version = "0.5.2" 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.2", path = "../symphonia-core" }symphonia-codec-adpcm-0.5.2/README.md000064400000000000000000000016411046102023000152550ustar 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 an open-source project and contributions are very welcome! If you would like to make a large contribution, please raise an issue ahead of time to make sure your efforts fit into the project goals, and that no duplication of efforts occurs. All contributors will be credited within the CONTRIBUTORS file. symphonia-codec-adpcm-0.5.2/src/codec_ima.rs000064400000000000000000000071171046102023000170420ustar 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::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; //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.2/src/codec_ms.rs000064400000000000000000000116171046102023000167130ustar 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.2/src/common.rs000064400000000000000000000014551046102023000164260ustar 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.2/src/lib.rs000064400000000000000000000140261046102023000157020ustar 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() } }