Skip to main content

clack_plugin/process/audio/
input.rs

1use crate::internal_utils::slice_from_external_parts;
2use crate::prelude::Audio;
3use crate::process::audio::{BufferError, SampleType};
4use clack_common::process::ConstantMask;
5use clap_sys::audio_buffer::clap_audio_buffer;
6use std::slice::Iter;
7
8/// An iterator of all the available [`InputPort`]s from an [`Audio`] struct.
9pub struct InputPortsIter<'a> {
10    inputs: Iter<'a, clap_audio_buffer>,
11    frames_count: u32,
12}
13
14impl<'a> InputPortsIter<'a> {
15    #[inline]
16    pub(crate) fn new(audio: &Audio<'a>) -> Self {
17        Self {
18            inputs: audio.inputs.iter(),
19            frames_count: audio.frames_count,
20        }
21    }
22}
23
24impl<'a> Iterator for InputPortsIter<'a> {
25    type Item = InputPort<'a>;
26
27    #[inline]
28    fn next(&mut self) -> Option<Self::Item> {
29        self.inputs
30            .next()
31            // SAFETY: The Audio type this is built from ensures each buffer is valid
32            // and is of length frames_count.
33            .map(|buf| unsafe { InputPort::from_raw(buf, self.frames_count) })
34    }
35
36    #[inline]
37    fn size_hint(&self) -> (usize, Option<usize>) {
38        self.inputs.size_hint()
39    }
40}
41
42impl ExactSizeIterator for InputPortsIter<'_> {
43    #[inline]
44    fn len(&self) -> usize {
45        self.inputs.len()
46    }
47}
48
49/// An input audio port.
50#[derive(Copy, Clone)]
51pub struct InputPort<'a> {
52    inner: &'a clap_audio_buffer,
53    frames_count: u32,
54}
55
56impl<'a> InputPort<'a> {
57    /// # Safety
58    ///
59    /// * The provided buffer must be valid;
60    /// * `frames_count` *must* match the size of the buffers.
61    #[inline]
62    pub(crate) unsafe fn from_raw(inner: &'a clap_audio_buffer, frames_count: u32) -> Self {
63        Self {
64            inner,
65            frames_count,
66        }
67    }
68
69    /// Retrieves the input port's channels.
70    ///
71    /// Because each port can hold either [`f32`] or [`f64`] sample data, this method returns a
72    /// [`SampleType`] enum of the input channels, to indicate which one the port holds.
73    ///
74    /// # Errors
75    ///
76    /// This method returns a [`BufferError::InvalidChannelBuffer`] if the host provided neither
77    /// [`f32`] nor [`f64`] buffer type, which is invalid per the CLAP specification.
78    ///
79    /// # Example
80    ///
81    /// ```
82    /// use clack_plugin::process::audio::{InputChannels, InputPort, SampleType};
83    ///
84    /// # fn foo(port: InputPort) {
85    /// let port: InputPort = /* ... */
86    /// # port;
87    ///
88    /// // Decide what to do using by matching against every possible configuration
89    /// match port.channels().unwrap() {
90    ///     SampleType::F32(buf) => { /* Process the 32-bit buffer */ },
91    ///     SampleType::F64(buf) => { /* Process the 64-bit buffer */ },
92    ///     SampleType::Both(buf32, buf64) => { /* We have both buffers available */ }
93    /// }
94    ///
95    /// // If we're only interested in a single buffer type,
96    /// // we can use SampleType's helper methods:
97    /// let channels: InputChannels<f32> = port.channels().unwrap().into_f32().unwrap();
98    /// # }
99    /// ```
100    #[inline]
101    pub fn channels(
102        &self,
103    ) -> Result<SampleType<InputChannels<'a, f32>, InputChannels<'a, f64>>, BufferError> {
104        // SAFETY: this type ensures the provided buffer is valid
105        Ok(unsafe { SampleType::from_raw_buffer(self.inner) }?.map(
106            |data| InputChannels {
107                data,
108                frames_count: self.frames_count,
109            },
110            |data| InputChannels {
111                data,
112                frames_count: self.frames_count,
113            },
114        ))
115    }
116
117    /// Returns the number of frames to process in this block.
118    ///
119    /// This will always match the number of samples of every audio channel buffer.
120    #[inline]
121    pub fn frames_count(&self) -> u32 {
122        self.frames_count
123    }
124
125    /// The number of channels in this port.
126    #[inline]
127    pub fn channel_count(&self) -> u32 {
128        self.inner.channel_count
129    }
130
131    /// The latency from the audio interface for this port, in samples.
132    #[inline]
133    pub fn latency(&self) -> u32 {
134        self.inner.latency
135    }
136
137    /// The constant mask for this port.
138    #[inline]
139    pub fn constant_mask(&self) -> ConstantMask {
140        ConstantMask::from_bits(self.inner.constant_mask)
141    }
142}
143
144/// An [`InputPort`]'s channels' data buffers, which contains samples of a given type `S`.
145///
146/// The sample type `S` is always going to be either [`f32`] or [`f64`], as returned by
147/// [`InputPort::channels`].
148#[derive(Copy, Clone)]
149pub struct InputChannels<'a, S> {
150    frames_count: u32,
151    data: &'a [*mut S],
152}
153
154impl<'a, S> InputChannels<'a, S> {
155    /// Returns the number of frames to process in this block.
156    ///
157    /// This will always match the number of samples of every audio channel buffer.
158    #[inline]
159    pub fn frames_count(&self) -> u32 {
160        self.frames_count
161    }
162
163    /// Returns the raw pointer data, as provided by the host.
164    ///
165    /// In CLAP's API, hosts provide a port's audio data as an array of raw pointers, each of which points
166    /// to the start of a sample array of type `S` and of [`frames_count`](Self::frames_count) length.
167    #[inline]
168    pub fn raw_data(&self) -> &'a [*mut S] {
169        self.data
170    }
171
172    /// The number of channels.
173    #[inline]
174    pub fn channel_count(&self) -> u32 {
175        // This is always constructed from u32, so overflow should not be able to happen
176        #[allow(clippy::cast_possible_truncation)]
177        {
178            self.data.len() as u32
179        }
180    }
181
182    /// Retrieves the sample buffer of the channel at a given index.
183    ///
184    /// If there is no channel at the given index (i.e. `channel_index` is greater or equal than
185    /// [`channel_count`](Self::channel_count)), this returns [`None`].
186    #[inline]
187    pub fn channel(&self, channel_index: u32) -> Option<&'a [S]> {
188        // SAFETY: this type guarantees the buffer pointer is valid and of size frames_count
189        unsafe {
190            self.data
191                .get(channel_index as usize)
192                .map(|data| slice_from_external_parts(*data, self.frames_count as usize))
193        }
194    }
195
196    /// Gets an iterator over all the port's channels' sample buffers.
197    #[inline]
198    pub fn iter(&self) -> InputChannelsIter<'a, S> {
199        InputChannelsIter {
200            data: self.data.iter(),
201            frames_count: self.frames_count,
202        }
203    }
204}
205
206impl<'a, T> IntoIterator for InputChannels<'a, T> {
207    type Item = &'a [T];
208    type IntoIter = InputChannelsIter<'a, T>;
209
210    #[inline]
211    fn into_iter(self) -> Self::IntoIter {
212        self.iter()
213    }
214}
215
216impl<'a, T> IntoIterator for &'a InputChannels<'a, T> {
217    type Item = &'a [T];
218    type IntoIter = InputChannelsIter<'a, T>;
219
220    #[inline]
221    fn into_iter(self) -> Self::IntoIter {
222        self.iter()
223    }
224}
225
226/// An iterator over all of an [`InputPort`]'s channels' sample buffers.
227pub struct InputChannelsIter<'a, T> {
228    pub(crate) data: Iter<'a, *mut T>,
229    pub(crate) frames_count: u32,
230}
231
232impl<'a, T> Iterator for InputChannelsIter<'a, T> {
233    type Item = &'a [T];
234
235    #[inline]
236    fn next(&mut self) -> Option<Self::Item> {
237        self.data
238            .next()
239            // SAFETY: iterator can only get created from an InputChannels, which guarantees
240            // the buffer is both valid and of length frames_count
241            .map(|ptr| unsafe { slice_from_external_parts(*ptr, self.frames_count as usize) })
242    }
243
244    #[inline]
245    fn size_hint(&self) -> (usize, Option<usize>) {
246        self.data.size_hint()
247    }
248}
249
250impl<S> ExactSizeIterator for InputChannelsIter<'_, S> {
251    #[inline]
252    fn len(&self) -> usize {
253        self.data.len()
254    }
255}