diff --git a/src/plugin.rs b/src/plugin.rs index 390f23a7..a414655e 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -243,6 +243,19 @@ pub trait Plugin: Default + Send + 'static { context: &mut impl ProcessContext, ) -> ProcessStatus; + /// Called when audio processing stops, for instance when the plugin is turned off. + /// This is the counterpart to [`reset()`][Self::reset()] which is called + /// when processing starts or resumes. + /// + /// Unlike [`deactivate()`][Self::deactivate()], this is called for temporary processing + /// interruptions like bypassing, not major lifecycle changes. + /// You can use this to gracefully handle the transition to a non-processing state, such as clearing + /// buffers, writing silence to displays, or saving state. + /// + /// This method is called from both CLAP (`stop_processing`) and VST3 (`setProcessing(false)`) + /// hosts when they temporarily stop sending audio to the plugin. + fn process_stopped(&mut self) {} + /// Called when the plugin is deactivated. The host will call /// [`initialize()`][Self::initialize()] again before the plugin resumes processing audio. These /// two functions will not be called when the host only temporarily stops processing audio. You diff --git a/src/wrapper/clap/wrapper.rs b/src/wrapper/clap/wrapper.rs index 1ff8e8a6..5ee0d18a 100644 --- a/src/wrapper/clap/wrapper.rs +++ b/src/wrapper/clap/wrapper.rs @@ -1939,6 +1939,10 @@ impl Wrapper

{ let wrapper = &*((*plugin).plugin_data as *const Self); wrapper.is_processing.store(false, Ordering::SeqCst); + + process_wrapper(|| { + wrapper.plugin.lock().process_stopped(); + }); } unsafe extern "C" fn reset(plugin: *const clap_plugin) { diff --git a/src/wrapper/vst3/wrapper.rs b/src/wrapper/vst3/wrapper.rs index f284af54..69c9e7e0 100644 --- a/src/wrapper/vst3/wrapper.rs +++ b/src/wrapper/vst3/wrapper.rs @@ -922,6 +922,11 @@ impl IAudioProcessor for Wrapper

{ }; process_wrapper(|| plugin.reset()); + } else { + // Process stopped - call the plugin's process_stopped() method + process_wrapper(|| { + self.inner.plugin.lock().process_stopped(); + }); } // We don't have any special handling for suspending and resuming plugins, yet