Use new buffer management for the dummy backend
This commit is contained in:
parent
ca4569e03a
commit
9d45cbf1d9
|
@ -1,4 +1,5 @@
|
|||
use std::num::NonZeroU32;
|
||||
use std::ptr::NonNull;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use super::super::config::WrapperConfig;
|
||||
|
@ -8,6 +9,7 @@ use crate::buffer::Buffer;
|
|||
use crate::context::process::Transport;
|
||||
use crate::midi::PluginNoteEvent;
|
||||
use crate::plugin::Plugin;
|
||||
use crate::wrapper::util::buffer_management::{BufferManager, ChannelPointers};
|
||||
|
||||
/// 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
|
||||
|
@ -31,114 +33,139 @@ impl<P: Plugin> Backend<P> for Dummy {
|
|||
+ Send,
|
||||
) {
|
||||
// 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 =
|
||||
Duration::from_secs_f32(self.config.period_size as f32 / self.config.sample_rate);
|
||||
|
||||
let num_samples = self.config.period_size as usize;
|
||||
let num_output_channels = self
|
||||
.audio_io_layout
|
||||
.main_output_channels
|
||||
.map(NonZeroU32::get)
|
||||
.unwrap_or_default() as usize;
|
||||
let mut channels =
|
||||
vec![vec![0.0f32; self.config.period_size as usize]; num_output_channels];
|
||||
let mut buffer = Buffer::default();
|
||||
unsafe {
|
||||
buffer.set_slices(self.config.period_size as usize, |output_slices| {
|
||||
// SAFETY: `channels` is no longer used directly after this
|
||||
*output_slices = channels
|
||||
.iter_mut()
|
||||
.map(|channel| &mut *(channel.as_mut_slice() as *mut [f32]))
|
||||
.collect();
|
||||
})
|
||||
}
|
||||
let num_input_channels = self
|
||||
.audio_io_layout
|
||||
.main_input_channels
|
||||
.map(NonZeroU32::get)
|
||||
.unwrap_or_default() as usize;
|
||||
let mut main_io_storage = vec![vec![0.0f32; num_samples]; num_output_channels];
|
||||
|
||||
// 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];
|
||||
vec![0.0f32; num_samples];
|
||||
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();
|
||||
})
|
||||
}
|
||||
aux_input_buffers.push(aux_buffer);
|
||||
}
|
||||
|
||||
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];
|
||||
vec![0.0f32; num_samples];
|
||||
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
|
||||
// We need pointers to this storage to emulate the API used by plugins
|
||||
let mut main_io_channel_pointers: Vec<*mut f32> = main_io_storage
|
||||
.iter_mut()
|
||||
.map(|channel| &mut *(channel.as_mut_slice() as *mut [f32]))
|
||||
.map(|channel_slice| channel_slice.as_mut_ptr())
|
||||
.collect();
|
||||
let mut aux_input_channel_pointers: Vec<Vec<*mut f32>> = aux_input_storage
|
||||
.iter_mut()
|
||||
.map(|aux_input_storage| {
|
||||
aux_input_storage
|
||||
.iter_mut()
|
||||
.map(|channel_slice| channel_slice.as_mut_ptr())
|
||||
.collect()
|
||||
})
|
||||
}
|
||||
aux_output_buffers.push(aux_buffer);
|
||||
}
|
||||
.collect();
|
||||
let mut aux_output_channel_pointers: Vec<Vec<*mut f32>> = aux_output_storage
|
||||
.iter_mut()
|
||||
.map(|aux_output_storage| {
|
||||
aux_output_storage
|
||||
.iter_mut()
|
||||
.map(|channel_slice| channel_slice.as_mut_ptr())
|
||||
.collect()
|
||||
})
|
||||
.collect();
|
||||
|
||||
// The `BufferManager` can then manage buffers using this storage just like in every other
|
||||
// backend
|
||||
let mut buffer_manager =
|
||||
BufferManager::for_audio_io_layout(num_samples, self.audio_io_layout);
|
||||
|
||||
// This queue will never actually be used
|
||||
let mut midi_output_events = Vec::with_capacity(1024);
|
||||
let mut num_processed_samples = 0;
|
||||
let mut num_processed_samples = 0usize;
|
||||
loop {
|
||||
let period_start = Instant::now();
|
||||
|
||||
let mut transport = Transport::new(self.config.sample_rate);
|
||||
transport.pos_samples = Some(num_processed_samples);
|
||||
transport.pos_samples = Some(num_processed_samples as i64);
|
||||
transport.tempo = Some(self.config.tempo as f64);
|
||||
transport.time_sig_numerator = Some(self.config.timesig_num as i32);
|
||||
transport.time_sig_denominator = Some(self.config.timesig_denom as i32);
|
||||
transport.playing = true;
|
||||
|
||||
for channel in buffer.as_slice() {
|
||||
for channel in &mut main_io_storage {
|
||||
channel.fill(0.0);
|
||||
}
|
||||
for aux_buffer in &mut aux_input_buffers {
|
||||
for channel in aux_buffer.as_slice() {
|
||||
for aux_buffer in &mut aux_input_storage {
|
||||
for channel in aux_buffer {
|
||||
channel.fill(0.0);
|
||||
}
|
||||
}
|
||||
for aux_buffer in &mut aux_output_buffers {
|
||||
for channel in aux_buffer.as_slice() {
|
||||
for aux_buffer in &mut aux_output_storage {
|
||||
for channel in aux_buffer {
|
||||
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]),
|
||||
let buffers = unsafe {
|
||||
buffer_manager.create_buffers(num_samples, |buffer_sources| {
|
||||
*buffer_sources.main_output_channel_pointers = Some(ChannelPointers {
|
||||
ptrs: NonNull::new(main_io_channel_pointers.as_mut_ptr()).unwrap(),
|
||||
num_channels: main_io_channel_pointers.len(),
|
||||
});
|
||||
*buffer_sources.main_input_channel_pointers = Some(ChannelPointers {
|
||||
ptrs: NonNull::new(main_io_channel_pointers.as_mut_ptr()).unwrap(),
|
||||
num_channels: num_input_channels.min(main_io_channel_pointers.len()),
|
||||
});
|
||||
|
||||
for (input_source_channel_pointers, input_channel_pointers) in buffer_sources
|
||||
.aux_input_channel_pointers
|
||||
.iter_mut()
|
||||
.zip(aux_input_channel_pointers.iter_mut())
|
||||
{
|
||||
*input_source_channel_pointers = Some(ChannelPointers {
|
||||
ptrs: NonNull::new(input_channel_pointers.as_mut_ptr()).unwrap(),
|
||||
num_channels: input_channel_pointers.len(),
|
||||
});
|
||||
}
|
||||
|
||||
for (output_source_channel_pointers, output_channel_pointers) in buffer_sources
|
||||
.aux_output_channel_pointers
|
||||
.iter_mut()
|
||||
.zip(aux_output_channel_pointers.iter_mut())
|
||||
{
|
||||
*output_source_channel_pointers = Some(ChannelPointers {
|
||||
ptrs: NonNull::new(output_channel_pointers.as_mut_ptr()).unwrap(),
|
||||
num_channels: output_channel_pointers.len(),
|
||||
});
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
midi_output_events.clear();
|
||||
let mut aux = AuxiliaryBuffers {
|
||||
inputs: buffers.aux_inputs,
|
||||
outputs: buffers.aux_outputs,
|
||||
};
|
||||
if !cb(
|
||||
&mut buffer,
|
||||
buffers.main_buffer,
|
||||
&mut aux,
|
||||
transport,
|
||||
&[],
|
||||
|
@ -147,7 +174,7 @@ impl<P: Plugin> Backend<P> for Dummy {
|
|||
break;
|
||||
}
|
||||
|
||||
num_processed_samples += buffer.samples() as i64;
|
||||
num_processed_samples += num_samples;
|
||||
|
||||
let period_end = Instant::now();
|
||||
std::thread::sleep((period_start + interval).saturating_duration_since(period_end));
|
||||
|
|
Loading…
Reference in a new issue