Skip to content

Commit 852eb44

Browse files
committed
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.
1 parent 7c7acfd commit 852eb44

File tree

7 files changed

+44
-37
lines changed

7 files changed

+44
-37
lines changed

examples/gain/src/lib.rs

+15-3
Original file line numberDiff line numberDiff line change
@@ -113,16 +113,28 @@ pub struct GainProcessor {
113113
params: GainParams,
114114
}
115115

116+
impl GainProcessor {
117+
fn handle_event(&mut self, event: &Event) {
118+
if let Data::ParamChange { id, value } = event.data {
119+
self.params.set_param(id, value);
120+
}
121+
}
122+
}
123+
116124
impl Processor for GainProcessor {
117125
fn reset(&mut self) {}
118126

127+
fn flush(&mut self, events: Events) {
128+
for event in events {
129+
self.handle_event(event);
130+
}
131+
}
132+
119133
fn process(&mut self, buffers: Buffers, events: Events) {
120134
let mut buffers: (BufferMut,) = buffers.try_into().unwrap();
121135
for (mut buffer, events) in buffers.0.split_at_events(events) {
122136
for event in events {
123-
if let Data::ParamChange { id, value } = event.data {
124-
self.params.set_param(id, value);
125-
}
137+
self.handle_event(event);
126138
}
127139

128140
for sample in buffer.samples() {

src/format/clap/instance.rs

+2-21
Original file line numberDiff line numberDiff line change
@@ -394,16 +394,7 @@ impl<P: Plugin> Instance<P> {
394394
instance.sync_processor(&mut process_state.events);
395395

396396
if !process_state.events.is_empty() {
397-
process_state.buffer_ptrs.fill(NonNull::dangling().as_ptr());
398-
processor.process(
399-
Buffers::from_raw_parts(
400-
&process_state.buffer_data,
401-
&process_state.buffer_ptrs,
402-
0,
403-
0,
404-
),
405-
Events::new(&process_state.events),
406-
);
397+
processor.flush(Events::new(&process_state.events));
407398
}
408399

409400
processor.reset();
@@ -810,8 +801,6 @@ impl<P: Plugin> Instance<P> {
810801

811802
// If we are in the active state, flush will be called on the audio thread.
812803
if let Some(processor) = &mut process_state.processor {
813-
process_state.buffer_ptrs.fill(NonNull::dangling().as_ptr());
814-
815804
process_state.events.clear();
816805
instance.sync_processor(&mut process_state.events);
817806
instance.process_param_events(in_, &mut process_state.events);
@@ -822,15 +811,7 @@ impl<P: Plugin> Instance<P> {
822811
0,
823812
);
824813

825-
processor.process(
826-
Buffers::from_raw_parts(
827-
&process_state.buffer_data,
828-
&process_state.buffer_ptrs,
829-
0,
830-
0,
831-
),
832-
Events::new(&process_state.events),
833-
);
814+
processor.flush(Events::new(&process_state.events));
834815
}
835816
// Otherwise, flush will be called on the main thread.
836817
else {

src/format/clap/tests.rs

+1
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ struct TestProcessor;
7777

7878
impl Processor for TestProcessor {
7979
fn reset(&mut self) {}
80+
fn flush(&mut self, _events: Events) {}
8081
fn process(&mut self, _buffers: Buffers, _events: Events) {}
8182
}
8283

src/format/vst3/buffers.rs

+17-8
Original file line numberDiff line numberDiff line change
@@ -87,14 +87,26 @@ impl ScratchBuffers {
8787
self.moves.reserve(in_out_channels);
8888
}
8989

90+
/// Set up buffer pointers for the processor given a VST3 `ProcessData` struct.
91+
///
92+
/// This method is responsible for detecting if any of the buffers for an input bus are aliased
93+
/// by a output buffer and, if so, copying those inputs to scratch buffers. It is also
94+
/// responsible for detecting if separate input and output buffers have been passed for an
95+
/// in-out bus and copying those inputs to the corresponding outputs.
96+
///
97+
/// This method will return `Err` if the channel counts do not match the current layout or if
98+
/// the buffer's length exceeds the maximum buffer size. It will return `Ok(None)` if the
99+
/// buffer's length is 0, as hosts are not guaranteed to provide the correct number of inputs
100+
/// and outputs in that case, and we don't need to construct a `Buffers` object as we will be
101+
/// calling `Processor::flush` instead of `Processor::process`.
90102
pub unsafe fn get_buffers(
91103
&mut self,
92104
buses: &[BusInfo],
93105
input_bus_map: &[usize],
94106
output_bus_map: &[usize],
95107
config: &Config,
96108
data: &ProcessData,
97-
) -> Result<Buffers, ()> {
109+
) -> Result<Option<Buffers>, ()> {
98110
let len = data.numSamples as usize;
99111
if len > config.max_buffer_size {
100112
return Err(());
@@ -103,7 +115,7 @@ impl ScratchBuffers {
103115
let mut scratch = &mut self.buffers[..];
104116

105117
if len == 0 {
106-
return Ok(self.get_empty_buffers());
118+
return Ok(None);
107119
}
108120

109121
let input_count = data.numInputs as usize;
@@ -242,11 +254,8 @@ impl ScratchBuffers {
242254

243255
self.output_ptrs.clear();
244256

245-
Ok(Buffers::from_raw_parts(&self.data, &self.ptrs, 0, len))
246-
}
247-
248-
pub fn get_empty_buffers(&mut self) -> Buffers {
249-
self.ptrs.fill(NonNull::dangling().as_ptr());
250-
unsafe { Buffers::from_raw_parts(&self.data, &self.ptrs, 0, 0) }
257+
Ok(Some(Buffers::from_raw_parts(
258+
&self.data, &self.ptrs, 0, len,
259+
)))
251260
}
252261
}

src/format/vst3/component.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -487,10 +487,7 @@ impl<P: Plugin> IAudioProcessorTrait for Component<P> {
487487
}
488488

489489
if !process_state.events.is_empty() {
490-
processor.process(
491-
process_state.scratch_buffers.get_empty_buffers(),
492-
Events::new(&process_state.events),
493-
);
490+
processor.flush(Events::new(&process_state.events));
494491
}
495492

496493
processor.reset();
@@ -563,7 +560,12 @@ impl<P: Plugin> IAudioProcessorTrait for Component<P> {
563560
}
564561
}
565562

566-
processor.process(buffers, Events::new(&process_state.events));
563+
let events = Events::new(&process_state.events);
564+
if let Some(buffers) = buffers {
565+
processor.process(buffers, events);
566+
} else {
567+
processor.flush(events);
568+
}
567569

568570
kResultOk
569571
}

src/format/vst3/tests.rs

+1
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ struct TestProcessor;
8686

8787
impl Processor for TestProcessor {
8888
fn reset(&mut self) {}
89+
fn flush(&mut self, _events: Events) {}
8990
fn process(&mut self, _buffers: Buffers, _events: Events) {}
9091
}
9192

src/process.rs

+1
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@ pub struct Config {
1111

1212
pub trait Processor: Send + Sized + 'static {
1313
fn reset(&mut self);
14+
fn flush(&mut self, events: Events);
1415
fn process(&mut self, buffers: Buffers, events: Events);
1516
}

0 commit comments

Comments
 (0)