Skip to main content

audiobox/
pcm.rs

1//! Raw PCM conversion, including G.711 A-law and ยต-law.
2use crate::{Audio, DecodeInfo, Dither, Endian, Error, Limits, Result, SampleFormat};
3
4pub fn decode_pcm(
5    bytes: &[u8],
6    format: SampleFormat,
7    endian: Endian,
8    channels: usize,
9    rate: u32,
10    limits: &Limits,
11) -> Result<Audio> {
12    let stride = channels
13        .checked_mul(format.bytes())
14        .filter(|&n| n > 0)
15        .ok_or_else(|| Error::invalid("Invalid PCM channel count"))?;
16    if bytes.len() % stride != 0 {
17        return Err(Error::decode("Incomplete PCM frame"));
18    }
19    let frames = bytes.len() / stride;
20    limits.check(frames, channels, rate)?;
21    let mut data = vec![vec![0.0; frames]; channels];
22    for (i, frame) in bytes.chunks_exact(stride).enumerate() {
23        for (c, sample) in frame.chunks_exact(format.bytes()).enumerate() {
24            data[c][i] = read_sample(sample, format, endian)?;
25        }
26    }
27    Audio::decoded(
28        data,
29        rate,
30        DecodeInfo {
31            sample_format: Some(format),
32            ..Default::default()
33        },
34    )
35}
36
37pub(crate) fn read_sample(b: &[u8], f: SampleFormat, e: Endian) -> Result<f32> {
38    let le = e == Endian::Little;
39    let u = |n: usize| {
40        let mut v = 0u64;
41        for i in 0..n {
42            v |= (b[if le { i } else { n - 1 - i }] as u64) << (8 * i);
43        }
44        v
45    };
46    let s = match f {
47        SampleFormat::U8 => (b[0] as f32 - 128.0) / 128.0,
48        SampleFormat::S8 => b[0] as i8 as f32 / 128.0,
49        SampleFormat::S16 => u(2) as i16 as f32 / 32768.0,
50        SampleFormat::S24 => ((u(3) as i32) << 8 >> 8) as f32 / 8388608.0,
51        SampleFormat::S32 => u(4) as i32 as f32 / 2147483648.0,
52        SampleFormat::F32 => f32::from_bits(u(4) as u32),
53        SampleFormat::F64 => f64::from_bits(u(8)) as f32,
54        SampleFormat::Alaw => decode_alaw(b[0]) as f32 / 32768.0,
55        SampleFormat::Ulaw => decode_ulaw(b[0]) as f32 / 32768.0,
56    };
57    if !s.is_finite() {
58        return Err(Error::decode("Non-finite PCM sample"));
59    }
60    Ok(s)
61}
62pub fn encode_pcm(audio: &Audio, format: SampleFormat, endian: Endian) -> Result<Vec<u8>> {
63    encode_pcm_with_dither(audio, format, endian, Dither::None)
64}
65
66/// Encode interleaved PCM with optional seeded noise at the final integer quantizer.
67/// The seed restarts on each call. For chunked input, use
68/// [`crate::stream::PcmEncoder::with_dither`] to retain its state across chunks.
69/// Float and G.711 samples reject enabled dither with
70/// [`crate::ErrorCode::InvalidArgument`].
71pub fn encode_pcm_with_dither(
72    audio: &Audio,
73    format: SampleFormat,
74    endian: Endian,
75    dither: Dither,
76) -> Result<Vec<u8>> {
77    validate_dither(format, dither)?;
78    encode_quantized(
79        audio,
80        format,
81        endian,
82        &mut quantizers(format, dither, audio.channels()),
83    )
84}
85
86pub(crate) fn validate_dither(format: SampleFormat, dither: Dither) -> Result<()> {
87    if dither != Dither::None
88        && !matches!(
89            format,
90            SampleFormat::U8
91                | SampleFormat::S8
92                | SampleFormat::S16
93                | SampleFormat::S24
94                | SampleFormat::S32
95        )
96    {
97        return Err(Error::invalid("Dither requires linear integer PCM output"));
98    }
99    Ok(())
100}
101
102// SplitMix64, with independently mixed initial channel states. All arithmetic is
103// wrapping u64; the top 53 bits of each draw are exactly representable as f64.
104const DITHER_STEP: u64 = 0x9e37_79b9_7f4a_7c15;
105fn mix(mut value: u64) -> u64 {
106    value = (value ^ (value >> 30)).wrapping_mul(0xbf58_476d_1ce4_e5b9);
107    value = (value ^ (value >> 27)).wrapping_mul(0x94d0_49bb_1331_11eb);
108    value ^ (value >> 31)
109}
110
111#[derive(Debug)]
112pub(crate) struct Quantizer {
113    scale: f64,
114    state: Option<u64>,
115}
116impl Quantizer {
117    pub(crate) fn new(bits: u32, dither: Dither, channel: usize) -> Self {
118        Self {
119            scale: (1u64 << (bits - 1)) as f64,
120            state: match dither {
121                Dither::None => None,
122                Dither::Tpdf { seed } => {
123                    Some(mix(seed ^ (channel as u64 + 1).wrapping_mul(DITHER_STEP)))
124                }
125            },
126        }
127    }
128    pub(crate) fn sample(&mut self, sample: f32) -> i64 {
129        let noise = if let Some(state) = &mut self.state {
130            let mut draw = || {
131                *state = state.wrapping_add(DITHER_STEP);
132                (mix(*state) >> 11) as f64 / (1u64 << 53) as f64
133            };
134            draw() - draw()
135        } else {
136            0.0
137        };
138        // Add in destination LSBs in f64, not f32: even 32-bit dither survives.
139        (sample as f64 * self.scale + noise)
140            .round()
141            .clamp(-self.scale, self.scale - 1.0) as i64
142    }
143}
144
145pub(crate) fn quantizers(format: SampleFormat, dither: Dither, channels: usize) -> Vec<Quantizer> {
146    if dither == Dither::None {
147        Vec::new()
148    } else {
149        (0..channels)
150            .map(|c| Quantizer::new(format.bits() as u32, dither, c))
151            .collect()
152    }
153}
154
155pub(crate) fn encode_quantized(
156    audio: &Audio,
157    format: SampleFormat,
158    endian: Endian,
159    quantizers: &mut [Quantizer],
160) -> Result<Vec<u8>> {
161    let size = audio
162        .frames()
163        .checked_mul(audio.channels())
164        .and_then(|n| n.checked_mul(format.bytes()))
165        .ok_or_else(|| Error::encode("PCM size overflow"))?;
166    let mut out = Vec::with_capacity(size);
167    for i in 0..audio.frames() {
168        for (channel, c) in audio.all_channels().iter().enumerate() {
169            if let Some(q) = quantizers.get_mut(channel) {
170                let value = q.sample(c[i]);
171                write_value(
172                    &mut out,
173                    (if format == SampleFormat::U8 {
174                        value + 128
175                    } else {
176                        value
177                    }) as u64,
178                    format.bytes(),
179                    endian,
180                );
181            } else {
182                write_sample(&mut out, c[i], format, endian);
183            }
184        }
185    }
186    Ok(out)
187}
188pub(crate) fn write_sample(out: &mut Vec<u8>, sample: f32, f: SampleFormat, e: Endian) {
189    let n = f.bytes();
190    let quant = |bits: u32| -> i64 {
191        let scale = (1u64 << (bits - 1)) as f64;
192        (sample as f64 * scale).round().clamp(-scale, scale - 1.0) as i64
193    };
194    let value = match f {
195        SampleFormat::U8 => (quant(8) + 128) as u64,
196        SampleFormat::S8 => quant(8) as u64,
197        SampleFormat::S16 => quant(16) as u64,
198        SampleFormat::S24 => quant(24) as u64,
199        SampleFormat::S32 => quant(32) as u64,
200        SampleFormat::F32 => sample.to_bits() as u64,
201        SampleFormat::F64 => (sample as f64).to_bits(),
202        SampleFormat::Alaw => encode_alaw(quant(16) as i16) as u64,
203        SampleFormat::Ulaw => encode_ulaw(quant(16) as i16) as u64,
204    };
205    write_value(out, value, n, e);
206}
207fn write_value(out: &mut Vec<u8>, value: u64, n: usize, e: Endian) {
208    for i in 0..n {
209        let shift = if e == Endian::Little { i } else { n - 1 - i };
210        out.push((value >> (shift * 8)) as u8);
211    }
212}
213pub fn decode_ulaw(value: u8) -> i16 {
214    let u = !value;
215    let t = (((u & 15) as i32) * 8 + 132) << ((u >> 4) & 7);
216    if u & 128 != 0 {
217        (132 - t) as i16
218    } else {
219        (t - 132) as i16
220    }
221}
222pub fn encode_ulaw(sample: i16) -> u8 {
223    let n = sample as i32;
224    let mask = if n < 0 { 0x7f } else { 0xff };
225    let n = n.abs().min(32635) + 132;
226    let mut exp = 7u8;
227    let mut bit = 0x4000;
228    while exp > 0 && n & bit == 0 {
229        exp -= 1;
230        bit >>= 1;
231    }
232    ((exp << 4) | ((n >> (exp + 3)) & 15) as u8) ^ mask
233}
234pub fn decode_alaw(value: u8) -> i16 {
235    let a = value ^ 0x55;
236    let seg = (a >> 4) & 7;
237    let mut n = ((a & 15) as i32) << 4;
238    n += if seg == 0 { 8 } else { 264 };
239    if seg > 1 {
240        n <<= seg - 1;
241    }
242    if a & 128 != 0 { n as i16 } else { -n as i16 }
243}
244pub fn encode_alaw(sample: i16) -> u8 {
245    let n = sample as i32;
246    let mask = if n >= 0 { 0xd5 } else { 0x55 };
247    let n = if n >= 0 { n } else { -n - 1 };
248    let mut seg = 0u8;
249    let mut bound = 255;
250    while n > bound && seg < 7 {
251        seg += 1;
252        bound = (bound << 1) | 1;
253    }
254    let shift = if seg == 0 { 4 } else { seg + 3 };
255    ((seg << 4) | ((n >> shift) & 15) as u8) ^ mask
256}
257
258const IMA_STEPS: [i32; 89] = [
259    7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, 60, 66,
260    73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449,
261    494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 2272,
262    2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493,
263    10442, 11487, 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767,
264];
265pub(crate) fn decode_ima(
266    bytes: &[u8],
267    channels: usize,
268    rate: u32,
269    block: usize,
270    samples_per_block: usize,
271    limits: &Limits,
272) -> Result<Audio> {
273    if !(1..=2).contains(&channels)
274        || block < channels * 4
275        || samples_per_block == 0
276        || bytes.len() % block != 0
277    {
278        return Err(Error::decode("Invalid IMA ADPCM blocks"));
279    }
280    let frames = (bytes.len() / block)
281        .checked_mul(samples_per_block)
282        .ok_or_else(|| Error::limit("ADPCM frame count overflow"))?;
283    limits.check(frames, channels, rate)?;
284    let mut data: Vec<Vec<f32>> = (0..channels).map(|_| Vec::with_capacity(frames)).collect();
285    for b in bytes.chunks_exact(block) {
286        decode_ima_block(b, samples_per_block, &mut data)?;
287    }
288    Audio::decoded(data, rate, DecodeInfo::default())
289}
290
291/// Appends one IMA ADPCM block of one or two channels to `data`. Allocates nothing
292/// when `data` has room for `samples_per_block` more samples.
293pub(crate) fn decode_ima_block(
294    b: &[u8],
295    samples_per_block: usize,
296    data: &mut [Vec<f32>],
297) -> Result<()> {
298    let channels = data.len();
299    let mut predictor = [0i32; 2];
300    let mut index = [0i32; 2];
301    for c in 0..channels {
302        predictor[c] = i16::from_le_bytes([b[c * 4], b[c * 4 + 1]]) as i32;
303        index[c] = b[c * 4 + 2] as i32;
304        if index[c] > 88 {
305            return Err(Error::decode("Invalid ADPCM step index"));
306        }
307        data[c].push(predictor[c] as f32 / 32768.0);
308    }
309    let mut pos = channels * 4;
310    let mut emitted = [1; 2];
311    while pos < b.len() {
312        for c in 0..channels {
313            let count = if channels == 1 { b.len() - pos } else { 4 };
314            let chunk = b
315                .get(pos..pos + count)
316                .ok_or_else(|| Error::decode("Incomplete ADPCM channel group"))?;
317            for &v in chunk {
318                for shift in [0, 4] {
319                    if emitted[c] >= samples_per_block {
320                        break;
321                    }
322                    let code = (v >> shift) & 15;
323                    let step = IMA_STEPS[index[c] as usize];
324                    let diff = (step >> 3)
325                        + if code & 1 != 0 { step >> 2 } else { 0 }
326                        + if code & 2 != 0 { step >> 1 } else { 0 }
327                        + if code & 4 != 0 { step } else { 0 };
328                    predictor[c] = (predictor[c] + if code & 8 != 0 { -diff } else { diff })
329                        .clamp(-32768, 32767);
330                    index[c] =
331                        (index[c] + [-1, -1, -1, -1, 2, 4, 6, 8][(code & 7) as usize]).clamp(0, 88);
332                    data[c].push(predictor[c] as f32 / 32768.0);
333                    emitted[c] += 1;
334                }
335            }
336            pos += count;
337        }
338    }
339    if emitted[..channels].iter().any(|&n| n != samples_per_block) {
340        return Err(Error::decode("ADPCM block has too few samples"));
341    }
342    Ok(())
343}