1
0
Fork 0

Add input and output events to Backend trait

This commit is contained in:
Robbert van der Helm 2022-06-14 22:48:36 +02:00
parent e967e04856
commit 4e021dd0bb
4 changed files with 117 additions and 90 deletions

View file

@ -1,6 +1,7 @@
pub use self::dummy::Dummy; pub use self::dummy::Dummy;
pub use self::jack::Jack; pub use self::jack::Jack;
pub use crate::buffer::Buffer; pub use crate::buffer::Buffer;
use crate::midi::NoteEvent;
mod dummy; mod dummy;
mod jack; mod jack;
@ -12,7 +13,9 @@ pub trait Backend: 'static + Send + Sync {
/// buffers for the wrapped plugin's outputs. Any inputs will have already been copied to this /// buffers for the wrapped plugin's outputs. Any inputs will have already been copied to this
/// buffer. This will block until the process callback returns `false`. /// buffer. This will block until the process callback returns `false`.
/// ///
/// TODO: MIDI
/// TODO: Auxiliary inputs and outputs /// TODO: Auxiliary inputs and outputs
fn run(&mut self, cb: impl FnMut(&mut Buffer) -> bool + 'static + Send); fn run(
&mut self,
cb: impl FnMut(&mut Buffer, &[NoteEvent], &mut Vec<NoteEvent>) -> bool + 'static + Send,
);
} }

View file

@ -3,6 +3,7 @@ use std::time::{Duration, Instant};
use super::super::config::WrapperConfig; use super::super::config::WrapperConfig;
use super::Backend; use super::Backend;
use crate::buffer::Buffer; use crate::buffer::Buffer;
use crate::midi::NoteEvent;
/// This backend doesn't input or output any audio or MIDI. It only exists so the standalone /// This backend doesn't input or output any audio or MIDI. It only exists so the standalone
/// application can continue to run even when there is no audio backend available. This can be /// application can continue to run even when there is no audio backend available. This can be
@ -12,7 +13,10 @@ pub struct Dummy {
} }
impl Backend for Dummy { impl Backend for Dummy {
fn run(&mut self, mut cb: impl FnMut(&mut Buffer) -> bool + 'static + Send) { fn run(
&mut self,
mut cb: impl FnMut(&mut Buffer, &[NoteEvent], &mut Vec<NoteEvent>) -> bool + 'static + Send,
) {
// We can't really do anything meaningful here, so we'll simply periodically call the // We can't really do anything meaningful here, so we'll simply periodically call the
// callback with empty buffers. // callback with empty buffers.
let interval = let interval =
@ -33,6 +37,8 @@ impl Backend for Dummy {
}) })
} }
// These will never actually be used
let mut midi_output_events = Vec::with_capacity(1024);
loop { loop {
let period_start = Instant::now(); let period_start = Instant::now();
@ -40,7 +46,8 @@ impl Backend for Dummy {
channel.fill(0.0); channel.fill(0.0);
} }
if !cb(&mut buffer) { midi_output_events.clear();
if !cb(&mut buffer, &[], &mut midi_output_events) {
break; break;
} }

View file

@ -10,7 +10,7 @@ use jack::{
use super::super::config::WrapperConfig; use super::super::config::WrapperConfig;
use super::Backend; use super::Backend;
use crate::buffer::Buffer; use crate::buffer::Buffer;
use crate::midi::MidiConfig; use crate::midi::{MidiConfig, NoteEvent};
use crate::plugin::Plugin; use crate::plugin::Plugin;
/// Uses JACK audio and MIDI. /// Uses JACK audio and MIDI.
@ -32,7 +32,10 @@ enum Task {
} }
impl Backend for Jack { impl Backend for Jack {
fn run(&mut self, mut cb: impl FnMut(&mut Buffer) -> bool + 'static + Send) { fn run(
&mut self,
mut cb: impl FnMut(&mut Buffer, &[NoteEvent], &mut Vec<NoteEvent>) -> bool + 'static + Send,
) {
let client = self.client.take().unwrap(); let client = self.client.take().unwrap();
let buffer_size = client.buffer_size(); let buffer_size = client.buffer_size();
@ -43,9 +46,14 @@ impl Backend for Jack {
}) })
} }
let mut input_events = Vec::with_capacity(2048);
let mut output_events = Vec::with_capacity(2048);
let (control_sender, control_receiver) = channel::bounded(32); let (control_sender, control_receiver) = channel::bounded(32);
let inputs = self.inputs.clone(); let inputs = self.inputs.clone();
let outputs = self.outputs.clone(); let outputs = self.outputs.clone();
let midi_input = self.midi_input.clone();
let midi_output = self.midi_output.clone();
let process_handler = ClosureProcessHandler::new(move |_client, ps| { let process_handler = ClosureProcessHandler::new(move |_client, ps| {
// In theory we could handle `num_frames <= buffer_size`, but JACK will never chop up // In theory we could handle `num_frames <= buffer_size`, but JACK will never chop up
// buffers like that so we'll just make it easier for ourselves by not supporting that // buffers like that so we'll just make it easier for ourselves by not supporting that
@ -76,7 +84,12 @@ impl Backend for Jack {
}) })
} }
if cb(&mut buffer) { // TODO: Read MIDI, convert to events
output_events.clear();
if cb(&mut buffer, &input_events, &mut output_events) {
// TODO: Convert output events to MIDI, send to the output port
Control::Continue Control::Continue
} else { } else {
control_sender.send(Task::Shutdown).unwrap(); control_sender.send(Task::Shutdown).unwrap();

View file

@ -364,12 +364,15 @@ impl<P: Plugin, B: Backend> Wrapper<P, B> {
// TODO: We should add a way to pull the transport information from the JACK backend // TODO: We should add a way to pull the transport information from the JACK backend
let mut num_processed_samples = 0; let mut num_processed_samples = 0;
self.clone().backend.borrow_mut().run(move |buffer| { self.clone()
.backend
.borrow_mut()
.run(move |buffer, input_events, output_events| {
if should_terminate.load(Ordering::SeqCst) { if should_terminate.load(Ordering::SeqCst) {
return false; return false;
} }
// TODO: Process incoming events // TODO: Do something with the input and output events
let sample_rate = self.buffer_config.sample_rate; let sample_rate = self.buffer_config.sample_rate;
let mut transport = Transport::new(sample_rate); let mut transport = Transport::new(sample_rate);
@ -403,7 +406,8 @@ impl<P: Plugin, B: Backend> Wrapper<P, B> {
// We'll always write these events to the first sample, so even when we add note output we // We'll always write these events to the first sample, so even when we add note output we
// shouldn't have to think about interleaving events here // shouldn't have to think about interleaving events here
let mut parameter_values_changed = false; let mut parameter_values_changed = false;
while let Some((param_ptr, normalized_value)) = self.unprocessed_param_changes.pop() { while let Some((param_ptr, normalized_value)) = self.unprocessed_param_changes.pop()
{
unsafe { param_ptr.set_normalized_value(normalized_value) }; unsafe { param_ptr.set_normalized_value(normalized_value) };
unsafe { param_ptr.update_smoother(sample_rate, false) }; unsafe { param_ptr.update_smoother(sample_rate, false) };
parameter_values_changed = true; parameter_values_changed = true;