1use crate::*;
2use alloc::vec::Vec;
3use core::fmt::Display;
4
5pub enum PcmError {
6 TooShort,
7 BadMagicNumber,
8 BadSampleRate(u16),
9}
10
11impl Display for PcmError {
12 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
13 match self {
14 Self::TooShort => write!(f, "file is too short"),
15 Self::BadMagicNumber => write!(f, "bad magic number"),
16 Self::BadSampleRate(sr) => write!(f, "bad sample rate: expected 44100, got {sr}"),
17 }
18 }
19}
20
21pub struct Pcm<R: embedded_io::Read> {
23 reader: R,
24 _sample_rate: u16,
25 is16: bool,
26 stereo: bool,
27 _adpcm: bool,
28}
29
30impl<R: embedded_io::Read> Pcm<R> {
31 pub fn from_file(mut reader: R) -> Result<Self, PcmError> {
37 let mut header = [0u8; 4];
38 let res = reader.read_exact(&mut header);
39 if res.is_err() {
40 return Err(PcmError::TooShort);
41 }
42 if header[0] != 0x31 {
43 return Err(PcmError::BadMagicNumber);
44 }
45 let sample_rate = u16::from_le_bytes([header[2], header[3]]);
46 if sample_rate != 44100 {
47 return Err(PcmError::BadSampleRate(sample_rate));
48 }
49 Ok(Self {
50 reader,
51 _sample_rate: sample_rate,
52 stereo: header[1] & 0b_100 != 0,
53 is16: header[1] & 0b_010 != 0,
54 _adpcm: header[1] & 0b_001 != 0,
55 })
56 }
57}
58
59impl<R: embedded_io::Read> Processor for Pcm<R> {
60 fn process_children(&mut self, _cn: &mut Vec<Node>) -> Option<Frame> {
61 let f = match (self.is16, self.stereo) {
62 (false, false) => {
64 let mut buf = [0u8; 8];
65 self.reader.read_exact(&mut buf).ok()?;
66 let s = Sample::new(i8s_to_f32s(buf));
67 Frame::mono(s)
68 }
69 (false, true) => {
71 let mut buf = [0u8; 16];
72 self.reader.read_exact(&mut buf).ok()?;
73 let left = Sample::new(i8s_to_f32s_left(buf));
74 let right = Sample::new(i8s_to_f32s_right(buf));
75 Frame::stereo(left, right)
76 }
77 (true, false) => {
79 let mut buf = [0u8; 16];
80 self.reader.read_exact(&mut buf).ok()?;
81 let s = Sample::new(i16s_to_f32s(buf));
82 Frame::mono(s)
83 }
84 (true, true) => {
86 let mut buf = [0u8; 32];
87 self.reader.read_exact(&mut buf).ok()?;
88 let left = Sample::new(i16s_to_f32s_left(buf));
89 let right = Sample::new(i16s_to_f32s_right(buf));
90 Frame::stereo(left, right)
91 }
92 };
93 Some(f)
94 }
95}
96
97fn i8s_to_f32s(us: [u8; 8]) -> [f32; 8] {
98 [
99 i8_to_f32(us[0]),
100 i8_to_f32(us[1]),
101 i8_to_f32(us[2]),
102 i8_to_f32(us[3]),
103 i8_to_f32(us[4]),
104 i8_to_f32(us[5]),
105 i8_to_f32(us[6]),
106 i8_to_f32(us[7]),
107 ]
108}
109
110fn i8s_to_f32s_left(us: [u8; 16]) -> [f32; 8] {
111 [
112 i8_to_f32(us[0]),
113 i8_to_f32(us[2]),
114 i8_to_f32(us[4]),
115 i8_to_f32(us[6]),
116 i8_to_f32(us[8]),
117 i8_to_f32(us[10]),
118 i8_to_f32(us[12]),
119 i8_to_f32(us[14]),
120 ]
121}
122
123fn i8s_to_f32s_right(us: [u8; 16]) -> [f32; 8] {
124 [
125 i8_to_f32(us[1]),
126 i8_to_f32(us[3]),
127 i8_to_f32(us[5]),
128 i8_to_f32(us[7]),
129 i8_to_f32(us[9]),
130 i8_to_f32(us[11]),
131 i8_to_f32(us[13]),
132 i8_to_f32(us[15]),
133 ]
134}
135
136fn i16s_to_f32s(us: [u8; 16]) -> [f32; 8] {
137 [
138 i16_to_f32(us[0], us[1]),
139 i16_to_f32(us[2], us[3]),
140 i16_to_f32(us[4], us[5]),
141 i16_to_f32(us[6], us[7]),
142 i16_to_f32(us[8], us[9]),
143 i16_to_f32(us[10], us[11]),
144 i16_to_f32(us[12], us[13]),
145 i16_to_f32(us[14], us[15]),
146 ]
147}
148
149fn i16s_to_f32s_left(us: [u8; 32]) -> [f32; 8] {
150 [
151 i16_to_f32(us[0], us[1]),
152 i16_to_f32(us[4], us[5]),
153 i16_to_f32(us[8], us[9]),
154 i16_to_f32(us[12], us[13]),
155 i16_to_f32(us[16], us[17]),
156 i16_to_f32(us[20], us[21]),
157 i16_to_f32(us[24], us[25]),
158 i16_to_f32(us[28], us[29]),
159 ]
160}
161
162fn i16s_to_f32s_right(us: [u8; 32]) -> [f32; 8] {
163 [
164 i16_to_f32(us[2], us[3]),
165 i16_to_f32(us[6], us[7]),
166 i16_to_f32(us[10], us[11]),
167 i16_to_f32(us[14], us[15]),
168 i16_to_f32(us[18], us[19]),
169 i16_to_f32(us[22], us[23]),
170 i16_to_f32(us[26], us[27]),
171 i16_to_f32(us[30], us[31]),
172 ]
173}
174
175fn i8_to_f32(u: u8) -> f32 {
176 #[expect(clippy::cast_possible_wrap)]
177 let i = u as i8;
178 f32::from(i) / f32::from(i8::MAX)
179}
180
181fn i16_to_f32(l: u8, r: u8) -> f32 {
182 let i = i16::from_le_bytes([l, r]);
183 f32::from(i) / f32::from(i16::MAX)
184}