Interaction
Purposefully Unopinionated
Legato aims to leave UI up to the user. This means you can write your own UI with Webview technologies, frameworks like ICED, Bevvy, or EGUI, or even easily make terminal applications with Ratatui.
Modifying the Runtime
In summary, you have four ways to change values in the runtime:
Message Passing
These are drained once per audio block. Simply send a message to your node like so:
let (app, mut frontend) = LegatoBuilder::<Unconfigured>::new(config, ports).build_dsl(&graph);
let res = frontend.send_node_msg(
"example",
legato::msg::NodeMessage::SetParam(ParamPayload {
param_name: "freq",
value: legato::msg::RtValue::F32(440.0),
}),
);
Param Store
Additionally, you can use the param node to get a smoothed f32 value.
This is good for say something like a gain value, referenced by mutliple nodes.
frontend.set_param("freq", 440.0); // Your freq node outputs 440.0 aduio rate at the next block
External Input
You can add an audio rate external input with a SPSC, like so:
let (producer, consumer) = rtrb::RingBuffer::new(4096 * 4); // 4 frames of headroom
let (app, _) = LegatoBuilder::<Unconfigured>::new(config, ports)
// Adding the audio input here
.register_audio_input("one", consumer, 1, config.block_size)
.build_dsl(&graph);
AudioInterface::builder(&host, config)
// Starts the input thread. Skip this if managing your own input.
.input(InputSpec {
producer,
chans: 1,
device: DeviceSelection::Default,
})
.build(app)
.expect("Failed to start audio")
.run_forever(); // Blocks here
Custom Nodes
If you need audio rate logic, and the above do not suffice, consider a custom node. You can read more about this in the custom nodes section.