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::num::NonZeroU32;
use std::ptr::NonNull;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use super::super::config::WrapperConfig; use super::super::config::WrapperConfig;
@ -8,6 +9,7 @@ use crate::buffer::Buffer;
use crate::context::process::Transport; use crate::context::process::Transport;
use crate::midi::PluginNoteEvent; use crate::midi::PluginNoteEvent;
use crate::plugin::Plugin; 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 /// 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
@ -31,114 +33,139 @@ impl<P: Plugin> Backend<P> for Dummy {
+ Send, + 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 =
Duration::from_secs_f32(self.config.period_size as f32 / self.config.sample_rate); 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 let num_output_channels = self
.audio_io_layout .audio_io_layout
.main_output_channels .main_output_channels
.map(NonZeroU32::get) .map(NonZeroU32::get)
.unwrap_or_default() as usize; .unwrap_or_default() as usize;
let mut channels = let num_input_channels = self
vec![vec![0.0f32; self.config.period_size as usize]; num_output_channels]; .audio_io_layout
let mut buffer = Buffer::default(); .main_input_channels
unsafe { .map(NonZeroU32::get)
buffer.set_slices(self.config.period_size as usize, |output_slices| { .unwrap_or_default() as usize;
// SAFETY: `channels` is no longer used directly after this let mut main_io_storage = vec![vec![0.0f32; num_samples]; num_output_channels];
*output_slices = channels
.iter_mut()
.map(|channel| &mut *(channel.as_mut_slice() as *mut [f32]))
.collect();
})
}
// We'll do the same thing for auxiliary inputs and outputs, so the plugin always gets the // We'll do the same thing for auxiliary inputs and outputs, so the plugin always gets the
// buffers it expects // buffers it expects
let mut aux_input_storage: Vec<Vec<Vec<f32>>> = Vec::new(); 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 { for channel_count in self.audio_io_layout.aux_input_ports {
aux_input_storage.push(vec![ aux_input_storage.push(vec![
vec![0.0f32; self.config.period_size as usize]; vec![0.0f32; num_samples];
channel_count.get() 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();
})
}
aux_input_buffers.push(aux_buffer);
} }
let mut aux_output_storage: Vec<Vec<Vec<f32>>> = Vec::new(); 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 { for channel_count in self.audio_io_layout.aux_output_ports {
aux_output_storage.push(vec![ aux_output_storage.push(vec![
vec![0.0f32; self.config.period_size as usize]; vec![0.0f32; num_samples];
channel_count.get() 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();
})
}
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 // 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 = 0usize;
loop { loop {
let period_start = Instant::now(); let period_start = Instant::now();
let mut transport = Transport::new(self.config.sample_rate); 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.tempo = Some(self.config.tempo as f64);
transport.time_sig_numerator = Some(self.config.timesig_num as i32); transport.time_sig_numerator = Some(self.config.timesig_num as i32);
transport.time_sig_denominator = Some(self.config.timesig_denom as i32); transport.time_sig_denominator = Some(self.config.timesig_denom as i32);
transport.playing = true; transport.playing = true;
for channel in buffer.as_slice() { for channel in &mut main_io_storage {
channel.fill(0.0); channel.fill(0.0);
} }
for aux_buffer in &mut aux_input_buffers { for aux_buffer in &mut aux_input_storage {
for channel in aux_buffer.as_slice() { for channel in aux_buffer {
channel.fill(0.0); channel.fill(0.0);
} }
} }
for aux_buffer in &mut aux_output_buffers { for aux_buffer in &mut aux_output_storage {
for channel in aux_buffer.as_slice() { for channel in aux_buffer {
channel.fill(0.0); channel.fill(0.0);
} }
} }
// SAFETY: Shortening these borrows is safe as even if the plugin overwrites the let buffers = unsafe {
// slices (which it cannot do without using unsafe code), then they buffer_manager.create_buffers(num_samples, |buffer_sources| {
// would still be reset on the next iteration *buffer_sources.main_output_channel_pointers = Some(ChannelPointers {
let mut aux = unsafe { ptrs: NonNull::new(main_io_channel_pointers.as_mut_ptr()).unwrap(),
AuxiliaryBuffers { num_channels: main_io_channel_pointers.len(),
inputs: &mut *(aux_input_buffers.as_mut_slice() as *mut [Buffer]), });
outputs: &mut *(aux_output_buffers.as_mut_slice() as *mut [Buffer]), *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(); midi_output_events.clear();
let mut aux = AuxiliaryBuffers {
inputs: buffers.aux_inputs,
outputs: buffers.aux_outputs,
};
if !cb( if !cb(
&mut buffer, buffers.main_buffer,
&mut aux, &mut aux,
transport, transport,
&[], &[],
@ -147,7 +174,7 @@ impl<P: Plugin> Backend<P> for Dummy {
break; break;
} }
num_processed_samples += buffer.samples() as i64; num_processed_samples += num_samples;
let period_end = Instant::now(); let period_end = Instant::now();
std::thread::sleep((period_start + interval).saturating_duration_since(period_end)); std::thread::sleep((period_start + interval).saturating_duration_since(period_end));