1
0
Fork 0

Consider block start with buffer management

This broke sample accurate automation.
This commit is contained in:
Robbert van der Helm 2023-04-24 23:47:29 +02:00
parent 4912962551
commit 5e69910616
7 changed files with 157 additions and 143 deletions

View file

@ -24,6 +24,11 @@ state is to list breaking changes.
structure and to more explicitly mention that the non-lifecycle methods are structure and to more explicitly mention that the non-lifecycle methods are
called once immediately after creating the plugin object. called once immediately after creating the plugin object.
### Fixed
- The buffer changes from March 31st broke the sample accurate automation
feature. This has now been fixed.
## [2023-04-22] ## [2023-04-22]
### Added ### Added

View file

@ -2020,84 +2020,85 @@ impl<P: ClapPlugin> Wrapper<P> {
// TODO: Like with VST3, should we expose some way to access or set the silence/constant // TODO: Like with VST3, should we expose some way to access or set the silence/constant
// flags? // flags?
let mut buffer_manager = wrapper.buffer_manager.borrow_mut(); let mut buffer_manager = wrapper.buffer_manager.borrow_mut();
let buffers = buffer_manager.create_buffers(block_len, |buffer_source| { let buffers =
// Explicitly take plugins with no main output that does have auxiliary outputs buffer_manager.create_buffers(block_start, block_len, |buffer_source| {
// into account. Shouldn't happen, but if we just start copying audio here then // Explicitly take plugins with no main output that does have auxiliary
// that would result in unsoundness. // outputs into account. Shouldn't happen, but if we just start copying
if process.audio_outputs_count > 0 // audio here then that would result in unsoundness.
&& !process.audio_outputs.is_null() if process.audio_outputs_count > 0
&& !(*process.audio_outputs).data32.is_null() && !process.audio_outputs.is_null()
&& has_main_output && !(*process.audio_outputs).data32.is_null()
{ && has_main_output
let audio_output = &*process.audio_outputs;
let ptrs = NonNull::new(audio_output.data32 as *mut *mut f32).unwrap();
let num_channels = audio_output.channel_count as usize;
*buffer_source.main_output_channel_pointers =
Some(ChannelPointers { ptrs, num_channels });
}
if process.audio_inputs_count > 0
&& !process.audio_inputs.is_null()
&& !(*process.audio_inputs).data32.is_null()
&& has_main_input
{
let audio_input = &*process.audio_inputs;
let ptrs = NonNull::new(audio_input.data32 as *mut *mut f32).unwrap();
let num_channels = audio_input.channel_count as usize;
*buffer_source.main_input_channel_pointers =
Some(ChannelPointers { ptrs, num_channels });
}
if !process.audio_inputs.is_null() {
for (aux_input_no, aux_input_channel_pointers) in buffer_source
.aux_input_channel_pointers
.iter_mut()
.enumerate()
{ {
let aux_input_idx = aux_input_no + aux_input_start_idx; let audio_output = &*process.audio_outputs;
if aux_input_idx > process.audio_inputs_count as usize { let ptrs = NonNull::new(audio_output.data32 as *mut *mut f32).unwrap();
break; let num_channels = audio_output.channel_count as usize;
}
let audio_input = &*process.audio_inputs.add(aux_input_idx); *buffer_source.main_output_channel_pointers =
match NonNull::new(audio_input.data32 as *mut *mut f32) { Some(ChannelPointers { ptrs, num_channels });
Some(ptrs) => { }
let num_channels = audio_input.channel_count as usize;
*aux_input_channel_pointers = if process.audio_inputs_count > 0
Some(ChannelPointers { ptrs, num_channels }); && !process.audio_inputs.is_null()
&& !(*process.audio_inputs).data32.is_null()
&& has_main_input
{
let audio_input = &*process.audio_inputs;
let ptrs = NonNull::new(audio_input.data32 as *mut *mut f32).unwrap();
let num_channels = audio_input.channel_count as usize;
*buffer_source.main_input_channel_pointers =
Some(ChannelPointers { ptrs, num_channels });
}
if !process.audio_inputs.is_null() {
for (aux_input_no, aux_input_channel_pointers) in buffer_source
.aux_input_channel_pointers
.iter_mut()
.enumerate()
{
let aux_input_idx = aux_input_no + aux_input_start_idx;
if aux_input_idx > process.audio_inputs_count as usize {
break;
}
let audio_input = &*process.audio_inputs.add(aux_input_idx);
match NonNull::new(audio_input.data32 as *mut *mut f32) {
Some(ptrs) => {
let num_channels = audio_input.channel_count as usize;
*aux_input_channel_pointers =
Some(ChannelPointers { ptrs, num_channels });
}
None => continue,
} }
None => continue,
} }
} }
}
if !process.audio_outputs.is_null() { if !process.audio_outputs.is_null() {
for (aux_output_no, aux_output_channel_pointers) in buffer_source for (aux_output_no, aux_output_channel_pointers) in buffer_source
.aux_output_channel_pointers .aux_output_channel_pointers
.iter_mut() .iter_mut()
.enumerate() .enumerate()
{ {
let aux_output_idx = aux_output_no + aux_output_start_idx; let aux_output_idx = aux_output_no + aux_output_start_idx;
if aux_output_idx > process.audio_outputs_count as usize { if aux_output_idx > process.audio_outputs_count as usize {
break; break;
} }
let audio_output = &*process.audio_outputs.add(aux_output_idx); let audio_output = &*process.audio_outputs.add(aux_output_idx);
match NonNull::new(audio_output.data32 as *mut *mut f32) { match NonNull::new(audio_output.data32 as *mut *mut f32) {
Some(ptrs) => { Some(ptrs) => {
let num_channels = audio_output.channel_count as usize; let num_channels = audio_output.channel_count as usize;
*aux_output_channel_pointers = *aux_output_channel_pointers =
Some(ChannelPointers { ptrs, num_channels }); Some(ChannelPointers { ptrs, num_channels });
}
None => continue,
} }
None => continue,
} }
} }
} });
});
// If the host does not provide outputs or if it does not provide the required // If the host does not provide outputs or if it does not provide the required
// number of channels (should not happen, but Ableton Live does this for bypassed // number of channels (should not happen, but Ableton Live does this for bypassed

