clack_plugin/process/audio/pair.rs
1use crate::internal_utils::{slice_from_external_parts, slice_from_external_parts_mut};
2use crate::process::Audio;
3use crate::process::audio::pair::ChannelPair::*;
4use crate::process::audio::{BufferError, InputPort, OutputPort, SampleType};
5use clack_common::process::{AudioPortProcessingInfo, ConstantMask};
6use clap_sys::audio_buffer::clap_audio_buffer;
7use std::slice::{Iter, IterMut};
8
9/// A pair of Input and Output ports.
10///
11/// Note that in case of asymmetric port layouts (e.g. side-chain), there may not
12/// be an associated output port to an input port, or vice-versa. The same goes for
13/// paired channels.
14///
15/// In those cases, a given pair will only contain one port instead of two. However,
16/// a [`PortPair`] is always guaranteed to contain at least one port, be it an input or output.
17pub struct PortPair<'a> {
18 input: Option<&'a clap_audio_buffer>,
19 output: Option<&'a mut clap_audio_buffer>,
20 frames_count: u32,
21}
22
23impl<'a> PortPair<'a> {
24 /// # Safety
25 ///
26 /// * Both provided buffers must be valid (if not `None`);
27 /// * `frames_count` *must* match the size of the buffers.
28 #[inline]
29 pub(crate) unsafe fn from_raw(
30 input: Option<&'a clap_audio_buffer>,
31 output: Option<&'a mut clap_audio_buffer>,
32 frames_count: u32,
33 ) -> Option<Self> {
34 match (input, output) {
35 (None, None) => None,
36 (input, output) => Some(PortPair {
37 input,
38 output,
39 frames_count,
40 }),
41 }
42 }
43
44 /// Gets the [`InputPort`] of this pair.
45 ///
46 /// If the port layout is asymmetric and there is no input port, this returns [`None`].
47 #[inline]
48 pub fn input(&self) -> Option<InputPort<'_>> {
49 self.input
50 // SAFETY: this type ensures the buffer is valid and matches frame_count
51 .map(|i| unsafe { InputPort::from_raw(i, self.frames_count) })
52 }
53
54 /// Gets the [`OutputPort`] of this pair.
55 ///
56 /// If the port layout is asymmetric and there is no output port, this returns [`None`].
57 #[inline]
58 pub fn output(&mut self) -> Option<OutputPort<'_>> {
59 self.output
60 .as_mut()
61 // SAFETY: this type ensures the buffer is valid and matches frame_count
62 .map(|i| unsafe { OutputPort::from_raw(i, self.frames_count) })
63 }
64
65 /// Retrieves the port info for the input of this pair.
66 ///
67 /// If the port layout is asymmetric and there is no input port, this returns [`None`].
68 #[inline]
69 pub fn input_info(&self) -> Option<AudioPortProcessingInfo> {
70 self.input
71 .as_ref()
72 .map(|buf| AudioPortProcessingInfo::from_raw(buf))
73 }
74
75 /// Retrieves the port info for the output of this pair.
76 ///
77 /// If the port layout is asymmetric and there is no output port, this returns [`None`].
78 #[inline]
79 pub fn output_info(&self) -> Option<AudioPortProcessingInfo> {
80 self.output
81 .as_ref()
82 .map(|buf| AudioPortProcessingInfo::from_raw(buf))
83 }
84
85 /// Retrieves the port pair's channels.
86 ///
87 /// Because each port can hold either [`f32`] or [`f64`] sample data, this method returns a
88 /// [`SampleType`] enum of the paired channels, to indicate which one the ports holds.
89 ///
90 /// # Errors
91 ///
92 /// This method returns a [`BufferError::InvalidChannelBuffer`] if the host provided neither
93 /// [`f32`] nor [`f64`] buffer type, which is invalid per the CLAP specification.
94 ///
95 /// Additionally, if the two port have different buffer sample types (i.e. one holds [`f32`]
96 /// and the other holds [`f64`]), then a [`BufferError::MismatchedBufferPair`] error is returned.
97 ///
98 /// # Example
99 ///
100 /// ```
101 /// use clack_plugin::process::audio::{PairedChannels, PortPair, SampleType};
102 ///
103 /// # fn foo(port: PortPair) {
104 /// let mut port: PortPair = /* ... */
105 /// # port;
106 ///
107 /// // Decide what to do using by matching against every possible configuration
108 /// match port.channels().unwrap() {
109 /// SampleType::F32(buf) => { /* Process the 32-bit buffers */ },
110 /// SampleType::F64(buf) => { /* Process the 64-bit buffers */ },
111 /// SampleType::Both(buf32, buf64) => { /* We have both types of buffers available */ }
112 /// }
113 ///
114 /// // If we're only interested in a single buffer type,
115 /// // we can use SampleType's helper methods:
116 /// let channels: PairedChannels<f32> = port.channels().unwrap().into_f32().unwrap();
117 /// # }
118 /// ```
119 #[inline]
120 pub fn channels(
121 &mut self,
122 ) -> Result<SampleType<PairedChannels<'a, f32>, PairedChannels<'a, f64>>, BufferError> {
123 let input = match self.input {
124 None => SampleType::Both([].as_slice(), [].as_slice()),
125 // SAFETY: this type ensures the buffer is valid
126 Some(buffer) => unsafe { SampleType::from_raw_buffer(buffer)? },
127 };
128
129 let output = match self.output.as_mut() {
130 None => SampleType::Both([].as_mut_slice(), [].as_mut_slice()),
131 // SAFETY: this type ensures the buffer is valid
132 Some(buffer) => unsafe { SampleType::from_raw_buffer_mut(buffer)? },
133 };
134
135 Ok(input.try_match_with(output)?.map(
136 |(i, o)| PairedChannels {
137 input_data: i,
138 output_data: o,
139 frames_count: self.frames_count,
140 },
141 |(i, o)| PairedChannels {
142 input_data: i,
143 output_data: o,
144 frames_count: self.frames_count,
145 },
146 ))
147 }
148
149 /// The number of channels in this port pair.
150 ///
151 /// Since there may be more channels in one port than in the other, this method also counts
152 /// the partial [`ChannelPair`]s that can be returned, and therefore returns the maximum number
153 /// of channels between the two ports.
154 #[inline]
155 pub fn channel_pair_count(&self) -> usize {
156 let in_channels = self.input.map(|b| b.channel_count).unwrap_or(0);
157 let out_channels = self.output.as_ref().map(|b| b.channel_count).unwrap_or(0);
158
159 in_channels.max(out_channels) as usize
160 }
161
162 /// Returns the number of frames to process in this block.
163 ///
164 /// This will always match the number of samples of every audio channel buffer. The two ports
165 /// *cannot* have different buffer sizes.
166 #[inline]
167 pub fn frames_count(&self) -> u32 {
168 self.frames_count
169 }
170
171 /// The latency from and to the audio interface for this port pair, in samples.
172 ///
173 /// This returns a tuple containing the latenciess for the input and output port,
174 /// respectively.
175 ///
176 /// If one port isn't present in this pair, then [`None`] is returned.
177 #[inline]
178 pub fn latencies(&self) -> (Option<u32>, Option<u32>) {
179 (
180 self.input.map(|i| i.latency),
181 self.output.as_ref().map(|o| o.latency),
182 )
183 }
184
185 /// The [`ConstantMask`]s for the two ports.
186 ///
187 /// This returns a tuple containing the [`ConstantMask`]s for the input and output port,
188 /// respectively.
189 ///
190 /// If one port isn't present in this pair, then [`ConstantMask::FULLY_CONSTANT`] is returned.
191 #[inline]
192 pub fn constant_masks(&self) -> (ConstantMask, ConstantMask) {
193 (
194 self.input
195 .map(|i| ConstantMask::from_bits(i.constant_mask))
196 .unwrap_or(ConstantMask::FULLY_CONSTANT),
197 self.output
198 .as_ref()
199 .map(|o| ConstantMask::from_bits(o.constant_mask))
200 .unwrap_or(ConstantMask::FULLY_CONSTANT),
201 )
202 }
203}
204
205/// An [`PortPair`]'s channels' data buffers, which contains samples of a given type `S`.
206///
207/// The sample type `S` is always going to be either [`f32`] or [`f64`], as returned by
208/// [`PortPair::channels`].
209pub struct PairedChannels<'a, S> {
210 input_data: &'a [*mut S],
211 output_data: &'a mut [*mut S],
212 frames_count: u32,
213}
214
215impl<'a, S> PairedChannels<'a, S> {
216 /// Returns the number of frames to process in this block.
217 ///
218 /// This will always match the number of samples of every audio channel buffer, from both
219 /// the input and output port.
220 #[inline]
221 pub fn frames_count(&self) -> u32 {
222 self.frames_count
223 }
224
225 /// The number of input channels.
226 #[inline]
227 pub fn input_channel_count(&self) -> usize {
228 self.input_data.len()
229 }
230
231 /// The number of output channels.
232 #[inline]
233 pub fn output_channel_count(&self) -> usize {
234 self.output_data.len()
235 }
236
237 /// The total number of channel pairs.
238 ///
239 /// Since there may be more channels in one port than in the other, this method also counts
240 /// the partial [`ChannelPair`]s that can be returned, and therefore returns the maximum number
241 /// of channels between the input and output ports.
242 #[inline]
243 pub fn channel_pair_count(&self) -> usize {
244 self.input_channel_count().max(self.output_channel_count())
245 }
246
247 /// Retrieves the pair of sample buffers for the pair of channels at a given index.
248 ///
249 /// If there is no channel at the given index (i.e. `channel_index` is greater or equal than
250 /// [`channel_pair_count`](Self::channel_pair_count)), this returns [`None`].
251 ///
252 /// See [`ChannelPair`]'s documentation for examples on how to access sample buffers from it.
253 #[inline]
254 pub fn channel_pair(&mut self, index: usize) -> Option<ChannelPair<'a, S>> {
255 let input = self
256 .input_data
257 .get(index)
258 // SAFETY: this type ensures the pointer is valid and the slice is frames_count-long
259 .map(|ptr| unsafe { slice_from_external_parts(*ptr, self.frames_count as usize) });
260
261 let output = self
262 .output_data
263 .get(index)
264 // SAFETY: this type ensures the pointer is valid and the slice is frames_count-long
265 .map(|ptr| unsafe { slice_from_external_parts_mut(*ptr, self.frames_count as usize) });
266
267 ChannelPair::from_optional_io(input, output)
268 }
269
270 /// Gets an iterator over all the ports' [`ChannelPair`]s.
271 #[inline]
272 pub fn iter_mut(&mut self) -> PairedChannelsIter<'_, S> {
273 PairedChannelsIter {
274 input_iter: self.input_data.iter(),
275 output_iter: self.output_data.iter_mut(),
276 frames_count: self.frames_count,
277 }
278 }
279}
280
281impl<'a, S> IntoIterator for PairedChannels<'a, S> {
282 type Item = ChannelPair<'a, S>;
283 type IntoIter = PairedChannelsIter<'a, S>;
284
285 #[inline]
286 fn into_iter(self) -> Self::IntoIter {
287 PairedChannelsIter {
288 input_iter: self.input_data.iter(),
289 output_iter: self.output_data.iter_mut(),
290 frames_count: self.frames_count,
291 }
292 }
293}
294
295/// An iterator over all of a [`PortPair`]'s [`ChannelPair`]s.
296pub struct PairedChannelsIter<'a, S> {
297 input_iter: Iter<'a, *mut S>,
298 output_iter: IterMut<'a, *mut S>,
299 frames_count: u32,
300}
301
302impl<'a, S> Iterator for PairedChannelsIter<'a, S> {
303 type Item = ChannelPair<'a, S>;
304
305 #[inline]
306 fn next(&mut self) -> Option<Self::Item> {
307 let input = self
308 .input_iter
309 .next()
310 // SAFETY: this type ensures the pointer is valid and the slice is frames_count-long
311 .map(|ptr| unsafe { slice_from_external_parts(*ptr, self.frames_count as usize) });
312
313 // SAFETY: this type ensures the pointer is valid and the slice is frames_count-long
314 let output = self.output_iter.next().map(|ptr| unsafe {
315 slice_from_external_parts_mut((*ptr) as *mut _, self.frames_count as usize)
316 });
317
318 ChannelPair::from_optional_io(input, output)
319 }
320
321 #[inline]
322 fn size_hint(&self) -> (usize, Option<usize>) {
323 (self.len(), Some(self.len()))
324 }
325}
326
327impl<S> ExactSizeIterator for PairedChannelsIter<'_, S> {
328 #[inline]
329 fn len(&self) -> usize {
330 self.input_iter.len().max(self.output_iter.len())
331 }
332}
333
334/// An iterator of all of the available [`PortPair`]s from an [`Audio`] struct.
335pub struct PortPairsIter<'a> {
336 inputs: Iter<'a, clap_audio_buffer>,
337 outputs: IterMut<'a, clap_audio_buffer>,
338 frames_count: u32,
339}
340
341impl<'a> PortPairsIter<'a> {
342 #[inline]
343 pub(crate) fn new(audio: &'a mut Audio<'_>) -> Self {
344 Self {
345 inputs: audio.inputs.iter(),
346 outputs: audio.outputs.iter_mut(),
347 frames_count: audio.frames_count,
348 }
349 }
350}
351
352impl<'a> Iterator for PortPairsIter<'a> {
353 type Item = PortPair<'a>;
354
355 #[inline]
356 fn next(&mut self) -> Option<Self::Item> {
357 // SAFETY: the audio type this is created from
358 unsafe { PortPair::from_raw(self.inputs.next(), self.outputs.next(), self.frames_count) }
359 }
360
361 #[inline]
362 fn size_hint(&self) -> (usize, Option<usize>) {
363 (self.len(), Some(self.len()))
364 }
365}
366
367impl ExactSizeIterator for PortPairsIter<'_> {
368 #[inline]
369 fn len(&self) -> usize {
370 self.inputs.len().max(self.outputs.len())
371 }
372}
373
374/// A pair of input and output channel buffers.
375///
376/// Because port and channel layouts may differ between inputs and outputs, a [`ChannelPair`]
377/// may actually contain only an input or an output instead of both.
378///
379/// This enum also allows to check for the fairly common case where Host may re-use the same
380/// buffer for both the input and output, and expect the plugin to do in-place processing.
381pub enum ChannelPair<'a, S> {
382 /// There is only an input channel present, there was no matching output.
383 InputOnly(&'a [S]),
384 /// There is only an output channel present, there was no matching input.
385 OutputOnly(&'a mut [S]),
386 /// Both the input and output channels are present, and available separately.
387 InputOutput(&'a [S], &'a mut [S]),
388 /// Both the input and output channels are present, but they actually share the same buffer.
389 ///
390 /// In this case, the slice is already filled with the input channel's data, and the host
391 /// considers the contents of this buffer after processing to be the output channel's data.
392 InPlace(&'a mut [S]),
393}
394
395impl<'a, S> ChannelPair<'a, S> {
396 #[inline]
397 pub(crate) fn from_optional_io(
398 input: Option<&'a [S]>,
399 output: Option<&'a mut [S]>,
400 ) -> Option<ChannelPair<'a, S>> {
401 match (input, output) {
402 (None, None) => None,
403 (Some(input), None) => Some(InputOnly(input)),
404 (None, Some(output)) => Some(OutputOnly(output)),
405 (Some(input), Some(output)) => Some(if input.as_ptr() == output.as_ptr() {
406 InPlace(output)
407 } else {
408 InputOutput(input, output)
409 }),
410 }
411 }
412
413 /// Attempts to retrieve the input channel's buffer data, if the input channel is present.
414 #[inline]
415 pub fn input(&'a self) -> Option<&'a [S]> {
416 match self {
417 InputOnly(i) | InputOutput(i, _) => Some(i),
418 OutputOnly(_) => None,
419 InPlace(io) => Some(io),
420 }
421 }
422
423 /// Attempts to retrieve a read-only reference to the output channel's buffer data,
424 /// if the output channel is present.
425 #[inline]
426 pub fn output(&'a self) -> Option<&'a [S]> {
427 match self {
428 OutputOnly(o) | InputOutput(_, o) | InPlace(o) => Some(o),
429 InputOnly(_) => None,
430 }
431 }
432
433 /// Attempts to retrieve a read-write reference to the output channel's buffer data,
434 /// if the output channel is present.
435 #[inline]
436 pub fn output_mut(&'a mut self) -> Option<&'a mut [S]> {
437 match self {
438 OutputOnly(o) | InputOutput(_, o) | InPlace(o) => Some(o),
439 InputOnly(_) => None,
440 }
441 }
442}