voicemeeter/
types.rs

1//! Basic types used in voicemeeter
2
3/// A Zero Indexed Index
4#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
5#[repr(transparent)]
6pub struct ZIndex(pub(crate) i32);
7
8impl std::fmt::Display for ZIndex {
9    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
10        f.write_str(&self.0.to_string())
11    }
12}
13impl From<usize> for ZIndex {
14    fn from(i: usize) -> Self {
15        ZIndex(i as i32)
16    }
17}
18
19impl From<i32> for ZIndex {
20    fn from(i: i32) -> Self {
21        ZIndex(i)
22    }
23}
24
25impl From<u32> for ZIndex {
26    fn from(i: u32) -> Self {
27        ZIndex(i as i32)
28    }
29}
30
31/// A macro button. Zero indexed
32#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
33#[repr(transparent)]
34pub struct LogicalButton(pub ZIndex);
35
36impl std::fmt::Display for LogicalButton {
37    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38        write!(f, "MB:{}", self.0 .0)
39    }
40}
41
42impl From<usize> for LogicalButton {
43    fn from(i: usize) -> Self {
44        LogicalButton(ZIndex(i as i32))
45    }
46}
47
48impl From<i32> for LogicalButton {
49    fn from(i: i32) -> Self {
50        LogicalButton(ZIndex(i))
51    }
52}
53
54impl From<u32> for LogicalButton {
55    fn from(i: u32) -> Self {
56        LogicalButton(ZIndex(i as i32))
57    }
58}
59
60/// Voicemeeter Parameter
61#[aliri_braid::braid()]
62pub struct ParameterName;
63
64/// Voicemeeter application type.
65#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
66#[repr(C)]
67pub enum VoicemeeterApplication {
68    /// Standard "base" voicemeeter.
69    Voicemeeter = 1,
70    /// Voicemeeter Banana.
71    VoicemeeterBanana = 2,
72    /// Voicemeeter Potato.
73    VoicemeeterPotato = 3,
74    /// Voicemeeter Potato x64.
75    PotatoX64Bits = 6,
76    /// Unknown voicemeeter type
77    Other,
78    /// No voicmeeter running
79    None = 255,
80}
81
82impl VoicemeeterApplication {
83    /// Return all possible devices for this application
84    pub const fn devices(&self) -> &'static [Device] {
85        use self::Device::*;
86        match self {
87            VoicemeeterApplication::Voicemeeter => {
88                &[Strip1, Strip2, VirtualInput, OutputA1, VirtualOutputB1]
89            }
90            VoicemeeterApplication::VoicemeeterBanana => &[
91                Strip1,
92                Strip2,
93                Strip3,
94                VirtualInput,
95                VirtualInputAux,
96                OutputA1,
97                OutputA2,
98                OutputA3,
99                VirtualOutputB1,
100                VirtualOutputB2,
101            ],
102            VoicemeeterApplication::VoicemeeterPotato | VoicemeeterApplication::PotatoX64Bits => {
103                Device::all()
104            }
105            VoicemeeterApplication::Other | VoicemeeterApplication::None => &[],
106        }
107    }
108}
109
110impl std::fmt::Display for VoicemeeterApplication {
111    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
112        match self {
113            VoicemeeterApplication::Voicemeeter => f.write_str("Voicemeeter"),
114            VoicemeeterApplication::VoicemeeterBanana => f.write_str("VoicemeeterBanana"),
115            VoicemeeterApplication::VoicemeeterPotato => f.write_str("VoicemeeterPotato"),
116            VoicemeeterApplication::PotatoX64Bits => f.write_str("VoicemeeterPotatoX64Bits"),
117            VoicemeeterApplication::Other => f.write_str("VoicemeeterUnknown"),
118            VoicemeeterApplication::None => f.write_str("None"),
119        }
120    }
121}
122
123impl From<i32> for VoicemeeterApplication {
124    fn from(ty: i32) -> Self {
125        match ty {
126            1 => VoicemeeterApplication::Voicemeeter,
127            2 => VoicemeeterApplication::VoicemeeterBanana,
128            3 => VoicemeeterApplication::VoicemeeterPotato,
129            6 => VoicemeeterApplication::PotatoX64Bits,
130            _ => VoicemeeterApplication::Other,
131        }
132    }
133}
134
135/// Level type, used for [`VoicemeeterRemote::get_level`](super::VoicemeeterRemote::get_level)
136#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
137#[repr(C)]
138pub enum LevelType {
139    /// Pre fader input levels.
140    PreFaderInputLevels = 0,
141    /// Pre fader output levels.
142    PostFaderInputLevels = 1,
143    /// Post mute input levels.
144    PostMuteInputLevels = 2,
145    /// Output levels
146    OutputLevels = 3,
147    #[doc(hidden)]
148    Other,
149}
150
151impl From<i32> for LevelType {
152    fn from(ty: i32) -> Self {
153        match ty {
154            0 => LevelType::PreFaderInputLevels,
155            1 => LevelType::PostFaderInputLevels,
156            2 => LevelType::PostMuteInputLevels,
157            3 => LevelType::OutputLevels,
158            _ => LevelType::Other,
159        }
160    }
161}
162
163/// A device.
164#[derive(Debug, Clone, Copy, Eq, PartialEq)]
165pub enum Device {
166    /// Input Strip 1. Available on all Voicemeeter versions.
167    Strip1,
168    /// Input Strip 2. Available on all Voicemeeter versions.
169    Strip2,
170    /// Input Strip 3. Available on Voicemeeter Banana and Potato.
171    Strip3,
172    /// Input Strip 4. Available on Voicemeeter Potato.
173    Strip4,
174    /// Input Strip 5. Available on Voicemeeter Potato.
175    Strip5,
176    /// Output A1. Available on all Voicemeeter versions.
177    OutputA1,
178    /// Output A2. Available on all Voicemeeter versions.
179    OutputA2,
180    /// Output A3. Available on Voicemeeter Banana and Potato.
181    OutputA3,
182    /// Output A4. Available on Voicemeeter Potato.
183    OutputA4,
184    /// Output A5. Available on Voicemeeter Potato.
185    OutputA5,
186    /// Virtual Output B1. Available on all Voicemeeter versions.
187    VirtualOutputB1,
188    /// Virtual Output B2. Available on Voicemeeter Banana and Potato.
189    VirtualOutputB2,
190    /// Virtual Output B3. Available on Voicemeeter Potato.
191    VirtualOutputB3,
192    /// Virtual Input. Available on all Voicemeeter versions.
193    VirtualInput,
194    /// Virtual Input Aux. Available on Voicemeeter Banana and Potato.
195    VirtualInputAux,
196    /// Virtual Input8. Available on Voicemeeter Potato.
197    VirtualInput8,
198}
199
200impl std::str::FromStr for Device {
201    type Err = ParseDeviceError;
202
203    fn from_str(s: &str) -> Result<Self, Self::Err> {
204        match s.to_ascii_lowercase().replace(" ", "").as_str() {
205            "strip1" | "input1" => Ok(Device::Strip1),
206            "strip2" | "input2" => Ok(Device::Strip2),
207            "strip3" | "input3" => Ok(Device::Strip3),
208            "strip4" | "input4" => Ok(Device::Strip4),
209            "strip5" | "input5" => Ok(Device::Strip5),
210            "strip6" | "input6" | "vi" | "virtualinput" => Ok(Device::VirtualInput),
211            "strip7" | "input7" | "viaux" | "virtualinputaux" | "inputaux" => {
212                Ok(Device::VirtualInputAux)
213            }
214            "strip8" | "input8" | "vi8" | "virtualinput8" => Ok(Device::VirtualInput8),
215            "a1" | "outputa1" => Ok(Device::OutputA1),
216            "a2" | "outputa2" => Ok(Device::OutputA2),
217            "a3" | "outputa3" => Ok(Device::OutputA3),
218            "a4" | "outputa4" => Ok(Device::OutputA4),
219            "a5" | "outputa5" => Ok(Device::OutputA5),
220            "b1" | "virtualoutputb1" | "virtualb1" => Ok(Device::VirtualOutputB1),
221            "b2" | "virtualoutputb2" | "virtualb2" => Ok(Device::VirtualOutputB2),
222            "b3" | "virtualoutputb3" | "virtualb3" => Ok(Device::VirtualOutputB3),
223            _ => Err(ParseDeviceError(s.to_owned())),
224        }
225    }
226}
227
228#[derive(Debug, thiserror::Error, Clone)]
229#[error("could not parse device from string: {0}")]
230/// Error when parsing a device from a string
231pub struct ParseDeviceError(String);
232
233/// Index in the buffers for a [devices'](Device) channel.
234#[derive(Debug, Clone, Copy)]
235pub struct ChannelIndex {
236    /// Start index.
237    pub start: usize,
238    /// End index.
239    pub size: usize,
240}
241
242impl ChannelIndex {
243    /// Create a new index.
244    pub(crate) const fn new(start: usize, size: usize) -> Self {
245        Self { start, size }
246    }
247
248    /// Get the channel index for
249    pub fn get(&self, channel: usize) -> Option<usize> {
250        (self.start..(self.start + self.size)).nth(channel)
251    }
252}
253const fn ci(start: usize, size: usize) -> Option<ChannelIndex> {
254    Some(ChannelIndex::new(start, size))
255}
256
257impl Device {
258    /// Get the [`ChannelIndex`] for this channel in the buffers when in [main mode](crate::interface::callback::CallbackCommand::BufferMain), if available in the current program.
259    pub const fn main(
260        &self,
261        program: &VoicemeeterApplication,
262    ) -> (Option<ChannelIndex>, Option<ChannelIndex>) {
263        match program {
264            VoicemeeterApplication::Voicemeeter => match self {
265                Device::Strip1 => (ci(0, 2), None),
266                Device::Strip2 => (ci(2, 2), None),
267                Device::OutputA1 => (ci(12, 8), ci(0, 8)),
268                //Device::OutputA2 => (ci(12, 8), ci(0, 8)),
269                Device::VirtualOutputB1 => (ci(20, 8), ci(8, 8)),
270                Device::VirtualInput => (ci(4, 8), None),
271                _ => (None, None),
272            },
273            VoicemeeterApplication::VoicemeeterBanana => match self {
274                Device::Strip1 => (ci(0, 2), None),
275                Device::Strip2 => (ci(2, 2), None),
276                Device::Strip3 => (ci(4, 2), None),
277                Device::OutputA1 => (ci(22, 8), ci(0, 8)),
278                Device::OutputA2 => (ci(30, 8), ci(8, 8)),
279                Device::OutputA3 => (ci(38, 8), ci(16, 8)),
280                Device::VirtualOutputB1 => (ci(46, 8), ci(24, 8)),
281                Device::VirtualOutputB2 => (ci(54, 8), ci(32, 8)),
282                Device::VirtualInput => (ci(6, 8), None),
283                Device::VirtualInputAux => (ci(14, 8), None),
284                _ => (None, None),
285            },
286            VoicemeeterApplication::VoicemeeterPotato | VoicemeeterApplication::PotatoX64Bits => {
287                match self {
288                    Device::Strip1 => (ci(0, 2), None),
289                    Device::Strip2 => (ci(2, 2), None),
290                    Device::Strip3 => (ci(4, 2), None),
291                    Device::Strip4 => (ci(6, 2), None),
292                    Device::Strip5 => (ci(8, 2), None),
293                    Device::OutputA1 => (ci(34, 8), ci(0, 8)),
294                    Device::OutputA2 => (ci(42, 8), ci(8, 8)),
295                    Device::OutputA3 => (ci(50, 8), ci(16, 8)),
296                    Device::OutputA4 => (ci(58, 8), ci(24, 8)),
297                    Device::OutputA5 => (ci(66, 8), ci(32, 8)),
298                    Device::VirtualOutputB1 => (ci(74, 8), ci(40, 8)),
299                    Device::VirtualOutputB2 => (ci(82, 8), ci(48, 8)),
300                    Device::VirtualOutputB3 => (ci(82, 8), ci(56, 8)),
301                    Device::VirtualInput => (ci(10, 8), None),
302                    Device::VirtualInputAux => (ci(18, 8), None),
303                    Device::VirtualInput8 => (ci(26, 8), None),
304                }
305            }
306            _ => (None, None),
307        }
308    }
309    /// Get the [`ChannelIndex`] for this channel in the buffers when in [input mode](crate::interface::callback::CallbackCommand::BufferIn), if available in the current program.
310    pub const fn input(&self, program: &VoicemeeterApplication) -> Option<ChannelIndex> {
311        match self {
312            Device::OutputA1
313            | Device::OutputA2
314            | Device::OutputA3
315            | Device::OutputA4
316            | Device::OutputA5
317            | Device::VirtualOutputB1
318            | Device::VirtualOutputB2
319            | Device::VirtualOutputB3 => None,
320            _ => self.main(program).0,
321        }
322    }
323    /// Get the [`ChannelIndex`] for this channel in the buffers when in [output mode](crate::interface::callback::CallbackCommand::BufferOut), if available in the current program.
324    pub const fn output(&self, program: &VoicemeeterApplication) -> Option<ChannelIndex> {
325        self.main(program).1
326    }
327    /// Get all channels available.
328    pub const fn all() -> &'static [Self] {
329        &[
330            Device::Strip1,
331            Device::Strip2,
332            Device::Strip3,
333            Device::Strip4,
334            Device::Strip5,
335            Device::OutputA1,
336            Device::OutputA2,
337            Device::OutputA3,
338            Device::OutputA4,
339            Device::OutputA5,
340            Device::VirtualOutputB1,
341            Device::VirtualOutputB2,
342            Device::VirtualOutputB3,
343            Device::VirtualInput,
344            Device::VirtualInputAux,
345            Device::VirtualInput8,
346        ]
347    }
348
349    /// Gives the devices number for the current application for getting level.
350    pub(crate) fn as_level_device_num(
351        &self,
352        program: &VoicemeeterApplication,
353        level_type: LevelType,
354        channel: usize,
355    ) -> Option<usize> {
356        match level_type {
357            LevelType::PreFaderInputLevels
358            | LevelType::PostFaderInputLevels
359            | LevelType::PostMuteInputLevels => self.input(program)?.get(channel),
360            LevelType::OutputLevels => self.output(program)?.get(channel),
361            LevelType::Other => None,
362        }
363    }
364
365    /// Get the strip index for this device in the current program.
366    pub const fn as_strip_index(&self, program: &VoicemeeterApplication) -> Option<ZIndex> {
367        let i = match program {
368            VoicemeeterApplication::Voicemeeter => Some(match self {
369                Device::Strip1 => 0,
370                Device::Strip2 => 1,
371                Device::VirtualInput => 2,
372                _ => return None,
373            }),
374            VoicemeeterApplication::VoicemeeterBanana => Some(match self {
375                Device::Strip1 => 0,
376                Device::Strip2 => 1,
377                Device::Strip3 => 2,
378                Device::VirtualInput => 3,
379                Device::VirtualInputAux => 4,
380                _ => return None,
381            }),
382            VoicemeeterApplication::VoicemeeterPotato | VoicemeeterApplication::PotatoX64Bits => {
383                Some(match self {
384                    Device::Strip1 => 0,
385                    Device::Strip2 => 1,
386                    Device::Strip3 => 2,
387                    Device::Strip4 => 3,
388                    Device::Strip5 => 4,
389                    Device::VirtualInput => 5,
390                    Device::VirtualInputAux => 6,
391                    Device::VirtualInput8 => 7,
392                    _ => return None,
393                })
394            }
395            _ => return None,
396        };
397        match i {
398            Some(i) => Some(ZIndex(i)),
399            None => None,
400        }
401    }
402
403    /// Get the bus index for this device in the current program.
404    pub const fn as_bus_index(
405        &self,
406        program: &VoicemeeterApplication,
407    ) -> Option<(ZIndex, &'static str)> {
408        let i = match program {
409            VoicemeeterApplication::Voicemeeter => Some(match self {
410                Device::OutputA1 => (0, "A1"),
411                Device::OutputA2 => (1, "A2"),
412                Device::VirtualOutputB1 => (2, "B1"),
413                _ => return None,
414            }),
415            VoicemeeterApplication::VoicemeeterBanana => Some(match self {
416                Device::OutputA1 => (0, "A1"),
417                Device::OutputA2 => (1, "A2"),
418                Device::OutputA3 => (2, "A3"),
419                Device::VirtualOutputB1 => (3, "B1"),
420                Device::VirtualOutputB2 => (4, "B2"),
421                _ => return None,
422            }),
423            VoicemeeterApplication::VoicemeeterPotato | VoicemeeterApplication::PotatoX64Bits => {
424                Some(match self {
425                    Device::OutputA1 => (0, "A1"),
426                    Device::OutputA2 => (1, "A2"),
427                    Device::OutputA3 => (2, "A3"),
428                    Device::OutputA4 => (3, "A4"),
429                    Device::OutputA5 => (4, "A5"),
430                    Device::VirtualOutputB1 => (5, "B1"),
431                    Device::VirtualOutputB2 => (6, "B2"),
432                    Device::VirtualOutputB3 => (7, "B3"),
433                    _ => return None,
434                })
435            }
436            _ => return None,
437        };
438        match i {
439            Some((i, s)) => Some((ZIndex(i), s)),
440            None => None,
441        }
442    }
443
444    /// Check if this device is a strip
445    pub fn is_strip(&self) -> bool {
446        matches!(
447            self,
448            Device::Strip1
449                | Device::Strip2
450                | Device::Strip3
451                | Device::Strip4
452                | Device::Strip5
453                | Device::VirtualInput
454                | Device::VirtualInputAux
455                | Device::VirtualInput8
456        )
457    }
458
459    /// Check if this device is a bus
460    pub fn is_bus(&self) -> bool {
461        matches!(
462            self,
463            Device::OutputA1
464                | Device::OutputA2
465                | Device::OutputA3
466                | Device::OutputA4
467                | Device::OutputA5
468                | Device::VirtualOutputB1
469                | Device::VirtualOutputB2
470                | Device::VirtualOutputB3
471        )
472    }
473}
474
475/// Bus mode
476#[derive(Debug, Clone, Copy, PartialEq, Eq)]
477pub enum BusMode {
478    /// Bus mode normal
479    Normal,
480    /// Bus mode Amix
481    Amix,
482    /// Bus mode Bmix
483    Bmix,
484    /// Bus mode Repeat
485    Repeat,
486    /// Bus mode Composite
487    Composite,
488    /// Bus mode TVMix
489    TvMix,
490    /// Bus mode UpMix21
491    UpMix21,
492    /// Bus mode UpMix41
493    UpMix41,
494    /// Bus mode UpMix61
495    UpMix61,
496    /// Bus mode CenterOnly
497    CenterOnly,
498    /// Bus mode LFEOnly
499    LfeOnly,
500    /// Bus mode RearOnly
501    RearOnly,
502}
503
504impl std::fmt::Display for BusMode {
505    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
506        match self {
507            BusMode::Normal => f.write_str("normal"),
508            BusMode::Amix => f.write_str("Amix"),
509            BusMode::Bmix => f.write_str("Bmix"),
510            BusMode::Repeat => f.write_str("Repeat"),
511            BusMode::Composite => f.write_str("Composite"),
512            BusMode::TvMix => f.write_str("TVMix"),
513            BusMode::UpMix21 => f.write_str("UpMix21"),
514            BusMode::UpMix41 => f.write_str("UpMix41"),
515            BusMode::UpMix61 => f.write_str("UpMix61"),
516            BusMode::CenterOnly => f.write_str("CenterOnly"),
517            BusMode::LfeOnly => f.write_str("LFEOnly"),
518            BusMode::RearOnly => f.write_str("RearOnly"),
519        }
520    }
521}