From 9d45cbf1d9df2f46be11cbc9b736838cbb17fa23 Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Fri, 31 Mar 2023 19:22:20 +0200 Subject: [PATCH] Use new buffer management for the dummy backend --- src/wrapper/standalone/backend/dummy.rs | 147 ++++++++++++++---------- 1 file changed, 87 insertions(+), 60 deletions(-) diff --git a/src/wrapper/standalone/backend/dummy.rs b/src/wrapper/standalone/backend/dummy.rs index 31455ca9..7dd78c50 100644 --- a/src/wrapper/standalone/backend/dummy.rs +++ b/src/wrapper/standalone/backend/dummy.rs @@ -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 Backend

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::new(); - let mut aux_input_buffers: Vec = 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::new(); - let mut aux_output_buffers: Vec = 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> = 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> = 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 Backend

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));