From 852eb44cffae34fddce66fae61406579014d948c Mon Sep 17 00:00:00 2001 From: glowcoil Date: Sat, 7 Sep 2024 09:17:17 -0500 Subject: [PATCH] introduce Processor::flush method Introduce a `Processor::flush` method for handling events without a corresponding set of audio buffers. Update the VST3 and CLAP backends to call `flush` wherever they currently call `process` with a zero-length buffer. --- examples/gain/src/lib.rs | 18 +++++++++++++++--- src/format/clap/instance.rs | 23 ++--------------------- src/format/clap/tests.rs | 1 + src/format/vst3/buffers.rs | 25 +++++++++++++++++-------- src/format/vst3/component.rs | 12 +++++++----- src/format/vst3/tests.rs | 1 + src/process.rs | 1 + 7 files changed, 44 insertions(+), 37 deletions(-) diff --git a/examples/gain/src/lib.rs b/examples/gain/src/lib.rs index 4a8259f..75b4432 100644 --- a/examples/gain/src/lib.rs +++ b/examples/gain/src/lib.rs @@ -113,16 +113,28 @@ pub struct GainProcessor { params: GainParams, } +impl GainProcessor { + fn handle_event(&mut self, event: &Event) { + if let Data::ParamChange { id, value } = event.data { + self.params.set_param(id, value); + } + } +} + impl Processor for GainProcessor { fn reset(&mut self) {} + fn flush(&mut self, events: Events) { + for event in events { + self.handle_event(event); + } + } + fn process(&mut self, buffers: Buffers, events: Events) { let mut buffers: (BufferMut,) = buffers.try_into().unwrap(); for (mut buffer, events) in buffers.0.split_at_events(events) { for event in events { - if let Data::ParamChange { id, value } = event.data { - self.params.set_param(id, value); - } + self.handle_event(event); } for sample in buffer.samples() { diff --git a/src/format/clap/instance.rs b/src/format/clap/instance.rs index dbe88a1..feba206 100644 --- a/src/format/clap/instance.rs +++ b/src/format/clap/instance.rs @@ -394,16 +394,7 @@ impl Instance

{ instance.sync_processor(&mut process_state.events); if !process_state.events.is_empty() { - process_state.buffer_ptrs.fill(NonNull::dangling().as_ptr()); - processor.process( - Buffers::from_raw_parts( - &process_state.buffer_data, - &process_state.buffer_ptrs, - 0, - 0, - ), - Events::new(&process_state.events), - ); + processor.flush(Events::new(&process_state.events)); } processor.reset(); @@ -810,8 +801,6 @@ impl Instance

{ // If we are in the active state, flush will be called on the audio thread. if let Some(processor) = &mut process_state.processor { - process_state.buffer_ptrs.fill(NonNull::dangling().as_ptr()); - process_state.events.clear(); instance.sync_processor(&mut process_state.events); instance.process_param_events(in_, &mut process_state.events); @@ -822,15 +811,7 @@ impl Instance

{ 0, ); - processor.process( - Buffers::from_raw_parts( - &process_state.buffer_data, - &process_state.buffer_ptrs, - 0, - 0, - ), - Events::new(&process_state.events), - ); + processor.flush(Events::new(&process_state.events)); } // Otherwise, flush will be called on the main thread. else { diff --git a/src/format/clap/tests.rs b/src/format/clap/tests.rs index 57bc549..8d2c73f 100644 --- a/src/format/clap/tests.rs +++ b/src/format/clap/tests.rs @@ -77,6 +77,7 @@ struct TestProcessor; impl Processor for TestProcessor { fn reset(&mut self) {} + fn flush(&mut self, _events: Events) {} fn process(&mut self, _buffers: Buffers, _events: Events) {} } diff --git a/src/format/vst3/buffers.rs b/src/format/vst3/buffers.rs index 1500644..505696c 100644 --- a/src/format/vst3/buffers.rs +++ b/src/format/vst3/buffers.rs @@ -87,6 +87,18 @@ impl ScratchBuffers { self.moves.reserve(in_out_channels); } + /// Set up buffer pointers for the processor given a VST3 `ProcessData` struct. + /// + /// This method is responsible for detecting if any of the buffers for an input bus are aliased + /// by a output buffer and, if so, copying those inputs to scratch buffers. It is also + /// responsible for detecting if separate input and output buffers have been passed for an + /// in-out bus and copying those inputs to the corresponding outputs. + /// + /// This method will return `Err` if the channel counts do not match the current layout or if + /// the buffer's length exceeds the maximum buffer size. It will return `Ok(None)` if the + /// buffer's length is 0, as hosts are not guaranteed to provide the correct number of inputs + /// and outputs in that case, and we don't need to construct a `Buffers` object as we will be + /// calling `Processor::flush` instead of `Processor::process`. pub unsafe fn get_buffers( &mut self, buses: &[BusInfo], @@ -94,7 +106,7 @@ impl ScratchBuffers { output_bus_map: &[usize], config: &Config, data: &ProcessData, - ) -> Result { + ) -> Result, ()> { let len = data.numSamples as usize; if len > config.max_buffer_size { return Err(()); @@ -103,7 +115,7 @@ impl ScratchBuffers { let mut scratch = &mut self.buffers[..]; if len == 0 { - return Ok(self.get_empty_buffers()); + return Ok(None); } let input_count = data.numInputs as usize; @@ -242,11 +254,8 @@ impl ScratchBuffers { self.output_ptrs.clear(); - Ok(Buffers::from_raw_parts(&self.data, &self.ptrs, 0, len)) - } - - pub fn get_empty_buffers(&mut self) -> Buffers { - self.ptrs.fill(NonNull::dangling().as_ptr()); - unsafe { Buffers::from_raw_parts(&self.data, &self.ptrs, 0, 0) } + Ok(Some(Buffers::from_raw_parts( + &self.data, &self.ptrs, 0, len, + ))) } } diff --git a/src/format/vst3/component.rs b/src/format/vst3/component.rs index 7bfecb8..6634481 100644 --- a/src/format/vst3/component.rs +++ b/src/format/vst3/component.rs @@ -487,10 +487,7 @@ impl IAudioProcessorTrait for Component

{ } if !process_state.events.is_empty() { - processor.process( - process_state.scratch_buffers.get_empty_buffers(), - Events::new(&process_state.events), - ); + processor.flush(Events::new(&process_state.events)); } processor.reset(); @@ -563,7 +560,12 @@ impl IAudioProcessorTrait for Component

{ } } - processor.process(buffers, Events::new(&process_state.events)); + let events = Events::new(&process_state.events); + if let Some(buffers) = buffers { + processor.process(buffers, events); + } else { + processor.flush(events); + } kResultOk } diff --git a/src/format/vst3/tests.rs b/src/format/vst3/tests.rs index e8c7fbe..7e3cccf 100644 --- a/src/format/vst3/tests.rs +++ b/src/format/vst3/tests.rs @@ -86,6 +86,7 @@ struct TestProcessor; impl Processor for TestProcessor { fn reset(&mut self) {} + fn flush(&mut self, _events: Events) {} fn process(&mut self, _buffers: Buffers, _events: Events) {} } diff --git a/src/process.rs b/src/process.rs index 01ab962..215e7d5 100644 --- a/src/process.rs +++ b/src/process.rs @@ -11,5 +11,6 @@ pub struct Config { pub trait Processor: Send + Sized + 'static { fn reset(&mut self); + fn flush(&mut self, events: Events); fn process(&mut self, buffers: Buffers, events: Events); }