firewire_dice_protocols/tcelectronic/
shell.rs

1// SPDX-License-Identifier: LGPL-3.0-or-later
2// Copyright (c) 2020 Takashi Sakamoto
3
4//! Protocol defined by TC Electronic for Konnekt 24d, Konnekt 8, Konnekt Live, and Impact Twin.
5//!
6//! The module includes structure, enumeration, and trait and its implementation for protocol
7//! defined by TC Electronic for Konnekt 24d, Konnekt 8, Konnekt Live, and Impact Twin.
8
9pub mod itwin;
10pub mod k24d;
11pub mod k8;
12pub mod klive;
13
14use super::{ch_strip::*, reverb::*, *};
15
16const SHELL_KNOB_NOTIFY_FLAG: u32 = 0x00010000;
17const SHELL_CONFIG_NOTIFY_FLAG: u32 = 0x00020000;
18const SHELL_MIXER_NOTIFY_FLAG: u32 = 0x00040000;
19const SHELL_REVERB_NOTIFY_FLAG: u32 = 0x00080000;
20const SHELL_CH_STRIP_NOTIFY_FLAG: u32 = 0x00100000;
21// NOTE: 0x00200000 is for tuner.
22// NOTE: 0x00400000 is unidentified.
23const SHELL_HW_STATE_NOTIFY_FLAG: u32 = 0x01000000;
24
25const SHELL_CH_STRIP_COUNT: usize = 2;
26
27/// State of jack sense for analog input.
28#[derive(Debug, Copy, Clone, PartialEq, Eq)]
29pub enum ShellAnalogJackState {
30    /// Select front jack instead of rear.
31    FrontSelected,
32    /// Detect plug insertion in front jack.
33    FrontInserted,
34    /// Detect plug insertion in front jack with attenuation.
35    FrontInsertedAttenuated,
36    /// Select rear jack instead of front.
37    RearSelected,
38    /// Detect plug insertion in rear jack.
39    RearInserted,
40}
41
42impl Default for ShellAnalogJackState {
43    fn default() -> Self {
44        Self::FrontSelected
45    }
46}
47
48impl ShellAnalogJackState {
49    const FRONT_SELECTED: u32 = 0x00;
50    const FRONT_INSERTED: u32 = 0x05;
51    const FRONT_INSERTED_ATTENUATED: u32 = 0x06;
52    const REAR_SELECTED: u32 = 0x07;
53    const REAR_INSERTED: u32 = 0x08;
54}
55
56fn serialize_analog_jack_state(state: &ShellAnalogJackState, raw: &mut [u8]) -> Result<(), String> {
57    assert!(raw.len() >= 4);
58
59    let val = match state {
60        ShellAnalogJackState::FrontSelected => ShellAnalogJackState::FRONT_SELECTED,
61        ShellAnalogJackState::FrontInserted => ShellAnalogJackState::FRONT_INSERTED,
62        ShellAnalogJackState::FrontInsertedAttenuated => {
63            ShellAnalogJackState::FRONT_INSERTED_ATTENUATED
64        }
65        ShellAnalogJackState::RearSelected => ShellAnalogJackState::REAR_SELECTED,
66        ShellAnalogJackState::RearInserted => ShellAnalogJackState::REAR_INSERTED,
67    };
68
69    serialize_u32(&val, raw);
70
71    Ok(())
72}
73
74fn deserialize_analog_jack_state(
75    state: &mut ShellAnalogJackState,
76    raw: &[u8],
77) -> Result<(), String> {
78    assert!(raw.len() >= 4);
79
80    let mut val = 0u32;
81    deserialize_u32(&mut val, raw);
82
83    *state = match val & 0xff {
84        ShellAnalogJackState::FRONT_INSERTED => ShellAnalogJackState::FrontInserted,
85        ShellAnalogJackState::FRONT_INSERTED_ATTENUATED => {
86            ShellAnalogJackState::FrontInsertedAttenuated
87        }
88        ShellAnalogJackState::REAR_SELECTED => ShellAnalogJackState::RearSelected,
89        ShellAnalogJackState::REAR_INSERTED => ShellAnalogJackState::RearInserted,
90        ShellAnalogJackState::FRONT_SELECTED => ShellAnalogJackState::FrontSelected,
91        _ => Err(format!("Invalid value of analog jack state: {}", val))?,
92    };
93    Ok(())
94}
95
96/// The number of analog inputs which has jack sense.
97pub const SHELL_ANALOG_JACK_STATE_COUNT: usize = 2;
98
99/// Hardware state.
100#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
101pub struct ShellHwState {
102    /// The state of analog jack with sense.
103    pub analog_jack_states: [ShellAnalogJackState; SHELL_ANALOG_JACK_STATE_COUNT],
104    /// The state of FireWire LED.
105    pub firewire_led: FireWireLedState,
106}
107
108impl ShellHwState {
109    pub(crate) const SIZE: usize = 28;
110}
111
112fn serialize_hw_state(state: &ShellHwState, raw: &mut [u8]) -> Result<(), String> {
113    assert!(raw.len() >= ShellHwState::SIZE);
114
115    serialize_analog_jack_state(&state.analog_jack_states[0], &mut raw[..4])?;
116    serialize_analog_jack_state(&state.analog_jack_states[1], &mut raw[4..8])?;
117    serialize_fw_led_state(&state.firewire_led, &mut raw[20..24])?;
118
119    Ok(())
120}
121
122fn deserialize_hw_state(state: &mut ShellHwState, raw: &[u8]) -> Result<(), String> {
123    assert!(raw.len() >= ShellHwState::SIZE);
124
125    deserialize_analog_jack_state(&mut state.analog_jack_states[0], &raw[..4])?;
126    deserialize_analog_jack_state(&mut state.analog_jack_states[1], &raw[4..8])?;
127    deserialize_fw_led_state(&mut state.firewire_led, &raw[20..24])?;
128
129    Ok(())
130}
131
132/// Parameter of monitor source.
133#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
134pub struct MonitorSrcParam {
135    ///  ch 1 gain to mixer ch 1/2 (0xfffffc18..0x00000000, -90.0..0.00 dB)
136    pub gain_to_mixer: i32,
137    ///  ch 1 pan to mixer ch 1/2 (0xffffffce..0x00000032, -50.0..+50.0 dB)
138    pub pan_to_mixer: i32,
139    ///  ch 1 gain to send ch 1/2 (0xfffffc18..0x00000000, -90.0..0.00 dB)
140    pub gain_to_send: i32,
141}
142
143impl MonitorSrcParam {
144    const SIZE: usize = 12;
145}
146
147fn serialize_monitor_source_param(param: &MonitorSrcParam, raw: &mut [u8]) -> Result<(), String> {
148    assert!(raw.len() >= MonitorSrcParam::SIZE);
149
150    serialize_i32(&param.gain_to_mixer, &mut raw[..4]);
151    serialize_i32(&param.pan_to_mixer, &mut raw[4..8]);
152    serialize_i32(&param.gain_to_send, &mut raw[8..12]);
153
154    Ok(())
155}
156
157fn deserialize_monitor_source_param(param: &mut MonitorSrcParam, raw: &[u8]) -> Result<(), String> {
158    assert!(raw.len() >= MonitorSrcParam::SIZE);
159
160    deserialize_i32(&mut param.gain_to_mixer, &raw[..4]);
161    deserialize_i32(&mut param.pan_to_mixer, &raw[4..8]);
162    deserialize_i32(&mut param.gain_to_send, &raw[8..12]);
163
164    Ok(())
165}
166
167/// Monitor source.
168#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
169pub struct ShellMonitorSrcPair {
170    ///  Stereo channel link for the pair.
171    pub stereo_link: bool,
172    /// Parameters of monitor source for left and right channels in its order.
173    pub params: [MonitorSrcParam; 2],
174}
175
176impl ShellMonitorSrcPair {
177    const SIZE: usize = 28;
178}
179
180fn serialize_monitor_source_pair(pair: &ShellMonitorSrcPair, raw: &mut [u8]) -> Result<(), String> {
181    assert!(raw.len() >= ShellMonitorSrcPair::SIZE);
182
183    serialize_bool(&pair.stereo_link, &mut raw[..4]);
184    serialize_monitor_source_param(&pair.params[0], &mut raw[4..16])?;
185    serialize_monitor_source_param(&pair.params[1], &mut raw[16..28])?;
186    Ok(())
187}
188
189fn deserialize_monitor_source_pair(
190    pair: &mut ShellMonitorSrcPair,
191    raw: &[u8],
192) -> Result<(), String> {
193    assert!(raw.len() >= ShellMonitorSrcPair::SIZE);
194
195    deserialize_bool(&mut pair.stereo_link, &raw[..4]);
196    deserialize_monitor_source_param(&mut pair.params[0], &raw[4..16])?;
197    deserialize_monitor_source_param(&mut pair.params[1], &raw[16..28])?;
198    Ok(())
199}
200
201/// Mute state for monitor sources.
202#[derive(Debug, Clone, PartialEq, Eq)]
203pub struct ShellMonitorSrcMute {
204    /// For stream inputs.
205    pub stream: bool,
206    /// For analog inputs.
207    pub analog: Vec<bool>,
208    /// For digital inputs.
209    pub digital: Vec<bool>,
210}
211
212/// State of mixer.
213#[derive(Debug, Clone, PartialEq, Eq)]
214pub struct ShellMixerState {
215    /// For stream inputs.
216    pub stream: ShellMonitorSrcPair,
217    /// For analog inputs.
218    pub analog: Vec<ShellMonitorSrcPair>,
219    /// For digital inputs.
220    pub digital: Vec<ShellMonitorSrcPair>,
221    pub mutes: ShellMonitorSrcMute,
222    /// The level of output volume.
223    pub output_volume: i32,
224    /// Whether to dim level of output volume
225    pub output_dim_enable: bool,
226    /// The level of output volume at dimmed.
227    pub output_dim_volume: i32,
228}
229
230const SHELL_MIXER_MONITOR_SRC_COUNT: usize = 10;
231
232impl ShellMixerState {
233    pub(crate) const SIZE: usize = ShellMonitorSrcPair::SIZE * SHELL_MIXER_MONITOR_SRC_COUNT + 36;
234}
235
236/// The type of monitor source.
237#[derive(Debug, Copy, Clone, PartialEq, Eq)]
238pub enum ShellMixerMonitorSrcType {
239    /// Stream input.
240    Stream,
241    /// Analog input.
242    Analog,
243    /// S/PDIF input.
244    Spdif,
245    /// ADAT input.
246    Adat,
247    /// ADAT input and S/PDIF input.
248    AdatSpdif,
249}
250
251/// The trait for specification of mixer.
252pub trait ShellMixerStateSpecification {
253    /// The sources of monitor.
254    const MONITOR_SRC_MAP: [Option<ShellMixerMonitorSrcType>; SHELL_MIXER_MONITOR_SRC_COUNT];
255
256    /// The number of analog input pairs.
257    fn analog_input_pair_count() -> usize {
258        Self::MONITOR_SRC_MAP
259            .iter()
260            .filter(|&&m| m == Some(ShellMixerMonitorSrcType::Analog))
261            .count()
262    }
263
264    /// The number of digital input pairs.
265    fn digital_input_pair_count() -> usize {
266        Self::MONITOR_SRC_MAP
267            .iter()
268            .filter(|&&m| {
269                m != Some(ShellMixerMonitorSrcType::Analog)
270                    && m != Some(ShellMixerMonitorSrcType::Stream)
271                    && m.is_some()
272            })
273            .count()
274    }
275
276    /// Instantiate state of mixer.
277    fn create_mixer_state() -> ShellMixerState {
278        let analog_input_pair_count = Self::analog_input_pair_count();
279        let digital_input_pair_count = Self::digital_input_pair_count();
280
281        ShellMixerState {
282            stream: Default::default(),
283            analog: vec![Default::default(); analog_input_pair_count],
284            digital: vec![Default::default(); digital_input_pair_count],
285            mutes: ShellMonitorSrcMute {
286                stream: Default::default(),
287                analog: vec![Default::default(); analog_input_pair_count * 2],
288                digital: vec![Default::default(); digital_input_pair_count * 2],
289            },
290            output_volume: Default::default(),
291            output_dim_enable: Default::default(),
292            output_dim_volume: Default::default(),
293        }
294    }
295}
296
297fn serialize_mixer_state<T: ShellMixerStateSpecification>(
298    state: &ShellMixerState,
299    raw: &mut [u8],
300) -> Result<(), String> {
301    serialize_monitor_source_pair(&state.stream, &mut raw[..ShellMonitorSrcPair::SIZE])?;
302
303    // For analog inputs.
304    T::MONITOR_SRC_MAP
305        .iter()
306        .enumerate()
307        .filter(|(_, &m)| m == Some(ShellMixerMonitorSrcType::Analog))
308        .zip(&state.analog)
309        .try_for_each(|((i, _), src)| {
310            let pos = i * ShellMonitorSrcPair::SIZE;
311            serialize_monitor_source_pair(src, &mut raw[pos..(pos + ShellMonitorSrcPair::SIZE)])
312        })?;
313
314    // For digital inputs.
315    T::MONITOR_SRC_MAP
316        .iter()
317        .enumerate()
318        .filter(|(_, &m)| {
319            m.is_some()
320                && m != Some(ShellMixerMonitorSrcType::Analog)
321                && m != Some(ShellMixerMonitorSrcType::Stream)
322        })
323        .zip(&state.digital)
324        .try_for_each(|((i, _), src)| {
325            let pos = i * ShellMonitorSrcPair::SIZE;
326            serialize_monitor_source_pair(src, &mut raw[pos..(pos + ShellMonitorSrcPair::SIZE)])
327        })?;
328
329    // For mixer output.
330    serialize_bool(&state.output_dim_enable, &mut raw[280..284]);
331    serialize_i32(&state.output_volume, &mut raw[284..288]);
332    serialize_i32(&state.output_dim_volume, &mut raw[296..300]);
333
334    // For mute of sources.
335    let mut mutes = 0u32;
336    if state.mutes.stream {
337        mutes |= 0x00000001;
338    }
339    state
340        .mutes
341        .analog
342        .iter()
343        .chain(&state.mutes.digital)
344        .enumerate()
345        .filter(|(_, &muted)| muted)
346        .for_each(|(i, _)| {
347            mutes |= 1 << (8 + i);
348        });
349    serialize_u32(&mutes, &mut raw[308..312]);
350
351    Ok(())
352}
353
354fn deserialize_mixer_state<T: ShellMixerStateSpecification>(
355    state: &mut ShellMixerState,
356    raw: &[u8],
357) -> Result<(), String> {
358    deserialize_monitor_source_pair(&mut state.stream, &raw[..ShellMonitorSrcPair::SIZE])?;
359
360    // For analog inputs.
361    T::MONITOR_SRC_MAP
362        .iter()
363        .enumerate()
364        .filter(|(_, &m)| m == Some(ShellMixerMonitorSrcType::Analog))
365        .zip(&mut state.analog)
366        .try_for_each(|((i, _), src)| {
367            let pos = i * ShellMonitorSrcPair::SIZE;
368            deserialize_monitor_source_pair(src, &raw[pos..(pos + ShellMonitorSrcPair::SIZE)])
369        })?;
370
371    // For digital inputs.
372    T::MONITOR_SRC_MAP
373        .iter()
374        .enumerate()
375        .filter(|(_, &m)| m.is_some() && m != Some(ShellMixerMonitorSrcType::Analog))
376        .zip(&mut state.digital)
377        .try_for_each(|((i, _), src)| {
378            let pos = i * ShellMonitorSrcPair::SIZE;
379            deserialize_monitor_source_pair(src, &raw[pos..(pos + ShellMonitorSrcPair::SIZE)])
380        })?;
381
382    // For mixer output.
383    deserialize_bool(&mut state.output_dim_enable, &raw[280..284]);
384    deserialize_i32(&mut state.output_volume, &raw[284..288]);
385    deserialize_i32(&mut state.output_dim_volume, &raw[296..300]);
386
387    // For mute of sources.
388    let mut mutes = 0u32;
389    deserialize_u32(&mut mutes, &raw[308..312]);
390    state.mutes.stream = mutes & 0x00000001 > 0;
391    state
392        .mutes
393        .analog
394        .iter_mut()
395        .chain(&mut state.mutes.digital)
396        .enumerate()
397        .for_each(|(i, muted)| {
398            *muted = mutes & (1 << (8 + i)) > 0;
399        });
400
401    Ok(())
402}
403
404/// Return configuration of reverb effect.
405#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
406pub struct ShellReverbReturn {
407    /// Whether to use reverb effect as plugin. When enabled, return of reverb effect is delivered
408    /// by rx stream.
409    pub plugin_mode: bool,
410    /// The gain to return reverb effect to mixer output.
411    pub return_gain: i32,
412    /// Whether to mute return reverb effect to mixer output.
413    pub return_mute: bool,
414}
415
416impl ShellReverbReturn {
417    pub(crate) const SIZE: usize = 12;
418}
419
420fn serialize_reverb_return(state: &ShellReverbReturn, raw: &mut [u8]) -> Result<(), String> {
421    assert!(raw.len() >= ShellReverbReturn::SIZE);
422
423    serialize_bool(&state.plugin_mode, &mut raw[..4]);
424    serialize_i32(&state.return_gain, &mut raw[4..8]);
425    serialize_bool(&state.return_mute, &mut raw[8..12]);
426
427    Ok(())
428}
429
430fn deserialize_reverb_return(state: &mut ShellReverbReturn, raw: &[u8]) -> Result<(), String> {
431    assert!(raw.len() >= ShellReverbReturn::SIZE);
432
433    deserialize_bool(&mut state.plugin_mode, &raw[..4]);
434    deserialize_i32(&mut state.return_gain, &raw[4..8]);
435    deserialize_bool(&mut state.return_mute, &raw[8..12]);
436
437    Ok(())
438}
439
440/// Meter information. -1000..0 (-94.0..0 dB).
441#[derive(Default, Debug, Clone, PartialEq, Eq)]
442pub struct ShellMixerMeter {
443    /// Detected signal level of stream inputs.
444    pub stream_inputs: Vec<i32>,
445    /// Detected signal level of analog inputs.
446    pub analog_inputs: Vec<i32>,
447    /// Detected signal level of digital inputs.
448    pub digital_inputs: Vec<i32>,
449    /// Detected signal level of main outputs.
450    pub main_outputs: Vec<i32>,
451}
452
453impl ShellMixerMeter {
454    pub(crate) const SIZE: usize = 0x5c;
455}
456
457/// Specification for meter function of mixer.
458pub trait ShellMixerMeterSpecification {
459    const ANALOG_INPUT_COUNT: usize;
460    const DIGITAL_INPUT_COUNT: usize;
461
462    const STREAM_INPUT_COUNT: usize = 2;
463    const MAIN_OUTPUT_COUNT: usize = 2;
464    const MAX_STREAM_INPUT_COUNT: usize = 8;
465    const MAX_ANALOG_INPUT_COUNT: usize = 4;
466    const MAX_DIGITAL_INPUT_COUNT: usize = 8;
467
468    fn create_meter_state() -> ShellMixerMeter {
469        ShellMixerMeter {
470            stream_inputs: vec![Default::default(); Self::STREAM_INPUT_COUNT],
471            analog_inputs: vec![Default::default(); Self::ANALOG_INPUT_COUNT],
472            digital_inputs: vec![Default::default(); Self::DIGITAL_INPUT_COUNT],
473            main_outputs: vec![Default::default(); Self::MAIN_OUTPUT_COUNT],
474        }
475    }
476}
477
478fn serialize_mixer_meter<T: ShellMixerMeterSpecification>(
479    state: &ShellMixerMeter,
480    raw: &mut [u8],
481) -> Result<(), String> {
482    assert!(raw.len() >= ShellMixerMeter::SIZE);
483
484    let mut offset = 0;
485    state.stream_inputs.iter().enumerate().for_each(|(i, m)| {
486        let pos = offset + i * 4;
487        serialize_i32(m, &mut raw[pos..(pos + 4)]);
488    });
489
490    offset += T::MAX_STREAM_INPUT_COUNT * 4;
491    state
492        .analog_inputs
493        .iter()
494        .take(T::ANALOG_INPUT_COUNT)
495        .take(T::MAX_ANALOG_INPUT_COUNT)
496        .enumerate()
497        .for_each(|(i, m)| {
498            let pos = offset + i * 4;
499            serialize_i32(m, &mut raw[pos..(pos + 4)]);
500        });
501
502    offset += T::MAX_ANALOG_INPUT_COUNT * 4;
503    state
504        .digital_inputs
505        .iter()
506        .take(T::DIGITAL_INPUT_COUNT)
507        .take(T::MAX_DIGITAL_INPUT_COUNT)
508        .enumerate()
509        .for_each(|(i, m)| {
510            let pos = offset + i * 4;
511            serialize_i32(m, &mut raw[pos..(pos + 4)]);
512        });
513
514    offset += T::MAX_DIGITAL_INPUT_COUNT * 4;
515    state.main_outputs.iter().enumerate().for_each(|(i, m)| {
516        let pos = offset + i * 4;
517        serialize_i32(m, &mut raw[pos..(pos + 4)]);
518    });
519
520    Ok(())
521}
522
523fn deserialize_mixer_meter<T: ShellMixerMeterSpecification>(
524    state: &mut ShellMixerMeter,
525    raw: &[u8],
526) -> Result<(), String> {
527    assert!(raw.len() >= ShellMixerMeter::SIZE);
528
529    let mut offset = 0;
530    state
531        .stream_inputs
532        .iter_mut()
533        .enumerate()
534        .for_each(|(i, m)| {
535            let pos = offset + i * 4;
536            deserialize_i32(m, &raw[pos..(pos + 4)]);
537        });
538
539    offset += T::MAX_STREAM_INPUT_COUNT * 4;
540    state
541        .analog_inputs
542        .iter_mut()
543        .take(T::ANALOG_INPUT_COUNT)
544        .take(T::MAX_ANALOG_INPUT_COUNT)
545        .enumerate()
546        .for_each(|(i, m)| {
547            let pos = offset + i * 4;
548            deserialize_i32(m, &raw[pos..(pos + 4)]);
549        });
550
551    offset += T::MAX_ANALOG_INPUT_COUNT * 4;
552    state
553        .digital_inputs
554        .iter_mut()
555        .take(T::DIGITAL_INPUT_COUNT)
556        .take(T::MAX_DIGITAL_INPUT_COUNT)
557        .enumerate()
558        .for_each(|(i, m)| {
559            let pos = offset + i * 4;
560            deserialize_i32(m, &raw[pos..(pos + 4)]);
561        });
562
563    offset += T::MAX_DIGITAL_INPUT_COUNT * 4;
564    state
565        .main_outputs
566        .iter_mut()
567        .enumerate()
568        .for_each(|(i, m)| {
569            let pos = offset + i * 4;
570            deserialize_i32(m, &raw[pos..(pos + 4)]);
571        });
572
573    Ok(())
574}
575
576/// Available source for physical output.
577#[derive(Debug, Copy, Clone, PartialEq, Eq)]
578pub enum ShellPhysOutSrc {
579    /// Stream input.
580    Stream,
581    /// Analog input 1/2.
582    Analog01,
583    /// Mixer output 1/2.
584    MixerOut01,
585    /// Send 1/2.
586    MixerSend01,
587}
588
589impl Default for ShellPhysOutSrc {
590    fn default() -> Self {
591        Self::Stream
592    }
593}
594
595const PHYS_OUT_SRCS: &[ShellPhysOutSrc] = &[
596    ShellPhysOutSrc::Stream,
597    ShellPhysOutSrc::Analog01,
598    ShellPhysOutSrc::MixerOut01,
599    ShellPhysOutSrc::MixerSend01,
600];
601
602const PHYS_OUT_SRC_LABEL: &str = "physical output source";
603
604fn serialize_phys_out_src(src: &ShellPhysOutSrc, raw: &mut [u8]) -> Result<(), String> {
605    serialize_position(PHYS_OUT_SRCS, src, raw, PHYS_OUT_SRC_LABEL)
606}
607
608fn deserialize_phys_out_src(src: &mut ShellPhysOutSrc, raw: &[u8]) -> Result<(), String> {
609    deserialize_position(PHYS_OUT_SRCS, src, raw, PHYS_OUT_SRC_LABEL)
610}
611
612/// Format of optical input interface.
613#[derive(Debug, Copy, Clone, PartialEq, Eq)]
614pub enum ShellOptInputIfaceFormat {
615    /// ADAT 1/2/3/4/5/6/7/8.
616    Adat0to7,
617    /// ADAT 1/2/3/4/5/6 and S/PDIF 1/2.
618    Adat0to5Spdif01,
619    /// S/PDIF 1/2 in both coaxial and optical interfaces.
620    Toslink01Spdif01,
621}
622
623const OPT_INPUT_IFACE_FMT_LABELS: &str = "optical input format";
624
625const OPT_INPUT_IFACE_FMTS: &[ShellOptInputIfaceFormat] = &[
626    ShellOptInputIfaceFormat::Adat0to7,
627    ShellOptInputIfaceFormat::Adat0to5Spdif01,
628    ShellOptInputIfaceFormat::Toslink01Spdif01,
629];
630
631impl Default for ShellOptInputIfaceFormat {
632    fn default() -> Self {
633        ShellOptInputIfaceFormat::Adat0to7
634    }
635}
636
637/// Format of optical output interface.
638#[derive(Debug, Copy, Clone, PartialEq, Eq)]
639pub enum ShellOptOutputIfaceFormat {
640    Adat,
641    Spdif,
642}
643
644impl Default for ShellOptOutputIfaceFormat {
645    fn default() -> Self {
646        Self::Adat
647    }
648}
649
650const OPT_OUTPUT_IFACE_FMT_LABELS: &str = "optical output format";
651
652const OPT_OUTPUT_IFACE_FMTS: &[ShellOptOutputIfaceFormat] = &[
653    ShellOptOutputIfaceFormat::Adat,
654    ShellOptOutputIfaceFormat::Spdif,
655];
656
657/// Source for optical output interface.
658#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
659pub struct ShellOptOutputSrc(pub ShellPhysOutSrc);
660
661const OPT_OUT_SRC_LABEL: &str = "optical output source";
662
663/// Configuration for optical interface.
664#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
665pub struct ShellOptIfaceConfig {
666    pub input_format: ShellOptInputIfaceFormat,
667    pub output_format: ShellOptOutputIfaceFormat,
668    pub output_source: ShellOptOutputSrc,
669}
670
671impl ShellOptIfaceConfig {
672    const SIZE: usize = 12;
673}
674
675fn serialize_opt_iface_config(config: &ShellOptIfaceConfig, raw: &mut [u8]) -> Result<(), String> {
676    assert!(raw.len() >= ShellOptIfaceConfig::SIZE);
677
678    serialize_position(
679        OPT_INPUT_IFACE_FMTS,
680        &config.input_format,
681        &mut raw[..4],
682        OPT_INPUT_IFACE_FMT_LABELS,
683    )?;
684    serialize_position(
685        OPT_OUTPUT_IFACE_FMTS,
686        &config.output_format,
687        &mut raw[4..8],
688        OPT_OUTPUT_IFACE_FMT_LABELS,
689    )?;
690    serialize_position(
691        PHYS_OUT_SRCS,
692        &config.output_source.0,
693        &mut raw[8..],
694        OPT_OUT_SRC_LABEL,
695    )?;
696    Ok(())
697}
698
699fn deserialize_opt_iface_config(
700    config: &mut ShellOptIfaceConfig,
701    raw: &[u8],
702) -> Result<(), String> {
703    assert!(raw.len() >= ShellOptIfaceConfig::SIZE);
704
705    deserialize_position(
706        OPT_INPUT_IFACE_FMTS,
707        &mut config.input_format,
708        &raw[..4],
709        OPT_INPUT_IFACE_FMT_LABELS,
710    )?;
711    deserialize_position(
712        OPT_OUTPUT_IFACE_FMTS,
713        &mut config.output_format,
714        &raw[4..8],
715        OPT_OUTPUT_IFACE_FMT_LABELS,
716    )?;
717    deserialize_position(
718        PHYS_OUT_SRCS,
719        &mut config.output_source.0,
720        &raw[8..],
721        OPT_OUT_SRC_LABEL,
722    )?;
723    Ok(())
724}
725
726/// Source of coaxial output interface.
727#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
728pub struct ShellCoaxOutPairSrc(pub ShellPhysOutSrc);
729
730const COAX_OUT_PAIR_SRC_LABEL: &str = "coaxial output pair source";
731
732fn serialize_coax_out_pair_source(src: &ShellCoaxOutPairSrc, raw: &mut [u8]) -> Result<(), String> {
733    serialize_position(PHYS_OUT_SRCS, &src.0, raw, COAX_OUT_PAIR_SRC_LABEL)
734}
735
736fn deserialize_coax_out_pair_source(
737    src: &mut ShellCoaxOutPairSrc,
738    raw: &[u8],
739) -> Result<(), String> {
740    deserialize_position(PHYS_OUT_SRCS, &mut src.0, raw, COAX_OUT_PAIR_SRC_LABEL)
741}
742
743/// Available source for sampling clock.
744#[derive(Debug, Copy, Clone, PartialEq, Eq)]
745pub enum ShellStandaloneClockSource {
746    /// Signal from optical input interface.
747    Optical,
748    /// Signal from coaxial input interface.
749    Coaxial,
750    /// Internal oscillator.
751    Internal,
752}
753
754impl Default for ShellStandaloneClockSource {
755    fn default() -> Self {
756        Self::Internal
757    }
758}
759
760const STANDALONE_CLOCK_SOURCE_LABEL: &str = "Standalone clock source";
761
762/// Function specification for standalone clock source.
763pub trait ShellStandaloneClockSpecification {
764    /// The list of available sources.
765    const STANDALONE_CLOCK_SOURCES: &'static [ShellStandaloneClockSource];
766}
767
768/// Serialize for segment layout.
769fn serialize_standalone_clock_source<T: ShellStandaloneClockSpecification>(
770    src: &ShellStandaloneClockSource,
771    raw: &mut [u8],
772) -> Result<(), String> {
773    serialize_position(
774        T::STANDALONE_CLOCK_SOURCES,
775        src,
776        raw,
777        STANDALONE_CLOCK_SOURCE_LABEL,
778    )
779}
780
781/// Deserialize for segment layout.
782fn deserialize_standalone_clock_source<T: ShellStandaloneClockSpecification>(
783    src: &mut ShellStandaloneClockSource,
784    raw: &[u8],
785) -> Result<(), String> {
786    deserialize_position(
787        T::STANDALONE_CLOCK_SOURCES,
788        src,
789        raw,
790        STANDALONE_CLOCK_SOURCE_LABEL,
791    )
792}
793
794/// Stereo pair of audio data channels in isochronous packet stream available as single source of
795/// mixer.
796#[derive(Debug, Copy, Clone, PartialEq, Eq)]
797pub enum ShellMixerStreamSourcePair {
798    /// 1st pair of audio data channels.
799    Stream0_1,
800    /// 2nd pair of audio data channels.
801    Stream2_3,
802    /// 3rd pair of audio data channels.
803    Stream4_5,
804    /// 4th pair of audio data channels.
805    Stream6_7,
806    /// 5th pair of audio data channels.
807    Stream8_9,
808    /// 6th pair of audio data channels.
809    Stream10_11,
810    /// 7th pair of audio data channels.
811    Stream12_13,
812}
813
814impl Default for ShellMixerStreamSourcePair {
815    fn default() -> Self {
816        ShellMixerStreamSourcePair::Stream0_1
817    }
818}
819
820const MIXER_STREAM_SOURCE_PAIR_LABEL: &str = "Mixer stream source pair";
821
822/// Specification for source pair of stream to mixer.
823pub trait ShellMixerStreamSourcePairSpecification {
824    const MIXER_STREAM_SOURCE_PAIRS: &'static [ShellMixerStreamSourcePair];
825}
826
827/// Serialize for source pair.
828fn serialize_mixer_stream_source_pair<T: ShellMixerStreamSourcePairSpecification>(
829    pair: &ShellMixerStreamSourcePair,
830    raw: &mut [u8],
831) -> Result<(), String> {
832    serialize_position(
833        T::MIXER_STREAM_SOURCE_PAIRS,
834        pair,
835        raw,
836        MIXER_STREAM_SOURCE_PAIR_LABEL,
837    )
838}
839
840/// Deserialize for source pair.
841fn deserialize_mixer_stream_source_pair<T: ShellMixerStreamSourcePairSpecification>(
842    pair: &mut ShellMixerStreamSourcePair,
843    raw: &[u8],
844) -> Result<(), String> {
845    deserialize_position(
846        T::MIXER_STREAM_SOURCE_PAIRS,
847        pair,
848        raw,
849        MIXER_STREAM_SOURCE_PAIR_LABEL,
850    )
851}
852
853/// Target of 1st knob.
854#[derive(Debug, Copy, Clone, PartialEq, Eq)]
855pub enum ShellKnob0Target {
856    /// Analog input 1.
857    Analog0,
858    /// Analog input 2.
859    Analog1,
860    /// Analog input 3 and 4.
861    Analog2_3,
862    /// S/PDIF input 1 and 2.
863    Spdif0_1,
864    /// Compression ratio of channel strip effect to analog input 1.
865    ChannelStrip0,
866    /// Compression ratio of channel strip effect to analog input 2.
867    ChannelStrip1,
868    /// Reverb ratio or decay time of reverb effect.
869    Reverb,
870    /// Ratio to multiplex stream inputs in mixer.
871    Mixer,
872    /// Configured by mixer settings.
873    Configurable,
874}
875
876const KNOB0_TARGET_LABEL: &str = "Knob 0 target";
877
878/// Function specification of 1st knob.
879pub trait ShellKnob0TargetSpecification {
880    /// The list of targets supported for 1st knob.
881    const KNOB0_TARGETS: &'static [ShellKnob0Target];
882}
883
884/// Serialize for 1st knob.
885fn serialize_knob0_target<T: ShellKnob0TargetSpecification>(
886    target: &ShellKnob0Target,
887    raw: &mut [u8],
888) -> Result<(), String> {
889    serialize_position(T::KNOB0_TARGETS, target, raw, KNOB0_TARGET_LABEL)
890}
891
892/// Deserialize for 1st knob.
893fn deserialize_knob0_target<T: ShellKnob0TargetSpecification>(
894    target: &mut ShellKnob0Target,
895    raw: &[u8],
896) -> Result<(), String> {
897    deserialize_position(T::KNOB0_TARGETS, target, raw, KNOB0_TARGET_LABEL)
898}
899
900/// Target of 2nd knob.
901#[derive(Debug, Copy, Clone, PartialEq, Eq)]
902pub enum ShellKnob1Target {
903    /// ADAT input 1/2 or S/PDIF input 1/2 in optical interface.
904    Digital0_1,
905    /// ADAT input 3/4.
906    Digital2_3,
907    /// ADAT input 5/6.
908    Digital4_5,
909    /// ADAT input 7/8 or S/PDIF input 1/2 in coaxial interface.
910    Digital6_7,
911    /// Stream input to mixer.
912    Stream,
913    /// Reverb ratio or decay time of reverb return 1/2.
914    Reverb,
915    /// Normal/Dim Level of mixer output 1/2.
916    Mixer,
917    /// Pitch or tone of tuner.
918    TunerPitchTone,
919    /// Generate MIDI event.
920    MidiSend,
921}
922
923const KNOB1_TARGET_LABEL: &str = "Knob 1 target";
924
925/// Function specification of 2nd knob.
926pub trait ShellKnob1TargetSpecification {
927    /// The list of targets supported for 2nd knob.
928    const KNOB1_TARGETS: &'static [ShellKnob1Target];
929}
930
931/// Serialize for 1st knob.
932fn serialize_knob1_target<T: ShellKnob1TargetSpecification>(
933    target: &ShellKnob1Target,
934    raw: &mut [u8],
935) -> Result<(), String> {
936    serialize_position(T::KNOB1_TARGETS, target, raw, KNOB1_TARGET_LABEL)
937}
938
939/// Deserialize for 1st knob.
940fn deserialize_knob1_target<T: ShellKnob1TargetSpecification>(
941    target: &mut ShellKnob1Target,
942    raw: &[u8],
943) -> Result<(), String> {
944    deserialize_position(T::KNOB1_TARGETS, target, raw, KNOB1_TARGET_LABEL)
945}
946
947/// The size of segment for knob settings.
948pub(crate) const SHELL_KNOB_SEGMENT_SIZE: usize = 36;