Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "legato"
description = "Legato is a WIP audiograph and DSL for quickly developing audio applications"
version = "0.0.28"
version = "0.0.32"
edition = "2024"
repository="https://github.com/legato-dsp/legato"
license = "AGPL-3.0"
Expand Down
4 changes: 2 additions & 2 deletions crates/examples/poly.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ fn main() {
map { range: [-1.0, 1.0], new_range: [0.3, 0.7 ] },
}

midi {
midi {
poly_voice { chan: 0, voices: 5 }
}

Expand All @@ -180,7 +180,7 @@ fn main() {

let ports = PortBuilder::default().audio_out(2).build();

let (midi_rt_fe, _writer_fe) = start_midi_thread(
let midi_rt_fe = start_midi_thread(
256,
"my_port",
MidiPortKind::Index(0),
Expand Down
11 changes: 4 additions & 7 deletions crates/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ impl<S> LegatoBuilder<S>
where
S: CanBuild,
{
pub fn build(self) -> (LegatoApp, LegatoFrontend) {
pub fn build(mut self) -> (LegatoApp, LegatoFrontend) {
let mut runtime = self.runtime;

let cfg = runtime.get_config();
Expand All @@ -482,18 +482,15 @@ where
// Allocate all of the audio buffers needed at runtime
runtime.prepare();

if self.midi_runtime_frontend.is_some() {
if let Some(fe) = self.midi_runtime_frontend.take() {
let ctx = runtime.get_context_mut();
ctx.set_midi_store(MidiStore::new(256));
ctx.set_midi_runtime_frontend(fe);
}

let (producer, consumer) = rtrb::RingBuffer::new(512);

let mut app = LegatoApp::new(runtime, consumer);

if let Some(midi_rt) = self.midi_runtime_frontend {
app.set_midi_runtime(midi_rt);
}
let app = LegatoApp::new(runtime, consumer);

let rt_frontend = RuntimeFrontend::new(resources_frontend);

Expand Down
61 changes: 59 additions & 2 deletions crates/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use slotmap::new_key_type;

use crate::{
config::Config,
midi::{MidiError, MidiMessage, MidiStore},
midi::{MidiError, MidiMessage, MidiRuntimeFrontend, MidiStore},
resources::{
Resources,
params::{ParamError, ParamKey},
Expand All @@ -21,6 +21,7 @@ new_key_type! { struct ExternalAudioKey; }
pub struct AudioContext {
config: Config,
midi_store: Option<MidiStore>,
midi_runtime_frontend: Option<MidiRuntimeFrontend>,
resources: Resources,
block_start: Instant,
}
Expand All @@ -31,45 +32,101 @@ impl AudioContext {
config,
midi_store: None,
resources,
midi_runtime_frontend: None,
block_start: Instant::now(),
}
}
/// For a time being, this is a quick hack inside oversampling. I would recommend not using, as it does not reflex internal state!!!
pub fn set_sample_rate(&mut self, sr: usize) {
self.config.sample_rate = sr;
}

pub(crate) fn update_midi(&mut self) {
self.clear_midi();

let Some(runtime) = self.midi_runtime_frontend.take() else {
return;
};

while let Some(msg) = runtime.recv() {
if let Err(e) = self.insert_midi_msg(msg) {
eprintln!("{:?}", e);
}
}

self.midi_runtime_frontend = Some(runtime);
}

/// For a time being, this is a quick hack inside oversampling. I would recommend not using, as it does not reflex internal state!!!
pub fn set_block_size(&mut self, block_size: usize) {
self.config.block_size = block_size;
}

pub fn get_config(&self) -> Config {
self.config
}

pub fn get_resources(&self) -> &Resources {
&self.resources
}

pub fn set_resources(&mut self, resources: Resources) {
self.resources = resources;
}

pub fn get_resources_mut(&mut self) -> &mut Resources {
&mut self.resources
}

pub fn get_param(&self, key: &ParamKey) -> Result<f32, ParamError> {
self.resources.get_param(key)
}

pub fn sample_rate_f32(&self) -> f32 {
self.config.sample_rate as f32
}

#[inline(always)]
pub fn sample_rate(&self) -> usize {
self.config.sample_rate
}

// Add a midi store to the runtime.
pub fn set_midi_store(&mut self, store: MidiStore) {
self.midi_store = Some(store);
}

pub fn set_midi_runtime_frontend(&mut self, frontend: MidiRuntimeFrontend) {
self.midi_runtime_frontend = Some(frontend)
}

pub fn send_to_system_midi(
&mut self,
msg: MidiMessage,
instant: Instant,
) -> Result<(), MidiError> {
if let Some(inner) = &mut self.midi_runtime_frontend {
inner.writer_frontend.send_to_system_midi(msg, instant)
} else {
Err(MidiError::MissingRuntime)
}
}

#[inline(always)]
pub fn get_midi_store(&self) -> Option<&MidiStore> {
self.midi_store.as_ref()
}

#[inline(always)]
pub fn set_instant(&mut self) {
self.block_start = Instant::now()
}
pub fn get_instant(&mut self) -> Instant {

#[inline(always)]
pub fn get_instant(&self) -> Instant {
self.block_start
}

/// Insert a midi message into the store.
#[inline(always)]
pub fn insert_midi_msg(&mut self, msg: MidiMessage) -> Result<(), MidiError> {
Expand Down
22 changes: 3 additions & 19 deletions crates/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use crate::{
builder::ValidationError,
config::Config,
executor::OutputView,
midi::MidiRuntimeFrontend,
msg::{LegatoMsg, NodeMessage},
node::Inputs,
resources::{
Expand Down Expand Up @@ -53,15 +52,13 @@ pub enum LegatoError {

pub struct LegatoApp {
runtime: Runtime,
midi_runtime_frontend: Option<MidiRuntimeFrontend>,
msg_consumer: rtrb::Consumer<LegatoMsg>,
}

impl LegatoApp {
pub fn new(runtime: Runtime, receiver: rtrb::Consumer<LegatoMsg>) -> Self {
Self {
runtime,
midi_runtime_frontend: None,
msg_consumer: receiver,
}
}
Expand All @@ -72,18 +69,9 @@ impl LegatoApp {
///
/// This gives the data in a [[L,L,L], [R,R,R], etc] layout
pub fn next_block(&mut self, external_inputs: Option<&Inputs>) -> OutputView<'_> {
// If we have a midi runtime, drain it.
if let Some(midi_runtime) = &self.midi_runtime_frontend {
let ctx = self.runtime.get_context_mut();
// Clear our old messages
ctx.clear_midi();
while let Some(msg) = midi_runtime.recv() {
// TOOD: Realtime logging with channel maybe?
if let Err(e) = ctx.insert_midi_msg(msg) {
eprintln!("{:?}", e);
}
}
}
let ctx = self.runtime.get_context_mut();
ctx.update_midi();

// Drain messages for sample update
self.runtime.drain_external_sample_msg();

Expand All @@ -95,10 +83,6 @@ impl LegatoApp {
self.runtime.next_block(external_inputs)
}

pub fn set_midi_runtime(&mut self, rt: MidiRuntimeFrontend) {
self.midi_runtime_frontend = Some(rt);
}

pub fn get_config(&self) -> Config {
self.runtime.get_config()
}
Expand Down
Loading
Loading