Skip to content

Commit aa58d5c

Browse files
Merge pull request #93 from RustAudio/in-place-processing
Implement in-place processing (fix Ardour support)
2 parents 43c43f8 + 39cb5f5 commit aa58d5c

File tree

8 files changed

+512
-100
lines changed

8 files changed

+512
-100
lines changed

atom/src/port.rs

+2
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,13 @@ impl PortType for AtomPort {
105105
type InputPortType = PortReader<'static>;
106106
type OutputPortType = PortWriter<'static>;
107107

108+
#[inline]
108109
unsafe fn input_from_raw(pointer: NonNull<c_void>, _sample_count: u32) -> PortReader<'static> {
109110
let space = Space::from_atom(pointer.cast().as_ref());
110111
PortReader::new(space)
111112
}
112113

114+
#[inline]
113115
unsafe fn output_from_raw(pointer: NonNull<c_void>, _sample_count: u32) -> PortWriter<'static> {
114116
let space = RootMutSpace::from_atom(pointer.cast().as_mut());
115117
PortWriter::new(space)

core/src/port.rs

+15-89
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
11
//! Types to declare derivable port collections.
22
//!
33
//! 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.
4+
mod audio;
5+
mod control;
6+
mod cv;
7+
8+
pub use audio::*;
9+
pub use control::*;
10+
pub use cv::*;
11+
412
use std::ffi::c_void;
513
use std::ops::{Deref, DerefMut};
614
use std::ptr::NonNull;
7-
use urid::UriBound;
815

916
pub use lv2_core_derive::*;
1017

@@ -36,79 +43,6 @@ pub trait PortType {
3643
unsafe fn output_from_raw(pointer: NonNull<c_void>, sample_count: u32) -> Self::OutputPortType;
3744
}
3845

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.
42-
pub struct Audio;
43-
44-
unsafe impl UriBound for Audio {
45-
const URI: &'static [u8] = ::lv2_sys::LV2_CORE__AudioPort;
46-
}
47-
48-
impl 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.
68-
pub struct Control;
69-
70-
unsafe impl UriBound for Control {
71-
const URI: &'static [u8] = ::lv2_sys::LV2_CORE__ControlPort;
72-
}
73-
74-
impl 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.
91-
pub struct CV;
92-
93-
unsafe impl UriBound for CV {
94-
const URI: &'static [u8] = ::lv2_sys::LV2_CORE__CVPort;
95-
}
96-
97-
impl 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-
11246
/// Abstraction of safe port handles.
11347
pub trait PortHandle: Sized {
11448
/// Try to create a port handle from a port connection pointer and the sample count.
@@ -140,13 +74,9 @@ impl<T: PortType> Deref for InputPort<T> {
14074
impl<T: PortType> PortHandle for InputPort<T> {
14175
#[inline]
14276
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-
}
77+
Some(Self {
78+
port: T::input_from_raw(NonNull::new(pointer)?, sample_count),
79+
})
15080
}
15181
}
15282

@@ -176,13 +106,9 @@ impl<T: PortType> DerefMut for OutputPort<T> {
176106
impl<T: PortType> PortHandle for OutputPort<T> {
177107
#[inline]
178108
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-
}
109+
Some(Self {
110+
port: T::output_from_raw(NonNull::new(pointer)?, sample_count),
111+
})
186112
}
187113
}
188114

