use {
crate::{
makepad_platform::*,
audio_traits::*,
},
std::any::TypeId,
std::sync::{Arc, Mutex},
};
live_design!{
AudioGraph= {{AudioGraph}} {
}
}
pub enum FromUI {
AllNotesOff,
MidiData(MidiData),
NewRoot(Box<dyn AudioGraphNode + Send>),
DisplayAudio(AudioBuffer),
}
pub enum AudioGraphAction<'a> {
DisplayAudio {
active: bool,
voice: usize,
buffer: &'a AudioBuffer
},
VoiceOff {voice: usize}
}
#[derive(Live, LiveRegister)]
pub struct AudioGraph {
#[live] root: AudioComponentRef,
#[rust] from_ui: FromUISender<FromUI>,
#[rust] to_ui: ToUIReceiver<ToUIDisplayMsg>,
}
impl LiveHook for AudioGraph {
fn after_new_from_doc(&mut self, cx: &mut Cx) {
Self::start_audio_output(cx, self.from_ui.receiver(), self.to_ui.sender());
if let Some(root) = self.root.as_mut() {
let graph_node = root.get_graph_node(cx);
let _ = self.from_ui.send(FromUI::NewRoot(graph_node));
}
}
fn skip_apply(&mut self, _cx: &mut Cx, apply: &mut Apply, index: usize, nodes: &[LiveNode])->Option<usize>{
if let ApplyFrom::UpdateFromDoc{..} = apply.from{
return Some(nodes.skip_node(index))
}
None
}
}
struct Node {
from_ui: FromUIReceiver<FromUI>,
display_buffers: Vec<AudioBuffer>,
root: Option<Box<dyn AudioGraphNode + Send >>
}
impl AudioGraph {
pub fn state_by_type<T: 'static + AudioGraphNode + Send> (&mut self) -> Option<&mut T>{
None
}
pub fn by_type<T: 'static + AudioComponent>(&mut self) -> Option<&mut T> {
if let Some(child) = self.root.audio_query(&AudioQuery::TypeId(TypeId::of::<T>()), &mut None).into_found() {
return child.downcast_mut::<T>()
}
None
}
pub fn send_midi_data(&self, data: MidiData) {
let _ = self.from_ui.send(FromUI::MidiData(data));
}
pub fn all_notes_off(&self) {
let _ = self.from_ui.send(FromUI::AllNotesOff);
}
fn render_to_output_buffer(node: &mut Node, to_ui: &ToUISender<ToUIDisplayMsg>, info: AudioInfo, output: &mut AudioBuffer) {
while let Ok(msg) = node.from_ui.try_recv() {
match msg {
FromUI::DisplayAudio(buf) => {
node.display_buffers.push(buf);
}
FromUI::NewRoot(new_root) => {
node.root = Some(new_root);
}
FromUI::MidiData(data) => {
if let Some(root) = node.root.as_mut() {
root.handle_midi_data(data);
}
}
FromUI::AllNotesOff=>{
if let Some(root) = node.root.as_mut() {
root.all_notes_off();
}
}
}
}
if let Some(root) = node.root.as_mut() {
let mut dg = DisplayAudioGraph {
to_ui,
buffers: &mut node.display_buffers
};
root.render_to_audio_buffer(info, &mut [output], &[], &mut dg);
}
}
fn start_audio_output(cx: &mut Cx, from_ui: FromUIReceiver<FromUI>, to_ui: ToUISender<ToUIDisplayMsg>) {
let mut buffers = Vec::new();
for _ in 0..512 {
buffers.push(AudioBuffer::new_with_size(512, 2));
}
let state = Arc::new(Mutex::new(Node {
from_ui,
display_buffers: buffers,
root: None
}));
let to_ui = Arc::new(Mutex::new(to_ui));
cx.audio_output(0, move | info, output_buffer | {
let mut state = state.lock().unwrap();
let to_ui = to_ui.lock().unwrap();
Self::render_to_output_buffer(&mut state, &to_ui, info, output_buffer);
});
}
pub fn handle_event_with(
&mut self,
cx: &mut Cx,
event: &Event,
dispatch_action: &mut dyn FnMut(&mut Cx, AudioGraphAction)
) {
if let Some(root) = self.root.as_mut() {
root.handle_event_with(cx, event, &mut | _, _ | {});
}
while let Ok(to_ui) = self.to_ui.try_recv() {
match to_ui {
ToUIDisplayMsg::DisplayAudio {voice, buffer, active} => {
dispatch_action(cx, AudioGraphAction::DisplayAudio {buffer: &buffer, voice, active});
self.from_ui.send(FromUI::DisplayAudio(buffer)).unwrap();
},
ToUIDisplayMsg::VoiceOff {voice} => {
dispatch_action(cx, AudioGraphAction::VoiceOff {voice});
},
ToUIDisplayMsg::OutOfBuffers => { }
}
}
}
}