firewheel_core/
mask.rs

1use core::{ops::Range, u64};
2
3/// An optional optimization hint on which channels contain all
4/// zeros (silence). The first bit (`0x1`) is the first channel,
5/// the second bit is the second channel, and so on.
6#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
7pub struct SilenceMask(pub u64);
8
9impl SilenceMask {
10    /// A mask with no channels marked as silent
11    pub const NONE_SILENT: Self = Self(0);
12
13    /// A mask with only the first channel marked as silent
14    pub const MONO_SILENT: Self = Self(0b1);
15
16    /// A mask with only the first two channels marked as silent
17    pub const STEREO_SILENT: Self = Self(0b11);
18
19    /// Construct a new [`SilenceMask`] with all channels marked as
20    /// silent.
21    ///
22    /// `num_channels` must be less than or equal to `64`.
23    pub const fn new_all_silent(num_channels: usize) -> Self {
24        if num_channels >= 64 {
25            Self(u64::MAX)
26        } else {
27            Self((0b1 << num_channels) - 1)
28        }
29    }
30
31    /// Returns `true` if the channel is marked as silent, `false`
32    /// otherwise.
33    ///
34    /// `i` must be less than `64`.
35    pub const fn is_channel_silent(&self, i: usize) -> bool {
36        self.0 & (0b1 << i) != 0
37    }
38
39    /// Returns `true` if any channel is marked as silent, `false`
40    /// otherwise.
41    ///
42    /// `num_channels` must be less than or equal to `64`.
43    pub const fn any_channel_silent(&self, num_channels: usize) -> bool {
44        if num_channels >= 64 {
45            self.0 != 0
46        } else {
47            self.0 & ((0b1 << num_channels) - 1) != 0
48        }
49    }
50
51    /// Returns `true` if all channels are marked as silent, `false`
52    /// otherwise.
53    ///
54    /// `num_channels` must be less than or equal to `64`.
55    pub const fn all_channels_silent(&self, num_channels: usize) -> bool {
56        if num_channels >= 64 {
57            self.0 == u64::MAX
58        } else {
59            let mask = (0b1 << num_channels) - 1;
60            self.0 & mask == mask
61        }
62    }
63
64    /// Returns `true` if all channels in the given range are marked
65    /// as silent, `false` otherwise.
66    ///
67    /// This range must be in the range `[0, 64]`
68    pub const fn range_silent(&self, range: Range<usize>) -> bool {
69        if range.start >= 64 {
70            false
71        } else if range.end >= 64 {
72            let mask = u64::MAX & !((0b1 << range.start) - 1);
73            self.0 & mask == mask
74        } else {
75            let mask = ((0b1 << range.end) - 1) & !((0b1 << range.start) - 1);
76            self.0 & mask == mask
77        }
78    }
79
80    /// Mark/un-mark the given channel as silent.
81    ///
82    /// `i` must be less than `64`.
83    pub fn set_channel(&mut self, i: usize, silent: bool) {
84        if silent {
85            self.0 |= 0b1 << i;
86        } else {
87            self.0 &= !(0b1 << i);
88        }
89    }
90
91    pub const fn union(self, other: Self) -> Self {
92        SilenceMask(self.0 & other.0)
93    }
94
95    pub fn union_with(&mut self, other: Self) {
96        self.0 &= other.0;
97    }
98
99    pub fn to_constant_mask(self) -> ConstantMask {
100        ConstantMask(self.0)
101    }
102}
103
104/// An optional optimization hint on which channels have all samples
105/// set to the same value. The first bit (`0x1`) is the first
106/// channel, the second bit is the second channel, and so on.
107///
108/// This can be useful for nodes that use audio buffers as CV
109/// (control voltage) ports.
110#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
111pub struct ConstantMask(pub u64);
112
113impl ConstantMask {
114    /// A mask with no channels marked as constant
115    pub const NONE_CONSTANT: Self = Self(0);
116
117    /// A mask with only the first channel marked as constant
118    pub const MONO_CONSTANT: Self = Self(0b1);
119
120    /// A mask with only the first two channels marked as constant
121    pub const STEREO_CONSTANT: Self = Self(0b11);
122
123    /// Construct a new [`ConstantMask`] with all channels marked as
124    /// constant.
125    ///
126    /// `num_channels` must be less than or equal to `64`.
127    pub const fn new_all_constant(num_channels: usize) -> Self {
128        if num_channels >= 64 {
129            Self(u64::MAX)
130        } else {
131            Self((0b1 << num_channels) - 1)
132        }
133    }
134
135    /// Returns `true` if the channel is marked as constant, `false`
136    /// otherwise.
137    ///
138    /// `i` must be less than `64`.
139    pub const fn is_channel_constant(&self, i: usize) -> bool {
140        self.0 & (0b1 << i) != 0
141    }
142
143    /// Returns `true` if any channel is marked as constant, `false`
144    /// otherwise.
145    ///
146    /// `num_channels` must be less than or equal to `64`.
147    pub const fn any_channel_constant(&self, num_channels: usize) -> bool {
148        if num_channels >= 64 {
149            self.0 != 0
150        } else {
151            self.0 & ((0b1 << num_channels) - 1) != 0
152        }
153    }
154
155    /// Returns `true` if all channels are marked as constant, `false`
156    /// otherwise.
157    ///
158    /// `num_channels` must be less than or equal to `64`.
159    pub const fn all_channels_constant(&self, num_channels: usize) -> bool {
160        if num_channels >= 64 {
161            self.0 == u64::MAX
162        } else {
163            let mask = (0b1 << num_channels) - 1;
164            self.0 & mask == mask
165        }
166    }
167
168    /// Returns `true` if all channels in the given range are marked
169    /// as constant, `false` otherwise.
170    ///
171    /// This range must be in the range `[0, 64]`
172    pub const fn range_constant(&self, range: Range<usize>) -> bool {
173        if range.start >= 64 {
174            false
175        } else if range.end >= 64 {
176            let mask = u64::MAX & !((0b1 << range.start) - 1);
177            self.0 & mask == mask
178        } else {
179            let mask = ((0b1 << range.end) - 1) & !((0b1 << range.start) - 1);
180            self.0 & mask == mask
181        }
182    }
183
184    /// Mark/un-mark the given channel as constant.
185    ///
186    /// `i` must be less than `64`.
187    pub fn set_channel(&mut self, i: usize, constant: bool) {
188        if constant {
189            self.0 |= 0b1 << i;
190        } else {
191            self.0 &= !(0b1 << i);
192        }
193    }
194
195    pub const fn union(self, other: Self) -> Self {
196        ConstantMask(self.0 & other.0)
197    }
198
199    pub fn union_with(&mut self, other: Self) {
200        self.0 &= other.0;
201    }
202
203    /// Convert this constant mask into a silence mask.
204    pub fn to_silence_mask<V: AsRef<[f32]>>(self, channels: &[V]) -> SilenceMask {
205        let mut silence_mask = SilenceMask::NONE_SILENT;
206        for (i, ch) in channels.iter().enumerate() {
207            let silent = self.is_channel_constant(i) && ch.as_ref()[0] == 0.0;
208            silence_mask.set_channel(i, silent);
209        }
210
211        silence_mask
212    }
213
214    /// Convert this constant mask into a silence mask, assuming
215    /// that none of the slices in `channels` are empty.
216    ///
217    /// # Safety
218    /// All slices in `channels` must not be empty.
219    pub unsafe fn to_silence_mask_unchecked<V: AsRef<[f32]>>(self, channels: &[V]) -> SilenceMask {
220        let mut silence_mask = SilenceMask::NONE_SILENT;
221        for (i, ch) in channels.iter().enumerate() {
222            let silent =
223                unsafe { self.is_channel_constant(i) && *(ch.as_ref().get_unchecked(0)) == 0.0 };
224            silence_mask.set_channel(i, silent);
225        }
226
227        silence_mask
228    }
229}
230
231#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
232pub enum MaskType {
233    Silence(SilenceMask),
234    Constant(ConstantMask),
235}
236
237impl Default for MaskType {
238    fn default() -> Self {
239        MaskType::Silence(Default::default())
240    }
241}
242
243/// An optional hint on which channels are connected to other
244/// nodes in the graph. A bit set to `1` means that channel
245/// is connected to another node, and a bit set to `0` means
246/// that channel is not connected to any node.
247///
248/// The first bit (`0x1`) is the first channel, the second bit
249/// is the second channel, and so on.
250#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
251pub struct ConnectedMask(pub u64);
252
253impl ConnectedMask {
254    pub const NONE_CONNECTED: Self = Self(0);
255    pub const MONO_CONNECTED: Self = Self(0b1);
256    pub const STEREO_CONNECTED: Self = Self(0b11);
257
258    /// Returns `true` if the channel is connected to another node,
259    /// `false` otherwise.
260    ///
261    /// `i` must be less than `64`.
262    pub const fn is_channel_connected(&self, i: usize) -> bool {
263        self.0 & (0b1 << i) != 0
264    }
265
266    /// Returns `true` if all channels are marked as connected, `false`
267    /// otherwise.
268    ///
269    /// `num_channels` must be less than or equal to `64`.
270    pub const fn all_channels_connected(&self, num_channels: usize) -> bool {
271        if num_channels >= 64 {
272            self.0 == u64::MAX
273        } else {
274            let mask = (0b1 << num_channels) - 1;
275            self.0 & mask == mask
276        }
277    }
278
279    /// Mark/un-mark the given channel as connected.
280    ///
281    /// `i` must be less than `64`.
282    pub fn set_channel(&mut self, i: usize, connected: bool) {
283        if connected {
284            self.0 |= 0b1 << i;
285        } else {
286            self.0 &= !(0b1 << i);
287        }
288    }
289}