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}