Skip to main content

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}