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
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]
### 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
// flags?
let mut buffer_manager = wrapper.buffer_manager.borrow_mut();
let buffers = buffer_manager.create_buffers(block_len, |buffer_source| {
// Explicitly take plugins with no main output that does have auxiliary outputs
// into account. Shouldn't happen, but if we just start copying audio here then
// that would result in unsoundness.
if process.audio_outputs_count > 0
&& !process.audio_outputs.is_null()
&& !(*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 buffers =
buffer_manager.create_buffers(block_start, block_len, |buffer_source| {
// Explicitly take plugins with no main output that does have auxiliary
// outputs into account. Shouldn't happen, but if we just start copying
// audio here then that would result in unsoundness.
if process.audio_outputs_count > 0
&& !process.audio_outputs.is_null()
&& !(*process.audio_outputs).data32.is_null()
&& has_main_output
{
let aux_input_idx = aux_input_no + aux_input_start_idx;
if aux_input_idx > process.audio_inputs_count as usize {
break;
}
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;
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;
*buffer_source.main_output_channel_pointers =
Some(ChannelPointers { ptrs, num_channels });
}
*aux_input_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;
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() {
for (aux_output_no, aux_output_channel_pointers) in buffer_source
.aux_output_channel_pointers
.iter_mut()
.enumerate()
{
let aux_output_idx = aux_output_no + aux_output_start_idx;
if aux_output_idx > process.audio_outputs_count as usize {
break;
}
let audio_output = &*process.audio_outputs.add(aux_output_idx);
match NonNull::new(audio_output.data32 as *mut *mut f32) {
Some(ptrs) => {
let num_channels = audio_output.channel_count as usize;
*aux_output_channel_pointers =
Some(ChannelPointers { ptrs, num_channels });
if !process.audio_outputs.is_null() {
for (aux_output_no, aux_output_channel_pointers) in buffer_source
.aux_output_channel_pointers
.iter_mut()
.enumerate()
{
let aux_output_idx = aux_output_no + aux_output_start_idx;
if aux_output_idx > process.audio_outputs_count as usize {
break;
}
let audio_output = &*process.audio_outputs.add(aux_output_idx);
match NonNull::new(audio_output.data32 as *mut *mut f32) {
Some(ptrs) => {
let num_channels = audio_output.channel_count as usize;
*aux_output_channel_pointers =
Some(ChannelPointers { ptrs, num_channels });
}
None => continue,
}
None => continue,
}
}
}
});
});
// 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

View file

@ -825,7 +825,7 @@ impl CpalMidir {
{
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 {
ptrs: NonNull::new(main_io_channel_pointers.get().as_mut_ptr())
.unwrap(),

View file

@ -121,7 +121,7 @@ impl<P: Plugin> Backend<P> for Dummy {
}
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 {
ptrs: NonNull::new(main_io_channel_pointers.as_mut_ptr()).unwrap(),
num_channels: main_io_channel_pointers.len(),

View file

@ -204,7 +204,7 @@ impl<P: Plugin> Backend<P> for Jack {
}
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 {
ptrs: NonNull::new(main_output_channel_pointers.get().as_mut_ptr())
.unwrap(),

View file

@ -151,7 +151,9 @@ impl BufferManager {
/// uninitialized buffer data (aux outputs, and main output channels with no matching input
/// 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
///
@ -163,6 +165,7 @@ impl BufferManager {
/// or write to for the lifetime of the returned [`Buffers`].
pub unsafe fn create_buffers<'a, 'buffer: 'a>(
&'a mut self,
sample_offset: usize,
num_samples: usize,
set_buffer_sources: impl FnOnce(&mut BufferSource),
) -> Buffers<'a, 'buffer> {
@ -192,8 +195,10 @@ impl BufferManager {
output_channel_pointers.ptrs.as_ptr().add(channel_idx);
assert!(!output_channel_pointer.is_null());
*output_slice =
std::slice::from_raw_parts_mut(*output_channel_pointer, num_samples);
*output_slice = std::slice::from_raw_parts_mut(
(*output_channel_pointer).add(sample_offset),
num_samples,
);
}
// 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());
output_slice.copy_from_slice(std::slice::from_raw_parts_mut(
*input_channel_pointer,
(*input_channel_pointer).add(sample_offset),
num_samples,
))
}
@ -275,7 +280,7 @@ impl BufferManager {
nih_debug_assert!(num_samples <= channel.capacity());
channel.resize(num_samples, 0.0);
channel.copy_from_slice(std::slice::from_raw_parts_mut(
*input_channel_pointer,
(*input_channel_pointer).add(sample_offset),
num_samples,
))
}
@ -334,7 +339,7 @@ impl BufferManager {
assert!(!output_channel_pointer.is_null());
*output_slice = std::slice::from_raw_parts_mut(
*output_channel_pointer,
(*output_channel_pointer).add(sample_offset),
num_samples,
);
@ -424,7 +429,7 @@ mod miri {
// implementation for more information.
let mut buffer_manager = BufferManager::for_audio_io_layout(BUFFER_SIZE, AUDIO_IO_LAYOUT);
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 {
ptrs: NonNull::new(main_io_channel_pointers.as_mut_ptr()).unwrap(),
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
// any axuiliary inputs.
let mut buffer_manager = self.inner.buffer_manager.borrow_mut();
let buffers = buffer_manager.create_buffers(block_len, |buffer_source| {
if data.num_outputs > 0
&& !data.outputs.is_null()
&& !(*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 buffers =
buffer_manager.create_buffers(block_start, block_len, |buffer_source| {
if data.num_outputs > 0
&& !data.outputs.is_null()
&& !(*data.outputs).buffers.is_null()
&& has_main_output
{
let aux_input_idx = aux_input_no + aux_input_start_idx;
if aux_input_idx > data.num_outputs as usize {
break;
}
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;
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;
*buffer_source.main_output_channel_pointers =
Some(ChannelPointers { ptrs, num_channels });
}
*aux_input_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;
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() {
for (aux_output_no, aux_output_channel_pointers) in buffer_source
.aux_output_channel_pointers
.iter_mut()
.enumerate()
{
let aux_output_idx = aux_output_no + aux_output_start_idx;
if aux_output_idx > data.num_outputs as usize {
break;
}
let audio_output = &*data.outputs.add(aux_output_idx);
match NonNull::new(audio_output.buffers as *mut *mut f32) {
Some(ptrs) => {
let num_channels = audio_output.num_channels as usize;
*aux_output_channel_pointers =
Some(ChannelPointers { ptrs, num_channels });
if !data.outputs.is_null() {
for (aux_output_no, aux_output_channel_pointers) in buffer_source
.aux_output_channel_pointers
.iter_mut()
.enumerate()
{
let aux_output_idx = aux_output_no + aux_output_start_idx;
if aux_output_idx > data.num_outputs as usize {
break;
}
let audio_output = &*data.outputs.add(aux_output_idx);
match NonNull::new(audio_output.buffers as *mut *mut f32) {
Some(ptrs) => {
let num_channels = audio_output.num_channels as usize;
*aux_output_channel_pointers =
Some(ChannelPointers { ptrs, num_channels });
}
None => continue,
}
None => continue,
}
}
}
});
});
// 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