Skip to main content

embedded_audio/decode/
pcm.rs

1use crate::fixed::lerp_i8;
2
3/// Streaming 8-bit PCM (Tier B) with fractional speed resampling.
4#[derive(Debug, Clone, Copy)]
5pub struct Pcm8Stream<'a> {
6    data: &'a [u8],
7    phase_q16: u32,
8    speed_q16: u32,
9    looped: bool,
10    is_signed: bool,
11}
12
13impl<'a> Pcm8Stream<'a> {
14    pub fn new(data: &'a [u8], flags: u8) -> Self {
15        Self::with_speed(data, flags, 65536)
16    }
17
18    pub fn with_speed(data: &'a [u8], flags: u8, speed_q16: u32) -> Self {
19        Self {
20            data,
21            phase_q16: 0,
22            speed_q16,
23            looped: flags & crate::tier::flags::LOOP != 0,
24            is_signed: flags & crate::tier::flags::SIGNED != 0,
25        }
26    }
27
28    pub fn set_speed_q16(&mut self, speed_q16: u32) {
29        self.speed_q16 = speed_q16;
30    }
31
32    pub fn speed_q16(&self) -> u32 {
33        self.speed_q16
34    }
35
36    pub fn reset(&mut self) {
37        self.phase_q16 = 0;
38    }
39
40    pub fn is_done(&self) -> bool {
41        if self.data.is_empty() {
42            return true;
43        }
44        let pos = (self.phase_q16 >> 16) as usize;
45        !self.looped && pos >= self.data.len()
46    }
47
48    #[inline]
49    fn get_sample(&self, idx: usize) -> i8 {
50        if idx >= self.data.len() {
51            0
52        } else if self.is_signed {
53            self.data[idx] as i8
54        } else {
55            self.data[idx].wrapping_sub(128) as i8
56        }
57    }
58
59    pub fn next_sample(&mut self) -> Option<i8> {
60        if self.data.is_empty() {
61            return None;
62        }
63
64        let curr_idx = (self.phase_q16 >> 16) as usize;
65
66        if curr_idx >= self.data.len() {
67            if self.looped {
68                let len = self.data.len();
69                let wrap = (curr_idx % len) << 16;
70                self.phase_q16 = (wrap as u32) | (self.phase_q16 & 0xFFFF);
71            } else {
72                return None;
73            }
74        }
75
76        let idx = (self.phase_q16 >> 16) as usize;
77        let frac = ((self.phase_q16 >> 8) & 0xFF) as u8;
78
79        let a = self.get_sample(idx);
80        let next_idx = if idx + 1 < self.data.len() {
81            idx + 1
82        } else if self.looped {
83            0
84        } else {
85            idx
86        };
87        let b = self.get_sample(next_idx);
88
89        let sample = lerp_i8(a, b, frac);
90        self.phase_q16 = self.phase_q16.wrapping_add(self.speed_q16);
91
92        Some(sample)
93    }
94}