1use crate::{Frame, SoundHandle};
2use parking_lot::{Mutex, MutexGuard};
3use std::sync::Arc;
4
5pub trait Renderer: Clone + Send + 'static {
7 fn next_frame(&mut self, sample_rate: u32) -> Frame;
12
13 #[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#[derive(Debug, Clone, Default)]
24pub struct DefaultRenderer {
25 pub sounds: Vec<SoundHandle>,
27 pub last_buffer_size: usize,
29}
30
31impl DefaultRenderer {
32 #[inline]
35 pub fn add_sound(&mut self, sound: impl Into<SoundHandle>) {
36 self.sounds.push(sound.into());
37 }
38
39 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 let mut out = Frame::ZERO;
49
50 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#[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 pub fn new(renderer: R) -> Self {
86 Self(Arc::new(Mutex::new(renderer)))
87 }
88
89 #[inline(always)]
91 pub fn guard(&self) -> MutexGuard<'_, R> {
92 self.0.lock()
93 }
94}