Consider block start with buffer management
This broke sample accurate automation.
This commit is contained in:
parent
4912962551
commit
5e69910616
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue