1pub 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;
21const SHELL_HW_STATE_NOTIFY_FLAG: u32 = 0x01000000;
24
25const SHELL_CH_STRIP_COUNT: usize = 2;
26
27#[derive(Debug, Copy, Clone, PartialEq, Eq)]
29pub enum ShellAnalogJackState {
30 FrontSelected,
32 FrontInserted,
34 FrontInsertedAttenuated,
36 RearSelected,
38 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
96pub const SHELL_ANALOG_JACK_STATE_COUNT: usize = 2;
98
99#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
101pub struct ShellHwState {
102 pub analog_jack_states: [ShellAnalogJackState; SHELL_ANALOG_JACK_STATE_COUNT],
104 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#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
134pub struct MonitorSrcParam {
135 pub gain_to_mixer: i32,
137 pub pan_to_mixer: i32,
139 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(¶m.gain_to_mixer, &mut raw[..4]);
151 serialize_i32(¶m.pan_to_mixer, &mut raw[4..8]);
152 serialize_i32(¶m.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#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
169pub struct ShellMonitorSrcPair {
170 pub stereo_link: bool,
172 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#[derive(Debug, Clone, PartialEq, Eq)]
203pub struct ShellMonitorSrcMute {
204 pub stream: bool,
206 pub analog: Vec<bool>,
208 pub digital: Vec<bool>,
210}
211
212#[derive(Debug, Clone, PartialEq, Eq)]
214pub struct ShellMixerState {
215 pub stream: ShellMonitorSrcPair,
217 pub analog: Vec<ShellMonitorSrcPair>,
219 pub digital: Vec<ShellMonitorSrcPair>,
221 pub mutes: ShellMonitorSrcMute,
222 pub output_volume: i32,
224 pub output_dim_enable: bool,
226 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#[derive(Debug, Copy, Clone, PartialEq, Eq)]
238pub enum ShellMixerMonitorSrcType {
239 Stream,
241 Analog,
243 Spdif,
245 Adat,
247 AdatSpdif,
249}
250
251pub trait ShellMixerStateSpecification {
253 const MONITOR_SRC_MAP: [Option<ShellMixerMonitorSrcType>; SHELL_MIXER_MONITOR_SRC_COUNT];
255
256 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 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 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 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 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 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 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 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 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 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 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#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
406pub struct ShellReverbReturn {
407 pub plugin_mode: bool,
410 pub return_gain: i32,
412 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#[derive(Default, Debug, Clone, PartialEq, Eq)]
442pub struct ShellMixerMeter {
443 pub stream_inputs: Vec<i32>,
445 pub analog_inputs: Vec<i32>,
447 pub digital_inputs: Vec<i32>,
449 pub main_outputs: Vec<i32>,
451}
452
453impl ShellMixerMeter {
454 pub(crate) const SIZE: usize = 0x5c;
455}
456
457pub 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#[derive(Debug, Copy, Clone, PartialEq, Eq)]
578pub enum ShellPhysOutSrc {
579 Stream,
581 Analog01,
583 MixerOut01,
585 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#[derive(Debug, Copy, Clone, PartialEq, Eq)]
614pub enum ShellOptInputIfaceFormat {
615 Adat0to7,
617 Adat0to5Spdif01,
619 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#[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#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
659pub struct ShellOptOutputSrc(pub ShellPhysOutSrc);
660
661const OPT_OUT_SRC_LABEL: &str = "optical output source";
662
663#[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#[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#[derive(Debug, Copy, Clone, PartialEq, Eq)]
745pub enum ShellStandaloneClockSource {
746 Optical,
748 Coaxial,
750 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
762pub trait ShellStandaloneClockSpecification {
764 const STANDALONE_CLOCK_SOURCES: &'static [ShellStandaloneClockSource];
766}
767
768fn 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
781fn 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#[derive(Debug, Copy, Clone, PartialEq, Eq)]
797pub enum ShellMixerStreamSourcePair {
798 Stream0_1,
800 Stream2_3,
802 Stream4_5,
804 Stream6_7,
806 Stream8_9,
808 Stream10_11,
810 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
822pub trait ShellMixerStreamSourcePairSpecification {
824 const MIXER_STREAM_SOURCE_PAIRS: &'static [ShellMixerStreamSourcePair];
825}
826
827fn 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
840fn 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#[derive(Debug, Copy, Clone, PartialEq, Eq)]
855pub enum ShellKnob0Target {
856 Analog0,
858 Analog1,
860 Analog2_3,
862 Spdif0_1,
864 ChannelStrip0,
866 ChannelStrip1,
868 Reverb,
870 Mixer,
872 Configurable,
874}
875
876const KNOB0_TARGET_LABEL: &str = "Knob 0 target";
877
878pub trait ShellKnob0TargetSpecification {
880 const KNOB0_TARGETS: &'static [ShellKnob0Target];
882}
883
884fn 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
892fn 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#[derive(Debug, Copy, Clone, PartialEq, Eq)]
902pub enum ShellKnob1Target {
903 Digital0_1,
905 Digital2_3,
907 Digital4_5,
909 Digital6_7,
911 Stream,
913 Reverb,
915 Mixer,
917 TunerPitchTone,
919 MidiSend,
921}
922
923const KNOB1_TARGET_LABEL: &str = "Knob 1 target";
924
925pub trait ShellKnob1TargetSpecification {
927 const KNOB1_TARGETS: &'static [ShellKnob1Target];
929}
930
931fn 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
939fn 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
947pub(crate) const SHELL_KNOB_SEGMENT_SIZE: usize = 36;