Skip to main content

clack_host/
process.rs

1//! Plugin audio processing types and related utilities.
2//!
3//! A plugin's audio processor can be in two states, either `started` or `stopped`, depending on
4//! whether it is currently continuously processing audio, or has been put to sleep by the host,
5//! respectively.
6//!
7//! These states are represented by the [`StartedPluginAudioProcessor`] and [`StoppedPluginAudioProcessor`]
8//! types respectively, using a type-state pattern that only expose the methods that are valid for
9//! the plugin's current state.
10//!
11//! Alternatively, users can also use the [`PluginAudioProcessor`] convenience type that internalizes
12//! the state instead, and allows it to change and be checked at runtime.
13
14use self::audio_buffers::InputAudioBuffers;
15use crate::host::HostHandlers;
16use crate::plugin::{PluginAudioProcessorHandle, PluginInstanceError, PluginSharedHandle};
17use crate::prelude::{OutputAudioBuffers, PluginInstance};
18use crate::process::PluginAudioProcessor::*;
19use clack_common::events::event_types::TransportEvent;
20use clack_common::events::io::{InputEvents, OutputEvents};
21use clap_sys::process::clap_process;
22use std::cell::UnsafeCell;
23use std::error::Error;
24use std::fmt::{Debug, Display, Formatter};
25use std::marker::PhantomData;
26use std::sync::Arc;
27
28use crate::plugin::instance::PluginInstanceInner;
29pub use clack_common::process::*;
30
31#[allow(missing_docs)] // TODO: doc this
32pub mod audio_buffers;
33
34/// A handle to a plugin's audio processor that can be in either its `started` or `stopped` state.
35///
36/// This is a convenience type that can be used where the type-states [`StartedPluginAudioProcessor`] and
37/// [`StoppedPluginAudioProcessor`] are not very ergonomic, or to perform operations that are common
38/// to both states.
39///
40/// Note that in order to maintain thread-safety, this type must be either dropped or stopped and
41/// passed to either [`PluginInstance::deactivate`] or [`PluginInstance::deactivate_with`], *before*
42/// the [`PluginInstance`] itself is dropped. If this is not done, the plugin instance will never
43/// be deactivated or destroyed, and will leak all its associated resources.
44pub enum PluginAudioProcessor<H: HostHandlers> {
45    /// The audio processor is in it's `started` state.
46    Started(StartedPluginAudioProcessor<H>),
47    /// The audio processor is in it's `stopped` state.
48    Stopped(StoppedPluginAudioProcessor<H>),
49}
50
51impl<H: HostHandlers> PluginAudioProcessor<H> {
52    /// Resets the plugin's audio processing state.
53    ///
54    /// This clears all the plugin's internal buffers, kills all voices, and resets all processing
55    /// state such as envelopes, LFOs, oscillators, filters, etc.
56    ///
57    /// Calling this method allows the `steady_time` parameter passed to [`process`](StartedPluginAudioProcessor::process)
58    /// to jump backwards.
59    #[inline]
60    pub fn reset(&mut self) {
61        match self {
62            Started(s) => s.reset(),
63            Stopped(s) => s.reset(),
64        }
65    }
66
67    /// Accesses the [`SharedHandler`] for this instance, using the provided closure.
68    ///
69    /// This function returns the return value of the provided closure directly.
70    ///
71    /// Note that the lifetime of the [`SharedHandler`] cannot be statically known, as it is bound
72    /// to the plugin instance itself.
73    ///
74    /// Unlike [`access_handler`](self.access_handler) and
75    /// [`access_handler_mut`](self.access_handler_mut), there is no way to obtain a mutable
76    /// reference to the [`SharedHandler`], as it may be concurrently accessed by other threads.
77    ///
78    /// [`SharedHandler`]: crate::prelude::SharedHandler
79    #[inline]
80    pub fn access_shared_handler<'s, R>(
81        &'s self,
82        access: impl for<'a> FnOnce(&'s <H as HostHandlers>::Shared<'a>) -> R,
83    ) -> R {
84        match self {
85            Started(s) => s.access_shared_handler(access),
86            Stopped(s) => s.access_shared_handler(access),
87        }
88    }
89
90    /// Accesses the [`AudioProcessorHandler`] for this instance, using the provided closure.
91    ///
92    /// This function returns the return value of the provided closure directly.
93    ///
94    /// Note that the lifetime of the [`AudioProcessorHandler`] cannot be statically known, as it is bound
95    /// to the plugin instance itself.
96    ///
97    /// See the [`access_handler_mut`](self.access_handler_mut) method to receive a mutable
98    /// reference to the [`AudioProcessorHandler`] instead.
99    ///
100    /// [`AudioProcessorHandler`]: crate::prelude::AudioProcessorHandler
101    #[inline]
102    pub fn access_handler<'s, R>(
103        &'s self,
104        access: impl for<'a> FnOnce(&'s <H as HostHandlers>::AudioProcessor<'a>) -> R,
105    ) -> R {
106        match self {
107            Started(s) => s.access_handler(access),
108            Stopped(s) => s.access_handler(access),
109        }
110    }
111
112    /// Accesses the [`AudioProcessorHandler`] for this instance, using the provided closure.
113    ///
114    /// This function returns the return value of the provided closure directly.
115    ///
116    /// Note that the lifetime of the [`AudioProcessorHandler`] cannot be statically known, as it is bound
117    /// to the plugin instance itself.
118    ///
119    /// See the [`access_handler`](self.access_handler) method to receive a shared
120    /// reference to the [`AudioProcessorHandler`] instead.
121    ///
122    /// [`AudioProcessorHandler`]: crate::prelude::AudioProcessorHandler
123    #[inline]
124    pub fn access_handler_mut<'s, R>(
125        &'s mut self,
126        access: impl for<'a> FnOnce(&'s mut <H as HostHandlers>::AudioProcessor<'a>) -> R,
127    ) -> R {
128        match self {
129            Started(s) => s.access_handler_mut(access),
130            Stopped(s) => s.access_handler_mut(access),
131        }
132    }
133
134    /// Returns this plugin instance's audio processor handle.
135    #[inline]
136    pub fn plugin_handle(&mut self) -> PluginAudioProcessorHandle<'_> {
137        match self {
138            Started(s) => s.plugin_handle(),
139            Stopped(s) => s.plugin_handle(),
140        }
141    }
142
143    /// Returns this plugin instance's shared handle.
144    #[inline]
145    pub fn shared_plugin_handle(&self) -> PluginSharedHandle<'_> {
146        match self {
147            Started(s) => s.shared_plugin_handle(),
148            Stopped(s) => s.shared_plugin_handle(),
149        }
150    }
151
152    /// Returns `true` if this audio processor was created from the given plugin instance.
153    #[inline]
154    pub fn matches(&self, instance: &PluginInstance<H>) -> bool {
155        match &self {
156            Started(s) => s.matches(instance),
157            Stopped(s) => s.matches(instance),
158        }
159    }
160
161    /// Returns `true` if this audio processor is its `started` state, `false` otherwise.
162    #[inline]
163    pub fn is_started(&self) -> bool {
164        match self {
165            Stopped(_) => false,
166            Started(_) => true,
167        }
168    }
169
170    /// Returns this audio processor as a shared reference to its [`StartedPluginAudioProcessor`]
171    /// state, if it is in the `started` state.
172    ///
173    /// # Errors
174    ///
175    /// This returns a [`PluginInstanceError::ProcessingStopped`] error if the audio processor is
176    /// in the `stopped` state.
177    #[inline]
178    pub fn as_started(&self) -> Result<&StartedPluginAudioProcessor<H>, PluginInstanceError> {
179        match self {
180            Started(s) => Ok(s),
181            Stopped(_) => Err(PluginInstanceError::ProcessingStopped),
182        }
183    }
184
185    /// Returns this audio processor as a mutable reference to its [`StartedPluginAudioProcessor`]
186    /// state, if it is in the `started` state.
187    ///
188    /// # Errors
189    ///
190    /// This returns a [`PluginInstanceError::ProcessingStopped`] error if the audio processor is
191    /// in the `stopped` state.
192    #[inline]
193    pub fn as_started_mut(
194        &mut self,
195    ) -> Result<&mut StartedPluginAudioProcessor<H>, PluginInstanceError> {
196        match self {
197            Started(s) => Ok(s),
198            Stopped(_) => Err(PluginInstanceError::ProcessingStopped),
199        }
200    }
201
202    /// Returns this audio processor as a shared reference to its [`StoppedPluginAudioProcessor`]
203    /// state, if it is in the `stopped` state.
204    ///
205    /// # Errors
206    ///
207    /// This returns a [`PluginInstanceError::ProcessingStarted`] error if the audio processor is
208    /// in the `started` state.
209    #[inline]
210    pub fn as_stopped(&self) -> Result<&StoppedPluginAudioProcessor<H>, PluginInstanceError> {
211        match self {
212            Stopped(s) => Ok(s),
213            Started(_) => Err(PluginInstanceError::ProcessingStarted),
214        }
215    }
216
217    /// Returns this audio processor as a mutable reference to its [`StoppedPluginAudioProcessor`]
218    /// state, if it is in the `stopped` state.
219    ///
220    /// # Errors
221    ///
222    /// This returns a [`PluginInstanceError::ProcessingStarted`] error if the audio processor is
223    /// in the `started` state.
224    #[inline]
225    pub fn as_stopped_mut(
226        &mut self,
227    ) -> Result<&mut StoppedPluginAudioProcessor<H>, PluginInstanceError> {
228        match self {
229            Stopped(s) => Ok(s),
230            Started(_) => Err(PluginInstanceError::ProcessingStarted),
231        }
232    }
233
234    /// Starts this audio processor, and returns a mutable reference to its
235    /// [`StartedPluginAudioProcessor`] state.
236    ///
237    /// # Errors
238    ///
239    /// If the start operation failed, this returns a [`PluginInstanceError::StartProcessingFailed`] error.
240    /// If the audio processor was already started, this returns a
241    /// [`PluginInstanceError::ProcessingStarted`] error.
242    #[inline]
243    pub fn start_processing(
244        &mut self,
245    ) -> Result<&mut StartedPluginAudioProcessor<H>, PluginInstanceError> {
246        let inner = match self {
247            Started(_) => return Err(PluginInstanceError::ProcessingStarted),
248            Stopped(a) => a.inner.clone(),
249        };
250
251        let Ok(started) = StoppedPluginAudioProcessor::new(inner).start_processing() else {
252            return Err(PluginInstanceError::StartProcessingFailed);
253        };
254
255        *self = Started(started);
256
257        Ok(match self {
258            Started(s) => s,
259            _ => unreachable!(),
260        })
261    }
262
263    /// Starts this audio processor, and returns a mutable reference to its
264    /// [`StoppedPluginAudioProcessor`] state.
265    ///
266    /// # Errors
267    ///
268    /// If the audio processor was already stopped, this returns a
269    /// [`PluginInstanceError::ProcessingStopped`] error.
270    #[inline]
271    pub fn stop_processing(
272        &mut self,
273    ) -> Result<&mut StoppedPluginAudioProcessor<H>, PluginInstanceError> {
274        let inner = match self {
275            Stopped(_) => return Err(PluginInstanceError::ProcessingStopped),
276            Started(a) => a.inner.clone(),
277        };
278
279        let stopped = StartedPluginAudioProcessor::new(inner).stop_processing();
280
281        *self = Stopped(stopped);
282
283        Ok(match self {
284            Stopped(s) => s,
285            _ => unreachable!(),
286        })
287    }
288
289    /// Starts this audio processor, if it is not already started, and returns a mutable reference
290    /// to its [`StartedPluginAudioProcessor`] state.
291    ///
292    /// If its already started, this does nothing and returns the mutable reference directly.
293    ///
294    /// # Errors
295    ///
296    /// If this audio processor was in its `stopped` state and the start operation failed, this
297    /// returns a [`PluginInstanceError::StartProcessingFailed`] error.
298    #[inline]
299    pub fn ensure_processing_started(
300        &mut self,
301    ) -> Result<&mut StartedPluginAudioProcessor<H>, PluginInstanceError> {
302        match self {
303            Started(s) => Ok(s),
304            _ => self.start_processing(),
305        }
306    }
307
308    /// Stops this audio processor, if it is not already stopped, and returns a mutable reference
309    /// to its [`StoppedPluginAudioProcessor`] state.
310    ///
311    /// If its already stopped, this does nothing and returns the mutable reference directly.
312    ///
313    /// This operation is infallible.
314    #[inline]
315    pub fn ensure_processing_stopped(&mut self) -> &mut StoppedPluginAudioProcessor<H> {
316        let inner = match self {
317            Stopped(s) => return s,
318            Started(a) => a.inner.clone(),
319        };
320
321        let stopped = StartedPluginAudioProcessor::new(inner).stop_processing();
322
323        *self = Stopped(stopped);
324
325        match self {
326            Stopped(s) => s,
327            _ => unreachable!(),
328        }
329    }
330
331    /// Starts this audio processor, if it is not already started, and returns its
332    /// [`StartedPluginAudioProcessor`] state, consuming the [`PluginAudioProcessor`] instance in
333    /// the process.
334    ///
335    /// If it is already started, this does nothing and returns the [`StartedPluginAudioProcessor`] state directly.
336    ///
337    /// # Errors
338    ///
339    /// If this audio processor was in its `stopped` state and the start operation failed, this
340    /// returns a [`ProcessingStartError`], from which the [`StoppedPluginAudioProcessor`] can be
341    /// recovered.
342    #[inline]
343    pub fn into_started(self) -> Result<StartedPluginAudioProcessor<H>, ProcessingStartError<H>> {
344        match self {
345            Started(s) => Ok(s),
346            Stopped(s) => s.start_processing(),
347        }
348    }
349
350    /// Stops this audio processor, if it is not already stopped, and returns its
351    /// [`StoppedPluginAudioProcessor`] state, consuming the [`PluginAudioProcessor`] instance in
352    /// the process.
353    ///
354    /// If it is already stopped, this does nothing and returns the [`StoppedPluginAudioProcessor`] state directly.
355    ///
356    /// This operation is infallible.
357    #[inline]
358    pub fn into_stopped(self) -> StoppedPluginAudioProcessor<H> {
359        match self {
360            Started(s) => s.stop_processing(),
361            Stopped(s) => s,
362        }
363    }
364}
365
366impl<H: HostHandlers> From<StartedPluginAudioProcessor<H>> for PluginAudioProcessor<H> {
367    #[inline]
368    fn from(p: StartedPluginAudioProcessor<H>) -> Self {
369        Started(p)
370    }
371}
372
373impl<H: HostHandlers> From<StoppedPluginAudioProcessor<H>> for PluginAudioProcessor<H> {
374    #[inline]
375    fn from(p: StoppedPluginAudioProcessor<H>) -> Self {
376        Stopped(p)
377    }
378}
379
380/// A handle to a plugin's audio processor that is in the `started` state.
381///
382/// A host can call [`process`] or [`stop_processing`] on a plugin which audio processor is in
383/// this state.
384///
385/// This type is generic over the [`HostHandlers`] type that was used to create the plugin instance.
386/// The [shared] and [audio processor] handlers can be accessed with the
387/// [`access_shared_handler`](Self::access_shared_handler),
388/// [`access_handler`](Self::access_handler) and [`access_handler_mut`](Self::access_handler_mut)
389/// methods.
390///
391/// Note that in order to maintain thread-safety, this type must be either dropped or stopped and
392/// passed to either [`PluginInstance::deactivate`] or [`PluginInstance::deactivate_with`], *before*
393/// the [`PluginInstance`] itself is dropped. If this is not done, the plugin instance will never
394/// be deactivated or destroyed, and will leak all its associated resources.
395///
396/// [`process`]: Self::process
397/// [`stop_processing`]: Self::stop_processing
398/// [shared]: crate::prelude::SharedHandler
399/// [audio processor]: crate::prelude::AudioProcessorHandler
400/// [`destroy`](PluginInstance::deactivate)
401pub struct StartedPluginAudioProcessor<H: HostHandlers> {
402    inner: Arc<PluginInstanceInner<H>>,
403    _no_sync: PhantomData<UnsafeCell<()>>,
404}
405
406impl<H: HostHandlers> StartedPluginAudioProcessor<H> {
407    #[inline]
408    fn new(inner: Arc<PluginInstanceInner<H>>) -> Self {
409        Self {
410            inner,
411            _no_sync: PhantomData,
412        }
413    }
414
415    /// Process a chunk of audio frames and events.
416    ///
417    /// This plugin function requires the following arguments:
418    /// * `audio_inputs`: The [`InputAudioBuffers`] the plugin is going to read audio frames from.
419    ///   Can be [`InputAudioBuffers::empty`] if the plugin takes no audio input at all.
420    /// * `audio_output`: The [`OutputAudioBuffers`] the plugin is going to read audio frames from.
421    ///   Can be [`OutputAudioBuffers::empty`] if the plugin produces no audio output at all.
422    /// * `input_events`: The [`InputEvents`] list the plugin is going to receive events from.
423    ///   Can be [`InputEvents::empty`] if the plugin doesn't need to receive any events.
424    /// * `output_events`: The [`OutputEvents`] buffer the plugin is going to write the events it
425    ///   produces.
426    ///   Can be [`OutputEvents::void`] to ignore any events the plugin produces.
427    ///
428    /// Additionally, the following optional arguments can also be given:
429    ///
430    /// * `steady_time`: A steady sample time counter.
431    ///   This can be used to calculate the sleep duration between two process calls.
432    ///   This value may be specific to this plugin instance and have no relation to what
433    ///   other plugin instances may receive.
434    ///
435    ///   The only requirement is that this value must be increased by at least the frame count
436    ///   of the audio buffers (see [`InputAudioBuffers::min_available_frames_with`]) for the next
437    ///   call to `process`.
438    ///
439    ///   This value can never decrease between two calls to `process`, unless [`reset`]
440    ///   is called, or if it was increased beyond [`u64::MAX`] and it wrapped around.
441    ///
442    ///   This can be set to `None` if not available.
443    ///
444    /// * `transport`: Transport information, as of sample `0`. See the [`TransportEvent`]
445    ///   documentation for more details about the available transport information.
446    ///
447    ///   This can be `None` if no transport is available, i.e. if the host is free-running.
448    ///
449    /// Once processing is complete, the function returns a [`ProcessStatus`] to inform the host
450    /// whether the plugin can be put to sleep or not. See the [`ProcessStatus`] documentation
451    /// for more information.
452    ///
453    /// # Errors
454    ///
455    /// This function can return [`PluginInstanceError::NullProcessFunction`] if the plugin
456    /// implementation did not provide a valid underlying `process` function pointer.
457    ///
458    /// This can also return [`PluginInstanceError::ProcessingFailed`] if the `process` function
459    /// failed for any reason.
460    ///
461    /// [`reset`]: Self::reset
462    pub fn process(
463        &mut self,
464        audio_inputs: &InputAudioBuffers,
465        audio_outputs: &mut OutputAudioBuffers,
466        input_events: &InputEvents,
467        output_events: &mut OutputEvents,
468        steady_time: Option<u64>,
469        transport: Option<&TransportEvent>,
470    ) -> Result<ProcessStatus, PluginInstanceError> {
471        let frames_count = audio_inputs.min_available_frames_with(audio_outputs);
472
473        let process = clap_process {
474            frames_count,
475
476            in_events: input_events.as_raw(),
477            out_events: output_events.as_raw(),
478
479            audio_inputs: audio_inputs.as_raw_buffers().as_ptr(),
480            audio_outputs: audio_outputs.as_raw_buffers().as_mut_ptr(),
481            audio_inputs_count: audio_inputs.port_count(),
482            audio_outputs_count: audio_outputs.port_count(),
483
484            steady_time: match steady_time {
485                None => -1,
486                // This is a wrapping conversion from u64 to i64.
487                // The wrapping allows smooth operation from the plugin if steady_time does actually overflow an i64.
488                #[allow(clippy::cast_possible_wrap)] // Wrapping is actually wanted here!
489                Some(steady_time) => (steady_time & i64::MAX as u64) as i64,
490            },
491            transport: match transport {
492                None => core::ptr::null(),
493                Some(e) => e.as_raw(),
494            },
495        };
496
497        let instance = self.inner.raw_instance();
498
499        let process_fn = instance
500            .process
501            .ok_or(PluginInstanceError::NullProcessFunction)?;
502
503        // SAFETY: this type ensures the function pointer is valid
504        let status = unsafe { process_fn(instance, &process) };
505
506        match ProcessStatus::from_raw(status) {
507            None | Some(Err(())) => Err(PluginInstanceError::ProcessingFailed),
508            Some(Ok(status)) => Ok(status),
509        }
510    }
511
512    /// Resets the plugin's audio processing state.
513    ///
514    /// This clears all the plugin's internal buffers, kills all voices, and resets all processing
515    /// state such as envelopes, LFOs, oscillators, filters, etc.
516    ///
517    /// Calling this method allows the `steady_time` parameter passed to [`process`](Self::process)
518    /// to jump backwards.
519    #[inline]
520    pub fn reset(&mut self) {
521        // SAFETY: This type ensures this can only be called on the audio thread.
522        unsafe { self.inner.reset() }
523    }
524
525    /// Sends the plugin to sleep, implying the next [`process`](Self::process) call will not be
526    /// continuous with the last one.
527    ///
528    /// This method returns an audio processor in the [stopped](StoppedPluginAudioProcessor) state.
529    ///
530    /// This operation is infallible.
531    #[inline]
532    pub fn stop_processing(self) -> StoppedPluginAudioProcessor<H> {
533        let inner = self.inner;
534        // SAFETY: this is called on the audio thread
535        unsafe { inner.stop_processing() };
536
537        StoppedPluginAudioProcessor {
538            inner,
539            _no_sync: PhantomData,
540        }
541    }
542
543    /// Accesses the [`SharedHandler`] for this instance, using the provided closure.
544    ///
545    /// This function returns the return value of the provided closure directly.
546    ///
547    /// Note that the lifetime of the [`SharedHandler`] cannot be statically known, as it is bound
548    /// to the plugin instance itself.
549    ///
550    /// Unlike [`access_handler`](self.access_handler) and
551    /// [`access_handler_mut`](self.access_handler_mut), there is no way to obtain a mutable
552    /// reference to the [`SharedHandler`], as it may be concurrently accessed by other threads.
553    ///
554    /// [`SharedHandler`]: crate::prelude::SharedHandler
555    #[inline]
556    pub fn access_shared_handler<'s, R>(
557        &'s self,
558        access: impl for<'a> FnOnce(&'s <H as HostHandlers>::Shared<'a>) -> R,
559    ) -> R {
560        access(self.inner.wrapper().shared())
561    }
562
563    /// Accesses the [`AudioProcessorHandler`] for this instance, using the provided closure.
564    ///
565    /// This function returns the return value of the provided closure directly.
566    ///
567    /// Note that the lifetime of the [`AudioProcessorHandler`] cannot be statically known, as it is bound
568    /// to the plugin instance itself.
569    ///
570    /// See the [`access_handler_mut`](self.access_handler_mut) method to receive a mutable
571    /// reference to the [`AudioProcessorHandler`] instead.
572    ///
573    /// [`AudioProcessorHandler`]: crate::prelude::AudioProcessorHandler
574    #[inline]
575    pub fn access_handler<'s, R>(
576        &'s self,
577        access: impl for<'a> FnOnce(&'s <H as HostHandlers>::AudioProcessor<'a>) -> R,
578    ) -> R {
579        // SAFETY: we take &mut self, the only reference to the wrapper on the audio thread,
580        // therefore we can guarantee there are other references anywhere
581        // PANIC: This struct exists, therefore we are guaranteed the plugin is active
582        unsafe { access(self.inner.wrapper().audio_processor().unwrap().as_ref()) }
583    }
584
585    /// Accesses the [`AudioProcessorHandler`] for this instance, using the provided closure.
586    ///
587    /// This function returns the return value of the provided closure directly.
588    ///
589    /// Note that the lifetime of the [`AudioProcessorHandler`] cannot be statically known, as it is bound
590    /// to the plugin instance itself.
591    ///
592    /// See the [`access_handler`](self.access_handler) method to receive a shared
593    /// reference to the [`AudioProcessorHandler`] instead.
594    ///
595    /// [`AudioProcessorHandler`]: crate::prelude::AudioProcessorHandler
596    #[inline]
597    pub fn access_handler_mut<'s, R>(
598        &'s mut self,
599        access: impl for<'a> FnOnce(&'s mut <H as HostHandlers>::AudioProcessor<'a>) -> R,
600    ) -> R {
601        // SAFETY: we take &self, the only reference to the wrapper on the audio thread, therefore
602        // we can guarantee there are no mutable references anywhere
603        // PANIC: This struct exists, therefore we are guaranteed the plugin is active
604        unsafe { access(self.inner.wrapper().audio_processor().unwrap().as_mut()) }
605    }
606    /// Returns this plugin instance's audio processor handle.
607    #[inline]
608    pub fn plugin_handle(&mut self) -> PluginAudioProcessorHandle<'_> {
609        PluginAudioProcessorHandle::new(self.inner.raw_instance().into())
610    }
611
612    /// Returns this plugin instance's shared handle.
613    #[inline]
614    pub fn shared_plugin_handle(&self) -> PluginSharedHandle<'_> {
615        self.inner.plugin_shared()
616    }
617
618    /// Returns `true` if this audio processor was created from the given plugin instance.
619    #[inline]
620    pub fn matches(&self, instance: &PluginInstance<H>) -> bool {
621        Arc::ptr_eq(&self.inner, &instance.inner)
622    }
623}
624
625/// A handle to a plugin's audio processor that is in the `stopped` state.
626///
627/// This is the default state the plugin's audio processor will be in after calling [`activate`].
628///
629/// A host needs to call [`start_processing`] before it can call the [`process`] method to process
630/// audio and events.
631///
632/// This type is generic over the [`HostHandlers`] type that was used to create the plugin instance.
633/// The [shared] and [audio processor] handlers can be accessed with the
634/// [`access_shared_handler`](Self::access_shared_handler),
635/// [`access_handler`](Self::access_handler) and [`access_handler_mut`](Self::access_handler_mut)
636/// methods.
637///
638/// Note that in order to maintain thread-safety, this type must be either dropped or stopped and
639/// passed to either [`PluginInstance::deactivate`] or [`PluginInstance::deactivate_with`], *before*
640/// the [`PluginInstance`] itself is dropped. If this is not done, the plugin instance will never
641/// be deactivated or destroyed, and will leak all its associated resources.
642///
643/// [`activate`]: PluginInstance::activate
644/// [`process`]: StartedPluginAudioProcessor::process
645/// [`start_processing`]: Self::start_processing
646/// [shared]: crate::prelude::SharedHandler
647/// [audio processor]: crate::prelude::AudioProcessorHandler
648pub struct StoppedPluginAudioProcessor<H: HostHandlers> {
649    pub(crate) inner: Arc<PluginInstanceInner<H>>,
650    _no_sync: PhantomData<UnsafeCell<()>>,
651}
652
653impl<H: HostHandlers> StoppedPluginAudioProcessor<H> {
654    #[inline]
655    pub(crate) fn new(inner: Arc<PluginInstanceInner<H>>) -> Self {
656        Self {
657            inner,
658            _no_sync: PhantomData,
659        }
660    }
661
662    /// Resets the plugin's audio processing state.
663    ///
664    /// This clears all the plugin's internal buffers, kills all voices, and resets all processing
665    /// state such as envelopes, LFOs, oscillators, filters, etc.
666    ///
667    /// Calling this method allows the `steady_time` parameter passed to [`process`](StartedPluginAudioProcessor::process)
668    /// to jump backwards.
669    #[inline]
670    pub fn reset(&mut self) {
671        // SAFETY: This type ensures this can only be called on the audio thread.
672        unsafe { self.inner.reset() }
673    }
674
675    /// Indicates to the plugin that continuous processing is about to start.
676    ///
677    /// Calling this is required in order to be able to call the [`process`] method to process
678    /// audio and events.
679    ///
680    /// If this succeeds, this returns an audio processor in the [started](StartedPluginAudioProcessor)
681    /// state.
682    ///
683    /// # Errors
684    ///
685    /// This method can fail if the underlying plugin's implementation fails for any reason.
686    /// In this case, a [`ProcessingStartError`] is returned, from which the stopped audio processor
687    /// can be recovered.
688    ///
689    /// [`process`]: StartedPluginAudioProcessor::process
690    #[inline]
691    pub fn start_processing(
692        self,
693    ) -> Result<StartedPluginAudioProcessor<H>, ProcessingStartError<H>> {
694        // SAFETY: this is called on the audio thread
695        match unsafe { self.inner.start_processing() } {
696            Ok(()) => Ok(StartedPluginAudioProcessor {
697                inner: self.inner,
698                _no_sync: PhantomData,
699            }),
700            Err(_) => Err(ProcessingStartError { processor: self }),
701        }
702    }
703
704    /// Accesses the [`SharedHandler`] for this instance, using the provided closure.
705    ///
706    /// This function returns the return value of the provided closure directly.
707    ///
708    /// Note that the lifetime of the [`SharedHandler`] cannot be statically known, as it is bound
709    /// to the plugin instance itself.
710    ///
711    /// Unlike [`access_handler`](self.access_handler) and
712    /// [`access_handler_mut`](self.access_handler_mut), there is no way to obtain a mutable
713    /// reference to the [`SharedHandler`], as it may be concurrently accessed by other threads.
714    ///
715    /// [`SharedHandler`]: crate::prelude::SharedHandler
716    #[inline]
717    pub fn access_shared_handler<'s, R>(
718        &'s self,
719        access: impl for<'a> FnOnce(&'s <H as HostHandlers>::Shared<'a>) -> R,
720    ) -> R {
721        access(self.inner.wrapper().shared())
722    }
723
724    /// Accesses the [`AudioProcessorHandler`] for this instance, using the provided closure.
725    ///
726    /// This function returns the return value of the provided closure directly.
727    ///
728    /// Note that the lifetime of the [`AudioProcessorHandler`] cannot be statically known, as it is bound
729    /// to the plugin instance itself.
730    ///
731    /// See the [`access_handler_mut`](self.access_handler_mut) method to receive a mutable
732    /// reference to the [`AudioProcessorHandler`] instead.
733    ///
734    /// [`AudioProcessorHandler`]: crate::prelude::AudioProcessorHandler
735    #[inline]
736    pub fn access_handler<'s, R>(
737        &'s self,
738        access: impl for<'a> FnOnce(&'s <H as HostHandlers>::AudioProcessor<'a>) -> R,
739    ) -> R {
740        // SAFETY: we take &mut self, the only reference to the wrapper on the audio thread,
741        // therefore we can guarantee there are other references anywhere
742        // PANIC: This struct exists, therefore we are guaranteed the plugin is active
743        unsafe { access(self.inner.wrapper().audio_processor().unwrap().as_ref()) }
744    }
745
746    /// Accesses the [`AudioProcessorHandler`] for this instance, using the provided closure.
747    ///
748    /// This function returns the return value of the provided closure directly.
749    ///
750    /// Note that the lifetime of the [`AudioProcessorHandler`] cannot be statically known, as it is bound
751    /// to the plugin instance itself.
752    ///
753    /// See the [`access_handler`](self.access_handler) method to receive a shared
754    /// reference to the [`AudioProcessorHandler`] instead.
755    ///
756    /// [`AudioProcessorHandler`]: crate::prelude::AudioProcessorHandler
757    #[inline]
758    pub fn access_handler_mut<'s, R>(
759        &'s mut self,
760        access: impl for<'a> FnOnce(&'s mut <H as HostHandlers>::AudioProcessor<'a>) -> R,
761    ) -> R {
762        // SAFETY: we take &self, the only reference to the wrapper on the audio thread, therefore
763        // we can guarantee there are no mutable references anywhere
764        // PANIC: This struct exists, therefore we are guaranteed the plugin is active
765        unsafe { access(self.inner.wrapper().audio_processor().unwrap().as_mut()) }
766    }
767
768    /// Returns this plugin instance's audio processor handle.
769    #[inline]
770    pub fn plugin_handle(&mut self) -> PluginAudioProcessorHandle<'_> {
771        PluginAudioProcessorHandle::new(self.inner.raw_instance().into())
772    }
773
774    /// Returns this plugin instance's shared handle.
775    #[inline]
776    pub fn shared_plugin_handle(&self) -> PluginSharedHandle<'_> {
777        self.inner.plugin_shared()
778    }
779
780    /// Returns `true` if this audio processor was created from the given plugin instance.
781    #[inline]
782    pub fn matches(&self, instance: &PluginInstance<H>) -> bool {
783        Arc::ptr_eq(&self.inner, &instance.inner)
784    }
785}
786
787/// An error that occurred when a plugin instance couldn't start processing.
788///
789/// The [`StoppedPluginAudioProcessor`] can be recovered using the
790/// [`into_stopped_processor`](Self::into_stopped_processor) method.
791pub struct ProcessingStartError<H: HostHandlers> {
792    processor: StoppedPluginAudioProcessor<H>,
793}
794
795impl<H: HostHandlers> ProcessingStartError<H> {
796    /// Recovers the plugin instance's [`StoppedPluginAudioProcessor`] that failed to start.
797    #[inline]
798    pub fn into_stopped_processor(self) -> StoppedPluginAudioProcessor<H> {
799        self.processor
800    }
801}
802
803impl<H: HostHandlers> Debug for ProcessingStartError<H> {
804    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
805        f.write_str("Failed to start plugin processing")
806    }
807}
808
809impl<H: HostHandlers> Display for ProcessingStartError<H> {
810    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
811        f.write_str("Failed to start plugin processing")
812    }
813}
814
815impl<H: HostHandlers> Error for ProcessingStartError<H> {}
816
817#[cfg(test)]
818mod test {
819    extern crate static_assertions as sa;
820    use super::*;
821
822    sa::assert_not_impl_any!(StartedPluginAudioProcessor<()>: Sync);
823    sa::assert_not_impl_any!(StoppedPluginAudioProcessor<()>: Sync);
824}