View file

@ -825,7 +825,7 @@ impl CpalMidir {
{ {
let buffers = unsafe { let buffers = unsafe {
buffer_manager.create_buffers(buffer_size, |buffer_sources| { buffer_manager.create_buffers(0, buffer_size, |buffer_sources| {
*buffer_sources.main_output_channel_pointers = Some(ChannelPointers { *buffer_sources.main_output_channel_pointers = Some(ChannelPointers {
ptrs: NonNull::new(main_io_channel_pointers.get().as_mut_ptr()) ptrs: NonNull::new(main_io_channel_pointers.get().as_mut_ptr())
.unwrap(), .unwrap(),

View file

@ -121,7 +121,7 @@ impl<P: Plugin> Backend<P> for Dummy {
} }
let buffers = unsafe { let buffers = unsafe {
buffer_manager.create_buffers(num_samples, |buffer_sources| { buffer_manager.create_buffers(0, num_samples, |buffer_sources| {
*buffer_sources.main_output_channel_pointers = Some(ChannelPointers { *buffer_sources.main_output_channel_pointers = Some(ChannelPointers {
ptrs: NonNull::new(main_io_channel_pointers.as_mut_ptr()).unwrap(), ptrs: NonNull::new(main_io_channel_pointers.as_mut_ptr()).unwrap(),
num_channels: main_io_channel_pointers.len(), num_channels: main_io_channel_pointers.len(),

View file

@ -204,7 +204,7 @@ impl<P: Plugin> Backend<P> for Jack {
} }
let buffers = unsafe { let buffers = unsafe {
buffer_manager.create_buffers(num_frames as usize, |buffer_sources| { buffer_manager.create_buffers(0, num_frames as usize, |buffer_sources| {
*buffer_sources.main_output_channel_pointers = Some(ChannelPointers { *buffer_sources.main_output_channel_pointers = Some(ChannelPointers {
ptrs: NonNull::new(main_output_channel_pointers.get().as_mut_ptr()) ptrs: NonNull::new(main_output_channel_pointers.get().as_mut_ptr())
.unwrap(), .unwrap(),

View file

@ -151,7 +151,9 @@ impl BufferManager {
/// uninitialized buffer data (aux outputs, and main output channels with no matching input /// uninitialized buffer data (aux outputs, and main output channels with no matching input
/// channel) are filled with zeroes. /// channel) are filled with zeroes.
/// ///
/// If any of the output /// `sample_offset` and `num_samples` can be used to slice a set of host channel pointers for
/// sample accurate automation. If any of the outputs are missing because the host hasn't
/// provided enough channels or outputs, then they will be replaced by empty slices.
/// ///
/// # Panics /// # Panics
/// ///
@ -163,6 +165,7 @@ impl BufferManager {
/// or write to for the lifetime of the returned [`Buffers`]. /// or write to for the lifetime of the returned [`Buffers`].
pub unsafe fn create_buffers<'a, 'buffer: 'a>( pub unsafe fn create_buffers<'a, 'buffer: 'a>(
&'a mut self, &'a mut self,
sample_offset: usize,
num_samples: usize, num_samples: usize,
set_buffer_sources: impl FnOnce(&mut BufferSource), set_buffer_sources: impl FnOnce(&mut BufferSource),
) -> Buffers<'a, 'buffer> { ) -> Buffers<'a, 'buffer> {
@ -192,8 +195,10 @@ impl BufferManager {
output_channel_pointers.ptrs.as_ptr().add(channel_idx); output_channel_pointers.ptrs.as_ptr().add(channel_idx);
assert!(!output_channel_pointer.is_null()); assert!(!output_channel_pointer.is_null());
*output_slice = *output_slice = std::slice::from_raw_parts_mut(
std::slice::from_raw_parts_mut(*output_channel_pointer, num_samples); (*output_channel_pointer).add(sample_offset),
num_samples,
);
} }
// If the caller/host should have provided buffer pointers but didn't then we // If the caller/host should have provided buffer pointers but didn't then we
@ -229,7 +234,7 @@ impl BufferManager {
assert!(!input_channel_pointer.is_null()); assert!(!input_channel_pointer.is_null());
output_slice.copy_from_slice(std::slice::from_raw_parts_mut( output_slice.copy_from_slice(std::slice::from_raw_parts_mut(
*input_channel_pointer, (*input_channel_pointer).add(sample_offset),
num_samples, num_samples,
)) ))
} }
@ -275,7 +280,7 @@ impl BufferManager {
nih_debug_assert!(num_samples <= channel.capacity()); nih_debug_assert!(num_samples <= channel.capacity());
channel.resize(num_samples, 0.0); channel.resize(num_samples, 0.0);
channel.copy_from_slice(std::slice::from_raw_parts_mut( channel.copy_from_slice(std::slice::from_raw_parts_mut(
*input_channel_pointer, (*input_channel_pointer).add(sample_offset),
num_samples, num_samples,
)) ))
} }
@ -334,7 +339,7 @@ impl BufferManager {
assert!(!output_channel_pointer.is_null()); assert!(!output_channel_pointer.is_null());
*output_slice = std::slice::from_raw_parts_mut( *output_slice = std::slice::from_raw_parts_mut(
*output_channel_pointer, (*output_channel_pointer).add(sample_offset),
num_samples, num_samples,
); );
@ -424,7 +429,7 @@ mod miri {
// implementation for more information. // implementation for more information.
let mut buffer_manager = BufferManager::for_audio_io_layout(BUFFER_SIZE, AUDIO_IO_LAYOUT); let mut buffer_manager = BufferManager::for_audio_io_layout(BUFFER_SIZE, AUDIO_IO_LAYOUT);
let buffers = unsafe { let buffers = unsafe {
buffer_manager.create_buffers(BUFFER_SIZE, |buffer_sources| { buffer_manager.create_buffers(0, BUFFER_SIZE, |buffer_sources| {
*buffer_sources.main_output_channel_pointers = Some(ChannelPointers { *buffer_sources.main_output_channel_pointers = Some(ChannelPointers {
ptrs: NonNull::new(main_io_channel_pointers.as_mut_ptr()).unwrap(), ptrs: NonNull::new(main_io_channel_pointers.as_mut_ptr()).unwrap(),
num_channels: main_io_channel_pointers.len(), num_channels: main_io_channel_pointers.len(),

View file

@ -1229,81 +1229,84 @@ impl<P: Vst3Plugin> IAudioProcessor for Wrapper<P> {
// The buffer manager preallocated buffer slices for all the IO and storage for // The buffer manager preallocated buffer slices for all the IO and storage for
// any axuiliary inputs. // any axuiliary inputs.
let mut buffer_manager = self.inner.buffer_manager.borrow_mut(); let mut buffer_manager = self.inner.buffer_manager.borrow_mut();
let buffers = buffer_manager.create_buffers(block_len, |buffer_source| { let buffers =
if data.num_outputs > 0 buffer_manager.create_buffers(block_start, block_len, |buffer_source| {
&& !data.outputs.is_null() if data.num_outputs > 0
&& !(*data.outputs).buffers.is_null() && !data.outputs.is_null()
&& has_main_output && !(*data.outputs).buffers.is_null()
{ && has_main_output
let audio_output = &*data.outputs;
let ptrs = NonNull::new(audio_output.buffers as *mut *mut f32).unwrap();
let num_channels = audio_output.num_channels as usize;
*buffer_source.main_output_channel_pointers =
Some(ChannelPointers { ptrs, num_channels });
}
if data.num_inputs > 0
&& !data.inputs.is_null()
&& !(*data.inputs).buffers.is_null()
&& has_main_input
{
let audio_input = &*data.inputs;
let ptrs = NonNull::new(audio_input.buffers as *mut *mut f32).unwrap();
let num_channels = audio_input.num_channels as usize;
*buffer_source.main_input_channel_pointers =
Some(ChannelPointers { ptrs, num_channels });
}
if !data.inputs.is_null() {
for (aux_input_no, aux_input_channel_pointers) in buffer_source
.aux_input_channel_pointers
.iter_mut()
.enumerate()
{ {
let aux_input_idx = aux_input_no + aux_input_start_idx; let audio_output = &*data.outputs;
if aux_input_idx > data.num_outputs as usize { let ptrs =
break; NonNull::new(audio_output.buffers as *mut *mut f32).unwrap();
} let num_channels = audio_output.num_channels as usize;
let audio_input = &*data.inputs.add(aux_input_idx); *buffer_source.main_output_channel_pointers =
match NonNull::new(audio_input.buffers as *mut *mut f32) { Some(ChannelPointers { ptrs, num_channels });
Some(ptrs) => { }
let num_channels = audio_input.num_channels as usize;
*aux_input_channel_pointers = if data.num_inputs > 0
Some(ChannelPointers { ptrs, num_channels }); && !data.inputs.is_null()
&& !(*data.inputs).buffers.is_null()
&& has_main_input
{
let audio_input = &*data.inputs;
let ptrs =
NonNull::new(audio_input.buffers as *mut *mut f32).unwrap();
let num_channels = audio_input.num_channels as usize;
*buffer_source.main_input_channel_pointers =
Some(ChannelPointers { ptrs, num_channels });
}
if !data.inputs.is_null() {
for (aux_input_no, aux_input_channel_pointers) in buffer_source
.aux_input_channel_pointers
.iter_mut()
.enumerate()
{
let aux_input_idx = aux_input_no + aux_input_start_idx;
if aux_input_idx > data.num_outputs as usize {
break;
}
let audio_input = &*data.inputs.add(aux_input_idx);
match NonNull::new(audio_input.buffers as *mut *mut f32) {
Some(ptrs) => {
let num_channels = audio_input.num_channels as usize;
*aux_input_channel_pointers =
Some(ChannelPointers { ptrs, num_channels });
}
None => continue,
} }
None => continue,
} }
} }
}
if !data.outputs.is_null() { if !data.outputs.is_null() {
for (aux_output_no, aux_output_channel_pointers) in buffer_source for (aux_output_no, aux_output_channel_pointers) in buffer_source
.aux_output_channel_pointers .aux_output_channel_pointers
.iter_mut() .iter_mut()
.enumerate() .enumerate()
{ {
let aux_output_idx = aux_output_no + aux_output_start_idx; let aux_output_idx = aux_output_no + aux_output_start_idx;
if aux_output_idx > data.num_outputs as usize { if aux_output_idx > data.num_outputs as usize {
break; break;
} }
let audio_output = &*data.outputs.add(aux_output_idx); let audio_output = &*data.outputs.add(aux_output_idx);
match NonNull::new(audio_output.buffers as *mut *mut f32) { match NonNull::new(audio_output.buffers as *mut *mut f32) {
Some(ptrs) => { Some(ptrs) => {
let num_channels = audio_output.num_channels as usize; let num_channels = audio_output.num_channels as usize;
*aux_output_channel_pointers = *aux_output_channel_pointers =
Some(ChannelPointers { ptrs, num_channels }); Some(ChannelPointers { ptrs, num_channels });
}
None => continue,
} }
None => continue,
} }
} }
} });
});
// We already checked whether the host has initiated a parameter flush, but in // We already checked whether the host has initiated a parameter flush, but in
// case it still did something unexpected that we did not catch we'll still try // case it still did something unexpected that we did not catch we'll still try