Skip to main content

forge_dictate/
audio.rs

1//! The audio a transcription reads from.
2
3/// Sample rate every model in this crate expects, which is the rate
4/// capture opens a device at: one constant, so the two cannot drift.
5pub use forge_capture::SAMPLE_RATE;
6
7/// A buffer at another rate, brought to [`SAMPLE_RATE`] with the capture
8/// path's own filtered resampler: the one way a source declaring another
9/// rate becomes a source this crate accepts.
10pub use forge_capture::resample_mono;
11
12/// A pull-based source of mono audio.
13///
14/// Chunked rather than streamed so a source needs no hardware and no
15/// clock: a buffer already in memory drains through it as fast as the
16/// caller asks, and feeding a twenty second clip takes nowhere near
17/// twenty seconds.
18///
19/// The format accessors exist to be checked. A source whose rate or
20/// channel count does not match is rejected outright, because silently
21/// resampling or de-interleaving it would turn a wrong input into
22/// plausible output rather than an error, which is the failure nobody
23/// notices.
24pub trait AudioSource: Send {
25    /// Next samples, or None once the source is exhausted.
26    ///
27    /// Return None to end the stream; do not return an empty chunk to
28    /// mean "nothing yet". The drain is synchronous and would spin on
29    /// it, and a pull-based source has nothing to wait for.
30    fn next_chunk(&mut self) -> Option<Vec<f32>>;
31
32    /// Samples per second, as the source knows it to be.
33    fn sample_rate(&self) -> u32;
34
35    /// Interleaved channels. Deliberately without a default: a source
36    /// that has not thought about this is exactly the one that would
37    /// get it wrong.
38    fn channels(&self) -> u16;
39}
40
41/// Samples already in memory, the shape a file or a test uses.
42pub struct Samples {
43    samples: std::vec::IntoIter<f32>,
44    sample_rate: u32,
45    channels: u16,
46    chunk: usize,
47}
48
49impl Samples {
50    /// Mono samples at [`SAMPLE_RATE`].
51    pub fn mono(samples: impl Into<Vec<f32>>) -> Self {
52        Self::new(samples, SAMPLE_RATE, 1)
53    }
54
55    /// Samples at a rate and channel count the caller declares. What is
56    /// declared here is what an engine checks against.
57    pub fn new(samples: impl Into<Vec<f32>>, sample_rate: u32, channels: u16) -> Self {
58        Self { samples: samples.into().into_iter(), sample_rate, channels, chunk: 4096 }
59    }
60}
61
62impl AudioSource for Samples {
63    fn next_chunk(&mut self) -> Option<Vec<f32>> {
64        let chunk: Vec<f32> = self.samples.by_ref().take(self.chunk).collect();
65        (!chunk.is_empty()).then_some(chunk)
66    }
67
68    fn sample_rate(&self) -> u32 {
69        self.sample_rate
70    }
71
72    fn channels(&self) -> u16 {
73        self.channels
74    }
75}