Skip to main content

sim_lib_stream_audio/
spec.rs

1use sim_kernel::{Error, Result};
2pub use sim_lib_stream_core::PcmSampleFormat;
3
4/// Audio format description for a PCM stream: channel count, sample rate, and
5/// sample encoding.
6///
7/// A `PcmSpec` is the validated, immutable contract shared by PCM buffers,
8/// sources, and sinks. It is constructed through [`PcmSpec::i16`] or
9/// [`PcmSpec::f32`], which reject a zero channel count or zero sample rate, so a
10/// constructed value is always a usable audio configuration.
11///
12/// # Examples
13///
14/// ```
15/// use sim_lib_stream_audio::{PcmSampleFormat, PcmSpec};
16///
17/// let spec = PcmSpec::f32(2, 48_000)?;
18/// assert_eq!(spec.channels(), 2);
19/// assert_eq!(spec.sample_rate_hz(), 48_000);
20/// assert_eq!(spec.sample_format(), PcmSampleFormat::F32);
21/// # Ok::<(), sim_kernel::Error>(())
22/// ```
23#[derive(Clone, Copy, Debug, PartialEq, Eq)]
24pub struct PcmSpec {
25    channels: usize,
26    sample_rate_hz: u32,
27    sample_format: PcmSampleFormat,
28}
29
30impl PcmSpec {
31    /// Builds an interleaved 16-bit signed integer ([`PcmSampleFormat::I16`])
32    /// spec.
33    ///
34    /// Returns an error when `channels` or `sample_rate_hz` is zero.
35    pub fn i16(channels: usize, sample_rate_hz: u32) -> Result<Self> {
36        if channels == 0 {
37            return Err(Error::Eval(
38                "PCM spec channel count must be greater than zero".to_owned(),
39            ));
40        }
41        if sample_rate_hz == 0 {
42            return Err(Error::Eval(
43                "PCM spec sample rate must be greater than zero".to_owned(),
44            ));
45        }
46        Ok(Self {
47            channels,
48            sample_rate_hz,
49            sample_format: PcmSampleFormat::I16,
50        })
51    }
52
53    /// Builds an interleaved 32-bit float ([`PcmSampleFormat::F32`]) spec.
54    ///
55    /// Returns an error when `channels` or `sample_rate_hz` is zero.
56    pub fn f32(channels: usize, sample_rate_hz: u32) -> Result<Self> {
57        if channels == 0 {
58            return Err(Error::Eval(
59                "PCM spec channel count must be greater than zero".to_owned(),
60            ));
61        }
62        if sample_rate_hz == 0 {
63            return Err(Error::Eval(
64                "PCM spec sample rate must be greater than zero".to_owned(),
65            ));
66        }
67        Ok(Self {
68            channels,
69            sample_rate_hz,
70            sample_format: PcmSampleFormat::F32,
71        })
72    }
73
74    /// Returns the number of interleaved audio channels.
75    pub fn channels(self) -> usize {
76        self.channels
77    }
78
79    /// Returns the sample rate in hertz (frames per second).
80    pub fn sample_rate_hz(self) -> u32 {
81        self.sample_rate_hz
82    }
83
84    /// Returns the per-sample encoding.
85    pub fn sample_format(self) -> PcmSampleFormat {
86        self.sample_format
87    }
88}