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}