1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
//! Core types and traits to implement CLAP host callback handlers.
//!
//! The [`HostHandlers`] trait is the main one required to be implemented for a Clack host. It provides
//! the host's supported extensions and is associated to a main type implementing [`SharedHandler`] ,
//! as well as two more optional types implementing [`MainThreadHandler`] and [`AudioProcessorHandler`] (the
//! unit type `()` can be used as default implementations that do nothing).
//!
//! These three types must implement host interfaces to allow them to respond to various requests
//! from the plugin, following the CLAP thread model described below.
//!
//! # Thread specifications
//!
//! CLAP's thread model for plugins is split into three specifications of operations: those
//! happening in the main thread, those happening in an audio processing thread,
//! and thread-safe operations:
//!
//! * The *main thread* (`[main-thread]` in the CLAP specification): this is represented by a type
//! implementing the [`MainThreadHandler`] trait, which is neither [`Send`] nor [`Sync`], and lives
//! encapsulated in the [`PluginInstance`](crate::plugin::PluginInstance) struct.
//!
//! This type can handle all non-realtime-safe operations, such as those related to buffer
//! allocations or GUI handling, and extensions can extend its use to more kinds of operations.
//!
//! This type is intended to stay on the thread it was created in (i.e. the "main" thread):
//! implementations cannot [`Send`] this type to any other threads.
//!
//! * The *audio thread* (`[audio-thread]` in the CLAP specification): this is represented by a type
//! implementing the [`AudioProcessorHandler`] trait, which is [`Send`] but
//! [`!Sync`](Sync), and lives encapsulated in the
//! [`PluginAudioProcessor`](crate::process::PluginAudioProcessor) struct. It is only
//! instantiated when the [`activate`](crate::plugin::PluginInstance::activate) method is called,
//! and is dropped on [`deactivate`](crate::plugin::PluginInstance::deactivate). If it isn't
//! needed , `()` can be used instead.
//!
//! This type is designed to handle all DSP-related requests from the plugin and lives in one of
//! the host's audio threads, of which there may be multiple, if the host uses a thread pool for
//! example.
//!
//! The host is free to [`Send`] the [`AudioProcessorHandler`] type between any of its audio threads,
//! but any operation of this class is guaranteed to be called by only a single thread
//! simultaneously ([`!Sync`](Sync)).
//!
//! One exception is for CLAP plugins' activation and deactivation (represented in Clack by the
//! plugin type's construction and destruction), which is guaranteed to happen in the Main Thread
//! instead. This allows an [`AudioProcessorHandler`] implementation to receive temporary exclusive
//! references to the [`MainThreadHandler`] type during its construction and destruction, to take
//! and release ownership of extra buffers for instance.
//!
//! * *Thread-safe operations* (`[thread-safe]` in the CLAP specification) are represented by a type
//! implementing the [`SharedHandler`] trait, which is both [`Send`] and [`Sync`], and will be
//! shared between the main thread and the audio thread.
//!
//! It can be used to hold read-only data (such as all the detected plugin extensions), or to
//! hold any other kind of state that is to be synchronized between multiple threads.
//!
//! However, it should be noted that this type *can* be used by the plugin simultaneously from
//! threads that are neither the main thread nor the audio thread.
//!
//! # Example
//!
//! This example implements a basic host which is able to process callback requests from the plugin,
//! along with two extensions: `latency` and `log`.
//!
//! This is done by implementing the [`HostHandlers`] trait and specifying its associated types:
//! [`SharedHandler`], [`MainThreadHandler`], and [`AudioProcessorHandler`].
//!
//! Because our host supports some extensions, we also implement the [`HostHandlers::declare_extensions`]
//! method to declare them to the plugin, which requires us to implement the associated traits on
//! the appropriate [`HostHandlers`] associated types to handle the host-side.
//!
//! For more information about which extension traits needs to be implemented on which time, refer
//! to that extension's documentation.
//!
//! For more information about how to work with extensions, see the
//! [`extensions`](crate::extensions) module documentation.
//!
//! ```
//! use clack_host::events::event_types::*;
//! use clack_host::prelude::*;
//!
//! use clack_extensions::latency::*;
//! use clack_extensions::log::*;
//!
//! use std::sync::atomic::{AtomicBool, Ordering};
//! use std::sync::OnceLock;
//! use std::ffi::CStr;
//!
//! #[derive(Default)]
//! struct MyHostShared {
//! // A real-world implementation may use a fancier notification system.
//! // For this example, we are simply checking a handful of atomics from time to time.
//! restart_requested: AtomicBool,
//! process_requested: AtomicBool,
//! callback_requested: AtomicBool,
//!
//! // Queried extensions
//! // This may be none if the extension isn't supported by the plugin.
//! latency_extension: OnceLock<Option<PluginLatency>>
//! }
//!
//! impl<'a> SharedHandler<'a> for MyHostShared {
//! // Once the plugin is initializing, we can query its extensions
//! fn initializing(&self, instance: InitializingPluginHandle<'a>) {
//! let _ = self.latency_extension.set(instance.get_extension());
//! }
//!
//! fn request_restart(&self) { self.restart_requested.store(true, Ordering::SeqCst) }
//! fn request_process(&self) { self.process_requested.store(true, Ordering::SeqCst) }
//! fn request_callback(&self) { self.callback_requested.store(true, Ordering::SeqCst) }
//! }
//!
//! impl HostLogImpl for MyHostShared {
//! fn log(&self, severity: LogSeverity, message: &str) {
//! // A real-world implementation would make sure this is wait-free.
//! // But for this example, println! is good enough.
//! println!("[{severity}] [Plugin] {message}")
//! }
//! }
//!
//! struct MyHostMainThread<'a> {
//! shared: &'a MyHostShared,
//! instance: Option<InitializedPluginHandle<'a>>,
//!
//! latency_changed: bool
//! }
//!
//! impl<'a> MainThreadHandler<'a> for MyHostMainThread<'a> {
//! fn initialized(&mut self, instance: InitializedPluginHandle<'a>) {
//! self.instance = Some(instance);
//! }
//! }
//!
//! impl<'a> HostLatencyImpl for MyHostMainThread<'a> {
//! fn changed(&mut self) {
//! if let Some(Some(_latency)) = self.shared.latency_extension.get() {
//! self.latency_changed = true
//! }
//! }
//! }
//!
//! struct MyHost;
//! impl HostHandlers for MyHost {
//! type Shared<'a> = MyHostShared;
//!
//! type MainThread<'a> = MyHostMainThread<'a>;
//! type AudioProcessor<'a> = ();
//!
//! fn declare_extensions(builder: &mut HostExtensions<Self>, shared: &Self::Shared<'_>) {
//! builder
//! .register::<HostLog>()
//! .register::<HostLatency>();
//! }
//! }
//!
//! # pub fn main() -> Result<(), Box<dyn std::error::Error>> {
//! // Information about our totally legit host.
//! let host_info = HostInfo::new("Legit Studio", "Legit Ltd.", "https://example.com", "4.3.2")?;
//!
//! # mod diva { include!("entry/diva_stub.rs"); }
//! # let entry = PluginEntry::load_from_clack::<diva::Entry>(c"/home/user/.clap/u-he/libdiva.so")?;
//! # /*
//! let entry = PluginEntry::load("/home/user/.clap/u-he/libdiva.so")?;
//! # */
//!
//! let mut plugin_instance = PluginInstance::<MyHost>::new(
//! |_| MyHostShared::default(),
//! |shared| MyHostMainThread { shared, instance: None, latency_changed: false },
//! &entry,
//! // We're hard-coding a specific plugin to load for this example
//! c"com.u-he.diva",
//! &host_info
//! )?;
//!
//! // Assume we've activated the plugin and just done some processing.
//! /* ... */
//!
//! // Let's check if the plugin requested a callback, by accessing our shared host data.
//! let callback_requested: &AtomicBool = plugin_instance.access_shared_handler(|h| &h.callback_requested);
//!
//! // This fetches the previous value and sets it to false in a single atomic operation.
//! if callback_requested.fetch_and(false, Ordering::SeqCst) {
//! plugin_instance.call_on_main_thread_callback();
//! }
//!
//! // Do the same for the restart and process requests
//! /* ... */
//!
//! # Ok(()) }
//! ```
pub use HostError;
pub use HostExtensions;
pub use HostInfo;
use crate;
/// Host data and callbacks that are tied to `[main-thread]` operations.
///
/// This trait requires neither [`Send`] nor [`Sync`], as types implementing it are intended to
/// contain host data staying on the main thread.
///
/// This trait is bound to a lifetime (`'a`) that lives at least as long as the plugin instance
/// does. Since the plugin can call host callbacks during its destructor, this is actually kept alive
/// slightly longer.
///
/// See the [module docs](self) for more information, and for an example implementation.
/// Host data and callbacks that are tied to `[audio-thread]` operations.
///
/// This trait requires [`Send`], as a plugin's audio processor can be sent between multiple
/// threads, but can only be accessed by one thread at a time.
///
/// This trait is bound to the plugin audio processor's lifetime (`'a`).
///
/// This trait doesn't have any inherent methods, and serves only to restrict the lifetime and
/// [`Send`] bounds. However, extensions can add more callbacks to the [`HostHandlers::AudioProcessor`]
/// type.
///
/// See the [module docs](self) for more information, and for an example implementation.
/// Host data and callbacks that are tied to `[thread-safe]` operations.
///
/// This trait requires both [`Send`] *and* [`Sync`], as those callbacks and data can be used from
/// multiple different threads at the same time.
///
/// This trait is bound to a lifetime (`'a`) that lives at least as long as the plugin instance
/// does. Since the plugin can call host callbacks during its destructor, this is actually kept alive
/// slightly longer.
///
/// See the [module docs](self) for more information, and for an example implementation.
/// A set of host callback handlers.
///
/// This type does not hold any data nor is used at runtime. It exists only to tie
/// the [`Shared`](HostHandlers::Shared), [`MainThread`](HostHandlers::MainThread),
/// and [`AudioProcessor`](HostHandlers::AudioProcessor)
/// associated types together with the declared extensions.
///
/// See the [module docs](self) for more information, and for an example implementation.
// QoL implementations