Skip to main content

kittyaudio/
renderer.rs

1use crate::{Frame, SoundHandle};
2use parking_lot::{Mutex, MutexGuard};
3use std::sync::Arc;
4
5/// The audio renderer trait. Can be used to make custom audio renderers.
6pub trait Renderer: Clone + Send + 'static {
7    /// Render the next audio frame. The backend provides the sample rate and
8    /// expects the left and right channel values ([`Frame`]).
9    ///
10    /// Note: you can use a [`crate::Resampler`] to resample audio data.
11    fn next_frame(&mut self, sample_rate: u32) -> Frame;
12
13    /// This gets called when an audio buffer is done processing.
14    #[cfg(feature = "cpal")]
15    fn on_buffer<T>(&mut self, _buffer: &mut [T])
16    where
17        T: cpal::SizedSample + cpal::FromSample<f32>,
18    {
19    }
20}
21
22/// Default audio renderer.
23#[derive(Debug, Clone, Default)]
24pub struct DefaultRenderer {
25    /// All playing sounds.
26    pub sounds: Vec<SoundHandle>,
27    /// The last buffer size given by the [cpal] backend.
28    pub last_buffer_size: usize,
29}
30
31impl DefaultRenderer {
32    /// Start playing a sound. Accepts a type that can be converted into a
33    /// [`SoundHandle`].
34    #[inline]
35    pub fn add_sound(&mut self, sound: impl Into<SoundHandle>) {
36        self.sounds.push(sound.into());
37    }
38
39    /// Return whether the renderer has any playing sounds.
40    pub fn has_sounds(&self) -> bool {
41        !self.sounds.is_empty()
42    }
43}
44
45impl Renderer for DefaultRenderer {
46    fn next_frame(&mut self, sample_rate: u32) -> Frame {
47        // mix samples from all playing sounds
48        let mut out = Frame::ZERO;
49
50        // remove all sounds that finished playback
51        self.sounds.retain_mut(|sound| {
52            let frame = sound.next_frame(sample_rate);
53            if let Some(frame) = frame {
54                out += frame;
55                true
56            } else {
57                false
58            }
59        });
60
61        out
62    }
63
64    #[cfg(feature = "cpal")]
65    fn on_buffer<T>(&mut self, buffer: &mut [T])
66    where
67        T: cpal::SizedSample + cpal::FromSample<f32>,
68    {
69        self.last_buffer_size = buffer.len();
70    }
71}
72
73/// Wraps [`Renderer`] so it can be shared between threads.
74#[derive(Clone)]
75pub struct RendererHandle<R: Renderer>(Arc<Mutex<R>>);
76
77impl From<DefaultRenderer> for RendererHandle<DefaultRenderer> {
78    fn from(val: DefaultRenderer) -> Self {
79        RendererHandle::new(val)
80    }
81}
82
83impl<R: Renderer> RendererHandle<R> {
84    /// Create a new renderer handle.
85    pub fn new(renderer: R) -> Self {
86        Self(Arc::new(Mutex::new(renderer)))
87    }
88
89    /// Get a lock on the underlying renderer.
90    #[inline(always)]
91    pub fn guard(&self) -> MutexGuard<'_, R> {
92        self.0.lock()
93    }
94}