mleml/extra/builtin/
mixer_template.rs

1use std::mem::discriminant;
2
3use dasp::frame::Stereo;
4
5use crate::{
6    resource::{
7        JsonArray, LeftoverSound, Mixer, PremixedSound, ResConfig, ResState, Resource, StringError,
8    },
9    types::Sound,
10};
11
12/// A mixer template that is easy to create and use.
13pub struct SimpleMixer<'a> {
14    name: String,
15    id: String,
16    desc: String,
17    schema: ResConfig,
18    values: ResConfig,
19    mix: fn(
20        &[(bool, &'a [Stereo<f32>])],
21        u32,
22        &ResConfig,
23        &ResState,
24    ) -> Result<(Box<Sound>, Box<ResState>, LeftoverSound<'a>), StringError>,
25    check_state: fn(&ResState) -> bool,
26}
27
28impl<'a> SimpleMixer<'a> {
29    /// Create new SimpleMixer.
30    pub fn new(
31        name: String,
32        id: String,
33        desc: String,
34        schema: ResConfig,
35        values: ResConfig,
36        mix: fn(
37            PremixedSound,
38            u32,
39            &ResConfig,
40            &ResState,
41        ) -> Result<(Box<Sound>, Box<ResState>, LeftoverSound<'a>), StringError>,
42        check_state: fn(&ResState) -> bool,
43    ) -> Self {
44        SimpleMixer {
45            name,
46            id,
47            desc,
48            schema,
49            values,
50            mix,
51            check_state,
52        }
53    }
54}
55
56impl<'a> Resource for SimpleMixer<'a> {
57    fn orig_name(&self) -> &str {
58        self.name.as_str()
59    }
60
61    fn id(&self) -> &str {
62        self.id.as_str()
63    }
64
65    fn check_config(&self, conf: &ResConfig) -> Result<(), StringError> {
66        match json_array_find_deviation(&self.schema, conf) {
67            Some(i) => Err(StringError(format!("type mismatch at index {}", i))),
68            None => Ok(()),
69        }
70    }
71
72    fn check_state(&self, state: &ResState) -> Option<()> {
73        (self.check_state)(state).then_some(())
74    }
75
76    fn description(&self) -> &str {
77        self.desc.as_str()
78    }
79}
80
81impl<'a> Mixer<'a> for SimpleMixer<'a> {
82    fn get_values(&self) -> ResConfig {
83        self.values.clone()
84    }
85
86    fn mix(
87        &self,
88        channels: PremixedSound<'a>,
89        play_time: u32,
90        conf: &ResConfig,
91        state: &ResState,
92    ) -> Result<(Box<Sound>, Box<ResState>, LeftoverSound<'a>), StringError> {
93        (self.mix)(channels, play_time, conf, state)
94    }
95}
96
97fn json_array_find_deviation(reference: &JsonArray, given: &JsonArray) -> Option<usize> {
98    (0..given.len())
99        .find(|&i| discriminant(&reference.as_slice()[i]) != discriminant(&given.as_slice()[i]))
100}