makepad_audio_graph/
audio_traits.rs

1use {
2    std::collections::BTreeMap,
3    crate::{
4        makepad_platform::*,
5    }
6};
7
8
9// Audio component API
10
11
12
13pub enum AudioComponentAction{
14}
15
16pub trait AudioComponent: LiveApply {
17    fn ref_cast_type_id(&self) -> LiveType where Self: 'static {LiveType::of::<Self>()}
18    fn handle_event_with(&mut self, _cx: &mut Cx, event: &Event, dispatch_action: &mut dyn FnMut(&mut Cx, AudioComponentAction));
19    fn get_graph_node(&mut self, cx: &mut Cx) -> Box<dyn AudioGraphNode + Send>;
20    fn audio_query(&mut self, _query: &AudioQuery, _callback: &mut Option<AudioQueryCb>) -> AudioResult;
21}
22
23pub trait AudioGraphNode {
24    fn handle_midi_data(&mut self, data: MidiData);
25    fn all_notes_off(&mut self);
26    fn render_to_audio_buffer(
27        &mut self,
28        info: AudioInfo,
29        outputs: &mut [&mut AudioBuffer],
30        inputs: &[&AudioBuffer],
31        display: &mut DisplayAudioGraph
32    );
33}
34
35generate_any_trait_api!(AudioComponent);
36
37
38// Audio component registry
39
40
41pub enum ToUIDisplayMsg{
42    DisplayAudio{voice: usize, buffer:AudioBuffer, active:bool},
43    VoiceOff{voice: usize},
44    OutOfBuffers
45}
46
47pub struct DisplayAudioGraph<'a> {
48    pub to_ui: &'a ToUISender<ToUIDisplayMsg>, 
49    pub buffers: &'a mut Vec<AudioBuffer>,
50}
51
52// Audio component registry
53impl<'a> DisplayAudioGraph<'a>{
54    pub fn pop_buffer_resize(&mut self, frame_count:usize, channels:usize)->Option<AudioBuffer>{
55        if let Some(mut buf) = self.buffers.pop(){
56            buf.resize(frame_count, channels);
57            return Some(buf)
58        }
59        else{
60            self.to_ui.send(ToUIDisplayMsg::OutOfBuffers).unwrap();
61            None
62        }
63    }
64    pub fn send_buffer(&self, active:bool, voice: usize, buffer:AudioBuffer){
65        self.to_ui.send(ToUIDisplayMsg::DisplayAudio{active, voice, buffer}).unwrap();
66    }
67    
68    pub fn send_voice_off(&self, voice: usize){
69        self.to_ui.send(ToUIDisplayMsg::VoiceOff{voice}).unwrap();
70    }
71}
72
73
74#[derive(Default, LiveComponentRegistry)]
75pub struct AudioComponentRegistry {
76    pub map: BTreeMap<LiveType, (LiveComponentInfo, Box<dyn AudioComponentFactory>)>
77}
78
79pub trait AudioComponentFactory {
80    fn new(&self, cx: &mut Cx) -> Box<dyn AudioComponent>;
81}
82
83
84// Live bindings for AudioComponentRef
85
86pub struct AudioQueryCb<'a> {
87    pub cb: &'a mut dyn FnMut(&mut Box<dyn AudioComponent >)
88}
89
90impl<'a> AudioQueryCb<'a> {
91    pub fn call(&mut self, args: &mut Box<dyn AudioComponent >) {
92        let cb = &mut self.cb;
93        cb(args)
94    }
95}
96
97pub struct AudioComponentRef(Option<Box<dyn AudioComponent >>);
98
99impl AudioComponentRef {
100    pub fn _as_ref(&mut self) -> Option<&Box<dyn AudioComponent >> {
101        self.0.as_ref()
102    }
103    pub fn as_mut(&mut self) -> Option<&mut Box<dyn AudioComponent >> {
104        self.0.as_mut()
105    }
106    
107    pub fn audio_query(&mut self, query: &AudioQuery, callback: &mut Option<AudioQueryCb>) -> AudioResult {
108        if let Some(inner) = &mut self.0 {
109            match query {
110                AudioQuery::TypeId(id) => {
111                    if inner.ref_cast_type_id() == *id {
112                        if let Some(callback) = callback {
113                            callback.call(inner)
114                        }
115                        else {
116                            return AudioResult::found(inner)
117                        }
118                    }
119                },
120            }
121            inner.audio_query(query, callback)
122        }
123        else {
124            AudioResult::not_found()
125        }
126    }
127}
128
129impl LiveHook for AudioComponentRef {}
130impl LiveApply for AudioComponentRef {
131    fn apply(&mut self, cx: &mut Cx, apply: &mut Apply, index: usize, nodes: &[LiveNode]) -> usize {
132        if let LiveValue::Class {live_type, ..} = nodes[index].value {
133            if let Some(component) = &mut self.0 {
134                if component.ref_cast_type_id() != live_type {
135                    self.0 = None; // type changed, drop old component
136                }
137                else {
138                    return component.apply(cx, apply, index, nodes)
139                }
140            }
141            if let Some(component) = cx.live_registry.clone().borrow()
142                .components.get::<AudioComponentRegistry>().new(cx, live_type) {
143                self.0 = Some(component);
144                return self.0.as_mut().unwrap().apply(cx, apply, index, nodes);
145            }
146        }
147        else if let Some(component) = &mut self.0 {
148            return component.apply(cx, apply, index, nodes);
149        }
150        nodes.skip_node(index)
151    }
152}
153
154impl LiveNew for AudioComponentRef {
155    fn new(_cx: &mut Cx) -> Self {
156        Self (None)
157    }
158    
159    fn live_type_info(_cx: &mut Cx) -> LiveTypeInfo {
160        LiveTypeInfo {
161            module_id: LiveModuleId::from_str(&module_path!()).unwrap(),
162            live_type: LiveType::of::<dyn AudioComponent>(),
163            fields: Vec::new(),
164            live_ignore: true,
165            type_name: LiveId(0)
166        }
167    }
168}
169
170pub enum AudioQuery {
171    TypeId(std::any::TypeId),
172}
173
174pub type AudioResult<'a> = Result<(), &'a mut Box<dyn AudioComponent >>;
175
176pub trait AudioResultApi<'a> {
177    fn not_found() -> AudioResult<'a> {AudioResult::Ok(())}
178    fn found(arg: &'a mut Box<dyn AudioComponent>) -> AudioResult<'a> {AudioResult::Err(arg)}
179    fn is_not_found(&self) -> bool;
180    fn is_found(&self) -> bool;
181    fn into_found(self) -> Option<&'a mut Box<dyn AudioComponent >>;
182}
183impl<'a> AudioResultApi<'a> for AudioResult<'a> {
184    
185    fn is_not_found(&self) -> bool {
186        match *self {
187            Result::Ok(_) => true,
188            Result::Err(_) => false
189        }
190    }
191    fn is_found(&self) -> bool {
192        match *self {
193            Result::Ok(_) => false,
194            Result::Err(_) => true
195        }
196    }
197    fn into_found(self) -> Option<&'a mut Box<dyn AudioComponent >> {
198        match self {
199            Result::Ok(_) => None,
200            Result::Err(arg) => Some(arg)
201        }
202    }
203}
204
205/*
206pub enum AudioResult<'a> {
207    NotFound,
208    Found(&'a mut Box<dyn AudioComponent>)
209}
210
211impl<'a> FromResidual for AudioResult<'a> {
212    fn from_residual(residual: &'a mut Box<dyn AudioComponent>) -> Self {
213        Self::Found(residual)
214    }
215}
216
217impl<'a> Try for AudioResult<'a> {
218    type Output = ();
219    type Residual = &'a mut Box<dyn AudioComponent>;
220    
221    fn from_output(_: Self::Output) -> Self {
222        AudioResult::NotFound
223    }
224    
225    fn branch(self) -> ControlFlow<Self::Residual,
226    Self::Output> {
227        match self {
228            Self::NotFound => ControlFlow::Continue(()),
229            Self::Found(c) => ControlFlow::Break(c)
230        }
231    }
232}*/
233
234#[macro_export]
235macro_rules!register_audio_component {
236    ($cx:ident, $ ty: ident) => {
237        {
238            struct Factory();
239            impl AudioComponentFactory for Factory {
240                fn new(&self, cx: &mut Cx) -> Box<dyn AudioComponent> {
241                    Box::new( $ ty::new(cx))
242                }
243            }
244            register_component_factory!($cx, AudioComponentRegistry, $ ty, Factory);
245        }
246    }
247}