@@ -211,7 +137,7 @@ impl<T: PortHandle> PortHandle for Option<T> {
211137
/// optional_control_input: Option<InputPort<Control>>,
212138
/// }
213139
///
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.
140+
/// Please note that port indices are mapped in the order of occurrence; 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.
215141
pub trait PortCollection: Sized {
216142
/// The type of the port pointer cache.
217143
///

core/src/port/audio.rs

+155
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
use crate::port::PortType;
2+
use std::cell::Cell;
3+
use std::ffi::c_void;
4+
use std::ptr::NonNull;
5+
use urid::UriBound;
6+
7+
/// A port connected to an array of float audio samples. Using this port **requires** the `inPlaceBroken` feature.
8+
///
9+
/// Ports of this type are connected to a buffer of float audio samples, represented as a slice.
10+
///
11+
/// Audio samples are normalized between -1.0 and 1.0, though there is no requirement for samples to be strictly within this range.
12+
///
13+
/// See the [LV2 reference](https://lv2plug.in/ns/lv2core#AudioPort) for more information.
14+
///
15+
/// # Example
16+
///
17+
/// This very simple amplifier plugin multiplies the input sample by 2 and outputs the result.
18+
///
19+
/// ```
20+
/// # use lv2_core::prelude::*;
21+
/// # use urid::*;
22+
/// # #[uri("http://lv2plug.in/plugins.rs/simple_amp")]
23+
/// # struct SimpleAmp;
24+
/// #[derive(PortCollection)]
25+
/// struct SimpleAmpPorts {
26+
/// input: InputPort<Audio>,
27+
/// output: OutputPort<Audio>,
28+
/// }
29+
///
30+
/// impl Plugin for SimpleAmp {
31+
/// type Ports = SimpleAmpPorts;
32+
/// # type InitFeatures = ();
33+
/// # type AudioFeatures = ();
34+
/// # fn new(plugin_info: &PluginInfo,features: &mut Self::InitFeatures) -> Option<Self> {
35+
/// # unimplemented!()
36+
/// # }
37+
/// // some implementation details elided…
38+
///
39+
/// fn run(&mut self, ports: &mut SimpleAmpPorts, _: &mut (), _: u32) {
40+
/// // Input and Output dereference to `&[f32]` and `&mut [f32]`, respectively.
41+
/// let input = ports.input.iter();
42+
/// let output = ports.output.iter_mut();
43+
///
44+
/// for (input_sample, output_sample) in input.zip(output) {
45+
/// *output_sample = *input_sample * 2.0;
46+
/// }
47+
/// }
48+
/// }
49+
///
50+
///
51+
/// ```
52+
///
53+
/// # Safety
54+
///
55+
/// Using this port type requires the `inPlaceBroken` LV2 feature in your plugin. Because this port
56+
/// type uses shared (`&[f32]`) and exclusive (`&mut [f32]`) references to its data, LV2 hosts
57+
/// MUST NOT use the same buffer for both the input and the output.
58+
/// However, do note that some hosts (Ardour, Zrythm, etc.) do not support `inPlaceBroken` plugins.
59+
///
60+
/// Use [`InPlaceAudio`] instead if you do not want to enforce this restriction on hosts,
61+
/// and do not need references pointing into the buffer's contents.
62+
pub struct Audio;
63+
64+
unsafe impl UriBound for Audio {
65+
const URI: &'static [u8] = ::lv2_sys::LV2_CORE__AudioPort;
66+
}
67+
68+
impl PortType for Audio {
69+
type InputPortType = &'static [f32];
70+
type OutputPortType = &'static mut [f32];
71+
72+
#[inline]
73+
unsafe fn input_from_raw(pointer: NonNull<c_void>, sample_count: u32) -> Self::InputPortType {
74+
std::slice::from_raw_parts(pointer.as_ptr() as *const f32, sample_count as usize)
75+
}
76+
77+
#[inline]
78+
unsafe fn output_from_raw(pointer: NonNull<c_void>, sample_count: u32) -> Self::OutputPortType {
79+
std::slice::from_raw_parts_mut(pointer.as_ptr() as *mut f32, sample_count as usize)
80+
}
81+
}
82+
83+
/// A port connected to an array of float audio samples. This port type can safely operate on shared input and output buffers.
84+
///
85+
/// Ports of this type are connected to a buffer of float audio samples, represented as a slice of [`Cell`s](std::cell::Cell).
86+
///
87+
/// Audio samples are normalized between -1.0 and 1.0, though there is no requirement for samples to be strictly within this range.
88+
///
89+
/// See the [LV2 reference](https://lv2plug.in/ns/lv2core#AudioPort) for more information.
90+
///
91+
/// # Example
92+
///
93+
/// This very simple amplifier plugin multiplies the input sample by 2 and outputs the result.
94+
///
95+
/// ```
96+
/// # use lv2_core::prelude::*;
97+
/// # use urid::*;
98+
/// # #[uri("http://lv2plug.in/plugins.rs/simple_amp")]
99+
/// # struct SimpleAmp;
100+
/// #[derive(PortCollection)]
101+
/// struct SimpleAmpPorts {
102+
/// input: InputPort<InPlaceAudio>,
103+
/// output: OutputPort<InPlaceAudio>,
104+
/// }
105+
///
106+
/// impl Plugin for SimpleAmp {
107+
/// type Ports = SimpleAmpPorts;
108+
/// # type InitFeatures = ();
109+
/// # type AudioFeatures = ();
110+
/// # fn new(plugin_info: &PluginInfo,features: &mut Self::InitFeatures) -> Option<Self> {
111+
/// # unimplemented!()
112+
/// # }
113+
/// // some implementation details elided…
114+
///
115+
/// fn run(&mut self, ports: &mut SimpleAmpPorts, _: &mut (), _: u32) {
116+
/// // Input and Output both dereference to `&[Cell<f32>]`.
117+
/// let input = ports.input.iter();
118+
/// let output = ports.output.iter();
119+
///
120+
/// for (input_sample, output_sample) in input.zip(output) {
121+
/// output_sample.set(input_sample.get() * 2.0);
122+
/// }
123+
/// }
124+
/// }
125+
///
126+
///
127+
/// ```
128+
pub struct InPlaceAudio;
129+
130+
unsafe impl UriBound for InPlaceAudio {
131+
const URI: &'static [u8] = ::lv2_sys::LV2_CORE__AudioPort;
132+
}
133+
134+
impl PortType for InPlaceAudio {
135+
type InputPortType = &'static [Cell<f32>];
136+
type OutputPortType = &'static [Cell<f32>];
137+
138+
#[inline]
139+
unsafe fn input_from_raw(pointer: NonNull<c_void>, sample_count: u32) -> Self::InputPortType {
140+
Cell::from_mut(std::slice::from_raw_parts_mut(
141+
pointer.as_ptr() as *mut f32,
142+
sample_count as usize,
143+
))
144+
.as_slice_of_cells()
145+
}
146+
147+
#[inline]
148+
unsafe fn output_from_raw(pointer: NonNull<c_void>, sample_count: u32) -> Self::OutputPortType {
149+
Cell::from_mut(std::slice::from_raw_parts_mut(
150+
pointer.as_ptr() as *mut f32,
151+
sample_count as usize,
152+
))
153+
.as_slice_of_cells()
154+
}
155+
}

0 commit comments

Comments
 (0)