clack_plugin/plugin.rs
1//! Core types and traits to implement a Clack plugin.
2//!
3//! The [`PluginAudioProcessor`] trait is the main one required to be implemented for a Clack plugin. It
4//! can also be associated to two more types, implementing [`PluginMainThread`] and [`PluginShared`],
5//! following the CLAP thread model, as described below.
6//!
7//! # Thread model
8//!
9//! CLAP's thread model for plugins is split into three classes of operations: those happening in an
10//! audio processing thread, those happening in the main thread, and thread-safe operations:
11//!
12//! * The *audio thread* (`[audio-thread]` in the CLAP specification): this is represented by a type
13//! implementing the main [`PluginAudioProcessor`] trait (also named the audio processor), which is [`Send`] but
14//! [`!Sync`](Sync), and is the only one required to implement a Clack plugin.
15//!
16//! This type handles all DSP in one of the host's audio threads, of which there may be
17//! multiple, if the host uses a thread pool for example.
18//!
19//! The host is free to [`Send`] the [`PluginAudioProcessor`] type between any of its audio threads, but any
20//! operation of this class is guaranteed to be exclusive (`&mut`) to a single audio thread.
21//!
22//! One exception is for CLAP plugins' activation and deactivation (represented in Clack by the
23//! plugin type's construction and destruction), which is guaranteed to happen in the Main Thread
24//! instead. This allows the plugin's [`activate`](PluginAudioProcessor::activate) and
25//! [`deactivate`](PluginAudioProcessor::deactivate) methods to receive temporary exclusive references to the
26//! main thread type during its construction and destruction.
27//!
28//! * The *main thread* (`[main-thread]` in the CLAP specification): this is represented by a type
29//! implementing the [`PluginMainThread`] trait, which is neither [`Send`] nor [`Sync`]. If
30//! main-thread operations are not needed by a plugin implementation, `()` can be used instead.
31//!
32//! This type can handle all non-thread-safe operations, such as those related to GUI handling,
33//! however extensions can extend its use to more kinds of operations.
34//!
35//! The host cannot [`Send`] this type to any other threads, and this type has to be constructed
36//! before any other operation is done on the plugin.
37//!
38//! * *Thread-safe operations* (`[thread-safe]` in the CLAP specification) are represented by a type
39//! implementing the [`PluginShared`] trait, which is both [`Send`] and [`Sync`], and will be
40//! shared between the main thread and the audio thread. If it isn't needed , `()` can be used
41//! instead.
42//!
43//! It can be used to hold read-only data (such as all the detected host extensions), or to
44//! hold any other kind of synchronized state.
45//!
46//! However, it should be noted that this type *can* be used by the host simultaneously from
47//! threads that are neither the main thread nor the audio thread.
48
49use crate::extensions::PluginExtensions;
50use crate::host::HostAudioProcessorHandle;
51use crate::process::{Audio, Events, PluginAudioConfiguration, Process, ProcessStatus};
52
53mod error;
54mod instance;
55pub(crate) mod logging;
56
57pub use error::PluginError;
58pub use instance::*;
59
60pub use clack_common::plugin::*;
61
62/// The part of the data and operations of a plugin that are thread-safe.
63///
64/// The associated lifetime `'a` represents the lifetime of the plugin itself, as well as the
65/// lifetime of the data exposed by the host.
66///
67/// This type requires to be both [`Send`] and [`Sync`]: it can be used simultaneously by multiple
68/// threads, including (but not limited to) the main thread and the audio thread.
69///
70/// See the [module documentation](crate::plugin) for more information on the thread model.
71pub trait PluginShared<'a>: Sized + Send + Sync + 'a {}
72
73impl PluginShared<'_> for () {}
74
75/// The part of the data and operation of a plugin that must be on the main thread.
76///
77/// The associated lifetime `'a` represents the lifetime of the plugin itself, as well as the
78/// lifetime of the data exposed by the host.
79///
80/// This type requires neither [`Send`] nor [`Sync`]: it is guaranteed to stay on the main thread
81/// at all times.
82///
83/// See the [module documentation](crate::plugin) for more information on the thread model.
84pub trait PluginMainThread<'a, S: PluginShared<'a>>: Sized + 'a {
85 /// This is called by the host on the main thread, in response to a previous call to
86 /// [`HostSharedHandle::request_callback`](crate::host::HostSharedHandle::request_callback).
87 ///
88 /// The default implementation of this method does nothing.
89 #[inline]
90 fn on_main_thread(&self) {}
91}
92
93impl<'a, S: PluginShared<'a>> PluginMainThread<'a, S> for () {}
94
95/// The main trait required to implement a CLAP plugin.
96///
97/// Types implementing this trait are never instantiated and are not meant to contain any data.
98///
99/// Their purpose is to tie together the various subtypes that will be instantiated and live across
100/// different threads.
101///
102/// # Plugin instantiation
103///
104/// Plugin instantiation and initialization is not covered by this trait. The [`Shared`] and
105/// [`MainThread`] components are created from a [`PluginFactory`] implementation
106/// (in [`PluginFactory::create_plugin`]) using the [`PluginInstance::new`] method.
107///
108/// Alternatively, if custom [`PluginFactory`] and [`Entry`] implementations are not needed, one
109/// can use a [`SinglePluginEntry`] and implement its companion trait [`DefaultPluginFactory`]
110/// to implement the instantiation instead.
111///
112/// [`Shared`]: Self::Shared
113/// [`MainThread`]: Self::MainThread
114/// [`PluginFactory`]: crate::factory::plugin::PluginFactoryImpl
115/// [`PluginFactory::create_plugin`]: crate::factory::plugin::PluginFactoryImpl::create_plugin
116/// [`Entry`]: crate::entry::Entry
117/// [`SinglePluginEntry`]: crate::entry::SinglePluginEntry
118/// [`DefaultPluginFactory`]: crate::entry::DefaultPluginFactory
119pub trait Plugin: 'static {
120 /// The type holding the plugin's data and operations that belong to the audio thread.
121 ///
122 /// See the [module documentation](crate::plugin) for more information on the thread model.
123 type AudioProcessor<'a>: PluginAudioProcessor<'a, Self::Shared<'a>, Self::MainThread<'a>>;
124
125 /// The type holding the plugin's thread-safe data and operations.
126 ///
127 /// If not needed, the empty `()` type can be used instead.
128 ///
129 /// See the [module documentation](crate::plugin) for more information on the thread model.
130 type Shared<'a>: PluginShared<'a>;
131
132 /// The type holding the plugin's data and operations that belong to the main thread.
133 ///
134 /// If not needed, the empty `()` type can be used instead.
135 ///
136 /// See the [module documentation](crate::plugin) for more information on the thread model.
137 type MainThread<'a>: PluginMainThread<'a, Self::Shared<'a>>;
138
139 /// Declares the extensions this plugin supports.
140 ///
141 /// This is implemented by calling [`register`] on the given [`PluginExtensions`]
142 /// builder for every extension type that is supported.
143 ///
144 /// A reference to the [`Shared`](Self::Shared) type is also given. However, it can be `None`,
145 /// as the host is allowed to query extensions before the plugin has finished initializing.
146 ///
147 /// [`register`]: PluginExtensions::register
148 #[inline]
149 #[allow(unused_variables)]
150 fn declare_extensions(builder: &mut PluginExtensions<Self>, shared: Option<&Self::Shared<'_>>) {
151 }
152}
153
154/// The audio processor and main part of a plugin.
155///
156/// This type implements all DSP-related operations, most notably [`process`](PluginAudioProcessor::process),
157/// which processes all input and output audio and events.
158///
159/// The associated lifetime `'a` represents the lifetime of the plugin itself, as well as the
160/// lifetime of the data exposed by the host.
161///
162/// This type requires to be [`Send`] but not [`Sync`]: it can be sent between any of the host's
163/// threads, but none of its operations will be performed on multiple threads simultaneously.
164///
165/// The audio processor can also define two associated types, [`Shared`](Plugin::Shared) and
166/// [`MainThread`](Plugin::MainThread), allowing to execute operations in and hold data belonging
167/// to other threads. If they are not needed, the empty `()` type can be used instead, for convenience.
168///
169/// See the [module documentation](crate::plugin) for more information on the thread model.
170pub trait PluginAudioProcessor<'a, S: PluginShared<'a>, M: PluginMainThread<'a, S>>:
171 Sized + Send + 'a
172{
173 /// Creates and activates the audio processor.
174 ///
175 /// This method serves as a constructor for the audio processor, in which it can perform
176 /// non-realtime-safe initialization operations, such as allocating audio buffers using the
177 /// provided [`PluginAudioConfiguration`].
178 ///
179 /// This method is always executed on the main thread, allowing it to temporarily access main
180 /// thread data.
181 ///
182 /// # Arguments
183 ///
184 /// * `host`: an exclusive host handle that can be stored for the lifetime of the plugin.
185 /// * `main_thread`: a temporary exclusive reference to the plugin's main thread data.
186 /// * `shared`: a reference to the plugin's shared data, that can be stored for the lifetime of the plugin.
187 /// * `audio_config`: the [`PluginAudioConfiguration`], valid throughout the audio processor's lifetime.
188 ///
189 /// # Errors
190 ///
191 /// This operation may fail for any reason, in which case `Err` is returned
192 /// and the plugin is not activated.
193 ///
194 /// # Realtime Safety
195 ///
196 /// This method is not realtime-safe: it may perform memory allocations of audio buffers, or any
197 /// other initialization the plugin may deem necessary.
198 fn activate(
199 host: HostAudioProcessorHandle<'a>,
200 main_thread: &M,
201 shared: &'a S,
202 audio_config: PluginAudioConfiguration,
203 ) -> Result<Self, PluginError>;
204
205 /// Processes a chunk of audio samples and events.
206 ///
207 /// This method returns a [`ProcessStatus`] as a hint towards whether the host can set this
208 /// plugin to sleep, or if the plugin wants to process more audio or events.
209 /// This is only a hint however, and the host is free to ignore it.
210 ///
211 /// # Arguments
212 ///
213 /// * `process` contains metadata about the current process call, including transport information and a steady sample counter.
214 /// * `audio` contains references to all the audio buffers for this block.
215 /// * `events` contains both the [`InputEvents`](crate::prelude::InputEvents) list and the [`OutputEvents`](crate::prelude::OutputEvents) queue.
216 ///
217 /// # Realtime Safety
218 ///
219 /// This method *MUST* be realtime-safe, and is in fact the most performance-sensitive part
220 /// of the whole plugin implementation.
221 ///
222 /// # Errors
223 ///
224 /// This method may fail for any reason, depending on the plugin's implementation.
225 fn process(
226 &mut self,
227 process: Process,
228 audio: Audio,
229 events: Events,
230 ) -> Result<ProcessStatus, PluginError>;
231
232 /// Deactivates the audio processor.
233 ///
234 /// This method can serve as a destructor for the audio processor.
235 ///
236 /// This method is always executed on the main thread, allowing it to temporarily access main
237 /// thread data.
238 ///
239 /// # Arguments
240 ///
241 /// * `main_thread`: a temporary exclusive reference to the plugin's main thread data.
242 ///
243 /// # Realtime Safety
244 ///
245 /// This method is not realtime-safe: it may perform memory de-allocations of audio buffers, or
246 /// any other un-initialization the plugin may deem necessary.
247 #[allow(unused)]
248 #[inline]
249 fn deactivate(self, main_thread: &M) {}
250
251 /// Resets the plugin's audio processing state.
252 ///
253 /// This clears all the plugin's internal buffers, kills all voices, and resets all processing
254 /// state such as envelopes, LFOs, oscillators, filters, etc.
255 ///
256 /// Calling this method allows the `steady_time` parameter passed to [`process`](Self::process)
257 /// to jump backwards.
258 #[allow(unused)]
259 #[inline]
260 fn reset(&mut self) {}
261
262 /// Starts the plugin's continuous audio processing.
263 ///
264 /// This is called when the plugin needs to wake up from sleep, or after it was [activated](Self::activate).
265 ///
266 /// # Errors
267 ///
268 /// This method may fail for any reason, depending on the plugin's implementation.
269 #[inline]
270 fn start_processing(&mut self) -> Result<(), PluginError> {
271 Ok(())
272 }
273
274 /// Stops the plugin's continuous audio processing, indicating it is being sent to sleep.
275 ///
276 /// When this is called, the plugin's audio processor cannot assume that the next block of audio
277 /// and events it receives (if any) is contiguous to the last one it [processed](Self::process).
278 #[inline]
279 fn stop_processing(&mut self) {}
280}
281
282impl<'a, M: PluginMainThread<'a, S>, S: PluginShared<'a>> PluginAudioProcessor<'a, S, M> for () {
283 #[inline]
284 fn activate(
285 _host: HostAudioProcessorHandle<'a>,
286 _main_thread: &M,
287 _shared: &'a S,
288 _audio_config: PluginAudioConfiguration,
289 ) -> Result<Self, PluginError> {
290 Ok(())
291 }
292
293 #[inline]
294 fn process(
295 &mut self,
296 _process: Process,
297 _audio: Audio,
298 _events: Events,
299 ) -> Result<ProcessStatus, PluginError> {
300 Ok(ProcessStatus::Sleep)
301 }
302}