Skip to main content

clack_common/
process.rs

1//! Types exposing data and metadata to be used by plugins during audio processing.
2
3use clap_sys::process::*;
4use std::fmt::Debug;
5
6mod constant_mask;
7pub use constant_mask::*;
8
9/// Status returned by a plugin after processing.
10///
11/// This is mainly used as a way for the plugin to tell the host when it can be safely put to sleep.
12///
13/// Note that Clack uses a [`Result`] enum for relaying a failed processing to the host,
14/// unlike the C CLAP API which uses an extra state in enum (`CLAP_PROCESS_ERROR`) to indicate failure.
15#[repr(i32)]
16#[derive(Debug, Copy, Clone, Eq, PartialEq)]
17pub enum ProcessStatus {
18    /// Processing should continue: the plugin has no desire to be put to sleep.
19    Continue = CLAP_PROCESS_CONTINUE,
20    /// Processing should continue, unless all outputs are quiet.
21    ContinueIfNotQuiet = CLAP_PROCESS_CONTINUE_IF_NOT_QUIET,
22    /// The plugin is currently processing its tail (e.g. release, reverb, etc.).
23    ///
24    /// Use the `tail` extension to query the plugin for its current tail length.
25    Tail = CLAP_PROCESS_TAIL,
26    /// No more processing is required until the next event or variation in audio input.
27    Sleep = CLAP_PROCESS_SLEEP,
28}
29
30impl ProcessStatus {
31    /// Gets a [`ProcessStatus`] from the raw, C-FFI compatible value.
32    ///
33    /// In order to match Clack's APIs, this returns `Some(Err(()))` if the value is
34    /// `CLAP_PROCESS_ERROR`.
35    ///
36    /// If the given integer does not match any known CLAP Processing status codes, [`None`] is
37    /// returned.
38    #[inline]
39    pub fn from_raw(raw: clap_process_status) -> Option<Result<Self, ()>> {
40        use ProcessStatus::*;
41
42        match raw {
43            CLAP_PROCESS_CONTINUE => Some(Ok(Continue)),
44            CLAP_PROCESS_CONTINUE_IF_NOT_QUIET => Some(Ok(ContinueIfNotQuiet)),
45            CLAP_PROCESS_SLEEP => Some(Ok(Sleep)),
46            CLAP_PROCESS_TAIL => Some(Ok(Tail)),
47            CLAP_PROCESS_ERROR => Some(Err(())),
48            _ => None,
49        }
50    }
51
52    /// Combines two [`ProcessStatus`]es, returning one that meets the minimum processing requirements
53    /// of both statuses.
54    #[inline]
55    pub fn combined_with(self, other: ProcessStatus) -> ProcessStatus {
56        use ProcessStatus::*;
57
58        match (self, other) {
59            (Continue, _) | (_, Continue) => Continue,
60            (ContinueIfNotQuiet, _) | (_, ContinueIfNotQuiet) => ContinueIfNotQuiet,
61            (Tail, _) | (_, Tail) => Tail,
62            (Sleep, Sleep) => Sleep,
63        }
64    }
65}
66
67/// The audio configuration passed to a plugin's audio processor upon activation.
68///
69/// Those settings are constant throughout the audio processor's lifetime,
70/// i.e. from a plugin's activation until its deactivation.
71#[derive(Copy, Clone, Debug, PartialEq)]
72pub struct PluginAudioConfiguration {
73    /// The audio's sample rate.
74    pub sample_rate: f64,
75    /// The minimum amount of frames that will be processed at once.
76    pub min_frames_count: u32,
77    /// The maximum amount of frames that will be processed at once.
78    pub max_frames_count: u32,
79}
80
81impl PluginAudioConfiguration {
82    /// Validates this [`PluginAudioConfiguration`].
83    ///
84    /// # Panics
85    ///
86    /// This function will panic if either `min_frames_count` or `max_frames_count` is 0, or if
87    /// `min_frames_count` is greater than `max_frames_count`.
88    pub fn validate(&self) {
89        static MIN: &str = "min_frames_count";
90        static MAX: &str = "max_frames_count";
91        static INVALID: &str = "Invalid PluginAudioConfiguration: ";
92        static ZERO: &str = " cannot be 0";
93
94        if self.min_frames_count == 0 {
95            invalid();
96            #[cold]
97            fn invalid() -> ! {
98                panic!("{INVALID}{MIN}{ZERO}");
99            }
100        }
101
102        if self.max_frames_count == 0 {
103            invalid();
104            #[cold]
105            fn invalid() -> ! {
106                panic!("{INVALID}{MAX}{ZERO}");
107            }
108        }
109
110        if self.min_frames_count > self.max_frames_count {
111            invalid(self);
112            #[cold]
113            fn invalid(cfg: &PluginAudioConfiguration) -> ! {
114                panic!(
115                    "{INVALID}{MIN} ({}) is greater than {MAX} ({})",
116                    cfg.min_frames_count, cfg.max_frames_count
117                );
118            }
119        }
120    }
121}
122
123use clap_sys::audio_buffer::clap_audio_buffer;
124
125/// Processing-related information about an audio port.
126pub struct AudioPortProcessingInfo {
127    channel_count: u32,
128    latency: u32,
129    constant_mask: ConstantMask,
130}
131
132impl AudioPortProcessingInfo {
133    /// Extracts the processing-related information from a raw, C-FFI compatible audio buffer
134    /// descriptor.
135    #[inline]
136    pub fn from_raw(raw: &clap_audio_buffer) -> Self {
137        Self {
138            channel_count: raw.channel_count,
139            latency: raw.latency,
140            constant_mask: ConstantMask::from_bits(raw.constant_mask),
141        }
142    }
143
144    /// Returns the number of audio channels this port provides.
145    #[inline]
146    pub fn channel_count(&self) -> u32 {
147        self.channel_count
148    }
149
150    /// Returns the latency to or from the audio interface, in samples.
151    ///
152    /// Whether this latency is to or from the audio interface depends on which kind of port
153    /// this describes, an output port or an input port respectively
154    #[inline]
155    pub fn latency(&self) -> u32 {
156        self.latency
157    }
158
159    /// Returns the [`ConstantMask`] of this port, hinting which audio channels are constant.
160    #[inline]
161    pub fn constant_mask(&self) -> ConstantMask {
162        self.constant_mask
163    }
164}