sim_lib_stream_audio/
buffer.rs1use sim_kernel::{Error, Result};
2use sim_lib_stream_core::PcmPacket;
3
4use crate::{PcmSampleFormat, PcmSpec};
5
6#[derive(Clone, Debug)]
32pub struct PcmBuffer {
33 spec: PcmSpec,
34 frames: usize,
35 samples: PcmBufferSamples,
36}
37
38impl PartialEq for PcmBuffer {
39 fn eq(&self, other: &Self) -> bool {
40 self.spec == other.spec && self.frames == other.frames && self.samples == other.samples
41 }
42}
43
44impl Eq for PcmBuffer {}
45
46#[derive(Clone, Debug)]
47enum PcmBufferSamples {
48 I16(Vec<i16>),
49 F32(Vec<f32>),
50}
51
52impl PartialEq for PcmBufferSamples {
53 fn eq(&self, other: &Self) -> bool {
54 match (self, other) {
55 (Self::I16(left), Self::I16(right)) => left == right,
56 (Self::F32(left), Self::F32(right)) => {
57 left.len() == right.len()
58 && left
59 .iter()
60 .zip(right)
61 .all(|(left, right)| left.to_bits() == right.to_bits())
62 }
63 _ => false,
64 }
65 }
66}
67
68impl Eq for PcmBufferSamples {}
69
70impl PcmBuffer {
71 pub fn i16(spec: PcmSpec, frames: usize, samples_i16: Vec<i16>) -> Result<Self> {
76 if spec.sample_format() != PcmSampleFormat::I16 {
77 return Err(Error::Eval(
78 "PCM buffer requires an i16 PCM spec".to_owned(),
79 ));
80 }
81 let expected = expected_samples(spec.channels(), frames)?;
82 if samples_i16.len() != expected {
83 return Err(Error::Eval(format!(
84 "PCM buffer sample length {} does not match channels {} * frames {}",
85 samples_i16.len(),
86 spec.channels(),
87 frames
88 )));
89 }
90 Ok(Self {
91 spec,
92 frames,
93 samples: PcmBufferSamples::I16(samples_i16),
94 })
95 }
96
97 pub fn f32(spec: PcmSpec, frames: usize, samples_f32: Vec<f32>) -> Result<Self> {
103 if spec.sample_format() != PcmSampleFormat::F32 {
104 return Err(Error::Eval(
105 "PCM buffer requires an f32 PCM spec".to_owned(),
106 ));
107 }
108 let expected = expected_samples(spec.channels(), frames)?;
109 if samples_f32.len() != expected {
110 return Err(Error::Eval(format!(
111 "PCM buffer sample length {} does not match channels {} * frames {}",
112 samples_f32.len(),
113 spec.channels(),
114 frames
115 )));
116 }
117 validate_f32_samples(&samples_f32)?;
118 Ok(Self {
119 spec,
120 frames,
121 samples: PcmBufferSamples::F32(samples_f32),
122 })
123 }
124
125 pub fn from_packet(spec: PcmSpec, packet: &PcmPacket) -> Result<Self> {
131 if packet.channels() != spec.channels() {
132 return Err(Error::Eval(format!(
133 "PCM packet channel count {} does not match sink spec {}",
134 packet.channels(),
135 spec.channels()
136 )));
137 }
138 if packet.sample_format() != spec.sample_format() {
139 return Err(Error::Eval(format!(
140 "PCM packet sample format {:?} does not match sink spec {:?}",
141 packet.sample_format(),
142 spec.sample_format()
143 )));
144 }
145 match spec.sample_format() {
146 PcmSampleFormat::I16 => Self::i16(spec, packet.frames(), packet.samples_i16().to_vec()),
147 PcmSampleFormat::F32 => Self::f32(spec, packet.frames(), packet.samples_f32().to_vec()),
148 }
149 }
150
151 pub fn to_packet(&self) -> Result<PcmPacket> {
154 match &self.samples {
155 PcmBufferSamples::I16(samples) => {
156 PcmPacket::i16(self.spec.channels(), self.frames, samples.clone())
157 }
158 PcmBufferSamples::F32(samples) => {
159 PcmPacket::f32(self.spec.channels(), self.frames, samples.clone())
160 }
161 }
162 }
163
164 pub fn spec(&self) -> PcmSpec {
166 self.spec
167 }
168
169 pub fn frames(&self) -> usize {
171 self.frames
172 }
173
174 pub fn samples_i16(&self) -> &[i16] {
180 match &self.samples {
181 PcmBufferSamples::I16(samples) => samples,
182 PcmBufferSamples::F32(_) => panic!("PCM buffer does not contain i16 samples"),
183 }
184 }
185
186 pub fn samples_f32(&self) -> &[f32] {
192 match &self.samples {
193 PcmBufferSamples::F32(samples) => samples,
194 PcmBufferSamples::I16(_) => panic!("PCM buffer does not contain f32 samples"),
195 }
196 }
197}
198
199pub fn i16_sample_to_f32(sample: i16) -> f32 {
213 if sample < 0 {
214 f32::from(sample) / 32768.0
215 } else {
216 f32::from(sample) / f32::from(i16::MAX)
217 }
218}
219
220pub fn f32_sample_to_i16(sample: f32) -> Result<i16> {
225 if !sample.is_finite() {
226 return Err(Error::Eval("PCM f32 sample must be finite".to_owned()));
227 }
228 let clamped = sample.clamp(-1.0, 1.0);
229 if clamped < 0.0 {
230 Ok((clamped * 32768.0).round().max(f32::from(i16::MIN)) as i16)
231 } else {
232 Ok((clamped * f32::from(i16::MAX))
233 .round()
234 .min(f32::from(i16::MAX)) as i16)
235 }
236}
237
238pub fn i16_samples_to_f32(samples: &[i16]) -> Vec<f32> {
241 samples
242 .iter()
243 .map(|sample| i16_sample_to_f32(*sample))
244 .collect()
245}
246
247pub fn f32_samples_to_i16(samples: &[f32]) -> Result<Vec<i16>> {
252 samples
253 .iter()
254 .map(|sample| f32_sample_to_i16(*sample))
255 .collect()
256}
257
258pub fn i16_interleaved_to_planar(samples: &[i16], channels: usize) -> Result<Vec<Vec<i16>>> {
263 interleaved_to_planar(samples, channels)
264}
265
266pub fn i16_planar_to_interleaved(channels: &[Vec<i16>]) -> Result<Vec<i16>> {
271 planar_to_interleaved(channels)
272}
273
274pub fn f32_interleaved_to_planar(samples: &[f32], channels: usize) -> Result<Vec<Vec<f32>>> {
279 validate_f32_samples(samples)?;
280 interleaved_to_planar(samples, channels)
281}
282
283pub fn f32_planar_to_interleaved(channels: &[Vec<f32>]) -> Result<Vec<f32>> {
288 let samples = planar_to_interleaved(channels)?;
289 validate_f32_samples(&samples)?;
290 Ok(samples)
291}
292
293fn expected_samples(channels: usize, frames: usize) -> Result<usize> {
294 channels
295 .checked_mul(frames)
296 .ok_or_else(|| Error::Eval("PCM buffer sample count overflow".to_owned()))
297}
298
299fn validate_f32_samples(samples: &[f32]) -> Result<()> {
300 if let Some(index) = samples.iter().position(|sample| !sample.is_finite()) {
301 return Err(Error::Eval(format!(
302 "PCM f32 sample at {index} must be finite"
303 )));
304 }
305 Ok(())
306}
307
308fn interleaved_to_planar<T>(samples: &[T], channels: usize) -> Result<Vec<Vec<T>>>
309where
310 T: Copy,
311{
312 if channels == 0 {
313 return Err(Error::Eval(
314 "PCM channel count must be greater than zero".to_owned(),
315 ));
316 }
317 if !samples.len().is_multiple_of(channels) {
318 return Err(Error::Eval(format!(
319 "PCM interleaved sample length {} is not divisible by channels {}",
320 samples.len(),
321 channels
322 )));
323 }
324 let frames = samples.len() / channels;
325 let mut planar = vec![Vec::with_capacity(frames); channels];
326 for frame in samples.chunks(channels) {
327 for (channel, sample) in frame.iter().enumerate() {
328 planar[channel].push(*sample);
329 }
330 }
331 Ok(planar)
332}
333
334fn planar_to_interleaved<T>(channels: &[Vec<T>]) -> Result<Vec<T>>
335where
336 T: Copy,
337{
338 let Some(first) = channels.first() else {
339 return Err(Error::Eval(
340 "PCM planar data must contain at least one channel".to_owned(),
341 ));
342 };
343 let frames = first.len();
344 if let Some((index, channel)) = channels
345 .iter()
346 .enumerate()
347 .find(|(_, channel)| channel.len() != frames)
348 {
349 return Err(Error::Eval(format!(
350 "PCM planar channel {index} length {} does not match frame count {frames}",
351 channel.len()
352 )));
353 }
354 let mut interleaved = Vec::with_capacity(frames * channels.len());
355 for frame in 0..frames {
356 for channel in channels {
357 interleaved.push(channel[frame]);
358 }
359 }
360 Ok(interleaved)
361}