1
0
Fork 0

Use new buffer management for the dummy backend

This commit is contained in:
Robbert van der Helm 2023-03-31 19:22:20 +02:00
parent ca4569e03a
commit 9d45cbf1d9

View file

@ -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
.iter_mut()
.map(|channel| &mut *(channel.as_mut_slice() as *mut [f32]))
.collect();
})
}
aux_output_buffers.push(aux_buffer);
}
// 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_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()
})
.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));