firewire_dice_protocols/tcelectronic/
studio.rs

1// SPDX-License-Identifier: LGPL-3.0-or-later
2// Copyright (c) 2020 Takashi Sakamoto
3
4//! Protocol defined by TC Electronic for Studio Konnekt 48.
5//!
6//! The module includes structure, enumeration, and trait and its implementation for protocol
7//! defined by TC Electronic for Studio Konnekt 48.
8//!
9//! ## Diagram of internal signal flow
10//!
11//! ```text
12//!
13//! XLR input 1 ----------------or----+--------------------------> analog-input-1/2
14//! Phone input 1 --------------+     |
15//!                                   |
16//! XLR input 2 ----------------or----+
17//! Phone input 2 --------------+
18//!
19//! XLR input 3 ----------------or----+--------------------------> analog-input-3/4
20//! Phone input 3 --------------+     |
21//!                                   |
22//! XLR input 4 ----------------or----+
23//! Phone input 4 --------------+
24//!
25//! Phone input 5/6 ---------------------------------------------> analog-input-5/6
26//! Phone input 7/8 ---------------------------------------------> analog-input-7/8
27//! Phone input 9/10 --------------------------------------------> analog-input-9/10
28//!
29//! Phone input 11/12 ----------+--------------------------------> analog-input-11/12
30//! Mic in remote controller ---+
31//!
32//! Coaxial input 1/2 -------------------------------------------> coaxial-input-1/2
33//!
34//! Optical input 1 ------------+--------------------------------> optical-input-1..8
35//! Optical input 2 ------------+
36//!
37//!
38//! analog-input-1/2 --------------------------------------------> stream-output-A-1/2
39//! analog-input-3/4 --------------------------------------------> stream-output-A-3/4
40//! analog-input-5/6 --------------------------------------------> stream-output-A-5/6
41//! analog-input-7/8 --------------------------------------------> stream-output-A-7/8
42//! analog-input-9/10 -------------------------------------------> stream-output-A-9/10
43//! analog-input-11/12 ------------------------------------------> stream-output-A-11/12
44//! (blank) -----------------------------------------------------> stream-output-A-13/14
45//! coaxial-input-1/2 -------------------------------------------> stream-output-A-15/16
46//! optical-input-1..8 ------------------------------------------> stream-output-B-1..8
47//! channel-strip-effect-output-1/2 -----------------------------> stream-output-B-9/10
48//! channel-strip-effect-output-3/4 -----------------------------> stream-output-B-11/12
49//! reverb-effect-output-1/2 ------------------------------------> stream-output-B-13/14
50//! aux-output-1/2 ----------------------------------------------> stream-output-B-15/16
51//!
52//!
53//!                                            ++============++
54//! analog-input-1/2 ----+                     ||            ||
55//! analog-input-3/4 ----+                     ||            ||
56//! analog-input-5/6 ----+                     ||            ||
57//! analog-input-7/8 ----+                     ||            ||
58//! analog-input-9/10 ---+                     ||  channel   ||
59//! analog-input-11/12 --+-- (one of them) --> ||   strip    || --> channel-strip-effect-output-1/2
60//! coaxial-input-1/2 ---+  (internal mode)    ||  effects   ||     (can replace original signal)
61//! optical-input-1/2 ---+                     ||    1/2     ||
62//! optical-input-3/4 ---+                     ||            ||
63//! optical-input-5/6 ---+                     ||            ||
64//! optical-input-7/8 ---+                     ||            ||
65//! stream-input-B-9/10 ---- (plugin mode) --> ||            ||
66//!                                            ++============++
67//!
68//!                                            ++============++
69//! analog-input-1/2 ----+                     ||            ||
70//! analog-input-3/4 ----+                     ||            ||
71//! analog-input-5/6 ----+                     ||            ||
72//! analog-input-7/8 ----+                     ||            ||
73//! analog-input-9/10 ---+                     ||  channel   ||
74//! analog-input-11/12 --+-- (one of them) --> ||   strip    || --> channel-strip-effect-output-3/4
75//! coaxial-input-1/2 ---+  (internal mode)    ||  effects   ||     (can replace original signal)
76//! optical-input-1/2 ---+                     ||    3/4     ||
77//! optical-input-3/4 ---+                     ||            ||
78//! optical-input-5/6 ---+                     ||            ||
79//! optical-input-7/8 ---+                     ||            ||
80//! stream-input-B-11/12 --- (plugin mode) --> ||            ||
81//!                                            ++============++
82//!
83//!                                            ++============++
84//! analog-input-1/2 ------------------------> ||            ||
85//! analog-input-3/4 ------------------------> ||            ||
86//! analog-input-5/6 ------------------------> ||            ||
87//! analog-input-7/8 ------------------------> ||            ||
88//! analog-input-9/10 -----------------------> ||            ||
89//! analog-input-11/12 ----------------------> ||            ||
90//! coaxial-input-1/2 -----------------------> ||            || --> mixer-source-1/2
91//! optical-input-1/2 -----------------------> ||            || --> mixer-source-3/4
92//! optical-input-3/4 -----------------------> ||            || --> mixer-source-5/6
93//! optical-input-5/6 -----------------------> ||            || --> mixer-source-7/8
94//! optical-input-7/8 -----------------------> ||  44 x 24   || --> mixer-source-9/10
95//!                                            ||            || --> mixer-source-11/12
96//! stream-input-A-1/2 ----------------------> ||            || --> mixer-source-13/14
97//! stream-input-A-3/4 ----------------------> ||   router   || --> mixer-source-15/16
98//! stream-input-A-5/6 ----------------------> ||            || --> mixer-source-17/18
99//! stream-input-A-7/8 ----------------------> ||            || --> mixer-source-19/20
100//! stream-input-A-9/10 ---------------------> ||            || --> mixer-source-21/22
101//! stream-input-A-11/12 --------------------> ||            || --> mixer-source-23/24
102//! stream-input-A-13/14 (unused)              ||            ||
103//! stream-input-A-15/16 --------------------> ||            ||
104//!                                            ||            ||
105//! stream-input-B-1/2 ----------------------> ||            ||
106//! stream-input-B-3/4 ----------------------> ||            ||
107//! stream-input-B-5/6 ----------------------> ||            ||
108//! stream-input-B-7/8 ----------------------> ||            ||
109//!                                            ++============++
110//!
111//!                                            ++============++
112//! mixer-source-1/2 ----- (internal mode) --> ||            ||
113//! mixer-source-3/4 ----- (internal mode) --> ||            ||
114//! mixer-source-5/6 ----- (internal mode) --> ||            ||
115//! mixer-source-7/8 ----- (internal mode) --> ||            ||
116//! mixer-source-9/10 ---- (internal mode) --> ||   24 x 2   ||
117//! mixer-source-11/12 --- (internal mode) --> ||            ||
118//! mixer-source-13/14 --- (internal mode) --> ||   reverb   || --> reverb-effect-output-1/2
119//! mixer-source-15/16 --- (internal mode) --> ||            ||
120//! mixer-source-17/18 --- (internal mode) --> ||   effect   ||
121//! mixer-source-19/20 --- (internal mode) --> ||            ||
122//! mixer-source-21/22 --- (internal mode) --> ||            ||
123//! mixer-source-23/24 --- (internal mode) --> ||            ||
124//! stream-input-B-13/14 --(plugin mode) ----> ||            ||
125//!                                            ++============++
126//!
127//!                                            ++============++
128//! mixer-source-1/2 ------------------------> ||            ||
129//! mixer-source-3/4 ------------------------> ||            ||
130//! mixer-source-5/6 ------------------------> ||            ||
131//! mixer-source-7/8 ------------------------> ||   24 x 2   ||
132//! mixer-source-9/10 -----------------------> ||            ||
133//! mixer-source-11/12 ----------------------> ||   main     ||
134//! mixer-source-13/14 ----------------------> ||            || --> aux-output-3/4
135//! mixer-source-15/16 ----------------------> ||   mixer    ||
136//! mixer-source-17/18 ----------------------> ||            ||
137//! mixer-source-19/20 ----------------------> ||    3/4     ||
138//! mixer-source-21/22 ----------------------> ||            ||
139//! mixer-source-23/24 ----------------------> ||            ||
140//! reverb-effect-output-1/2 ----------------> ||            ||
141//!                                            ++============++
142//!
143//!                                            ++============++
144//! mixer-source-1/2 ------------------------> ||            ||
145//! mixer-source-3/4 ------------------------> ||            ||
146//! mixer-source-5/6 ------------------------> ||            ||
147//! mixer-source-7/8 ------------------------> ||   24 x 2   ||
148//! mixer-source-9/10 -----------------------> ||            ||
149//! mixer-source-11/12 ----------------------> || auxiliary  ||
150//! mixer-source-13/14 ----------------------> ||            || --> aux-output-1/2
151//! mixer-source-15/16 ----------------------> ||   mixer    ||
152//! mixer-source-17/18 ----------------------> ||            ||
153//! mixer-source-19/20 ----------------------> ||    1/2     ||
154//! mixer-source-21/22 ----------------------> ||            ||
155//! mixer-source-23/24 ----------------------> ||            ||
156//! reverb-effect-output-1/2 ----------------> ||            ||
157//!                                            ++============++
158//!
159//!                                            ++============++
160//! mixer-source-1/2 ------------------------> ||            ||
161//! mixer-source-3/4 ------------------------> ||            ||
162//! mixer-source-5/6 ------------------------> ||            ||
163//! mixer-source-7/8 ------------------------> ||   24 x 2   ||
164//! mixer-source-9/10 -----------------------> ||            ||
165//! mixer-source-11/12 ----------------------> || auxiliary  ||
166//! mixer-source-13/14 ----------------------> ||            || --> aux-output-3/4
167//! mixer-source-15/16 ----------------------> ||   mixer    ||
168//! mixer-source-17/18 ----------------------> ||            ||
169//! mixer-source-19/20 ----------------------> ||    3/4     ||
170//! mixer-source-21/22 ----------------------> ||            ||
171//! mixer-source-23/24 ----------------------> ||            ||
172//! reverb-effect-output-1/2 ----------------> ||            ||
173//!                                            ++============++
174//!
175//!                                            ++==========++
176//! analog-input-1/2 ------------------------> ||          ||
177//! analog-input-3/4 ------------------------> ||          ||
178//! analog-input-5/6 ------------------------> ||          ||
179//! analog-input-7/8 ------------------------> ||          ||
180//! analog-input-9/10 -----------------------> ||          ||
181//! analog-input-11/12 ----------------------> ||          ||
182//! coaxial-input-1/2 -----------------------> ||          ||
183//! optical-input-1/2 -----------------------> ||          ||
184//! optical-input-3/4 -----------------------> ||          || --> analog-output-1/2
185//! optical-input-5/6 -----------------------> ||          || --> headphone-output-1/2
186//! optical-input-7/8 -----------------------> || 54 x 24  || --> analog-output-5/6
187//!                                            ||          || --> analog-output-7/8
188//! stream-input-A-1/2 ----------------------> ||          || --> analog-output-9/10
189//! stream-input-A-3/4 ----------------------> ||  router  || --> analog-output-11/12
190//! stream-input-A-5/6 ----------------------> ||          || --> headphone-output-3/4
191//! stream-input-A-7/8 ----------------------> ||          || --> coaxial-output-1/2
192//! stream-input-A-9/10 ---------------------> ||          || --> coaxial-output-1/2
193//! stream-input-A-11/12 --------------------> ||          || --> optical-output-1..8
194//! stream-input-A-13/14 (unused)              ||          ||
195//! stream-input-A-15/16 --------------------> ||          ||
196//!                                            ||          ||
197//! stream-input-B-1/2 ----------------------> ||          ||
198//! stream-input-B-3/4 ----------------------> ||          ||
199//! stream-input-B-5/6 ----------------------> ||          ||
200//! stream-input-B-7/8 ----------------------> ||          ||
201//!                                            ||          ||
202//! mixer-output-1/2 ------------------------> ||          ||
203//! aux-output-1/2 --------------------------> ||          ||
204//! aux-output-3/4 --------------------------> ||          ||
205//! reverb-output-1/2 -----------------------> ||          ||
206//!                                            ++==========++
207//!
208//! ```
209
210use super::{ch_strip::*, reverb::*, *};
211
212/// Protocol implementation of Studio Konnekt 48.
213#[derive(Default, Debug)]
214pub struct Studiok48Protocol;
215
216impl TcatOperation for Studiok48Protocol {}
217
218impl TcatGlobalSectionSpecification for Studiok48Protocol {}
219
220/// Segment for output level. 0x0000..0x0013 (4 quads).
221pub type Studiok48LineOutLevelSegment = TcKonnektSegment<StudioLineOutLevel>;
222
223/// Segment for remote controller. 0x0014..0x0043 (12 quads).
224pub type Studiok48RemoteSegment = TcKonnektSegment<StudioRemote>;
225
226/// Segment for configuration. 0x0044..0x00a7 (25 quads).
227pub type Studiok48ConfigSegment = TcKonnektSegment<StudioConfig>;
228
229/// Segment for state of mixer. 0x00a8..0x03db (205 quads).
230pub type Studiok48MixerStateSegment = TcKonnektSegment<StudioMixerState>;
231
232/// Segment for physical output. 0x03dc..0x0593 (110 quads).
233pub type Studiok48PhysOutSegment = TcKonnektSegment<StudioPhysOut>;
234
235/// Segment for state of reverb effect. 0x0594..0x05d7. (17 quads)
236pub type Studiok48ReverbStateSegment = TcKonnektSegment<StudioReverbState>;
237
238/// Segment for states of channel strip effect. 0x05dc..0x081f (145 quads).
239pub type Studiok48ChStripStatesSegment = TcKonnektSegment<StudioChStripStates>;
240
241// NOTE: Segment for tuner. 0x0820..0x083f (8 quads).
242
243/// Segment for state of hardware. 0x2008..0x204b (17 quads).
244pub type Studiok48HwStateSegment = TcKonnektSegment<StudioHwState>;
245
246// NOTE: Segment for meter of remote controller. 0x204c..0x205b (4 quads).
247
248/// Segment for meter of mixer. 0x20b8..0x2137 (32 quads).
249pub type Studiok48MixerMeterSegment = TcKonnektSegment<StudioMixerMeter>;
250
251// NOTE: Segment for inidentified meter. 0x2138..0x2163 (11 quads).
252
253/// Segment for meter of reverb effect. 0x2164..0x217b (6 quads).
254pub type Studiok48ReverbMeterSegment = TcKonnektSegment<StudioReverbMeter>;
255
256/// Segment for meters of channel strip effect. 0x217c..0x21b7 (30 quads).
257pub type Studiok48ChStripMetersSegment = TcKonnektSegment<StudioChStripMeters>;
258
259macro_rules! segment_default {
260    ($p:ty, $t:ty) => {
261        impl Default for TcKonnektSegment<$t> {
262            fn default() -> Self {
263                Self {
264                    data: <$t>::default(),
265                    raw: vec![0; <$p as TcKonnektSegmentSerdes<$t>>::SIZE],
266                }
267            }
268        }
269    };
270}
271
272segment_default!(Studiok48Protocol, StudioLineOutLevel);
273segment_default!(Studiok48Protocol, StudioRemote);
274segment_default!(Studiok48Protocol, StudioConfig);
275segment_default!(Studiok48Protocol, StudioMixerState);
276segment_default!(Studiok48Protocol, StudioPhysOut);
277segment_default!(Studiok48Protocol, StudioReverbState);
278segment_default!(Studiok48Protocol, StudioChStripStates);
279segment_default!(Studiok48Protocol, StudioHwState);
280segment_default!(Studiok48Protocol, StudioMixerMeter);
281segment_default!(Studiok48Protocol, StudioReverbMeter);
282segment_default!(Studiok48Protocol, StudioChStripMeters);
283
284const STUDIO_LINE_OUT_LEVEL_NOTIFY_FLAG: u32 = 0x00010000;
285const STUDIO_REMOTE_NOTIFY_FLAG: u32 = 0x00020000;
286const STUDIO_CONFIG_NOTIFY_FLAG: u32 = 0x00040000;
287const STUDIO_MIXER_STATE_NOTIFY_FLAG: u32 = 0x00080000;
288const STUDIO_PHYS_OUT_NOTIFY_FLAG: u32 = 0x00100000;
289const STUDIO_REVERB_NOTIFY_CHANGE: u32 = 0x00200000;
290const STUDIO_CH_STRIP_NOTIFY_01_CHANGE: u32 = 0x00400000;
291const STUDIO_CH_STRIP_NOTIFY_23_CHANGE: u32 = 0x00800000;
292// NOTE: 0x01000000 is for tuner.
293// NOTE: 0x02000000 is unidentified.
294const STUDIO_HW_STATE_NOTIFY_FLAG: u32 = 0x04000000;
295// NOTE: 0x08000000 is for remote controller.
296
297/// Line output level.
298#[derive(Debug, Copy, Clone, PartialEq, Eq)]
299pub enum NominalSignalLevel {
300    /// +4dBu.
301    Professional,
302    /// -10dBV.
303    Consumer,
304}
305
306impl Default for NominalSignalLevel {
307    fn default() -> Self {
308        NominalSignalLevel::Professional
309    }
310}
311
312const NOMINAL_LEVELS: &[NominalSignalLevel] = &[
313    NominalSignalLevel::Professional,
314    NominalSignalLevel::Consumer,
315];
316
317const NOMINAL_LEVEL_LABEL: &str = "nominal level";
318
319fn serialize_nominal_level(level: &NominalSignalLevel, raw: &mut [u8]) -> Result<(), String> {
320    serialize_position(NOMINAL_LEVELS, level, raw, NOMINAL_LEVEL_LABEL)
321}
322
323fn deserialize_nominal_level(level: &mut NominalSignalLevel, raw: &[u8]) -> Result<(), String> {
324    deserialize_position(NOMINAL_LEVELS, level, raw, NOMINAL_LEVEL_LABEL)
325}
326
327/// Line output levels.
328#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
329pub struct StudioLineOutLevel {
330    pub line_45: NominalSignalLevel,
331    pub line_67: NominalSignalLevel,
332    pub line_89: NominalSignalLevel,
333    pub line_1011: NominalSignalLevel,
334}
335
336impl TcKonnektSegmentSerdes<StudioLineOutLevel> for Studiok48Protocol {
337    const NAME: &'static str = "line-output-level";
338    const OFFSET: usize = 0x0000;
339    const SIZE: usize = 20;
340
341    fn serialize(params: &StudioLineOutLevel, raw: &mut [u8]) -> Result<(), String> {
342        serialize_nominal_level(&params.line_45, &mut raw[4..8])?;
343        serialize_nominal_level(&params.line_67, &mut raw[8..12])?;
344        serialize_nominal_level(&params.line_89, &mut raw[12..16])?;
345        serialize_nominal_level(&params.line_1011, &mut raw[16..20])?;
346        Ok(())
347    }
348
349    fn deserialize(params: &mut StudioLineOutLevel, raw: &[u8]) -> Result<(), String> {
350        deserialize_nominal_level(&mut params.line_45, &raw[4..8])?;
351        deserialize_nominal_level(&mut params.line_67, &raw[8..12])?;
352        deserialize_nominal_level(&mut params.line_89, &raw[12..16])?;
353        deserialize_nominal_level(&mut params.line_1011, &raw[16..20])?;
354        Ok(())
355    }
356}
357
358impl TcKonnektMutableSegmentOperation<StudioLineOutLevel> for Studiok48Protocol {}
359
360impl TcKonnektNotifiedSegmentOperation<StudioLineOutLevel> for Studiok48Protocol {
361    const NOTIFY_FLAG: u32 = STUDIO_LINE_OUT_LEVEL_NOTIFY_FLAG;
362}
363
364/// Mode of remote effect button.
365#[derive(Debug, Copy, Clone, PartialEq, Eq)]
366pub enum RemoteEffectButtonMode {
367    /// For reverb effect.
368    Reverb,
369    /// For MIDI message generator.
370    Midi,
371}
372
373impl Default for RemoteEffectButtonMode {
374    fn default() -> Self {
375        Self::Reverb
376    }
377}
378
379const REMOTE_EFFECT_BUTTON_MODES: &[RemoteEffectButtonMode] =
380    &[RemoteEffectButtonMode::Reverb, RemoteEffectButtonMode::Midi];
381
382const REMOTE_EFFECT_BUTTON_MODE_LABEL: &str = "remote effect button mode";
383
384fn serialize_remote_effect_button_mode(
385    mode: &RemoteEffectButtonMode,
386    raw: &mut [u8],
387) -> Result<(), String> {
388    serialize_position(
389        REMOTE_EFFECT_BUTTON_MODES,
390        mode,
391        raw,
392        REMOTE_EFFECT_BUTTON_MODE_LABEL,
393    )
394}
395
396fn deserialize_remote_effect_button_mode(
397    mode: &mut RemoteEffectButtonMode,
398    raw: &[u8],
399) -> Result<(), String> {
400    deserialize_position(
401        REMOTE_EFFECT_BUTTON_MODES,
402        mode,
403        raw,
404        REMOTE_EFFECT_BUTTON_MODE_LABEL,
405    )
406}
407
408/// Mode of knob target at pushed state.
409#[derive(Debug, Copy, Clone, PartialEq, Eq)]
410pub enum KnobPushMode {
411    /// Left/Right balance.
412    Pan,
413    /// Gain to reverb effect.
414    GainToReverb,
415    /// Gain to 1st auxiliary mixer.
416    GainToAux0,
417    /// Gain to 2nd auxiliary mixer.
418    GainToAux1,
419}
420
421impl Default for KnobPushMode {
422    fn default() -> Self {
423        Self::Pan
424    }
425}
426
427const KNOB_PUSH_MODES: &[KnobPushMode] = &[
428    KnobPushMode::Pan,
429    KnobPushMode::GainToReverb,
430    KnobPushMode::GainToAux0,
431    KnobPushMode::GainToAux1,
432];
433
434const KNOB_PUSH_MODE_LABEL: &str = "knob push mode";
435
436fn serialize_knob_push_mode(mode: &KnobPushMode, raw: &mut [u8]) -> Result<(), String> {
437    serialize_position(KNOB_PUSH_MODES, mode, raw, KNOB_PUSH_MODE_LABEL)
438}
439
440fn deserialize_knob_push_mode(mode: &mut KnobPushMode, raw: &[u8]) -> Result<(), String> {
441    deserialize_position(KNOB_PUSH_MODES, mode, raw, KNOB_PUSH_MODE_LABEL)
442}
443
444/// The number of entries for user-assigned button.
445pub const STUDIO_REMOTE_USER_ASSIGN_COUNT: usize = 6;
446
447/// State of remote controller.
448#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
449pub struct StudioRemote {
450    /// Loaded program number.
451    pub prog: TcKonnektLoadedProgram,
452    /// Assignment of each user button to control one of source.
453    pub user_assigns: [SrcEntry; STUDIO_REMOTE_USER_ASSIGN_COUNT],
454    /// The mode of effect button.
455    pub effect_button_mode: RemoteEffectButtonMode,
456    /// Enable mode of fallback to master.
457    pub fallback_to_master_enable: bool,
458    /// The duration for the fallback mode.
459    pub fallback_to_master_duration: u32,
460    /// The mode at pushing knob.
461    pub knob_push_mode: KnobPushMode,
462}
463
464impl TcKonnektSegmentSerdes<StudioRemote> for Studiok48Protocol {
465    const NAME: &'static str = "remote-controller";
466    const OFFSET: usize = 0x0014;
467    const SIZE: usize = 48;
468
469    fn serialize(params: &StudioRemote, raw: &mut [u8]) -> Result<(), String> {
470        serialize_loaded_program(&params.prog, &mut raw[..4])?;
471        params
472            .user_assigns
473            .iter()
474            .enumerate()
475            .try_for_each(|(i, assign)| {
476                let pos = 4 + i * 4;
477                serialize_src_entry(assign, &mut raw[pos..(pos + 4)])
478            })?;
479        serialize_remote_effect_button_mode(&params.effect_button_mode, &mut raw[28..32])?;
480        serialize_bool(&params.fallback_to_master_enable, &mut raw[32..36]);
481        serialize_u32(&params.fallback_to_master_duration, &mut raw[36..40]);
482        serialize_knob_push_mode(&params.knob_push_mode, &mut raw[40..44])?;
483        Ok(())
484    }
485
486    fn deserialize(params: &mut StudioRemote, raw: &[u8]) -> Result<(), String> {
487        deserialize_loaded_program(&mut params.prog, &raw[..4])?;
488        params
489            .user_assigns
490            .iter_mut()
491            .enumerate()
492            .try_for_each(|(i, assign)| {
493                let pos = 4 + i * 4;
494                deserialize_src_entry(assign, &raw[pos..(pos + 4)])
495            })?;
496        deserialize_remote_effect_button_mode(&mut params.effect_button_mode, &raw[28..32])?;
497        deserialize_bool(&mut params.fallback_to_master_enable, &raw[32..36]);
498        deserialize_u32(&mut params.fallback_to_master_duration, &raw[36..40]);
499        deserialize_knob_push_mode(&mut params.knob_push_mode, &raw[40..44])?;
500        Ok(())
501    }
502}
503
504impl TcKonnektMutableSegmentOperation<StudioRemote> for Studiok48Protocol {}
505
506impl TcKonnektNotifiedSegmentOperation<StudioRemote> for Studiok48Protocol {
507    const NOTIFY_FLAG: u32 = STUDIO_REMOTE_NOTIFY_FLAG;
508}
509
510impl AsRef<TcKonnektLoadedProgram> for StudioRemote {
511    fn as_ref(&self) -> &TcKonnektLoadedProgram {
512        &self.prog
513    }
514}
515
516impl AsMut<TcKonnektLoadedProgram> for StudioRemote {
517    fn as_mut(&mut self) -> &mut TcKonnektLoadedProgram {
518        &mut self.prog
519    }
520}
521
522/// Mode of optical interface.
523#[derive(Debug, Copy, Clone, PartialEq, Eq)]
524pub enum OptIfaceMode {
525    /// For ADAT signal.
526    Adat,
527    /// For S/PDIF signal.
528    Spdif,
529}
530
531impl Default for OptIfaceMode {
532    fn default() -> Self {
533        Self::Adat
534    }
535}
536
537const OPT_IFACE_MODES: &[OptIfaceMode] = &[OptIfaceMode::Adat, OptIfaceMode::Spdif];
538
539const OPT_IFACE_MODE_LABEL: &str = "optical interface mode";
540
541fn serialize_opt_iface_mode(mode: &OptIfaceMode, raw: &mut [u8]) -> Result<(), String> {
542    serialize_position(OPT_IFACE_MODES, mode, raw, OPT_IFACE_MODE_LABEL)
543}
544
545fn deserialize_opt_iface_mode(mode: &mut OptIfaceMode, raw: &[u8]) -> Result<(), String> {
546    deserialize_position(OPT_IFACE_MODES, mode, raw, OPT_IFACE_MODE_LABEL)
547}
548
549/// Source of standalone clock.
550#[derive(Debug, Copy, Clone, PartialEq, Eq)]
551pub enum StudioStandaloneClkSrc {
552    /// From ADAT in optical input interface.
553    Adat,
554    /// From S/PDIF in 1st optical input interface.
555    SpdifOnOpt01,
556    /// From S/PDIF in 2nd optical input interface.
557    SpdifOnOpt23,
558    /// From S/PDIF in coaxial input interface.
559    SpdifOnCoax,
560    /// Word clock in BNC input interface.
561    WordClock,
562    /// Internal oscillator.
563    Internal,
564}
565
566impl Default for StudioStandaloneClkSrc {
567    fn default() -> Self {
568        Self::Internal
569    }
570}
571
572const STANDALONE_CLOCK_SOURCES: &[StudioStandaloneClkSrc] = &[
573    StudioStandaloneClkSrc::Adat,
574    StudioStandaloneClkSrc::SpdifOnOpt01,
575    StudioStandaloneClkSrc::SpdifOnOpt23,
576    StudioStandaloneClkSrc::SpdifOnCoax,
577    StudioStandaloneClkSrc::WordClock,
578    StudioStandaloneClkSrc::Internal,
579];
580
581const STANDALONE_CLOCK_SOURCE_LABEL: &str = "standalone clock source";
582
583fn serialize_standalone_clock_source(
584    src: &StudioStandaloneClkSrc,
585    raw: &mut [u8],
586) -> Result<(), String> {
587    serialize_position(
588        STANDALONE_CLOCK_SOURCES,
589        src,
590        raw,
591        STANDALONE_CLOCK_SOURCE_LABEL,
592    )
593}
594
595fn deserialize_standalone_clock_source(
596    src: &mut StudioStandaloneClkSrc,
597    raw: &[u8],
598) -> Result<(), String> {
599    deserialize_position(
600        STANDALONE_CLOCK_SOURCES,
601        src,
602        raw,
603        STANDALONE_CLOCK_SOURCE_LABEL,
604    )
605}
606
607/// Configuration.
608#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
609pub struct StudioConfig {
610    /// The mode of optical input/output interfaces.
611    pub opt_iface_mode: OptIfaceMode,
612    /// Source of sampling clock at standalone mode.
613    pub standalone_src: StudioStandaloneClkSrc,
614    /// Rate of sampling clock at standalone mode.
615    pub standalone_rate: TcKonnektStandaloneClockRate,
616    /// Whether to recover sampling clock from any source jitter.
617    pub clock_recovery: bool,
618    /// Configuration for midi event generator.
619    pub midi_send: TcKonnektMidiSender,
620}
621
622impl TcKonnektSegmentSerdes<StudioConfig> for Studiok48Protocol {
623    const NAME: &'static str = "configuration";
624    const OFFSET: usize = 0x0044;
625    const SIZE: usize = 100;
626
627    fn serialize(params: &StudioConfig, raw: &mut [u8]) -> Result<(), String> {
628        serialize_opt_iface_mode(&params.opt_iface_mode, &mut raw[..4])?;
629        serialize_standalone_clock_source(&params.standalone_src, &mut raw[4..8])?;
630        serialize_standalone_clock_rate(&params.standalone_rate, &mut raw[8..12])?;
631        serialize_bool(&params.clock_recovery, &mut raw[16..20]);
632        serialize_midi_sender(&params.midi_send, &mut raw[52..88])?;
633        Ok(())
634    }
635
636    fn deserialize(params: &mut StudioConfig, raw: &[u8]) -> Result<(), String> {
637        deserialize_opt_iface_mode(&mut params.opt_iface_mode, &raw[..4])?;
638        deserialize_standalone_clock_source(&mut params.standalone_src, &raw[4..8])?;
639        deserialize_standalone_clock_rate(&mut params.standalone_rate, &raw[8..12])?;
640        deserialize_bool(&mut params.clock_recovery, &raw[16..20]);
641        deserialize_midi_sender(&mut params.midi_send, &raw[52..88])?;
642        Ok(())
643    }
644}
645
646impl TcKonnektMutableSegmentOperation<StudioConfig> for Studiok48Protocol {}
647
648impl TcKonnektNotifiedSegmentOperation<StudioConfig> for Studiok48Protocol {
649    const NOTIFY_FLAG: u32 = STUDIO_CONFIG_NOTIFY_FLAG;
650}
651
652impl AsRef<TcKonnektStandaloneClockRate> for StudioConfig {
653    fn as_ref(&self) -> &TcKonnektStandaloneClockRate {
654        &self.standalone_rate
655    }
656}
657
658impl AsMut<TcKonnektStandaloneClockRate> for StudioConfig {
659    fn as_mut(&mut self) -> &mut TcKonnektStandaloneClockRate {
660        &mut self.standalone_rate
661    }
662}
663
664impl AsRef<TcKonnektMidiSender> for StudioConfig {
665    fn as_ref(&self) -> &TcKonnektMidiSender {
666        &self.midi_send
667    }
668}
669
670impl AsMut<TcKonnektMidiSender> for StudioConfig {
671    fn as_mut(&mut self) -> &mut TcKonnektMidiSender {
672        &mut self.midi_send
673    }
674}
675
676/// Entry of signal source.
677#[derive(Debug, Copy, Clone, PartialEq, Eq)]
678pub enum SrcEntry {
679    /// For unused.
680    Unused,
681    /// For analog 0..11.
682    Analog(usize), // 0x01..0x0c
683    /// For S/PDIF 0..1
684    Spdif(usize), // 0x0d..0x0e
685    /// For ADAT 0..7.
686    Adat(usize), // 0x0f..0x16
687    /// For stream A 0..11, 14,15.
688    StreamA(usize), // 0x37..0x46
689    /// For stream B 0..8.
690    StreamB(usize), // 0x47..0x58
691    /// For mixer output (main/aux0/aux1/reverb)
692    Mixer(usize), // 0x55..0x5c
693}
694
695impl SrcEntry {
696    const UNUSED: usize = 0x00;
697    const ANALOG_OFFSET: usize = 0x01;
698    const SPDIF_OFFSET: usize = 0x0d;
699    const ADAT_OFFSET: usize = 0x0f;
700    const STREAM_A_OFFSET: usize = 0x37;
701    const STREAM_B_OFFSET: usize = 0x47;
702    const MIXER_OFFSET: usize = 0x55;
703}
704
705impl Default for SrcEntry {
706    fn default() -> Self {
707        SrcEntry::Unused
708    }
709}
710
711fn serialize_src_entry(entry: &SrcEntry, raw: &mut [u8]) -> Result<(), String> {
712    assert!(raw.len() >= 4);
713
714    let val = (match entry {
715        SrcEntry::Unused => SrcEntry::UNUSED,
716        SrcEntry::Analog(ch) => SrcEntry::ANALOG_OFFSET + ch,
717        SrcEntry::Spdif(ch) => SrcEntry::SPDIF_OFFSET + ch,
718        SrcEntry::Adat(ch) => SrcEntry::ADAT_OFFSET + ch,
719        SrcEntry::StreamA(ch) => SrcEntry::STREAM_A_OFFSET + ch,
720        SrcEntry::StreamB(ch) => SrcEntry::STREAM_B_OFFSET + ch,
721        SrcEntry::Mixer(ch) => SrcEntry::MIXER_OFFSET + ch,
722    }) as u32;
723
724    serialize_u32(&val, raw);
725
726    Ok(())
727}
728
729fn deserialize_src_entry(entry: &mut SrcEntry, raw: &[u8]) -> Result<(), String> {
730    assert!(raw.len() >= 4);
731
732    let mut val = 0u32;
733    deserialize_u32(&mut val, raw);
734
735    let v = val as usize;
736    *entry = if v >= SrcEntry::ANALOG_OFFSET && v < SrcEntry::SPDIF_OFFSET {
737        SrcEntry::Analog(v - SrcEntry::ANALOG_OFFSET)
738    } else if v >= SrcEntry::SPDIF_OFFSET && v < SrcEntry::ADAT_OFFSET {
739        SrcEntry::Spdif(v - SrcEntry::SPDIF_OFFSET)
740    } else if v >= SrcEntry::ADAT_OFFSET && v < 0x17 {
741        SrcEntry::Adat(v - SrcEntry::ADAT_OFFSET)
742    } else if v >= SrcEntry::STREAM_A_OFFSET && v < SrcEntry::STREAM_B_OFFSET {
743        SrcEntry::StreamA(v - SrcEntry::STREAM_A_OFFSET)
744    } else if v >= SrcEntry::STREAM_B_OFFSET && v < SrcEntry::MIXER_OFFSET {
745        SrcEntry::StreamB(v - SrcEntry::STREAM_B_OFFSET)
746    } else if v >= SrcEntry::MIXER_OFFSET && v < 0x5d {
747        SrcEntry::Mixer(v - SrcEntry::MIXER_OFFSET)
748    } else {
749        SrcEntry::Unused
750    };
751
752    Ok(())
753}
754
755/// State of output pair.
756#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
757pub struct OutPair {
758    /// Whether to enable dim or not.
759    pub dim_enabled: bool,
760    /// Volume of the pair.
761    pub vol: i32,
762    /// Dimmed volume of the pair.
763    pub dim_vol: i32,
764}
765
766impl OutPair {
767    const SIZE: usize = 12;
768}
769
770fn serialize_out_pair(pair: &OutPair, raw: &mut [u8]) -> Result<(), String> {
771    assert!(raw.len() >= OutPair::SIZE);
772
773    serialize_bool(&pair.dim_enabled, &mut raw[..4]);
774    serialize_i32(&pair.vol, &mut raw[4..8]);
775    serialize_i32(&pair.dim_vol, &mut raw[8..12]);
776
777    Ok(())
778}
779
780fn deserialize_out_pair(pair: &mut OutPair, raw: &[u8]) -> Result<(), String> {
781    assert!(raw.len() >= OutPair::SIZE);
782
783    deserialize_bool(&mut pair.dim_enabled, &raw[..4]);
784    deserialize_i32(&mut pair.vol, &raw[4..8]);
785    deserialize_i32(&mut pair.dim_vol, &raw[8..12]);
786
787    Ok(())
788}
789
790/// The mode of entry for pair of source of monitor.
791#[derive(Debug, Copy, Clone, PartialEq, Eq)]
792pub enum MonitorSrcPairMode {
793    /// Inactive.
794    Inactive,
795    /// Active.
796    Active,
797    /// Always available.
798    Fixed,
799}
800
801impl Default for MonitorSrcPairMode {
802    fn default() -> Self {
803        Self::Inactive
804    }
805}
806
807const MONITOR_SRC_PAIR_MODES: &[MonitorSrcPairMode] = &[
808    MonitorSrcPairMode::Inactive,
809    MonitorSrcPairMode::Active,
810    MonitorSrcPairMode::Fixed,
811];
812
813const MONITOR_SRC_PAIR_MODE_LABEL: &str = "monitor source pair mode";
814
815fn serialize_monitor_src_pair_mode(
816    mode: &MonitorSrcPairMode,
817    raw: &mut [u8],
818) -> Result<(), String> {
819    serialize_position(
820        MONITOR_SRC_PAIR_MODES,
821        mode,
822        raw,
823        MONITOR_SRC_PAIR_MODE_LABEL,
824    )
825}
826
827fn deserialize_monitor_src_pair_mode(
828    mode: &mut MonitorSrcPairMode,
829    raw: &[u8],
830) -> Result<(), String> {
831    deserialize_position(
832        MONITOR_SRC_PAIR_MODES,
833        mode,
834        raw,
835        MONITOR_SRC_PAIR_MODE_LABEL,
836    )
837}
838
839/// Parameters of source of monitor.
840#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
841pub struct MonitorSrcParam {
842    /// Assigned mixer source.
843    pub src: SrcEntry,
844    /// Gain to main mixer, between -1000 and 0 (-72.00 and 0.00 dB).
845    pub gain_to_main: i32,
846    /// Left/Right balance to main mixer, between -50 and 50.
847    pub pan_to_main: i32,
848    /// Gain to reverb effect, between -1000 and 0 (-72.00 and 0.00 dB).
849    pub gain_to_reverb: i32,
850    /// Gain to 1st auxiliary mixer, between -1000 and 0 (-72.00 and 0.00 dB).
851    pub gain_to_aux0: i32,
852    /// Gain to 2nd auxiliary mixer, between -1000 and 0 (-72.00 and 0.00 dB).
853    pub gain_to_aux1: i32,
854}
855
856impl MonitorSrcParam {
857    const SIZE: usize = 24;
858}
859
860fn serialize_monitor_src_params(params: &MonitorSrcParam, raw: &mut [u8]) -> Result<(), String> {
861    assert!(raw.len() >= MonitorSrcParam::SIZE);
862
863    serialize_src_entry(&params.src, &mut raw[..4])?;
864    serialize_i32(&params.gain_to_main, &mut raw[4..8]);
865    serialize_i32(&params.pan_to_main, &mut raw[8..12]);
866    serialize_i32(&params.gain_to_reverb, &mut raw[12..16]);
867    serialize_i32(&params.gain_to_aux0, &mut raw[16..20]);
868    serialize_i32(&params.gain_to_aux1, &mut raw[20..24]);
869
870    Ok(())
871}
872
873fn deserialize_monitor_src_params(params: &mut MonitorSrcParam, raw: &[u8]) -> Result<(), String> {
874    assert!(raw.len() >= MonitorSrcParam::SIZE);
875
876    deserialize_src_entry(&mut params.src, &raw[..4])?;
877    deserialize_i32(&mut params.gain_to_main, &raw[4..8]);
878    deserialize_i32(&mut params.pan_to_main, &raw[8..12]);
879    deserialize_i32(&mut params.gain_to_reverb, &raw[12..16]);
880    deserialize_i32(&mut params.gain_to_aux0, &raw[16..20]);
881    deserialize_i32(&mut params.gain_to_aux1, &raw[20..24]);
882
883    Ok(())
884}
885
886/// Source of monitor.
887#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
888pub struct MonitorSrcPair {
889    /// Mode of source pair of monitor.
890    pub mode: MonitorSrcPairMode,
891    ///  Stereo channel link for the pair.
892    pub stereo_link: bool,
893    /// Parameters of monitor source for left and right channels in its order.
894    pub params: [MonitorSrcParam; 2],
895}
896
897impl MonitorSrcPair {
898    const SIZE: usize = 56;
899}
900
901fn serialize_monitor_src_pair(pair: &MonitorSrcPair, raw: &mut [u8]) -> Result<(), String> {
902    assert!(raw.len() >= MonitorSrcPair::SIZE);
903
904    serialize_monitor_src_pair_mode(&pair.mode, &mut raw[..4])?;
905    serialize_bool(&pair.stereo_link, &mut raw[4..8]);
906    serialize_monitor_src_params(&pair.params[0], &mut raw[8..32])?;
907    serialize_monitor_src_params(&pair.params[1], &mut raw[32..56])?;
908
909    Ok(())
910}
911
912fn deserialize_monitor_src_pair(pair: &mut MonitorSrcPair, raw: &[u8]) -> Result<(), String> {
913    assert!(raw.len() >= MonitorSrcPair::SIZE);
914
915    deserialize_monitor_src_pair_mode(&mut pair.mode, &raw[..4])?;
916    deserialize_bool(&mut pair.stereo_link, &raw[4..8]);
917    deserialize_monitor_src_params(&mut pair.params[0], &raw[8..32])?;
918    deserialize_monitor_src_params(&mut pair.params[1], &raw[32..56])?;
919
920    Ok(())
921}
922
923/// The number of pairs for source of monitor.
924pub const STUDIO_MIXER_SRC_PAIR_COUNT: usize = 12;
925
926/// State of mixer.
927#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
928pub struct StudioMixerState {
929    /// For mixer sources.
930    pub src_pairs: [MonitorSrcPair; STUDIO_MIXER_SRC_PAIR_COUNT],
931    /// Whethe to mute mixer sources.
932    pub mutes: [bool; STUDIO_MIXER_SRC_PAIR_COUNT],
933    /// Whether to mute reverb effect return.
934    pub reverb_return_mute: [bool; 3],
935    /// Gain of reverb effect return.
936    pub reverb_return_gain: [i32; 3],
937    /// Whether to use channel strip effects as plugin.
938    pub ch_strip_as_plugin: [bool; 2],
939    /// The source of channel strip effects.
940    pub ch_strip_src: [SrcEntry; 4],
941    /// Use 3rd and 4th channel strip effects at 88.2/96.0 kHz.
942    pub ch_strip_23_at_mid_rate: bool,
943    /// Settings for mixer outputs.
944    pub mixer_out: [OutPair; 3],
945    /// Control volume before/after mixing.
946    pub post_fader: [bool; 3],
947    /// Whether to enable mixer function or not.
948    pub enabled: bool,
949}
950
951impl TcKonnektSegmentSerdes<StudioMixerState> for Studiok48Protocol {
952    const NAME: &'static str = "mixer-state";
953    const OFFSET: usize = 0x00a8;
954    const SIZE: usize = 820;
955
956    fn serialize(params: &StudioMixerState, raw: &mut [u8]) -> Result<(), String> {
957        params.src_pairs.iter().enumerate().try_for_each(|(i, p)| {
958            let pos = i * MonitorSrcPair::SIZE;
959            serialize_monitor_src_pair(p, &mut raw[pos..(pos + MonitorSrcPair::SIZE)])
960        })?;
961        let mut val = 0u32;
962        params
963            .mutes
964            .iter()
965            .enumerate()
966            .filter(|(_, &m)| m)
967            .for_each(|(i, _)| {
968                val |= 1 << i;
969            });
970        serialize_u32(&val, &mut raw[672..676]);
971        serialize_bool(&params.reverb_return_mute[0], &mut raw[712..716]);
972        serialize_i32(&params.reverb_return_gain[0], &mut raw[716..720]);
973        serialize_bool(&params.reverb_return_mute[1], &mut raw[720..724]);
974        serialize_i32(&params.reverb_return_gain[1], &mut raw[724..728]);
975        serialize_bool(&params.reverb_return_mute[2], &mut raw[728..732]);
976        serialize_i32(&params.reverb_return_gain[2], &mut raw[732..736]);
977        serialize_bool(&params.ch_strip_as_plugin[0], &mut raw[736..740]);
978        serialize_bool(&params.ch_strip_as_plugin[1], &mut raw[740..744]);
979        params
980            .ch_strip_src
981            .iter()
982            .enumerate()
983            .try_for_each(|(i, entry)| {
984                let pos = 744 + i * 4;
985                serialize_src_entry(entry, &mut raw[pos..(pos + 4)])
986            })?;
987        serialize_bool(&params.ch_strip_23_at_mid_rate, &mut raw[760..764]);
988        serialize_out_pair(&params.mixer_out[0], &mut raw[764..776])?;
989        serialize_out_pair(&params.mixer_out[1], &mut raw[776..788])?;
990        serialize_out_pair(&params.mixer_out[2], &mut raw[788..800])?;
991        serialize_bool(&params.post_fader[0], &mut raw[800..804]);
992        serialize_bool(&params.post_fader[1], &mut raw[804..808]);
993        serialize_bool(&params.post_fader[2], &mut raw[808..812]);
994        serialize_bool(&params.enabled, &mut raw[812..816]);
995        Ok(())
996    }
997
998    fn deserialize(params: &mut StudioMixerState, raw: &[u8]) -> Result<(), String> {
999        params
1000            .src_pairs
1001            .iter_mut()
1002            .enumerate()
1003            .try_for_each(|(i, p)| {
1004                let pos = i * MonitorSrcPair::SIZE;
1005                deserialize_monitor_src_pair(p, &raw[pos..(pos + MonitorSrcPair::SIZE)])
1006            })?;
1007        let mut val = 0u32;
1008        deserialize_u32(&mut val, &raw[672..676]);
1009        params.mutes.iter_mut().enumerate().for_each(|(i, m)| {
1010            *m = (val & 1 << i) > 0;
1011        });
1012        deserialize_bool(&mut params.reverb_return_mute[0], &raw[712..716]);
1013        deserialize_i32(&mut params.reverb_return_gain[0], &raw[716..720]);
1014        deserialize_bool(&mut params.reverb_return_mute[1], &raw[720..724]);
1015        deserialize_i32(&mut params.reverb_return_gain[1], &raw[724..728]);
1016        deserialize_bool(&mut params.reverb_return_mute[2], &raw[728..732]);
1017        deserialize_i32(&mut params.reverb_return_gain[2], &raw[732..736]);
1018        deserialize_bool(&mut params.ch_strip_as_plugin[0], &raw[736..740]);
1019        deserialize_bool(&mut params.ch_strip_as_plugin[1], &raw[740..744]);
1020        params
1021            .ch_strip_src
1022            .iter_mut()
1023            .enumerate()
1024            .try_for_each(|(i, entry)| {
1025                let pos = 744 + i * 4;
1026                deserialize_src_entry(entry, &raw[pos..(pos + 4)])
1027            })?;
1028        deserialize_bool(&mut params.ch_strip_23_at_mid_rate, &raw[760..764]);
1029        deserialize_out_pair(&mut params.mixer_out[0], &raw[764..776])?;
1030        deserialize_out_pair(&mut params.mixer_out[1], &raw[776..788])?;
1031        deserialize_out_pair(&mut params.mixer_out[2], &raw[788..800])?;
1032        deserialize_bool(&mut params.post_fader[0], &raw[800..804]);
1033        deserialize_bool(&mut params.post_fader[1], &raw[804..808]);
1034        deserialize_bool(&mut params.post_fader[2], &raw[800..812]);
1035        deserialize_bool(&mut params.enabled, &raw[812..816]);
1036        Ok(())
1037    }
1038}
1039
1040impl TcKonnektMutableSegmentOperation<StudioMixerState> for Studiok48Protocol {}
1041
1042impl TcKonnektNotifiedSegmentOperation<StudioMixerState> for Studiok48Protocol {
1043    const NOTIFY_FLAG: u32 = STUDIO_MIXER_STATE_NOTIFY_FLAG;
1044}
1045
1046/// Parameter of each channel for source of physical output.
1047#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
1048pub struct PhysOutSrcParam {
1049    /// Source.
1050    pub src: SrcEntry,
1051    /// Volume.
1052    pub vol: i32,
1053    /// Delay.
1054    pub delay: i32,
1055}
1056
1057impl PhysOutSrcParam {
1058    const SIZE: usize = 12;
1059}
1060
1061fn serialize_phys_out_src_params(params: &PhysOutSrcParam, raw: &mut [u8]) -> Result<(), String> {
1062    assert!(raw.len() >= PhysOutSrcParam::SIZE);
1063
1064    serialize_src_entry(&params.src, &mut raw[..4])?;
1065    serialize_i32(&params.vol, &mut raw[4..8]);
1066    serialize_i32(&params.delay, &mut raw[8..12]);
1067
1068    Ok(())
1069}
1070
1071fn deserialize_phys_out_src_params(params: &mut PhysOutSrcParam, raw: &[u8]) -> Result<(), String> {
1072    assert!(raw.len() >= PhysOutSrcParam::SIZE);
1073
1074    deserialize_src_entry(&mut params.src, &raw[..4])?;
1075    deserialize_i32(&mut params.vol, &raw[4..8]);
1076    deserialize_i32(&mut params.delay, &raw[8..12]);
1077
1078    Ok(())
1079}
1080
1081/// Source of physical output.
1082#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
1083pub struct PhysOutPairSrc {
1084    /// Stereo channel link for the pair.
1085    pub stereo_link: bool,
1086    /// Parameters of sources for left and right channels.
1087    pub params: [PhysOutSrcParam; 2],
1088}
1089
1090impl PhysOutPairSrc {
1091    const SIZE: usize = 28;
1092}
1093
1094fn serialize_phys_out_pair_src(src: &PhysOutPairSrc, raw: &mut [u8]) -> Result<(), String> {
1095    assert!(raw.len() >= PhysOutPairSrc::SIZE);
1096
1097    serialize_bool(&src.stereo_link, &mut raw[..4]);
1098    serialize_phys_out_src_params(&src.params[0], &mut raw[4..16])?;
1099    serialize_phys_out_src_params(&src.params[1], &mut raw[16..28])?;
1100
1101    Ok(())
1102}
1103
1104fn deserialize_phys_out_pair_src(src: &mut PhysOutPairSrc, raw: &[u8]) -> Result<(), String> {
1105    assert!(raw.len() >= PhysOutPairSrc::SIZE);
1106
1107    deserialize_bool(&mut src.stereo_link, &raw[..4]);
1108    deserialize_phys_out_src_params(&mut src.params[0], &raw[4..16])?;
1109    deserialize_phys_out_src_params(&mut src.params[1], &raw[16..28])?;
1110
1111    Ok(())
1112}
1113
1114/// The highest frequency to cross over into LFE channel.
1115#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1116pub enum CrossOverFreq {
1117    /// 50 Hz.
1118    F50,
1119    /// 80 Hz.
1120    F80,
1121    /// 95 Hz.
1122    F95,
1123    /// 110 Hz.
1124    F110,
1125    /// 115 Hz.
1126    F115,
1127    /// 120 Hz.
1128    F120,
1129}
1130
1131impl Default for CrossOverFreq {
1132    fn default() -> Self {
1133        Self::F50
1134    }
1135}
1136
1137const CROSS_OVER_FREQS: &[CrossOverFreq] = &[
1138    CrossOverFreq::F50,
1139    CrossOverFreq::F80,
1140    CrossOverFreq::F95,
1141    CrossOverFreq::F110,
1142    CrossOverFreq::F115,
1143    CrossOverFreq::F120,
1144];
1145
1146const CROSS_OVER_FREQ_LABEL: &str = "cross over frequency";
1147
1148fn serialize_cross_over_freq(freq: &CrossOverFreq, raw: &mut [u8]) -> Result<(), String> {
1149    serialize_position(CROSS_OVER_FREQS, freq, raw, CROSS_OVER_FREQ_LABEL)
1150}
1151
1152fn deserialize_cross_over_freq(freq: &mut CrossOverFreq, raw: &[u8]) -> Result<(), String> {
1153    deserialize_position(CROSS_OVER_FREQS, freq, raw, CROSS_OVER_FREQ_LABEL)
1154}
1155
1156/// The frequency above cross over frequency into main channel.
1157#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1158pub enum HighPassFreq {
1159    /// Off.
1160    Off,
1161    /// Above 12 Hz per octave.
1162    Above12,
1163    /// Above 24 Hz per octave.
1164    Above24,
1165}
1166
1167impl Default for HighPassFreq {
1168    fn default() -> Self {
1169        HighPassFreq::Off
1170    }
1171}
1172
1173const HIGH_PASS_FREQS: &[HighPassFreq] = &[
1174    HighPassFreq::Off,
1175    HighPassFreq::Above12,
1176    HighPassFreq::Above24,
1177];
1178
1179const HIGH_PASS_FREQ_LABEL: &str = "high pass frequency";
1180
1181fn serialize_high_pass_freq(freq: &HighPassFreq, raw: &mut [u8]) -> Result<(), String> {
1182    serialize_position(HIGH_PASS_FREQS, freq, raw, HIGH_PASS_FREQ_LABEL)
1183}
1184
1185fn deserialize_high_pass_freq(freq: &mut HighPassFreq, raw: &[u8]) -> Result<(), String> {
1186    deserialize_position(HIGH_PASS_FREQS, freq, raw, HIGH_PASS_FREQ_LABEL)
1187}
1188
1189/// The frequency below cross over frequency into LFE channel.
1190#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1191pub enum LowPassFreq {
1192    /// Below 12 Hz per octave.
1193    Below12,
1194    /// Below 24 Hz per octave.
1195    Below24,
1196}
1197
1198impl Default for LowPassFreq {
1199    fn default() -> Self {
1200        LowPassFreq::Below12
1201    }
1202}
1203
1204fn serialize_low_pass_freq(freq: &LowPassFreq, raw: &mut [u8]) -> Result<(), String> {
1205    assert!(raw.len() >= 4);
1206
1207    let val = match freq {
1208        LowPassFreq::Below12 => 1u32,
1209        LowPassFreq::Below24 => 2,
1210    };
1211    serialize_u32(&val, raw);
1212
1213    Ok(())
1214}
1215
1216fn deserialize_low_pass_freq(freq: &mut LowPassFreq, raw: &[u8]) -> Result<(), String> {
1217    assert!(raw.len() >= 4);
1218
1219    let mut val = 0u32;
1220    deserialize_u32(&mut val, raw);
1221
1222    *freq = match val {
1223        1 => LowPassFreq::Below12,
1224        2 => LowPassFreq::Below24,
1225        _ => Err(format!("low pass frequency not found for value {}", val))?,
1226    };
1227
1228    Ok(())
1229}
1230
1231/// The maximum number of surround channel of which a output group consists.
1232pub const STUDIO_MAX_SURROUND_CHANNELS: usize = 8;
1233
1234/// The group to aggregate several outputs for surround channels.
1235#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
1236pub struct OutGroup {
1237    /// Assignment of physical outputs to the group.
1238    pub assigned_phys_outs: [bool; STUDIO_PHYS_OUT_PAIR_COUNT * 2],
1239    /// Whether to enable bass management.
1240    pub bass_management: bool,
1241    /// The sub channel to Low Frequency Effect (LFE).
1242    pub sub_channel: Option<usize>,
1243    /// The frequency above which signal is to main , below which signal is to Low Frequency Effect
1244    /// (LFE).
1245    pub main_cross_over_freq: CrossOverFreq,
1246    /// Gain for signal from main to Low Frequency Effect (LFE).
1247    pub main_level_to_sub: i32,
1248    /// Gain for signal from sub channel to Low Frequency Effect (LFE).
1249    pub sub_level_to_sub: i32,
1250    /// Frequency of high pass filter for the signal of main channel.
1251    pub main_filter_for_main: HighPassFreq,
1252    /// Frequency of low pass filter for the signal from main channel to sub channel.
1253    pub main_filter_for_sub: LowPassFreq,
1254}
1255
1256impl OutGroup {
1257    const SIZE: usize = 36;
1258}
1259
1260fn serialize_out_group(group: &OutGroup, raw: &mut [u8]) -> Result<(), String> {
1261    assert!(raw.len() >= OutGroup::SIZE);
1262
1263    // NOTE: when the value has bit flags more than 8, the ASIC to read the value is going to
1264    // freeze. The corruption can be recovered to recall the other program state (P1/P2/P3) by
1265    // the controller at standalone mode, then connect and factory reset by software.
1266    let mut val = 0u32;
1267    group
1268        .assigned_phys_outs
1269        .iter()
1270        .enumerate()
1271        .filter(|(_, &a)| a)
1272        .take(STUDIO_MAX_SURROUND_CHANNELS)
1273        .for_each(|(i, _)| {
1274            val |= 1 << i;
1275        });
1276    serialize_u32(&val, &mut raw[..4]);
1277    serialize_bool(&group.bass_management, &mut raw[4..8]);
1278    val = match group.sub_channel {
1279        Some(pos) => 1 << pos,
1280        None => 0,
1281    };
1282    serialize_u32(&val, &mut raw[12..16]);
1283    serialize_cross_over_freq(&group.main_cross_over_freq, &mut raw[16..20])?;
1284    serialize_i32(&group.main_level_to_sub, &mut raw[20..24]);
1285    serialize_i32(&group.sub_level_to_sub, &mut raw[24..28]);
1286    serialize_high_pass_freq(&group.main_filter_for_main, &mut raw[28..32])?;
1287    serialize_low_pass_freq(&group.main_filter_for_sub, &mut raw[32..])?;
1288
1289    Ok(())
1290}
1291
1292fn deserialize_out_group(group: &mut OutGroup, raw: &[u8]) -> Result<(), String> {
1293    assert!(raw.len() >= OutGroup::SIZE);
1294
1295    let mut val = 0u32;
1296    deserialize_u32(&mut val, &raw[..4]);
1297    group
1298        .assigned_phys_outs
1299        .iter_mut()
1300        .enumerate()
1301        .for_each(|(i, a)| *a = val & (1 << i) > 0);
1302    deserialize_bool(&mut group.bass_management, &raw[4..8]);
1303    deserialize_u32(&mut val, &raw[12..16]);
1304    group.sub_channel = (0..group.assigned_phys_outs.len())
1305        .position(|i| val & (1 << i) > 0)
1306        .map(|pos| pos as usize);
1307    deserialize_cross_over_freq(&mut group.main_cross_over_freq, &raw[16..20])?;
1308    deserialize_i32(&mut group.main_level_to_sub, &raw[20..24]);
1309    deserialize_i32(&mut group.sub_level_to_sub, &raw[24..28]);
1310    deserialize_high_pass_freq(&mut group.main_filter_for_main, &raw[28..32])?;
1311    deserialize_low_pass_freq(&mut group.main_filter_for_sub, &raw[32..])?;
1312
1313    Ok(())
1314}
1315
1316/// The number of pairs of physical output.
1317pub const STUDIO_PHYS_OUT_PAIR_COUNT: usize = 11;
1318
1319/// The number of groups to aggregate several outputs for surround channels.
1320pub const STUDIO_OUTPUT_GROUP_COUNT: usize = 3;
1321
1322/// Data of physical out segment.
1323#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
1324pub struct StudioPhysOut {
1325    /// The configuration for master output
1326    pub master_out: OutPair,
1327    /// The selected output group.
1328    pub selected_out_grp: usize,
1329    /// The source for pairs of physical output. It includes below pairs in
1330    /// the order:
1331    /// - main out 1/2
1332    /// - phone out 1/2
1333    /// - line out 5/6, 7/8, 9/10, 11/12,
1334    /// - S/PDIF out 1/2,
1335    /// - ADAT out 1/2, 3/4, 5/6, 7/8,
1336    pub out_pair_srcs: [PhysOutPairSrc; STUDIO_PHYS_OUT_PAIR_COUNT],
1337    /// The state of assignment to output group.
1338    pub out_assign_to_grp: [bool; STUDIO_PHYS_OUT_PAIR_COUNT * 2],
1339    /// Whether to mute any source to the physical output.
1340    pub out_mutes: [bool; STUDIO_PHYS_OUT_PAIR_COUNT * 2],
1341    /// The settings of each group for surround channels.
1342    pub out_grps: [OutGroup; STUDIO_OUTPUT_GROUP_COUNT],
1343}
1344
1345impl TcKonnektSegmentSerdes<StudioPhysOut> for Studiok48Protocol {
1346    const NAME: &'static str = "physical-output";
1347    const OFFSET: usize = 0x03dc;
1348    const SIZE: usize = 440;
1349
1350    fn serialize(params: &StudioPhysOut, raw: &mut [u8]) -> Result<(), String> {
1351        serialize_out_pair(&params.master_out, &mut raw[..12])?;
1352        params
1353            .out_pair_srcs
1354            .iter()
1355            .enumerate()
1356            .try_for_each(|(i, p)| {
1357                let pos = 16 + i * PhysOutPairSrc::SIZE;
1358                serialize_phys_out_pair_src(p, &mut raw[pos..(pos + PhysOutPairSrc::SIZE)])
1359            })?;
1360        serialize_usize(&params.selected_out_grp, &mut raw[12..16]);
1361        let mut val = 0u32;
1362        params
1363            .out_assign_to_grp
1364            .iter()
1365            .enumerate()
1366            .filter(|(_, &m)| m)
1367            .for_each(|(i, _)| {
1368                val |= 1 << i;
1369            });
1370        serialize_u32(&val, &mut raw[324..328]);
1371        let mut val = 0u32;
1372        params
1373            .out_mutes
1374            .iter()
1375            .enumerate()
1376            .filter(|(_, &d)| d)
1377            .for_each(|(i, _)| {
1378                val |= 1 << i;
1379            });
1380        serialize_u32(&val, &mut raw[328..332]);
1381        params.out_grps.iter().enumerate().try_for_each(|(i, s)| {
1382            let pos = 332 + OutGroup::SIZE * i;
1383            serialize_out_group(s, &mut raw[pos..(pos + OutGroup::SIZE)])
1384        })?;
1385        Ok(())
1386    }
1387
1388    fn deserialize(params: &mut StudioPhysOut, raw: &[u8]) -> Result<(), String> {
1389        deserialize_out_pair(&mut params.master_out, &raw[..12])?;
1390        params
1391            .out_pair_srcs
1392            .iter_mut()
1393            .enumerate()
1394            .try_for_each(|(i, p)| {
1395                let pos = 16 + i * PhysOutPairSrc::SIZE;
1396                deserialize_phys_out_pair_src(p, &raw[pos..(pos + PhysOutPairSrc::SIZE)])
1397            })?;
1398        let mut val = 0u32;
1399        deserialize_u32(&mut val, &raw[12..16]);
1400        deserialize_usize(&mut params.selected_out_grp, &raw[324..328]);
1401        params
1402            .out_assign_to_grp
1403            .iter_mut()
1404            .enumerate()
1405            .for_each(|(i, m)| {
1406                *m = val & (1 << i) > 0;
1407            });
1408        let mut val = 0u32;
1409        deserialize_u32(&mut val, &raw[328..332]);
1410        params.out_mutes.iter_mut().enumerate().for_each(|(i, d)| {
1411            *d = val & (1 << i) > 0;
1412        });
1413        params
1414            .out_grps
1415            .iter_mut()
1416            .enumerate()
1417            .try_for_each(|(i, s)| {
1418                let pos = 332 + OutGroup::SIZE * i;
1419                deserialize_out_group(s, &raw[pos..(pos + OutGroup::SIZE)])
1420            })?;
1421        Ok(())
1422    }
1423}
1424
1425impl TcKonnektMutableSegmentOperation<StudioPhysOut> for Studiok48Protocol {}
1426
1427impl TcKonnektNotifiedSegmentOperation<StudioPhysOut> for Studiok48Protocol {
1428    const NOTIFY_FLAG: u32 = STUDIO_PHYS_OUT_NOTIFY_FLAG;
1429}
1430
1431const STUDIO_CH_STRIP_COUNT: usize = 4;
1432
1433/// Configuration for reverb effect.
1434#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
1435pub struct StudioReverbState(pub ReverbState);
1436
1437impl TcKonnektSegmentSerdes<StudioReverbState> for Studiok48Protocol {
1438    const NAME: &'static str = "reverb-state";
1439    const OFFSET: usize = 0x0594;
1440    const SIZE: usize = ReverbState::SIZE;
1441
1442    fn serialize(params: &StudioReverbState, raw: &mut [u8]) -> Result<(), String> {
1443        serialize_reverb_state(&params.0, raw)
1444    }
1445
1446    fn deserialize(params: &mut StudioReverbState, raw: &[u8]) -> Result<(), String> {
1447        deserialize_reverb_state(&mut params.0, raw)
1448    }
1449}
1450
1451impl TcKonnektMutableSegmentOperation<StudioReverbState> for Studiok48Protocol {}
1452
1453impl TcKonnektNotifiedSegmentOperation<StudioReverbState> for Studiok48Protocol {
1454    const NOTIFY_FLAG: u32 = STUDIO_REVERB_NOTIFY_CHANGE;
1455}
1456
1457impl AsRef<ReverbState> for StudioReverbState {
1458    fn as_ref(&self) -> &ReverbState {
1459        &self.0
1460    }
1461}
1462
1463impl AsMut<ReverbState> for StudioReverbState {
1464    fn as_mut(&mut self) -> &mut ReverbState {
1465        &mut self.0
1466    }
1467}
1468
1469/// Configuration for channel strip effect.
1470#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
1471pub struct StudioChStripStates(pub [ChStripState; STUDIO_CH_STRIP_COUNT]);
1472
1473impl TcKonnektSegmentSerdes<StudioChStripStates> for Studiok48Protocol {
1474    const NAME: &'static str = "channel-strip-state";
1475    const OFFSET: usize = 0x05dc;
1476    const SIZE: usize = ChStripState::SIZE * STUDIO_CH_STRIP_COUNT + 8;
1477
1478    fn serialize(params: &StudioChStripStates, raw: &mut [u8]) -> Result<(), String> {
1479        serialize_ch_strip_states(&params.0, raw)
1480    }
1481
1482    fn deserialize(params: &mut StudioChStripStates, raw: &[u8]) -> Result<(), String> {
1483        deserialize_ch_strip_states(&mut params.0, raw)
1484    }
1485}
1486
1487impl TcKonnektMutableSegmentOperation<StudioChStripStates> for Studiok48Protocol {}
1488
1489impl TcKonnektNotifiedSegmentOperation<StudioChStripStates> for Studiok48Protocol {
1490    const NOTIFY_FLAG: u32 = STUDIO_CH_STRIP_NOTIFY_01_CHANGE | STUDIO_CH_STRIP_NOTIFY_23_CHANGE;
1491}
1492
1493impl AsRef<[ChStripState]> for StudioChStripStates {
1494    fn as_ref(&self) -> &[ChStripState] {
1495        &self.0
1496    }
1497}
1498
1499impl AsMut<[ChStripState]> for StudioChStripStates {
1500    fn as_mut(&mut self) -> &mut [ChStripState] {
1501        &mut self.0
1502    }
1503}
1504
1505#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1506/// State of jack sense for analog input.
1507pub enum StudioAnalogJackState {
1508    /// Select front jack instead of rear.
1509    FrontSelected,
1510    /// Detect plug insertion in front jack.
1511    FrontInserted,
1512    /// Select rear jack instead of front.
1513    RearSelected,
1514    /// Detect plug insertion in rear jack.
1515    RearInserted,
1516}
1517
1518impl Default for StudioAnalogJackState {
1519    fn default() -> Self {
1520        Self::FrontSelected
1521    }
1522}
1523
1524fn serialize_analog_jack_state(
1525    state: &StudioAnalogJackState,
1526    raw: &mut [u8],
1527) -> Result<(), String> {
1528    assert!(raw.len() >= 4);
1529
1530    let val = match state {
1531        StudioAnalogJackState::FrontSelected => 5,
1532        StudioAnalogJackState::FrontInserted => 6,
1533        StudioAnalogJackState::RearSelected => 7,
1534        StudioAnalogJackState::RearInserted => 8,
1535    };
1536
1537    serialize_u32(&val, raw);
1538
1539    Ok(())
1540}
1541
1542fn deserialize_analog_jack_state(
1543    state: &mut StudioAnalogJackState,
1544    raw: &[u8],
1545) -> Result<(), String> {
1546    assert!(raw.len() >= 4);
1547
1548    let mut val = 0u32;
1549    deserialize_u32(&mut val, raw);
1550
1551    *state = match val {
1552        8 => StudioAnalogJackState::RearInserted,
1553        7 => StudioAnalogJackState::RearSelected,
1554        6 => StudioAnalogJackState::FrontInserted,
1555        _ => StudioAnalogJackState::FrontSelected,
1556    };
1557
1558    Ok(())
1559}
1560
1561/// The number of analog inputs which has jack sense.
1562pub const STUDIO_ANALOG_JACK_STATE_COUNT: usize = 12;
1563
1564/// Hardware state.
1565#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
1566pub struct StudioHwState {
1567    /// The state of analog jack with sense.
1568    pub analog_jack_states: [StudioAnalogJackState; STUDIO_ANALOG_JACK_STATE_COUNT],
1569    /// State of headphone.
1570    pub hp_state: [bool; 2],
1571    /// State of FireWire LED.
1572    pub firewire_led: FireWireLedState,
1573    /// Whether knob of master level is actually effective for volume of master output. This is
1574    /// needed since the volume is controlled by remote controller as well.
1575    pub valid_master_level: bool,
1576}
1577
1578impl TcKonnektSegmentSerdes<StudioHwState> for Studiok48Protocol {
1579    const NAME: &'static str = "hardware-state";
1580    const OFFSET: usize = 0x2008;
1581    const SIZE: usize = 68;
1582
1583    fn serialize(params: &StudioHwState, raw: &mut [u8]) -> Result<(), String> {
1584        params
1585            .analog_jack_states
1586            .iter()
1587            .enumerate()
1588            .try_for_each(|(i, state)| {
1589                let pos = 4 * i;
1590                serialize_analog_jack_state(state, &mut raw[pos..(pos + 4)])
1591            })?;
1592        serialize_bool(&params.hp_state[0], &mut raw[48..56]);
1593        serialize_bool(&params.hp_state[1], &mut raw[48..56]);
1594        serialize_fw_led_state(&params.firewire_led, &mut raw[56..60])?;
1595        serialize_bool(&params.valid_master_level, &mut raw[60..64]);
1596        Ok(())
1597    }
1598
1599    fn deserialize(params: &mut StudioHwState, raw: &[u8]) -> Result<(), String> {
1600        params
1601            .analog_jack_states
1602            .iter_mut()
1603            .enumerate()
1604            .try_for_each(|(i, state)| {
1605                let pos = 4 * i;
1606                deserialize_analog_jack_state(state, &raw[pos..(pos + 4)])
1607            })?;
1608        deserialize_bool(&mut params.hp_state[0], &raw[48..52]);
1609        deserialize_bool(&mut params.hp_state[1], &raw[52..56]);
1610        deserialize_fw_led_state(&mut params.firewire_led, &raw[56..60])?;
1611        deserialize_bool(&mut params.valid_master_level, &raw[60..64]);
1612        Ok(())
1613    }
1614}
1615
1616impl TcKonnektMutableSegmentOperation<StudioHwState> for Studiok48Protocol {}
1617
1618impl TcKonnektNotifiedSegmentOperation<StudioHwState> for Studiok48Protocol {
1619    const NOTIFY_FLAG: u32 = STUDIO_HW_STATE_NOTIFY_FLAG;
1620}
1621
1622impl AsRef<FireWireLedState> for StudioHwState {
1623    fn as_ref(&self) -> &FireWireLedState {
1624        &self.firewire_led
1625    }
1626}
1627
1628impl AsMut<FireWireLedState> for StudioHwState {
1629    fn as_mut(&mut self) -> &mut FireWireLedState {
1630        &mut self.firewire_led
1631    }
1632}
1633
1634/// Hardware metering for mixer function.
1635#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
1636pub struct StudioMixerMeter {
1637    /// Detected signal level of main mixer sources.
1638    pub src_inputs: [i32; 24],
1639    /// Detected signal level of main mixer outputs.
1640    pub mixer_outputs: [i32; 2],
1641    /// Detected signal level of aux mixer outputs.
1642    pub aux_outputs: [i32; 4],
1643}
1644
1645impl TcKonnektSegmentSerdes<StudioMixerMeter> for Studiok48Protocol {
1646    const NAME: &'static str = "mixer-meter";
1647    const OFFSET: usize = 0x20b8;
1648    const SIZE: usize = 128;
1649
1650    fn serialize(params: &StudioMixerMeter, raw: &mut [u8]) -> Result<(), String> {
1651        params
1652            .src_inputs
1653            .iter()
1654            .chain(&params.mixer_outputs)
1655            .chain(&params.aux_outputs)
1656            .enumerate()
1657            .for_each(|(i, level)| {
1658                let pos = i * 4;
1659                serialize_i32(level, &mut raw[pos..(pos + 4)])
1660            });
1661
1662        Ok(())
1663    }
1664
1665    fn deserialize(params: &mut StudioMixerMeter, raw: &[u8]) -> Result<(), String> {
1666        params
1667            .src_inputs
1668            .iter_mut()
1669            .chain(&mut params.mixer_outputs)
1670            .chain(&mut params.aux_outputs)
1671            .enumerate()
1672            .for_each(|(i, level)| {
1673                let pos = i * 4;
1674                deserialize_i32(level, &raw[pos..(pos + 4)])
1675            });
1676
1677        Ok(())
1678    }
1679}
1680
1681/// Hardware metering for reverb effect.
1682#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
1683pub struct StudioReverbMeter(pub ReverbMeter);
1684
1685impl TcKonnektSegmentSerdes<StudioReverbMeter> for Studiok48Protocol {
1686    const NAME: &'static str = "reverb-meter";
1687    const OFFSET: usize = 0x2164;
1688    const SIZE: usize = ReverbMeter::SIZE;
1689
1690    fn serialize(params: &StudioReverbMeter, raw: &mut [u8]) -> Result<(), String> {
1691        serialize_reverb_meter(&params.0, raw)
1692    }
1693
1694    fn deserialize(params: &mut StudioReverbMeter, raw: &[u8]) -> Result<(), String> {
1695        deserialize_reverb_meter(&mut params.0, raw)
1696    }
1697}
1698
1699impl AsRef<ReverbMeter> for StudioReverbMeter {
1700    fn as_ref(&self) -> &ReverbMeter {
1701        &self.0
1702    }
1703}
1704
1705impl AsMut<ReverbMeter> for StudioReverbMeter {
1706    fn as_mut(&mut self) -> &mut ReverbMeter {
1707        &mut self.0
1708    }
1709}
1710
1711/// Hardware metering for channel strip effect.
1712#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
1713pub struct StudioChStripMeters(pub [ChStripMeter; STUDIO_CH_STRIP_COUNT]);
1714
1715impl TcKonnektSegmentSerdes<StudioChStripMeters> for Studiok48Protocol {
1716    const NAME: &'static str = "channel-strip-meter";
1717    const OFFSET: usize = 0x217c;
1718    const SIZE: usize = ChStripMeter::SIZE * STUDIO_CH_STRIP_COUNT + 8;
1719
1720    fn serialize(params: &StudioChStripMeters, raw: &mut [u8]) -> Result<(), String> {
1721        serialize_ch_strip_meters(&params.0, raw)
1722    }
1723
1724    fn deserialize(params: &mut StudioChStripMeters, raw: &[u8]) -> Result<(), String> {
1725        deserialize_ch_strip_meters(&mut params.0, raw)
1726    }
1727}
1728
1729impl AsRef<[ChStripMeter]> for StudioChStripMeters {
1730    fn as_ref(&self) -> &[ChStripMeter] {
1731        &self.0
1732    }
1733}
1734
1735impl AsMut<[ChStripMeter]> for StudioChStripMeters {
1736    fn as_mut(&mut self) -> &mut [ChStripMeter] {
1737        &mut self.0
1738    }
1739}