use crate::config::Config;
use crate::context::AudioContext;
use crate::executor::{Executor, OutputView};
use crate::graph::{Connection, GraphError};
use crate::msg::LegatoMsg;
use crate::node::{Inputs, LegatoNode};
use crate::ports::Ports;
use crate::resources::buffer::{AudioSampleError, decode_with_ffmpeg};
use crate::resources::params::{ParamError, ParamKey};
use crate::resources::{ResourceFrontend, Resources};
use slotmap::new_key_type;
use std::fmt::Debug;
pub const MAX_INPUTS: usize = 32;
new_key_type! {
pub struct NodeKey;
}
pub struct Runtime {
context: AudioContext,
executor: Executor,
ports: Ports,
}
impl Runtime {
pub fn new(context: AudioContext, ports: Ports) -> Self {
let executor = Executor::default();
Self {
context,
executor,
ports,
}
}
pub fn add_node(&mut self, node: LegatoNode) -> NodeKey {
self.executor.graph.add_node(node)
}
pub fn remove_node(&mut self, key: NodeKey) -> Option<LegatoNode> {
self.executor.graph.remove_node(key)
}
pub fn replace_node(&mut self, key: NodeKey, node: LegatoNode) {
self.executor.graph.replace(key, node);
}
pub fn add_edge(&mut self, connection: Connection) -> Result<Connection, GraphError> {
self.executor.graph.add_edge(connection)
}
pub fn remove_edge(&mut self, connection: Connection) -> Result<(), GraphError> {
self.executor.graph.remove_edge(connection)
}
pub fn set_sink_key(&mut self, key: NodeKey) -> Result<(), GraphError> {
self.executor.set_sink(key)
}
pub fn set_source_key(&mut self, key: NodeKey) -> Result<(), GraphError> {
self.executor.set_source(key)
}
pub fn set_resources(&mut self, resources: Resources) {
self.context.set_resources(resources);
}
pub fn get_context_mut(&mut self) -> &mut AudioContext {
&mut self.context
}
pub fn get_context(&mut self) -> &AudioContext {
&self.context
}
pub fn get_config(&self) -> Config {
self.context.get_config()
}
pub fn prepare(&mut self) {
let block_size = self.context.get_config().block_size;
assert!(block_size != 0 && block_size.is_multiple_of(2));
self.executor.prepare(block_size);
}
pub fn handle_msg(&mut self, msg: LegatoMsg) {
match msg {
LegatoMsg::NodeMessage(key, param_msg) => {
if let Some(node) = self.get_node_mut(&key) {
node.handle_msg(param_msg);
}
}
}
}
pub fn get_sample_rate(&self) -> usize {
self.context.get_config().sample_rate
}
pub fn get_node_ports(&self, key: &NodeKey) -> &Ports {
self.executor
.graph
.get_node(*key)
.unwrap()
.get_node()
.ports()
}
pub fn get_node(&self, key: &NodeKey) -> Option<&LegatoNode> {
self.executor.graph.get_node(*key)
}
pub fn get_node_mut(&mut self, key: &NodeKey) -> Option<&mut LegatoNode> {
self.executor.graph.get_node_mut(*key)
}
pub fn drain_external_sample_msg(&mut self) {
let resources = self.context.get_resources_mut();
resources.drain();
}
pub fn next_block(&mut self, external_inputs: Option<&Inputs>) -> OutputView<'_> {
self.executor.process(&mut self.context, external_inputs)
}
}
impl Debug for Runtime {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_map()
.entry(&"config", &self.context.get_config())
.key(&"graph")
.value(&self.executor.graph)
.entry(&"graph_ports", &self.ports)
.entry(&"sink_key", self.executor.sink())
.finish()
}
}
pub struct RuntimeFrontend {
resource_frontend: ResourceFrontend,
}
impl RuntimeFrontend {
pub fn new(resource_frontend: ResourceFrontend) -> Self {
Self { resource_frontend }
}
pub fn load_file(
&mut self,
name: &str,
path: &str,
chans: usize,
sr: u32,
) -> Result<(), AudioSampleError> {
match decode_with_ffmpeg(path, chans, sr) {
Ok(decoded) => self
.resource_frontend
.send_external_buffer(name, decoded)
.map_err(|_| AudioSampleError::FailedToSendToRuntime),
Err(_) => Err(AudioSampleError::FailedDecoding),
}
}
pub fn set_param(&mut self, name: &'static str, val: f32) -> Result<(), ParamError> {
if let Ok(key) = self.resource_frontend.get_param_key(name) {
return self.resource_frontend.set_param(key, val);
}
Err(ParamError::ParamNotFound)
}
pub fn get_param_key(&self, param_name: &'static str) -> Result<ParamKey, ParamError> {
self.resource_frontend.get_param_key(param_name)
}
}