clack_plugin/process.rs
1//! Types exposing data and metadata to be used by plugins during audio processing.
2//!
3//! All of those types are exclusively used in the [`Plugin::process`](crate::plugin::PluginAudioProcessor::process)
4//! method. See the [`Plugin`](crate::plugin::PluginAudioProcessor) trait documentation for examples on how these types interact.
5
6use clack_common::events::event_types::TransportEvent;
7use clack_common::events::io::{InputEvents, OutputEvents};
8use clap_sys::audio_buffer::clap_audio_buffer;
9use clap_sys::process::clap_process;
10use std::ops::RangeBounds;
11
12pub use clack_common::process::*;
13pub mod audio;
14use crate::internal_utils::{slice_from_external_parts, slice_from_external_parts_mut};
15use audio::*;
16
17/// Metadata about the current process call.
18///
19/// This exposes [transport information](Process::transport) (in the form of a [`TransportEvent`]), as well as a
20/// [steady sample time counter](Process::steady_time).
21///
22#[derive(Copy, Clone)]
23pub struct Process<'a> {
24 /// Transport information at sample 0.
25 ///
26 /// If this is set to [`None`], then this means the plugin is running is a free-running host,
27 /// and no transport events will be provided.
28 pub transport: Option<&'a TransportEvent>,
29 /// A steady sample time counter.
30 ///
31 /// This field can be used to calculate the sleep duration between two process calls.
32 /// This value may be specific to this plugin instance and have no relation to what
33 /// other plugin instances may receive.
34 ///
35 /// If no steady sample time counter is available from the host, this is set to [`None`].
36 ///
37 /// Note that this counter's maximum value is actually [`i64::MAX`], due to how it is
38 /// implemented in the CLAP specification.
39 pub steady_time: Option<u64>,
40}
41
42impl<'a> Process<'a> {
43 /// # Safety
44 ///
45 /// The user must ensure the given process struct is fully valid, and for the lifetime `'a`.
46 #[inline]
47 pub(crate) unsafe fn from_raw(raw: *const clap_process) -> Process<'a> {
48 let transport = (*raw).transport;
49 let steady_time = (*raw).steady_time;
50
51 Self {
52 steady_time: steady_time.try_into().ok(),
53 transport: if transport.is_null() {
54 None
55 } else {
56 Some(TransportEvent::from_raw_ref(&*transport))
57 },
58 }
59 }
60}
61
62/// Input and output events that occurred during this processing block.
63pub struct Events<'a> {
64 /// The input event buffer, for the plugin to read events from.
65 pub input: &'a InputEvents<'a>,
66 /// The output event buffer, for the plugin to push events into.
67 pub output: &'a mut OutputEvents<'a>,
68}
69
70impl Events<'_> {
71 /// # Safety
72 ///
73 /// The user must ensure the given process struct is fully valid, and for the lifetime `'a`.
74 pub(crate) unsafe fn from_raw(process: &clap_process) -> Self {
75 Self {
76 input: InputEvents::from_raw(&*process.in_events),
77 output: OutputEvents::from_raw_mut(&mut *(process.out_events as *mut _)),
78 }
79 }
80}
81
82/// Input and output audio buffers to processed by the plugin.
83///
84/// Audio data in CLAP follow the following tree structure:
85///
86/// * Plugins may have an arbitrary amount of input and output ports;
87/// * Each port can hold either 32-bit, or 64-bit floating-point sample data;
88/// * Port sample data is split in multiple channels (1 for mono, 2 for stereo, etc.);
89/// * Each channel is a raw buffer (i.e. slice) of either [`f32`] or [`f64`] samples.
90///
91/// This structure applies both to inputs and outputs: the [`Audio`] struct allows to retrieve
92/// [`InputPort`]s and [`OutputPort`]s separately, but they can also be accessed together as
93/// Input/Output [`PortPair`]s. This allows for the common use-case of borrowing both an input
94/// and its matching output for processing, while also being safe to hosts using the same buffer for
95/// both.
96///
97/// For each port type (input, output, or paired), ports can be accessed either individually with
98/// an index, or all at once with an iterator. For instance, [`InputPort`]s can be accessed either
99/// one-at-a-time with [`Audio::input_port`], or with an iterator from [`Audio::input_ports`]. A
100/// [`Audio::input_port_count`] method is also available. The same methods are available for
101/// [`OutputPort`]s and [`PortPair`]s.
102///
103/// Note that because ports can individually hold either 32-bit or 64-bit sample data, an extra
104/// sample type detection step is necessary before the port's channels themselves can be accessed.
105/// This is done through the [`channels`](InputPort::channels) methods on each port type, and
106/// returns a [`SampleType`] enum indicating whether the port's buffers hold 32-bit or 64-bit samples.
107///
108/// # Example
109///
110/// The following example implements a gain plugin that amplifies every input channel by `2`, and
111/// writes the result to a matching output channel.
112///
113/// ```
114/// use clack_plugin::prelude::*;
115///
116/// pub fn process(mut audio: Audio) -> Result<ProcessStatus, PluginError> {
117/// for mut port_pair in &mut audio {
118/// // For this example, we'll only care about 32-bit sample data.
119/// let Some(channel_pairs) = port_pair.channels()?.into_f32() else { continue };
120///
121/// for channel_pair in channel_pairs {
122/// match channel_pair {
123/// // If this input has no matching output, we simply do nothing with it.
124/// ChannelPair::InputOnly(_) => {}
125/// // If this output has no matching input, we fill it with silence.
126/// ChannelPair::OutputOnly(buf) => buf.fill(0.0),
127/// // If this is a separate pair of I/O buffers,
128/// // we can copy the input to the outputs while multiplying
129/// ChannelPair::InputOutput(input, output) => {
130/// for (input, output) in input.iter().zip(output) {
131/// *output = input * 2.0
132/// }
133/// }
134/// // If the host sent us a single buffer to be processed in-place
135/// // (i.e. input and output buffers point to the same location),
136/// // then we can do the processing in-place directly.
137/// ChannelPair::InPlace(buf) => {
138/// for sample in buf {
139/// *sample *= 2.0
140/// }
141/// }
142/// }
143/// }
144/// }
145///
146/// Ok(ProcessStatus::Continue)
147/// }
148/// ```
149///
150/// The following example shows how to gather different inputs and outputs simultaneously, and here
151/// uses it to simply swap the left and right stereo channels.
152///
153/// ```
154/// use clack_plugin::prelude::*;
155///
156/// pub fn process(mut audio: Audio) -> Result<ProcessStatus, PluginError> {
157/// for mut port_pair in &mut audio {
158/// // For this example, we'll only care about 32-bit sample data.
159/// let Some(mut channel_pairs) = port_pair.channels()?.into_f32() else { continue; };
160///
161/// // Buffers to hold pointers to the left and right channels
162/// let mut input_channels: [Option<&[f32]>; 2] = [None, None];
163/// let mut output_channels: [Option<&mut [f32]>; 2] = [None, None];
164///
165/// // Before we can process the buffers, we need to check all the necessary channels
166/// // are present, in case the host messed up the port configuration.
167/// // (Yes, some do.)
168/// for ((channel_pair, in_ptr), out_ptr) in channel_pairs
169/// .iter_mut()
170/// .zip(&mut input_channels)
171/// .zip(&mut output_channels)
172/// {
173/// // A separate pair of channels is just what we want for this example!
174/// // However, a real plugin implementation would need to gracefully handle
175/// // the other cases, including having spare input buffers ready for
176/// // in-place processing.
177/// if let ChannelPair::InputOutput(input, output) = channel_pair {
178/// *in_ptr = Some(input);
179/// *out_ptr = Some(output);
180/// }
181/// }
182///
183/// // Channel swap! (assuming all channels are there)
184/// if let (Some(in_l), Some(out_r)) = (&input_channels[0], &mut output_channels[1]) {
185/// out_r.copy_from_slice(in_l)
186/// }
187/// if let (Some(in_r), Some(out_l)) = (&input_channels[1], &mut output_channels[0]) {
188/// out_l.copy_from_slice(in_r)
189/// }
190/// }
191///
192/// Ok(ProcessStatus::Continue)
193/// }
194/// ```
195pub struct Audio<'a> {
196 inputs: &'a [clap_audio_buffer],
197 outputs: &'a mut [clap_audio_buffer],
198 frames_count: u32,
199}
200
201impl<'a> Audio<'a> {
202 /// Create a new [`Audio`] from the information in a given raw, C-FFI compatible `clap_process`
203 /// struct.
204 ///
205 /// # Safety
206 ///
207 /// Users must ensure all fields of the given `raw_process` are valid, and that all buffers
208 /// it points to stay valid for the given lifetime.
209 #[inline]
210 pub unsafe fn from_raw(raw_process: &clap_process) -> Audio<'_> {
211 Audio {
212 frames_count: raw_process.frames_count,
213 inputs: slice_from_external_parts(
214 raw_process.audio_inputs,
215 raw_process.audio_inputs_count as usize,
216 ),
217 outputs: slice_from_external_parts_mut(
218 raw_process.audio_outputs,
219 raw_process.audio_outputs_count as usize,
220 ),
221 }
222 }
223
224 /// Create a new [`Audio`] from raw buffer structs.
225 ///
226 /// # Safety
227 ///
228 /// The caller must ensure all buffer structs are valid for 'a, including all the buffer
229 /// pointers they contain.
230 ///
231 /// The caller must also ensure `frames_count` is lower than or equal to the sizes of the
232 /// channel buffers pointed to by `buffers`.
233 #[inline]
234 pub unsafe fn from_raw_buffers(
235 inputs: &'a [clap_audio_buffer],
236 outputs: &'a mut [clap_audio_buffer],
237 frames_count: u32,
238 ) -> Self {
239 Self {
240 inputs,
241 outputs,
242 frames_count,
243 }
244 }
245
246 /// Returns the raw input and output buffers structs, respectively.
247 #[inline]
248 pub fn raw_buffers(&mut self) -> (&'a [clap_audio_buffer], &mut [clap_audio_buffer]) {
249 (self.inputs, self.outputs)
250 }
251
252 /// Returns the raw input and output buffers structs, respectively, consuming the audio struct.
253 #[inline]
254 pub fn to_raw_buffers(self) -> (&'a [clap_audio_buffer], &'a mut [clap_audio_buffer]) {
255 (self.inputs, self.outputs)
256 }
257
258 /// Returns the raw input buffers structs.
259 #[inline]
260 pub fn raw_input_buffers(&self) -> &'a [clap_audio_buffer] {
261 self.inputs
262 }
263
264 /// Returns the raw output buffers structs.
265 #[inline]
266 pub fn raw_output_buffers(&mut self) -> &mut [clap_audio_buffer] {
267 self.outputs
268 }
269
270 /// Returns the raw output buffers structs, consuming the audio struct.
271 #[inline]
272 pub fn to_raw_output_buffers(self) -> &'a mut [clap_audio_buffer] {
273 self.outputs
274 }
275
276 /// Retrieves the [`InputPort`] at a given index.
277 ///
278 /// This returns [`None`] if there is no input port at the given index.
279 ///
280 /// See also the [`input_port_count`](Audio::input_port_count) method to know how many input
281 /// ports are available, and the [`input_ports`](Audio::input_ports) method to get all input ports at once.
282 #[inline]
283 pub fn input_port(&self, index: usize) -> Option<InputPort<'_>> {
284 self.inputs
285 .get(index)
286 // SAFETY: this type ensures the provided buffer is valid and frames_count is correct
287 .map(|buf| unsafe { InputPort::from_raw(buf, self.frames_count) })
288 }
289
290 /// Retrieves the [`AudioPortProcessingInfo`] of the [`InputPort`] at a given index.
291 ///
292 /// This returns [`None`] if there is no input port at the given index.
293 ///
294 /// See also the [`input_port_count`](Audio::input_port_count) method to know how many output
295 /// ports are available, and the [`input_ports_infos`](Audio::input_ports_infos) method to get the info of
296 /// all input ports at once.
297 #[inline]
298 pub fn input_port_info(&self, index: usize) -> Option<AudioPortProcessingInfo> {
299 self.inputs
300 .get(index)
301 .map(AudioPortProcessingInfo::from_raw)
302 }
303
304 /// Retrieves the number of available [`InputPort`]s.
305 #[inline]
306 pub fn input_port_count(&self) -> usize {
307 self.inputs.len()
308 }
309
310 /// Returns an iterator of all the available [`InputPort`]s at once.
311 ///
312 /// See also the [`input_port`](Audio::input_port) method to retrieve a single input port by
313 /// its index.
314 #[inline]
315 pub fn input_ports(&self) -> InputPortsIter<'_> {
316 InputPortsIter::new(self)
317 }
318
319 /// Retrieves the [`AudioPortProcessingInfo`] of all the available [`OutputPort`]s at once.
320 ///
321 /// See also the [`output_port_info`](Audio::output_port_info) method to retrieve a single
322 /// output port by its index.
323 #[inline]
324 pub fn input_ports_infos(&self) -> impl ExactSizeIterator<Item = AudioPortProcessingInfo> + '_ {
325 self.inputs.iter().map(AudioPortProcessingInfo::from_raw)
326 }
327
328 /// Retrieves the [`OutputPort`] at a given index.
329 ///
330 /// This returns [`None`] if there is no output port at the given index.
331 ///
332 /// See also the [`output_port_count`](Audio::output_port_count) method to know how many output
333 /// ports are available, and the [`output_ports`](Audio::output_ports) method to get all output ports at once.
334 #[inline]
335 pub fn output_port(&mut self, index: usize) -> Option<OutputPort<'_>> {
336 self.outputs
337 .get_mut(index)
338 // SAFETY: this type ensures the provided buffer is valid and frames_count is correct.
339 // Also, &mut ensures there is no input being read concurrently
340 .map(|buf| unsafe { OutputPort::from_raw(buf, self.frames_count) })
341 }
342
343 /// Retrieves the [`AudioPortProcessingInfo`] of the [`OutputPort`] at a given index.
344 ///
345 /// This returns [`None`] if there is no output port at the given index.
346 ///
347 /// See also the [`output_port_count`](Audio::output_port_count) method to know how many output
348 /// ports are available, and the [`output_ports_infos`](Audio::output_ports_infos) method to get the info of
349 /// all output ports at once.
350 #[inline]
351 pub fn output_port_info(&self, index: usize) -> Option<AudioPortProcessingInfo> {
352 self.outputs
353 .get(index)
354 .map(AudioPortProcessingInfo::from_raw)
355 }
356
357 /// Retrieves the number of available [`OutputPort`]s.
358 #[inline]
359 pub fn output_port_count(&self) -> usize {
360 self.outputs.len()
361 }
362
363 /// Returns an iterator of all the available [`OutputPort`]s at once.
364 ///
365 /// See also the [`output_port`](Audio::output_port) method to retrieve a single output port by
366 /// its index.
367 #[inline]
368 pub fn output_ports(&mut self) -> OutputPortsIter<'_> {
369 OutputPortsIter::new(self)
370 }
371
372 /// Retrieves the [`AudioPortProcessingInfo`] of all the available [`OutputPort`]s at once.
373 ///
374 /// See also the [`output_port_info`](Audio::output_port_info) method to retrieve a single
375 /// output port by its index.
376 #[inline]
377 pub fn output_ports_infos(
378 &self,
379 ) -> impl ExactSizeIterator<Item = AudioPortProcessingInfo> + '_ {
380 self.outputs.iter().map(AudioPortProcessingInfo::from_raw)
381 }
382
383 /// Retrieves the [`PortPair`] at a given index.
384 ///
385 /// This returns [`None`] if there is no available port at the given index.
386 ///
387 /// See also the [`port_pair_count`](Audio::port_pair_count) method to know how many port
388 /// pairs are available, and the [`port_pairs`](Audio::port_pairs) method to get all port pairs at once.
389 #[inline]
390 pub fn port_pair(&mut self, index: usize) -> Option<PortPair<'_>> {
391 // SAFETY: this type ensures the provided buffers are valid and frames_count is correct
392 unsafe {
393 PortPair::from_raw(
394 self.inputs.get(index),
395 self.outputs.get_mut(index),
396 self.frames_count,
397 )
398 }
399 }
400
401 /// Retrieves the number of available [`PortPair`]s.
402 ///
403 /// Because [`PortPair`] can be mismatched (i.e. have an input but no output, or vice-versa),
404 /// this is effectively equal to the maximum number of ports available, either on the input side
405 /// or the output side.
406 #[inline]
407 pub fn port_pair_count(&self) -> usize {
408 self.input_port_count().max(self.output_port_count())
409 }
410
411 /// Returns an iterator of all the available [`PortPair`]s at once.
412 ///
413 /// See also the [`port_pair`](Audio::port_pair) method to retrieve a single input port by
414 /// its index.
415 #[inline]
416 pub fn port_pairs(&mut self) -> PortPairsIter<'_> {
417 PortPairsIter::new(self)
418 }
419
420 /// Returns a sub-range of ports as a new [`Audio`] struct, similar to a subslice of items.
421 #[inline]
422 pub fn port_sub_range<R: RangeBounds<usize> + Clone>(&mut self, range: R) -> Audio<'_> {
423 let inputs = self
424 .inputs
425 .get((range.start_bound().cloned(), range.end_bound().cloned()))
426 .unwrap_or(&[]);
427
428 let outputs = self
429 .outputs
430 .get_mut((range.start_bound().cloned(), range.end_bound().cloned()))
431 .unwrap_or(&mut []);
432
433 Audio {
434 inputs,
435 outputs,
436 frames_count: self.frames_count,
437 }
438 }
439
440 /// Returns the number of frames to process in this block.
441 ///
442 /// This will always match the number of samples of every audio buffer in this [`Audio`] struct.
443 #[inline]
444 pub fn frames_count(&self) -> u32 {
445 self.frames_count
446 }
447}
448
449impl<'buf: 'a, 'a> IntoIterator for &'a mut Audio<'buf> {
450 type Item = PortPair<'a>;
451 type IntoIter = PortPairsIter<'a>;
452
453 /// Returns an iterator of all the available [`PortPair`]s at once. This is equivalent to using
454 /// [`port_pairs`](Audio::port_pairs).
455 #[inline]
456 fn into_iter(self) -> Self::IntoIter {
457 self.port_pairs()
458 }
459}