Skip to main content

vmix_tcp/
acts.rs

1use crate::commands::InputNumber;
2
3#[derive(Debug)]
4pub enum ActivatorsData {
5    Input(InputNumber, bool),
6    InputMix2(InputNumber, bool),
7    InputMix3(InputNumber, bool),
8    InputMix4(InputNumber, bool),
9    InputMix5(InputNumber, bool),
10    InputMix6(InputNumber, bool),
11    InputMix7(InputNumber, bool),
12    InputMix8(InputNumber, bool),
13    InputMix9(InputNumber, bool),
14    InputMix10(InputNumber, bool),
15    InputMix11(InputNumber, bool),
16    InputMix12(InputNumber, bool),
17    InputMix13(InputNumber, bool),
18    InputMix14(InputNumber, bool),
19    InputMix15(InputNumber, bool),
20    InputMix16(InputNumber, bool),
21    InputPreview(InputNumber, bool),
22    InputPreviewMix2(InputNumber, bool),
23    InputPreviewMix3(InputNumber, bool),
24    InputPreviewMix4(InputNumber, bool),
25    InputPreviewMix5(InputNumber, bool),
26    InputPreviewMix6(InputNumber, bool),
27    InputPreviewMix7(InputNumber, bool),
28    InputPreviewMix8(InputNumber, bool),
29    InputPreviewMix9(InputNumber, bool),
30    InputPreviewMix10(InputNumber, bool),
31    InputPreviewMix11(InputNumber, bool),
32    InputPreviewMix12(InputNumber, bool),
33    InputPreviewMix13(InputNumber, bool),
34    InputPreviewMix14(InputNumber, bool),
35    InputPreviewMix15(InputNumber, bool),
36    InputPreviewMix16(InputNumber, bool),
37    InputPlaying(InputNumber, bool),
38    InputVolume(InputNumber, f32),
39    InputHeadphones(InputNumber, f32),
40    MasterVolume(f32),
41    MasterHeadphones(f32),
42    BusAVolume(f32),
43    BusBVolume(f32),
44    BusCVolume(f32),
45    BusDVolume(f32),
46    BusEVolume(f32),
47    BusFVolume(f32),
48    BusGVolume(f32),
49    InputAudio(InputNumber, bool),
50    InputSolo(InputNumber, bool),
51    InputBusAAudio(InputNumber, bool),
52    InputBusBAudio(InputNumber, bool),
53    InputBusCAudio(InputNumber, bool),
54    InputBusDAudio(InputNumber, bool),
55    InputBusEAudio(InputNumber, bool),
56    InputBusFAudio(InputNumber, bool),
57    InputBusGAudio(InputNumber, bool),
58    InputMasterAudio(InputNumber, bool),
59    MasterAudio(bool),
60    BusAAudio(bool),
61    BusBAudio(bool),
62    BusCAudio(bool),
63    BusDAudio(bool),
64    BusEAudio(bool),
65    BusFAudio(bool),
66    BusGAudio(bool),
67    BusASolo(bool),
68    BusBSolo(bool),
69    BusCSolo(bool),
70    BusDSolo(bool),
71    BusESolo(bool),
72    BusFSolo(bool),
73    BusGSolo(bool),
74    FadeToBlack(bool),
75    Recording(bool),
76    Streaming(bool),
77    External(bool),
78    Fullscreen(bool),
79    Overlay1(InputNumber, bool),
80    Overlay2(InputNumber, bool),
81    Overlay3(InputNumber, bool),
82    Overlay4(InputNumber, bool),
83    ReplayPlaying(bool),
84    /// Unknown activator type with raw data
85    Unknown(Vec<String>),
86}
87
88// ActivatorsDataはマルチスレッド環境で安全に使用できる
89unsafe impl Send for ActivatorsData {}
90unsafe impl Sync for ActivatorsData {}
91
92// Helper functions to extract common functionality and handle errors safely
93fn parse_input_number(value: &str) -> InputNumber {
94    value.parse::<InputNumber>().unwrap_or(0)
95}
96
97fn parse_float(value: &str) -> f32 {
98    value.parse::<f32>().unwrap_or(0.0)
99}
100
101fn is_active(value: &str) -> bool {
102    value == "1"
103}
104
105// Higher-level helper functions for common patterns
106fn create_input_bool_variant(
107    values: &[String],
108    idx: usize,
109) -> Result<ActivatorsData, anyhow::Error> {
110    if values.len() <= idx + 1 {
111        // Not enough values, store as Unknown
112        return Ok(ActivatorsData::Unknown(values.to_vec()));
113    }
114
115    let input_num = parse_input_number(&values[idx]);
116    let is_active_val = if values.len() > idx + 1 {
117        is_active(&values[idx + 1])
118    } else {
119        false
120    };
121
122    match values[0].as_str() {
123        "Input" => Ok(ActivatorsData::Input(input_num, is_active_val)),
124        "InputMix2" => Ok(ActivatorsData::InputMix2(input_num, is_active_val)),
125        "InputMix3" => Ok(ActivatorsData::InputMix3(input_num, is_active_val)),
126        "InputMix4" => Ok(ActivatorsData::InputMix4(input_num, is_active_val)),
127        "InputMix5" => Ok(ActivatorsData::InputMix5(input_num, is_active_val)),
128        "InputMix6" => Ok(ActivatorsData::InputMix6(input_num, is_active_val)),
129        "InputMix7" => Ok(ActivatorsData::InputMix7(input_num, is_active_val)),
130        "InputMix8" => Ok(ActivatorsData::InputMix8(input_num, is_active_val)),
131        "InputMix9" => Ok(ActivatorsData::InputMix9(input_num, is_active_val)),
132        "InputMix10" => Ok(ActivatorsData::InputMix10(input_num, is_active_val)),
133        "InputMix11" => Ok(ActivatorsData::InputMix11(input_num, is_active_val)),
134        "InputMix12" => Ok(ActivatorsData::InputMix12(input_num, is_active_val)),
135        "InputMix13" => Ok(ActivatorsData::InputMix13(input_num, is_active_val)),
136        "InputMix14" => Ok(ActivatorsData::InputMix14(input_num, is_active_val)),
137        "InputMix15" => Ok(ActivatorsData::InputMix15(input_num, is_active_val)),
138        "InputMix16" => Ok(ActivatorsData::InputMix16(input_num, is_active_val)),
139        "InputPreview" => Ok(ActivatorsData::InputPreview(input_num, is_active_val)),
140        "InputPreviewMix2" => Ok(ActivatorsData::InputPreviewMix2(input_num, is_active_val)),
141        "InputPreviewMix3" => Ok(ActivatorsData::InputPreviewMix3(input_num, is_active_val)),
142        "InputPreviewMix4" => Ok(ActivatorsData::InputPreviewMix4(input_num, is_active_val)),
143        "InputPreviewMix5" => Ok(ActivatorsData::InputPreviewMix5(input_num, is_active_val)),
144        "InputPreviewMix6" => Ok(ActivatorsData::InputPreviewMix6(input_num, is_active_val)),
145        "InputPreviewMix7" => Ok(ActivatorsData::InputPreviewMix7(input_num, is_active_val)),
146        "InputPreviewMix8" => Ok(ActivatorsData::InputPreviewMix8(input_num, is_active_val)),
147        "InputPreviewMix9" => Ok(ActivatorsData::InputPreviewMix9(input_num, is_active_val)),
148        "InputPreviewMix10" => Ok(ActivatorsData::InputPreviewMix10(input_num, is_active_val)),
149        "InputPreviewMix11" => Ok(ActivatorsData::InputPreviewMix11(input_num, is_active_val)),
150        "InputPreviewMix12" => Ok(ActivatorsData::InputPreviewMix12(input_num, is_active_val)),
151        "InputPreviewMix13" => Ok(ActivatorsData::InputPreviewMix13(input_num, is_active_val)),
152        "InputPreviewMix14" => Ok(ActivatorsData::InputPreviewMix14(input_num, is_active_val)),
153        "InputPreviewMix15" => Ok(ActivatorsData::InputPreviewMix15(input_num, is_active_val)),
154        "InputPreviewMix16" => Ok(ActivatorsData::InputPreviewMix16(input_num, is_active_val)),
155        "InputPlaying" => Ok(ActivatorsData::InputPlaying(input_num, is_active_val)),
156        "InputAudio" => Ok(ActivatorsData::InputAudio(input_num, is_active_val)),
157        "InputSolo" => Ok(ActivatorsData::InputSolo(input_num, is_active_val)),
158        "InputBusAAudio" => Ok(ActivatorsData::InputBusAAudio(input_num, is_active_val)),
159        "InputBusBAudio" => Ok(ActivatorsData::InputBusBAudio(input_num, is_active_val)),
160        "InputBusCAudio" => Ok(ActivatorsData::InputBusCAudio(input_num, is_active_val)),
161        "InputBusDAudio" => Ok(ActivatorsData::InputBusDAudio(input_num, is_active_val)),
162        "InputBusEAudio" => Ok(ActivatorsData::InputBusEAudio(input_num, is_active_val)),
163        "InputBusFAudio" => Ok(ActivatorsData::InputBusFAudio(input_num, is_active_val)),
164        "InputBusGAudio" => Ok(ActivatorsData::InputBusGAudio(input_num, is_active_val)),
165        "InputMasterAudio" => Ok(ActivatorsData::InputMasterAudio(input_num, is_active_val)),
166        "Overlay1" => Ok(ActivatorsData::Overlay1(input_num, is_active_val)),
167        "Overlay2" => Ok(ActivatorsData::Overlay2(input_num, is_active_val)),
168        "Overlay3" => Ok(ActivatorsData::Overlay3(input_num, is_active_val)),
169        "Overlay4" => Ok(ActivatorsData::Overlay4(input_num, is_active_val)),
170        _ => Ok(ActivatorsData::Unknown(values.to_vec())),
171    }
172}
173
174fn create_input_float_variant(
175    values: &[String],
176    idx: usize,
177) -> Result<ActivatorsData, anyhow::Error> {
178    if values.len() <= idx + 1 {
179        // Not enough values, store as Unknown
180        return Ok(ActivatorsData::Unknown(values.to_vec()));
181    }
182
183    let input_num = parse_input_number(&values[idx]);
184    let volume = if values.len() > idx + 1 {
185        parse_float(&values[idx + 1])
186    } else {
187        0.0
188    };
189
190    match values[0].as_str() {
191        "InputVolume" => Ok(ActivatorsData::InputVolume(input_num, volume)),
192        "InputHeadphones" => Ok(ActivatorsData::InputHeadphones(input_num, volume)),
193        _ => Ok(ActivatorsData::Unknown(values.to_vec())),
194    }
195}
196
197fn create_single_float_variant(
198    values: &[String],
199    idx: usize,
200) -> Result<ActivatorsData, anyhow::Error> {
201    if values.len() <= idx {
202        // Not enough values, store as Unknown
203        return Ok(ActivatorsData::Unknown(values.to_vec()));
204    }
205
206    let volume = parse_float(&values[idx]);
207
208    match values[0].as_str() {
209        "MasterVolume" => Ok(ActivatorsData::MasterVolume(volume)),
210        "MasterHeadphones" => Ok(ActivatorsData::MasterHeadphones(volume)),
211        "BusAVolume" => Ok(ActivatorsData::BusAVolume(volume)),
212        "BusBVolume" => Ok(ActivatorsData::BusBVolume(volume)),
213        "BusCVolume" => Ok(ActivatorsData::BusCVolume(volume)),
214        "BusDVolume" => Ok(ActivatorsData::BusDVolume(volume)),
215        "BusEVolume" => Ok(ActivatorsData::BusEVolume(volume)),
216        "BusFVolume" => Ok(ActivatorsData::BusFVolume(volume)),
217        "BusGVolume" => Ok(ActivatorsData::BusGVolume(volume)),
218        _ => Ok(ActivatorsData::Unknown(values.to_vec())),
219    }
220}
221
222fn create_single_bool_variant(
223    values: &[String],
224    idx: usize,
225) -> Result<ActivatorsData, anyhow::Error> {
226    if values.len() <= idx {
227        // Not enough values, store as Unknown
228        return Ok(ActivatorsData::Unknown(values.to_vec()));
229    }
230
231    let is_active_val = is_active(&values[idx]);
232
233    match values[0].as_str() {
234        "MasterAudio" => Ok(ActivatorsData::MasterAudio(is_active_val)),
235        "BusAAudio" => Ok(ActivatorsData::BusAAudio(is_active_val)),
236        "BusBAudio" => Ok(ActivatorsData::BusBAudio(is_active_val)),
237        "BusCAudio" => Ok(ActivatorsData::BusCAudio(is_active_val)),
238        "BusDAudio" => Ok(ActivatorsData::BusDAudio(is_active_val)),
239        "BusEAudio" => Ok(ActivatorsData::BusEAudio(is_active_val)),
240        "BusFAudio" => Ok(ActivatorsData::BusFAudio(is_active_val)),
241        "BusGAudio" => Ok(ActivatorsData::BusGAudio(is_active_val)),
242        "BusASolo" => Ok(ActivatorsData::BusASolo(is_active_val)),
243        "BusBSolo" => Ok(ActivatorsData::BusBSolo(is_active_val)),
244        "BusCSolo" => Ok(ActivatorsData::BusCSolo(is_active_val)),
245        "BusDSolo" => Ok(ActivatorsData::BusDSolo(is_active_val)),
246        "BusESolo" => Ok(ActivatorsData::BusESolo(is_active_val)),
247        "BusFSolo" => Ok(ActivatorsData::BusFSolo(is_active_val)),
248        "BusGSolo" => Ok(ActivatorsData::BusGSolo(is_active_val)),
249        "FadeToBlack" => Ok(ActivatorsData::FadeToBlack(is_active_val)),
250        "Recording" => Ok(ActivatorsData::Recording(is_active_val)),
251        "Streaming" => Ok(ActivatorsData::Streaming(is_active_val)),
252        "External" => Ok(ActivatorsData::External(is_active_val)),
253        "Fullscreen" => Ok(ActivatorsData::Fullscreen(is_active_val)),
254        "ReplayPlaying" => Ok(ActivatorsData::ReplayPlaying(is_active_val)),
255        _ => Ok(ActivatorsData::Unknown(values.to_vec())),
256    }
257}
258
259impl TryFrom<&[String]> for ActivatorsData {
260    type Error = anyhow::Error;
261    fn try_from(value: &[String]) -> Result<Self, Self::Error> {
262        if value.is_empty() {
263            // Empty value array, store as Unknown
264            return Ok(ActivatorsData::Unknown(value.to_vec()));
265        }
266
267        let activator_type = value[0].as_str();
268
269        // Group activators by their parameter patterns
270        match activator_type {
271            // Input with boolean (InputNumber, bool)
272            "Input" | "InputMix2" | "InputMix3" | "InputMix4" | "InputMix5" | "InputMix6"
273            | "InputMix7" | "InputMix8" | "InputMix9" | "InputMix10" | "InputMix11"
274            | "InputMix12" | "InputMix13" | "InputMix14" | "InputMix15" | "InputMix16"
275            | "InputPreview" | "InputPreviewMix2" | "InputPreviewMix3" | "InputPreviewMix4"
276            | "InputPreviewMix5" | "InputPreviewMix6" | "InputPreviewMix7" | "InputPreviewMix8"
277            | "InputPreviewMix9" | "InputPreviewMix10" | "InputPreviewMix11"
278            | "InputPreviewMix12" | "InputPreviewMix13" | "InputPreviewMix14"
279            | "InputPreviewMix15" | "InputPreviewMix16" | "InputPlaying" | "InputAudio"
280            | "InputSolo" | "InputBusAAudio" | "InputBusBAudio" | "InputBusCAudio"
281            | "InputBusDAudio" | "InputBusEAudio" | "InputBusFAudio" | "InputBusGAudio"
282            | "InputMasterAudio" | "Overlay1" | "Overlay2" | "Overlay3" | "Overlay4" => {
283                create_input_bool_variant(value, 1)
284            }
285
286            // Input with float (InputNumber, f32)
287            "InputVolume" | "InputHeadphones" => create_input_float_variant(value, 1),
288
289            // Single float (f32)
290            "MasterVolume" | "MasterHeadphones" | "BusAVolume" | "BusBVolume" | "BusCVolume"
291            | "BusDVolume" | "BusEVolume" | "BusFVolume" | "BusGVolume" => {
292                create_single_float_variant(value, 1)
293            }
294
295            // Single boolean (bool)
296            "MasterAudio" | "BusAAudio" | "BusBAudio" | "BusCAudio" | "BusDAudio" | "BusEAudio"
297            | "BusFAudio" | "BusGAudio" | "BusASolo" | "BusBSolo" | "BusCSolo" | "BusDSolo"
298            | "BusESolo" | "BusFSolo" | "BusGSolo" | "FadeToBlack" | "Recording" | "Streaming"
299            | "External" | "Fullscreen" | "ReplayPlaying" => create_single_bool_variant(value, 1),
300
301            _ => {
302                // Store unknown activators with raw data instead of failing
303                Ok(ActivatorsData::Unknown(value.to_vec()))
304            }
305        }
306    }
307}