lv2rs_core/plugin.rs
1//! General Plugin-related traits and functions.
2use crate::{Feature, FeaturesList};
3
4use std::ffi::CStr;
5use std::os::raw::*;
6
7/**
8 Plugin Instance Handle.
9*/
10pub type Handle = *mut c_void;
11
12/**
13 Plugin Descriptor.
14
15 This structure provides the core functions necessary to instantiate and use
16 a plugin.
17*/
18#[repr(C)]
19pub struct Descriptor {
20 /**
21 A globally unique, case-sensitive identifier for this plugin.
22
23 This MUST be a valid URI string as defined by RFC 3986. All plugins with
24 the same URI MUST be compatible to some degree, see
25 http://lv2plug.in/ns/lv2core for details.
26 */
27 pub uri: *const c_char,
28
29 /**
30 Instantiate the plugin.
31
32 Note that instance initialisation should generally occur in activate()
33 rather than here. If a host calls instantiate(), it MUST call cleanup()
34 at some point in the future.
35
36 descriptor: Descriptor of the plugin to instantiate.
37
38 sample_rate: Sample rate, in Hz, for the new plugin instance.
39
40 bundle_path: Path to the LV2 bundle which contains this plugin
41 binary. It MUST include the trailing directory separator (e.g. '/') so
42 that simply appending a filename will yield the path to that file in the
43 bundle.
44
45 features: A NULL terminated array of LV2_Feature structs which
46 represent the features the host supports. Plugins may refuse to
47 instantiate if required features are not found here. However, hosts MUST
48 NOT use this as a discovery mechanism: instead, use the RDF data to
49 determine which features are required and do not attempt to instantiate
50 unsupported plugins at all. This parameter MUST NOT be NULL, i.e. a host
51 that supports no features MUST pass a single element array containing
52 NULL.
53
54 return value: A handle for the new plugin instance, or NULL if instantiation
55 has failed.
56 */
57 pub instantiate: unsafe extern "C" fn(
58 descriptor: *const Descriptor,
59 sample_rate: f64,
60 bundle_path: *const c_char,
61 features: *const *const Feature,
62 ) -> Handle,
63
64 /**
65 Connect a port on a plugin instance to a memory location.
66
67 Plugin writers should be aware that the host may elect to use the same
68 buffer for more than one port and even use the same buffer for both
69 input and output (see lv2:inPlaceBroken in lv2.ttl).
70
71 If the plugin has the feature lv2:hardRTCapable then there are various
72 things that the plugin MUST NOT do within the connect_port() function;
73 see lv2core.ttl for details.
74
75 connect_port() MUST be called at least once for each port before run()
76 is called, unless that port is lv2:connectionOptional. The plugin must
77 pay careful attention to the block size passed to run() since the block
78 allocated may only just be large enough to contain the data, and is not
79 guaranteed to remain constant between run() calls.
80
81 connect_port() may be called more than once for a plugin instance to
82 allow the host to change the buffers that the plugin is reading or
83 writing. These calls may be made before or after activate() or
84 deactivate() calls.
85
86 instance: Plugin instance containing the port.
87
88 port: Index of the port to connect. The host MUST NOT try to
89 connect a port index that is not defined in the plugin's RDF data. If
90 it does, the plugin's behaviour is undefined (a crash is likely).
91
92 data_location: Pointer to data of the type defined by the port
93 type in the plugin's RDF data (e.g. an array of float for an
94 lv2:AudioPort). This pointer must be stored by the plugin instance and
95 used to read/write data when run() is called. Data present at the time
96 of the connect_port() call MUST NOT be considered meaningful.
97 */
98 pub connect_port: unsafe extern "C" fn(instance: Handle, port: u32, data_location: *mut c_void),
99
100 /**
101 Initialise a plugin instance and activate it for use.
102
103 This is separated from instantiate() to aid real-time support and so
104 that hosts can reinitialise a plugin instance by calling deactivate()
105 and then activate(). In this case the plugin instance MUST reset all
106 state information dependent on the history of the plugin instance except
107 for any data locations provided by connect_port(). If there is nothing
108 for activate() to do then this field may be NULL.
109
110 When present, hosts MUST call this function once before run() is called
111 for the first time. This call SHOULD be made as close to the run() call
112 as possible and indicates to real-time plugins that they are now live,
113 however plugins MUST NOT rely on a prompt call to run() after
114 activate().
115
116 The host MUST NOT call activate() again until deactivate() has been
117 called first. If a host calls activate(), it MUST call deactivate() at
118 some point in the future. Note that connect_port() may be called before
119 or after activate().
120 */
121 pub activate: unsafe extern "C" fn(instance: Handle),
122
123 /**
124 Run a plugin instance for a block.
125
126 Note that if an activate() function exists then it must be called before
127 run(). If deactivate() is called for a plugin instance then run() may
128 not be called until activate() has been called again.
129
130 If the plugin has the feature lv2:hardRTCapable then there are various
131 things that the plugin MUST NOT do within the run() function (see
132 lv2core.ttl for details).
133
134 As a special case, when `sample_count` is 0, the plugin should update
135 any output ports that represent a single instant in time (e.g. control
136 ports, but not audio ports). This is particularly useful for latent
137 plugins, which should update their latency output port so hosts can
138 pre-roll plugins to compute latency. Plugins MUST NOT crash when
139 `sample_count` is 0.
140
141 instance: Instance to be run.
142
143 sample_count: The block size (in samples) for which the plugin
144 instance must run.
145 */
146 pub run: unsafe extern "C" fn(instance: Handle, n_samples: u32),
147
148 /**
149 Deactivate a plugin instance (counterpart to activate()).
150
151 Hosts MUST deactivate all activated instances after they have been run()
152 for the last time. This call SHOULD be made as close to the last run()
153 call as possible and indicates to real-time plugins that they are no
154 longer live, however plugins MUST NOT rely on prompt deactivation. If
155 there is nothing for deactivate() to do then this field may be NULL
156
157 Deactivation is not similar to pausing since the plugin instance will be
158 reinitialised by activate(). However, deactivate() itself MUST NOT fully
159 reset plugin state. For example, the host may deactivate a plugin, then
160 store its state (using some extension to do so).
161
162 Hosts MUST NOT call deactivate() unless activate() was previously
163 called. Note that connect_port() may be called before or after
164 deactivate().
165 */
166 pub deactivate: unsafe extern "C" fn(instance: Handle),
167
168 /**
169 Clean up a plugin instance (counterpart to instantiate()).
170
171 Once an instance of a plugin has been finished with it must be deleted
172 using this function. The instance handle passed ceases to be valid after
173 this call.
174
175 If activate() was called for a plugin instance then a corresponding call
176 to deactivate() MUST be made before cleanup() is called. Hosts MUST NOT
177 call cleanup() unless instantiate() was previously called.
178 */
179 pub cleanup: unsafe extern "C" fn(instance: Handle),
180
181 /**
182 Return additional plugin data defined by some extenion.
183
184 A typical use of this facility is to return a struct containing function
185 pointers to extend the LV2_Descriptor API.
186
187 The actual type and meaning of the returned object MUST be specified
188 precisely by the extension. This function MUST return NULL for any
189 unsupported URI. If a plugin does not support any extension data, this
190 field may be NULL.
191
192 The host is never responsible for freeing the returned value.
193 */
194 pub extension_data: unsafe extern "C" fn(uri: *const c_char) -> *const c_void,
195}
196
197/// LV2 plugin trait.
198///
199/// This trait helps you implementing plugins, since it requires you to implement all
200/// necessary functions.
201///
202/// Almost every plugin function call from the host will be checked and "safed" before these trait
203/// functions are called. Therefore, all of them are safe.
204pub trait Plugin {
205 /// Create a new instance of the plugin.
206 ///
207 /// Here, you should instantiate the plugin and supply it with general information. You can look
208 /// at the plugin descriptor, the audio frame rate of the current session, the path from which
209 /// the host has loaded the plugin and an slice of references to the features supported by the
210 /// host. If, for one reason or another, you find yourself in a situation where you can't
211 /// create a plugin instance, you can return `None`.
212 fn instantiate(
213 descriptor: &Descriptor,
214 rate: f64,
215 bundle_path: &CStr,
216 features: Option<&FeaturesList>,
217 ) -> Option<Self>
218 where
219 Self: Sized;
220
221 /// Set internal data pointers.
222 ///
223 /// This function will be called by the host when the location of a port has changed and the
224 /// plugin should update it's internal pointers.
225 ///
226 /// When this function is called, the data pointers may not be valid yet and therefore, you
227 /// shouldn't use them.
228 fn connect_port(&mut self, port: u32, data: *mut ());
229
230 /// Activate the plugin.
231 ///
232 /// If your plugin can be turned on or off, you should override this function and set the plugin
233 /// up for active use.
234 ///
235 /// The default implementation does nothing.
236 fn activate(&mut self) {}
237
238 /// Run plugin specific operations.
239 ///
240 /// This is where the action happens! Here, you should execute the actions that make your plugin
241 /// unique.
242 ///
243 /// Pointers, which were previously set by the [`connect_port`](#tyfunction.connect_port)
244 /// function are guaranteed to be valid now. If they aren't, it's the host's fault, not yours.
245 /// Also, sample arrays or atom sequence will have a length of `n_samples` elements. This
246 /// number may change during the life time of the plugin and therefore, you should not store
247 /// it somewhere.
248 fn run(&mut self, n_samples: u32);
249
250 /// Deactivate the plugin.
251 ///
252 /// If your plugin can be turned on or off, you should override this function and destroy the
253 /// plugins active state.
254 ///
255 /// The default implementation does nothing.
256 fn deactivate(&mut self) {}
257
258 /// Return extension specific data to the host.
259 ///
260 /// Some LV2 extensions require special data from a plugin in order to work. This is where you
261 /// provide the data. The passed C string reference is the URI of the extension in question and
262 /// you can return a static reference to some data. If you do not know the passed URI, you
263 /// should return `None`.
264 ///
265 /// The return value must be a static reference since we don't know how long it needs to be
266 /// alive; as stated in the [LV2 header](http://lv2plug.in/doc/html/group__core.html#ae907a7668d6579f099ac08c134b2e634),
267 /// the host is not responsible for freeing the returned value. Therefore, the referenced data
268 /// need to live for the entirety of the program.
269 fn extension_data(_uri: &CStr) -> Option<&'static ExtensionData> {
270 None
271 }
272}
273
274/// Marker trait for extension data.
275///
276/// This trait was introduced in order to make a [`Plugin`](trait.Plugin.html)'s
277/// [`extension_data`](trait.Plugin.html#method.extension_data) function more dynamic.
278/// Apart from that, it has absolutely no meaning.
279pub trait ExtensionData {}
280
281/// Helper function for the `instantiate` plugin call.
282///
283/// This function takes the raw parameters provided by the C API and turns them into safe Rust data
284/// types. Only functions generated by the `lv2_main` should call the function any other should not.
285pub unsafe fn instantiate<P: Plugin>(
286 descriptor: *const Descriptor,
287 rate: f64,
288 bundle_path: *const c_char,
289 features: *const *const Feature,
290) -> Handle {
291 let descriptor = match descriptor.as_ref() {
292 Some(desc) => desc,
293 None => return std::ptr::null_mut(),
294 };
295 let bundle_path = if bundle_path.is_null() {
296 return std::ptr::null_mut();
297 } else {
298 CStr::from_ptr(bundle_path as *const c_char)
299 };
300
301 let features = {
302 if features.is_null() {
303 None
304 } else {
305 let mut length = 0;
306 let mut features_cp = features;
307 loop {
308 match features_cp.as_ref() {
309 Some(feature) => {
310 if feature.is_null() {
311 break;
312 } else {
313 length += 1;
314 features_cp = features_cp.add(1);
315 }
316 }
317 None => return std::ptr::null_mut(),
318 }
319 }
320 Some(std::slice::from_raw_parts(
321 features as *const &'static Feature,
322 length,
323 ))
324 }
325 };
326
327 match P::instantiate(descriptor, rate, bundle_path, features) {
328 Some(instance) => {
329 let instance = Box::new(instance);
330 Box::leak(instance) as *const P as Handle
331 }
332 None => std::ptr::null_mut(),
333 }
334}
335
336/// Helper function for the `connect_port` plugin call.
337///
338/// This function takes the raw parameters provided by the C API and turns them into safe Rust data
339/// types. Only functions generated by the `lv2_main` should call the function any other should not.
340pub unsafe fn connect_port<P: Plugin>(instance: Handle, port: u32, data: *mut c_void) {
341 let instance = (instance as *mut P).as_mut().unwrap();
342 instance.connect_port(port, data as *mut ());
343}
344
345/// Helper function for the `activate` plugin call.
346///
347/// This function takes the raw parameters provided by the C API, turns them into safe Rust data
348/// types, and calls the trait's function. Only functions generated by the `lv2_main` should call
349/// this function, any other must not.
350pub unsafe fn activate<P: Plugin>(instance: Handle) {
351 let instance = (instance as *mut P).as_mut().unwrap();
352 instance.activate();
353}
354
355/// Helper function for the `run` plugin call.
356///
357/// This function takes the raw parameters provided by the C API, turns them into safe Rust data
358/// types, and calls the trait's function. Only functions generated by the `lv2_main` should call
359/// this function, any other must not.
360pub unsafe fn run<P: Plugin>(instance: Handle, n_samples: u32) {
361 let instance = (instance as *mut P).as_mut().unwrap();
362 instance.run(n_samples);
363}
364
365/// Helper function for the `deactivate` plugin call.
366///
367/// This function takes the raw parameters provided by the C API, turns them into safe Rust data
368/// types, and calls the trait's function. Only functions generated by the `lv2_main` should call
369/// this function, any other must not.
370pub unsafe fn deactivate<P: Plugin>(instance: Handle) {
371 let instance = (instance as *mut P).as_mut().unwrap();
372 instance.deactivate();
373}
374
375/// Helper function for the `cleanup` plugin call.
376///
377/// This function takes the raw parameters provided by the C API, turns them into safe Rust data
378/// types, and calls the trait's function. Only functions generated by the `lv2_main` should call
379/// this function, any other must not.
380pub unsafe fn cleanup<P: Plugin>(instance: Handle) {
381 core::ptr::drop_in_place(instance as *mut P);
382}
383
384/// Helper function for the `extension_data` plugin call.
385///
386/// This function takes the raw parameters provided by the C API, turns them into safe Rust data
387/// types, and calls the trait's function. Only functions generated by the `lv2_main` should call
388/// this function, any other must not.
389pub unsafe fn extension_data<P: Plugin>(uri: *const c_char) -> *const c_void {
390 let uri = CStr::from_ptr(uri);
391 let result = P::extension_data(uri);
392 std::mem::forget(uri);
393 match result {
394 Some(ext_data) => ext_data as *const ExtensionData as *const c_void,
395 None => std::ptr::null(),
396 }
397}