Add auxiliary buffers in dummy standalone backwend
This commit is contained in:
parent
a8be77a513
commit
9e2c2b776b
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::audio_setup::AuxiliaryBuffers;
|
||||||
use crate::context::process::Transport;
|
use crate::context::process::Transport;
|
||||||
use crate::midi::PluginNoteEvent;
|
use crate::midi::PluginNoteEvent;
|
||||||
|
|
||||||
|
@ -17,12 +18,11 @@ pub trait Backend<P: Plugin>: 'static + Send + Sync {
|
||||||
/// there's a new block of audio to be processed. The process callback receives the audio
|
/// there's a new block of audio to be processed. The process callback receives the audio
|
||||||
/// 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: Auxiliary inputs and outputs
|
|
||||||
fn run(
|
fn run(
|
||||||
&mut self,
|
&mut self,
|
||||||
cb: impl FnMut(
|
cb: impl FnMut(
|
||||||
&mut Buffer,
|
&mut Buffer,
|
||||||
|
&mut AuxiliaryBuffers,
|
||||||
Transport,
|
Transport,
|
||||||
&[PluginNoteEvent<P>],
|
&[PluginNoteEvent<P>],
|
||||||
&mut Vec<PluginNoteEvent<P>>,
|
&mut Vec<PluginNoteEvent<P>>,
|
||||||
|
|
|
@ -10,7 +10,7 @@ use rtrb::RingBuffer;
|
||||||
|
|
||||||
use super::super::config::WrapperConfig;
|
use super::super::config::WrapperConfig;
|
||||||
use super::Backend;
|
use super::Backend;
|
||||||
use crate::audio_setup::AudioIOLayout;
|
use crate::audio_setup::{AudioIOLayout, AuxiliaryBuffers};
|
||||||
use crate::buffer::Buffer;
|
use crate::buffer::Buffer;
|
||||||
use crate::context::process::Transport;
|
use crate::context::process::Transport;
|
||||||
use crate::midi::{MidiConfig, PluginNoteEvent};
|
use crate::midi::{MidiConfig, PluginNoteEvent};
|
||||||
|
@ -34,6 +34,7 @@ impl<P: Plugin> Backend<P> for Cpal {
|
||||||
&mut self,
|
&mut self,
|
||||||
cb: impl FnMut(
|
cb: impl FnMut(
|
||||||
&mut Buffer,
|
&mut Buffer,
|
||||||
|
&mut AuxiliaryBuffers,
|
||||||
Transport,
|
Transport,
|
||||||
&[PluginNoteEvent<P>],
|
&[PluginNoteEvent<P>],
|
||||||
&mut Vec<PluginNoteEvent<P>>,
|
&mut Vec<PluginNoteEvent<P>>,
|
||||||
|
@ -321,6 +322,7 @@ impl Cpal {
|
||||||
mut input_rb_consumer: Option<rtrb::Consumer<f32>>,
|
mut input_rb_consumer: Option<rtrb::Consumer<f32>>,
|
||||||
mut cb: impl FnMut(
|
mut cb: impl FnMut(
|
||||||
&mut Buffer,
|
&mut Buffer,
|
||||||
|
&mut AuxiliaryBuffers,
|
||||||
Transport,
|
Transport,
|
||||||
&[PluginNoteEvent<P>],
|
&[PluginNoteEvent<P>],
|
||||||
&mut Vec<PluginNoteEvent<P>>,
|
&mut Vec<PluginNoteEvent<P>>,
|
||||||
|
@ -404,6 +406,11 @@ impl Cpal {
|
||||||
midi_output_events.clear();
|
midi_output_events.clear();
|
||||||
if !cb(
|
if !cb(
|
||||||
&mut buffer,
|
&mut buffer,
|
||||||
|
// FIXME: Use zero filled buffers with the correct size instead
|
||||||
|
&mut AuxiliaryBuffers {
|
||||||
|
inputs: &mut [],
|
||||||
|
outputs: &mut [],
|
||||||
|
},
|
||||||
transport,
|
transport,
|
||||||
&midi_input_events,
|
&midi_input_events,
|
||||||
&mut midi_output_events,
|
&mut midi_output_events,
|
||||||
|
|
|
@ -3,7 +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::audio_setup::AudioIOLayout;
|
use crate::audio_setup::{AudioIOLayout, AuxiliaryBuffers};
|
||||||
use crate::buffer::Buffer;
|
use crate::buffer::Buffer;
|
||||||
use crate::context::process::Transport;
|
use crate::context::process::Transport;
|
||||||
use crate::midi::PluginNoteEvent;
|
use crate::midi::PluginNoteEvent;
|
||||||
|
@ -22,6 +22,7 @@ impl<P: Plugin> Backend<P> for Dummy {
|
||||||
&mut self,
|
&mut self,
|
||||||
mut cb: impl FnMut(
|
mut cb: impl FnMut(
|
||||||
&mut Buffer,
|
&mut Buffer,
|
||||||
|
&mut AuxiliaryBuffers,
|
||||||
Transport,
|
Transport,
|
||||||
&[PluginNoteEvent<P>],
|
&[PluginNoteEvent<P>],
|
||||||
&mut Vec<PluginNoteEvent<P>>,
|
&mut Vec<PluginNoteEvent<P>>,
|
||||||
|
@ -52,6 +53,50 @@ impl<P: Plugin> Backend<P> for Dummy {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We'll do the same thing for auxiliary inputs and outputs, so the plugin always gets the
|
||||||
|
// buffers it expects
|
||||||
|
let mut aux_input_storage: Vec<Vec<Vec<f32>>> = Vec::new();
|
||||||
|
let mut aux_input_buffers: Vec<Buffer> = Vec::new();
|
||||||
|
for channel_count in self.audio_io_layout.aux_input_ports {
|
||||||
|
aux_input_storage.push(vec![
|
||||||
|
vec![0.0f32; self.config.period_size as usize];
|
||||||
|
channel_count.get() as usize
|
||||||
|
]);
|
||||||
|
|
||||||
|
let aux_storage = aux_input_storage.last_mut().unwrap();
|
||||||
|
let mut aux_buffer = Buffer::default();
|
||||||
|
unsafe {
|
||||||
|
aux_buffer.set_slices(self.config.period_size as usize, |output_slices| {
|
||||||
|
// SAFETY: `aux_storage` is no longer used directly after this
|
||||||
|
*output_slices = aux_storage
|
||||||
|
.iter_mut()
|
||||||
|
.map(|channel| &mut *(channel.as_mut_slice() as *mut [f32]))
|
||||||
|
.collect();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut aux_output_storage: Vec<Vec<Vec<f32>>> = Vec::new();
|
||||||
|
let mut aux_output_buffers: Vec<Buffer> = Vec::new();
|
||||||
|
for channel_count in self.audio_io_layout.aux_output_ports {
|
||||||
|
aux_output_storage.push(vec![
|
||||||
|
vec![0.0f32; self.config.period_size as usize];
|
||||||
|
channel_count.get() as usize
|
||||||
|
]);
|
||||||
|
|
||||||
|
let aux_storage = aux_output_storage.last_mut().unwrap();
|
||||||
|
let mut aux_buffer = Buffer::default();
|
||||||
|
unsafe {
|
||||||
|
aux_buffer.set_slices(self.config.period_size as usize, |output_slices| {
|
||||||
|
// SAFETY: `aux_storage` is no longer used directly after this
|
||||||
|
*output_slices = aux_storage
|
||||||
|
.iter_mut()
|
||||||
|
.map(|channel| &mut *(channel.as_mut_slice() as *mut [f32]))
|
||||||
|
.collect();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This queue will never actually be used
|
// This queue will never actually be used
|
||||||
let mut midi_output_events = Vec::with_capacity(1024);
|
let mut midi_output_events = Vec::with_capacity(1024);
|
||||||
let mut num_processed_samples = 0;
|
let mut num_processed_samples = 0;
|
||||||
|
@ -68,9 +113,35 @@ impl<P: Plugin> Backend<P> for Dummy {
|
||||||
for channel in buffer.as_slice() {
|
for channel in buffer.as_slice() {
|
||||||
channel.fill(0.0);
|
channel.fill(0.0);
|
||||||
}
|
}
|
||||||
|
for aux_buffer in &mut aux_input_buffers {
|
||||||
|
for channel in aux_buffer.as_slice() {
|
||||||
|
channel.fill(0.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for aux_buffer in &mut aux_output_buffers {
|
||||||
|
for channel in aux_buffer.as_slice() {
|
||||||
|
channel.fill(0.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SAFETY: Shortening these borrows is safe as even if the plugin overwrites the
|
||||||
|
// slices (which it cannot do without using unsafe code), then they
|
||||||
|
// would still be reset on the next iteration
|
||||||
|
let mut aux = unsafe {
|
||||||
|
AuxiliaryBuffers {
|
||||||
|
inputs: &mut *(aux_input_buffers.as_mut_slice() as *mut [Buffer]),
|
||||||
|
outputs: &mut *(aux_output_buffers.as_mut_slice() as *mut [Buffer]),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
midi_output_events.clear();
|
midi_output_events.clear();
|
||||||
if !cb(&mut buffer, transport, &[], &mut midi_output_events) {
|
if !cb(
|
||||||
|
&mut buffer,
|
||||||
|
&mut aux,
|
||||||
|
transport,
|
||||||
|
&[],
|
||||||
|
&mut midi_output_events,
|
||||||
|
) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ use parking_lot::Mutex;
|
||||||
|
|
||||||
use super::super::config::WrapperConfig;
|
use super::super::config::WrapperConfig;
|
||||||
use super::Backend;
|
use super::Backend;
|
||||||
|
use crate::audio_setup::AuxiliaryBuffers;
|
||||||
use crate::buffer::Buffer;
|
use crate::buffer::Buffer;
|
||||||
use crate::context::process::Transport;
|
use crate::context::process::Transport;
|
||||||
use crate::midi::{MidiConfig, MidiResult, NoteEvent, PluginNoteEvent};
|
use crate::midi::{MidiConfig, MidiResult, NoteEvent, PluginNoteEvent};
|
||||||
|
@ -39,6 +40,7 @@ impl<P: Plugin> Backend<P> for Jack {
|
||||||
&mut self,
|
&mut self,
|
||||||
mut cb: impl FnMut(
|
mut cb: impl FnMut(
|
||||||
&mut Buffer,
|
&mut Buffer,
|
||||||
|
&mut AuxiliaryBuffers,
|
||||||
Transport,
|
Transport,
|
||||||
&[PluginNoteEvent<P>],
|
&[PluginNoteEvent<P>],
|
||||||
&mut Vec<PluginNoteEvent<P>>,
|
&mut Vec<PluginNoteEvent<P>>,
|
||||||
|
@ -134,7 +136,17 @@ impl<P: Plugin> Backend<P> for Jack {
|
||||||
}
|
}
|
||||||
|
|
||||||
output_events.clear();
|
output_events.clear();
|
||||||
if cb(&mut buffer, transport, &input_events, &mut output_events) {
|
if cb(
|
||||||
|
&mut buffer,
|
||||||
|
// TODO: Support auxiliary IO in the JACK backend
|
||||||
|
&mut AuxiliaryBuffers {
|
||||||
|
inputs: &mut [],
|
||||||
|
outputs: &mut [],
|
||||||
|
},
|
||||||
|
transport,
|
||||||
|
&input_events,
|
||||||
|
&mut output_events,
|
||||||
|
) {
|
||||||
if let Some(midi_output) = &midi_output {
|
if let Some(midi_output) = &midi_output {
|
||||||
let mut midi_output = midi_output.lock();
|
let mut midi_output = midi_output.lock();
|
||||||
let mut midi_writer = midi_output.writer(ps);
|
let mut midi_writer = midi_output.writer(ps);
|
||||||
|
|
|
@ -13,7 +13,6 @@ use std::thread;
|
||||||
use super::backend::Backend;
|
use super::backend::Backend;
|
||||||
use super::config::WrapperConfig;
|
use super::config::WrapperConfig;
|
||||||
use super::context::{WrapperGuiContext, WrapperInitContext, WrapperProcessContext};
|
use super::context::{WrapperGuiContext, WrapperInitContext, WrapperProcessContext};
|
||||||
use crate::audio_setup::AuxiliaryBuffers;
|
|
||||||
use crate::audio_setup::{AudioIOLayout, BufferConfig, ProcessMode};
|
use crate::audio_setup::{AudioIOLayout, BufferConfig, ProcessMode};
|
||||||
use crate::context::gui::AsyncExecutor;
|
use crate::context::gui::AsyncExecutor;
|
||||||
use crate::context::process::Transport;
|
use crate::context::process::Transport;
|
||||||
|
@ -466,7 +465,7 @@ impl<P: Plugin, B: Backend<P>> Wrapper<P, B> {
|
||||||
gui_task_sender: channel::Sender<GuiTask>,
|
gui_task_sender: channel::Sender<GuiTask>,
|
||||||
) {
|
) {
|
||||||
self.clone().backend.borrow_mut().run(
|
self.clone().backend.borrow_mut().run(
|
||||||
move |buffer, transport, input_events, output_events| {
|
move |buffer, aux, transport, input_events, output_events| {
|
||||||
// TODO: This process wrapper should actually be in the backends (since the backends
|
// TODO: This process wrapper should actually be in the backends (since the backends
|
||||||
// should also not allocate in their audio callbacks), but that's a bit more
|
// should also not allocate in their audio callbacks), but that's a bit more
|
||||||
// error prone
|
// error prone
|
||||||
|
@ -479,11 +478,7 @@ impl<P: Plugin, B: Backend<P>> Wrapper<P, B> {
|
||||||
let mut plugin = self.plugin.lock();
|
let mut plugin = self.plugin.lock();
|
||||||
if let ProcessStatus::Error(err) = plugin.process(
|
if let ProcessStatus::Error(err) = plugin.process(
|
||||||
buffer,
|
buffer,
|
||||||
// TODO: Provide extra inputs and outputs in the JACk backend
|
aux,
|
||||||
&mut AuxiliaryBuffers {
|
|
||||||
inputs: &mut [],
|
|
||||||
outputs: &mut [],
|
|
||||||
},
|
|
||||||
&mut self.make_process_context(transport, input_events, output_events),
|
&mut self.make_process_context(transport, input_events, output_events),
|
||||||
) {
|
) {
|
||||||
nih_error!("The plugin returned an error while processing:");
|
nih_error!("The plugin returned an error while processing:");
|
||||||
|
|
Loading…
Reference in a new issue