1#[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#[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#[aliri_braid::braid()]
62pub struct ParameterName;
63
64#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
66#[repr(C)]
67pub enum VoicemeeterApplication {
68 Voicemeeter = 1,
70 VoicemeeterBanana = 2,
72 VoicemeeterPotato = 3,
74 PotatoX64Bits = 6,
76 Other,
78 None = 255,
80}
81
82impl VoicemeeterApplication {
83 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#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
137#[repr(C)]
138pub enum LevelType {
139 PreFaderInputLevels = 0,
141 PostFaderInputLevels = 1,
143 PostMuteInputLevels = 2,
145 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#[derive(Debug, Clone, Copy, Eq, PartialEq)]
165pub enum Device {
166 Strip1,
168 Strip2,
170 Strip3,
172 Strip4,
174 Strip5,
176 OutputA1,
178 OutputA2,
180 OutputA3,
182 OutputA4,
184 OutputA5,
186 VirtualOutputB1,
188 VirtualOutputB2,
190 VirtualOutputB3,
192 VirtualInput,
194 VirtualInputAux,
196 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}")]
230pub struct ParseDeviceError(String);
232
233#[derive(Debug, Clone, Copy)]
235pub struct ChannelIndex {
236 pub start: usize,
238 pub size: usize,
240}
241
242impl ChannelIndex {
243 pub(crate) const fn new(start: usize, size: usize) -> Self {
245 Self { start, size }
246 }
247
248 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 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::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 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 pub const fn output(&self, program: &VoicemeeterApplication) -> Option<ChannelIndex> {
325 self.main(program).1
326 }
327 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 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 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 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 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 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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
477pub enum BusMode {
478 Normal,
480 Amix,
482 Bmix,
484 Repeat,
486 Composite,
488 TvMix,
490 UpMix21,
492 UpMix41,
494 UpMix61,
496 CenterOnly,
498 LfeOnly,
500 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}