lv2_core/port.rs
1//! Types to declare derivable port collections.
2//!
3//! Every plugin has a type of [`PortCollection`](trait.PortCollection.html) which is used to handle input/output ports. In order to make the creation of these port collection types easier, `PortCollection` can simply be derived. However, the macro that implements `PortCollection` requires the fields of the struct to have specific types. These types are provided in this module.
4use std::ffi::c_void;
5use std::ops::{Deref, DerefMut};
6use std::ptr::NonNull;
7use urid::UriBound;
8
9pub use lv2_core_derive::*;
10
11/// Generalization of port types.
12///
13/// A port can read input or create a pointer to the output, but the exact type of input/output (pointer) depends on the type of port. This trait generalizes these types and behaviour.
14pub trait PortType {
15 /// The type of input read by the port.
16 type InputPortType: Sized;
17 /// The type of output reference created by the port.
18 type OutputPortType: Sized;
19
20 /// Read data from the pointer or create a reference to the input.
21 ///
22 /// If the resulting data is a slice, `sample_count` is the length of the slice.
23 ///
24 /// # Safety
25 ///
26 /// This method is unsafe because one needs to de-reference a raw pointer to implement this method.
27 unsafe fn input_from_raw(pointer: NonNull<c_void>, sample_count: u32) -> Self::InputPortType;
28
29 /// Create a reference to the data where output should be written to.
30 ///
31 /// If the data is a slice, `sample_count` is the length of the slice.
32 ///
33 /// # Safety
34 ///
35 /// This method is unsafe because one needs to de-reference a raw pointer to implement this method.
36 unsafe fn output_from_raw(pointer: NonNull<c_void>, sample_count: u32) -> Self::OutputPortType;
37}
38
39/// Audio port type.
40///
41/// Audio ports are the most common type of input/output ports: Their input is a slice of audio samples, as well as their output.
42pub struct Audio;
43
44unsafe impl UriBound for Audio {
45 const URI: &'static [u8] = ::lv2_sys::LV2_CORE__AudioPort;
46}
47
48impl PortType for Audio {
49 type InputPortType = &'static [f32];
50 type OutputPortType = &'static mut [f32];
51
52 #[inline]
53 unsafe fn input_from_raw(pointer: NonNull<c_void>, sample_count: u32) -> Self::InputPortType {
54 std::slice::from_raw_parts(pointer.as_ptr() as *const f32, sample_count as usize)
55 }
56
57 #[inline]
58 unsafe fn output_from_raw(pointer: NonNull<c_void>, sample_count: u32) -> Self::OutputPortType {
59 std::slice::from_raw_parts_mut(pointer.as_ptr() as *mut f32, sample_count as usize)
60 }
61}
62
63/// Control value port type.
64///
65/// Control ports in general are used to control the behaviour of the plugin. These control value ports only have one value per `run` call and therefore don't have a fixed sampling rate.
66///
67/// Therefore, their input is a floating-point number and their output is a mutable reference to a floating-point number.
68pub struct Control;
69
70unsafe impl UriBound for Control {
71 const URI: &'static [u8] = ::lv2_sys::LV2_CORE__ControlPort;
72}
73
74impl PortType for Control {
75 type InputPortType = f32;
76 type OutputPortType = &'static mut f32;
77
78 #[inline]
79 unsafe fn input_from_raw(pointer: NonNull<c_void>, _sample_count: u32) -> f32 {
80 *(pointer.cast().as_ref())
81 }
82
83 unsafe fn output_from_raw(pointer: NonNull<c_void>, _sample_count: u32) -> &'static mut f32 {
84 (pointer.as_ptr() as *mut f32).as_mut().unwrap()
85 }
86}
87
88/// CV port type.
89///
90/// Control ports in general are used to control the behaviour of the plugin. CV ports are sampled just like [audio data](struct.Audio.html). This means that audio data is often valid CV data, but CV data generally is not audio data, because it may not be within the audio bounds of -1.0 to 1.0.
91pub struct CV;
92
93unsafe impl UriBound for CV {
94 const URI: &'static [u8] = ::lv2_sys::LV2_CORE__CVPort;
95}
96
97impl PortType for CV {
98 type InputPortType = &'static [f32];
99 type OutputPortType = &'static mut [f32];
100
101 #[inline]
102 unsafe fn input_from_raw(pointer: NonNull<c_void>, sample_count: u32) -> Self::InputPortType {
103 std::slice::from_raw_parts(pointer.as_ptr() as *const f32, sample_count as usize)
104 }
105
106 #[inline]
107 unsafe fn output_from_raw(pointer: NonNull<c_void>, sample_count: u32) -> Self::OutputPortType {
108 std::slice::from_raw_parts_mut(pointer.as_ptr() as *mut f32, sample_count as usize)
109 }
110}
111
112/// Abstraction of safe port handles.
113pub trait PortHandle: Sized {
114 /// Try to create a port handle from a port connection pointer and the sample count.
115 ///
116 /// If the pointer is null, this method will return `None`.
117 ///
118 /// # Safety
119 ///
120 /// Implementing this method requires a de-referentation of a raw pointer and therefore, it is unsafe.
121 unsafe fn from_raw(pointer: *mut c_void, sample_count: u32) -> Option<Self>;
122}
123
124/// Handle for input ports.
125///
126/// Fields of this type can be dereferenced to the input type of the port type.
127pub struct InputPort<T: PortType> {
128 port: T::InputPortType,
129}
130
131impl<T: PortType> Deref for InputPort<T> {
132 type Target = T::InputPortType;
133
134 #[inline]
135 fn deref(&self) -> &Self::Target {
136 &self.port
137 }
138}
139
140impl<T: PortType> PortHandle for InputPort<T> {
141 #[inline]
142 unsafe fn from_raw(pointer: *mut c_void, sample_count: u32) -> Option<Self> {
143 if let Some(pointer) = NonNull::new(pointer) {
144 Some(Self {
145 port: T::input_from_raw(pointer, sample_count),
146 })
147 } else {
148 None
149 }
150 }
151}
152
153/// Handle for output ports.
154///
155/// Fields of this type can be dereferenced to the output type of the port type.
156pub struct OutputPort<T: PortType> {
157 port: T::OutputPortType,
158}
159
160impl<T: PortType> Deref for OutputPort<T> {
161 type Target = T::OutputPortType;
162
163 #[inline]
164 fn deref(&self) -> &Self::Target {
165 &self.port
166 }
167}
168
169impl<T: PortType> DerefMut for OutputPort<T> {
170 #[inline]
171 fn deref_mut(&mut self) -> &mut Self::Target {
172 &mut self.port
173 }
174}
175
176impl<T: PortType> PortHandle for OutputPort<T> {
177 #[inline]
178 unsafe fn from_raw(pointer: *mut c_void, sample_count: u32) -> Option<Self> {
179 if let Some(pointer) = NonNull::new(pointer) {
180 Some(Self {
181 port: T::output_from_raw(pointer, sample_count),
182 })
183 } else {
184 None
185 }
186 }
187}
188
189impl<T: PortHandle> PortHandle for Option<T> {
190 unsafe fn from_raw(pointer: *mut c_void, sample_count: u32) -> Option<Self> {
191 Some(T::from_raw(pointer, sample_count))
192 }
193}
194
195/// Collection of IO ports.
196///
197/// Plugins do not handle port management on their own. Instead, they define a struct with all of the required ports. Then, the plugin instance will collect the port pointers from the host and create a `PortCollection` instance for every `run` call. Using this instance, plugins have access to all of their required ports.
198///
199/// # Implementing
200///
201/// The most convenient way to create a port collections is to define a struct with port types from the [`port`](index.html) module and then simply derive `PortCollection` for it. An example:
202///
203/// use lv2_core::port::*;
204///
205/// #[derive(PortCollection)]
206/// struct MyPortCollection {
207/// audio_input: InputPort<Audio>,
208/// audio_output: OutputPort<Audio>,
209/// control_input: InputPort<Control>,
210/// control_output: OutputPort<Control>,
211/// optional_control_input: Option<InputPort<Control>>,
212/// }
213///
214/// Please note that port indices are mapped in the order of occurence; In our example, the implementation will treat `audio_input` as port `0`, `audio_output` as port `1` and so on. Therefore, your plugin definition and your port collection have to match. Otherwise, undefined behaviour will occur.
215pub trait PortCollection: Sized {
216 /// The type of the port pointer cache.
217 ///
218 /// The host passes port pointers to the plugin one by one and in an undefined order. Therefore, the plugin instance can not collect these pointers in the port collection directly. Instead, the pointers are stored in a cache which is then used to create the proper port collection.
219 type Cache: PortPointerCache;
220
221 /// Try to construct a port collection instance from a port pointer cache.
222 ///
223 /// If one of the port connection pointers is null, this method will return `None`, because a `PortCollection` can not be constructed.
224 ///
225 /// # Safety
226 ///
227 /// Since the pointer cache is only storing the pointers, implementing this method requires the de-referencation of raw pointers and therefore, this method is unsafe.
228 unsafe fn from_connections(cache: &Self::Cache, sample_count: u32) -> Option<Self>;
229}
230
231impl PortCollection for () {
232 type Cache = ();
233
234 unsafe fn from_connections(_cache: &(), _sample_count: u32) -> Option<Self> {
235 Some(())
236 }
237}
238
239/// Cache for port connection pointers.
240///
241/// The host will pass the port connection pointers one by one and in an undefined order. Therefore, the `PortCollection` struct can not be created instantly. Instead, the pointers will be stored in a cache, which is then used to create a proper port collection for the plugin.
242pub trait PortPointerCache: Sized + Default {
243 /// Store the connection pointer for the port with index `index`.
244 ///
245 /// The passed pointer may not be valid yet and therefore, implementors should only store the pointer, not dereference it.
246 fn connect(&mut self, index: u32, pointer: *mut c_void);
247}
248
249impl PortPointerCache for () {
250 fn connect(&mut self, _index: u32, _pointer: *mut c_void) {}
251}