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}