1use {
14 super::*,
15 hinawa::{prelude::FwRespExt, FwResp},
16};
17
18const DSP_CMD_OFFSET: u64 = 0xffff00010000;
19const DSP_MSG_DST_HIGH_OFFSET: u32 = 0x0b38;
20const DSP_MSG_DST_LOW_OFFSET: u32 = 0x0b3c;
21
22const MAXIMUM_DSP_FRAME_SIZE: usize = 248;
23
24const CMD_RESOURCE: u8 = 0x23;
25const CMD_BYTE_MULTIPLE: u8 = 0x49;
26const CMD_QUADLET_MULTIPLE: u8 = 0x46;
27const CMD_DRAIN: u8 = 0x62;
28const CMD_END: u8 = 0x65;
29const CMD_BYTE_SINGLE: u8 = 0x69;
30const CMD_QUADLET_SINGLE: u8 = 0x66;
31
32const CMD_RESOURCE_LENGTH: usize = 6;
33const CMD_BYTE_SINGLE_LENGTH: usize = 6;
34const CMD_QUADLET_SINGLE_LENGTH: usize = 9;
35
36const MSG_DST_OFFSET_BEGIN: u64 = 0xffffe0000000;
37const MSG_DST_OFFSET_END: u64 = MSG_DST_OFFSET_BEGIN + 0x10000000;
38
39#[derive(Debug, Copy, Clone, Eq, PartialEq)]
41pub enum InputStereoPairMode {
42 LeftRight,
44 MonauralStereo,
46 Reserved(u8),
47}
48
49impl Default for InputStereoPairMode {
50 fn default() -> Self {
51 InputStereoPairMode::LeftRight
52 }
53}
54
55impl From<u8> for InputStereoPairMode {
56 fn from(val: u8) -> Self {
57 match val {
58 0 => Self::LeftRight,
59 1 => Self::MonauralStereo,
60 _ => Self::Reserved(val),
61 }
62 }
63}
64
65impl From<InputStereoPairMode> for u8 {
66 fn from(mode: InputStereoPairMode) -> Self {
67 match mode {
68 InputStereoPairMode::LeftRight => 0,
69 InputStereoPairMode::MonauralStereo => 1,
70 InputStereoPairMode::Reserved(val) => val,
71 }
72 }
73}
74
75#[derive(Debug, Copy, Clone, Eq, PartialEq)]
77pub enum RollOffLevel {
78 L6,
80 L12,
82 L18,
84 L24,
86 L30,
88 L36,
90 Reserved(u8),
91}
92
93impl Default for RollOffLevel {
94 fn default() -> Self {
95 Self::L6
96 }
97}
98
99impl From<u8> for RollOffLevel {
100 fn from(val: u8) -> Self {
101 match val {
102 0 => Self::L6,
103 1 => Self::L12,
104 2 => Self::L18,
105 3 => Self::L24,
106 4 => Self::L30,
107 5 => Self::L36,
108 _ => Self::Reserved(val),
109 }
110 }
111}
112
113impl From<RollOffLevel> for u8 {
114 fn from(level: RollOffLevel) -> Self {
115 match level {
116 RollOffLevel::L6 => 0,
117 RollOffLevel::L12 => 1,
118 RollOffLevel::L18 => 2,
119 RollOffLevel::L24 => 3,
120 RollOffLevel::L30 => 4,
121 RollOffLevel::L36 => 5,
122 RollOffLevel::Reserved(val) => val,
123 }
124 }
125}
126
127#[derive(Debug, Copy, Clone, Eq, PartialEq)]
129pub enum FilterType5 {
130 T1,
131 T2,
132 T3,
133 T4,
134 Shelf,
135 Reserved(u8),
136}
137
138impl Default for FilterType5 {
139 fn default() -> Self {
140 Self::T1
141 }
142}
143
144impl From<u8> for FilterType5 {
145 fn from(val: u8) -> Self {
146 match val {
147 0 => Self::T1,
148 1 => Self::T2,
149 2 => Self::T3,
150 3 => Self::T4,
151 4 => Self::Shelf,
152 _ => Self::Reserved(val),
153 }
154 }
155}
156
157impl From<FilterType5> for u8 {
158 fn from(filter_type: FilterType5) -> Self {
159 match filter_type {
160 FilterType5::T1 => 0,
161 FilterType5::T2 => 1,
162 FilterType5::T3 => 2,
163 FilterType5::T4 => 3,
164 FilterType5::Shelf => 4,
165 FilterType5::Reserved(val) => val,
166 }
167 }
168}
169
170#[derive(Debug, Copy, Clone, Eq, PartialEq)]
172pub enum FilterType4 {
173 T1,
174 T2,
175 T3,
176 T4,
177 Reserved(u8),
178}
179
180impl Default for FilterType4 {
181 fn default() -> Self {
182 Self::T1
183 }
184}
185
186impl From<u8> for FilterType4 {
187 fn from(val: u8) -> Self {
188 match val {
189 0 => Self::T1,
190 1 => Self::T2,
191 2 => Self::T3,
192 3 => Self::T4,
193 _ => Self::Reserved(val),
194 }
195 }
196}
197
198impl From<FilterType4> for u8 {
199 fn from(filter_type: FilterType4) -> Self {
200 match filter_type {
201 FilterType4::T1 => 0,
202 FilterType4::T2 => 1,
203 FilterType4::T3 => 2,
204 FilterType4::T4 => 3,
205 FilterType4::Reserved(val) => val,
206 }
207 }
208}
209
210#[derive(Debug, Copy, Clone, Eq, PartialEq)]
212pub enum LevelDetectMode {
213 Peak,
215 Rms,
217 Reserved(u8),
218}
219
220impl Default for LevelDetectMode {
221 fn default() -> Self {
222 Self::Peak
223 }
224}
225
226impl From<u8> for LevelDetectMode {
227 fn from(val: u8) -> Self {
228 match val {
229 0 => Self::Peak,
230 1 => Self::Rms,
231 _ => Self::Reserved(val),
232 }
233 }
234}
235
236impl From<LevelDetectMode> for u8 {
237 fn from(mode: LevelDetectMode) -> Self {
238 match mode {
239 LevelDetectMode::Peak => 0,
240 LevelDetectMode::Rms => 1,
241 LevelDetectMode::Reserved(val) => val,
242 }
243 }
244}
245
246#[derive(Debug, Copy, Clone, Eq, PartialEq)]
248pub enum LevelerMode {
249 Compress,
250 Limit,
251 Reserved(u8),
252}
253
254impl Default for LevelerMode {
255 fn default() -> Self {
256 LevelerMode::Compress
257 }
258}
259
260impl From<u8> for LevelerMode {
261 fn from(val: u8) -> Self {
262 match val {
263 0 => Self::Compress,
264 1 => Self::Limit,
265 _ => Self::Reserved(val),
266 }
267 }
268}
269
270impl From<LevelerMode> for u8 {
271 fn from(mode: LevelerMode) -> Self {
272 match mode {
273 LevelerMode::Compress => 0,
274 LevelerMode::Limit => 1,
275 LevelerMode::Reserved(val) => val,
276 }
277 }
278}
279
280#[derive(Debug, Clone, PartialEq)]
282pub enum EqualizerParameter {
283 Enable(bool),
284 HpfEnable(bool),
285 HpfSlope(RollOffLevel),
286 HpfFreq(u32),
287 LpfEnable(bool),
288 LpfSlope(RollOffLevel),
289 LpfFreq(u32),
290 LfEnable(bool),
291 LfType(FilterType5),
292 LfFreq(u32),
293 LfGain(f32),
294 LfWidth(f32),
295 LmfEnable(bool),
296 LmfType(FilterType4),
297 LmfFreq(u32),
298 LmfGain(f32),
299 LmfWidth(f32),
300 MfEnable(bool),
301 MfType(FilterType4),
302 MfFreq(u32),
303 MfGain(f32),
304 MfWidth(f32),
305 HmfEnable(bool),
306 HmfType(FilterType4),
307 HmfFreq(u32),
308 HmfGain(f32),
309 HmfWidth(f32),
310 HfEnable(bool),
311 HfType(FilterType5),
312 HfFreq(u32),
313 HfGain(f32),
314 HfWidth(f32),
315}
316
317#[derive(Debug, Clone, PartialEq)]
319pub enum DynamicsParameter {
320 Enable(bool),
321 CompEnable(bool),
322 CompDetectMode(LevelDetectMode),
323 CompThreshold(i32),
324 CompRatio(f32),
325 CompAttack(u32),
326 CompRelease(u32),
327 CompGain(f32),
328 LevelerEnable(bool),
329 LevelerMode(LevelerMode),
330 LevelerMakeup(u32),
331 LevelerReduce(u32),
332}
333
334fn to_bool(raw: &[u8]) -> bool {
335 assert_eq!(raw.len(), 1);
336
337 raw[0] > 0
338}
339
340fn to_usize(raw: &[u8]) -> usize {
341 assert_eq!(raw.len(), 1);
342
343 raw[0] as usize
344}
345
346fn to_i32(raw: &[u8]) -> i32 {
347 to_f32(raw) as i32
348}
349
350fn to_f32(raw: &[u8]) -> f32 {
351 assert_eq!(raw.len(), 4);
352
353 let mut quadlet = [0; 4];
354 quadlet.copy_from_slice(raw);
355
356 f32::from_le_bytes(quadlet)
357}
358
359fn to_u32(raw: &[u8]) -> u32 {
360 to_f32(raw) as u32
361}
362
363fn append_data(raw: &mut Vec<u8>, identifier: &[u8], vals: &[u8]) {
364 if vals.len() == 4 {
365 raw.push(CMD_QUADLET_SINGLE);
366 raw.extend_from_slice(identifier);
367 raw.extend_from_slice(vals);
368 } else {
369 raw.push(CMD_BYTE_SINGLE);
370 raw.extend_from_slice(vals);
371 raw.extend_from_slice(identifier);
372 }
373}
374
375#[derive(Debug, Copy, Clone, Eq, PartialEq)]
377pub enum FocusTarget {
378 Output(usize),
379 Input(usize),
380 Reserved(usize, usize),
381}
382
383impl Default for FocusTarget {
384 fn default() -> Self {
385 Self::Output(0)
386 }
387}
388
389impl From<&[u8]> for FocusTarget {
390 fn from(raw: &[u8]) -> Self {
391 match raw[3] {
392 0x01 => Self::Input(raw[0] as usize),
393 0x03 => Self::Output(raw[0] as usize),
394 _ => Self::Reserved(raw[3] as usize, raw[0] as usize),
395 }
396 }
397}
398
399impl From<&FocusTarget> for Vec<u8> {
400 fn from(target: &FocusTarget) -> Self {
401 match target {
402 FocusTarget::Input(ch) => vec![*ch as u8, 0x00, 0x00, 0x01],
403 FocusTarget::Output(ch) => vec![*ch as u8, 0x00, 0x00, 0x03],
404 FocusTarget::Reserved(dir, ch) => vec![*ch as u8, 0x00, 0x00, *dir as u8],
405 }
406 }
407}
408
409#[derive(Debug, Clone, PartialEq)]
411pub enum MonitorCmd {
412 Volume(f32),
413 TalkbackEnable(bool),
414 ListenbackEnable(bool),
415 TalkbackVolume(f32),
416 ListenbackVolume(f32),
417 Focus(FocusTarget),
418 ReturnAssign(usize),
419 Reserved(Vec<u8>, Vec<u8>),
420}
421
422impl MonitorCmd {
423 fn parse(identifier: &[u8], vals: &[u8]) -> Self {
424 assert_eq!(identifier.len(), 4);
425 assert!(vals.len() > 0);
426
427 match (identifier[3], identifier[2], identifier[1]) {
428 (0x00, 0x00, 0x00) => MonitorCmd::Volume(to_f32(vals)),
429 (0x00, 0x00, 0x01) => MonitorCmd::TalkbackEnable(to_bool(vals)),
430 (0x00, 0x00, 0x02) => MonitorCmd::ListenbackEnable(to_bool(vals)),
431 (0x00, 0x00, 0x05) => MonitorCmd::TalkbackVolume(to_f32(vals)),
435 (0x00, 0x00, 0x06) => MonitorCmd::ListenbackVolume(to_f32(vals)),
436 (0x00, 0x00, 0x07) => MonitorCmd::Focus(FocusTarget::from(vals)),
437 (0x00, 0x00, 0x08) => MonitorCmd::ReturnAssign(to_usize(vals)),
438 _ => MonitorCmd::Reserved(identifier.to_vec(), vals.to_vec()),
439 }
440 }
441
442 fn build(&self, raw: &mut Vec<u8>) {
443 match self {
444 MonitorCmd::Volume(val) => append_f32(raw, 0x00, 0x00, 0x00, 0, *val),
445 MonitorCmd::TalkbackEnable(val) => append_u8(raw, 0x00, 0x00, 0x01, 0, *val as u8),
446 MonitorCmd::ListenbackEnable(val) => append_u8(raw, 0x00, 0x00, 0x02, 0, *val as u8),
447 MonitorCmd::TalkbackVolume(val) => append_f32(raw, 0x00, 0x00, 0x05, 0, *val),
448 MonitorCmd::ListenbackVolume(val) => append_f32(raw, 0x00, 0x00, 0x06, 0, *val),
449 MonitorCmd::Focus(target) => {
450 append_data(raw, &[0x00, 0x07, 0x00, 0x00], &Vec::from(target))
451 }
452 MonitorCmd::ReturnAssign(target) => append_u8(raw, 0x00, 0x00, 0x08, 0, *target as u8),
453 MonitorCmd::Reserved(identifier, vals) => append_data(raw, identifier, vals),
454 }
455 }
456}
457
458#[derive(Debug, Clone, PartialEq)]
460pub enum InputCmd {
461 Phase(usize, bool),
462 Pair(usize, bool),
463 Gain(usize, i32),
464 Swap(usize, bool),
465 StereoMode(usize, InputStereoPairMode),
466 Width(usize, f32),
467 Equalizer(usize, EqualizerParameter),
468 Dynamics(usize, DynamicsParameter),
469 ReverbSend(usize, f32),
470 ReverbLrBalance(usize, f32),
471 Pad(usize, bool),
472 NominalLevel(usize, NominalSignalLevel),
473 Phantom(usize, bool),
474 Limitter(usize, bool),
475 Lookahead(usize, bool),
476 Softclip(usize, bool),
477 Reserved(Vec<u8>, Vec<u8>),
478}
479
480impl InputCmd {
481 fn parse(identifier: &[u8], vals: &[u8]) -> Self {
482 assert_eq!(identifier.len(), 4);
483 assert!(vals.len() > 0);
484
485 let ch = identifier[0] as usize;
486
487 match (identifier[3], identifier[2], identifier[1]) {
488 (0x01, 0x00, 0x00) => InputCmd::Phase(ch, to_bool(vals)),
489 (0x01, 0x00, 0x01) => InputCmd::Pair(ch, to_bool(vals)),
490 (0x01, 0x00, 0x02) => InputCmd::Gain(ch, to_i32(vals)),
491 (0x01, 0x00, 0x03) => InputCmd::Swap(ch, to_bool(vals)),
492 (0x01, 0x00, 0x04) => InputCmd::StereoMode(ch, InputStereoPairMode::from(vals[0])),
493 (0x01, 0x00, 0x05) => InputCmd::Width(ch, to_f32(vals)),
494 (0x01, 0x00, 0x06) => InputCmd::Limitter(ch, to_bool(vals)),
495 (0x01, 0x00, 0x07) => InputCmd::Lookahead(ch, to_bool(vals)),
496 (0x01, 0x00, 0x08) => InputCmd::Softclip(ch, to_bool(vals)),
497 (0x01, 0x00, 0x09) => InputCmd::Pad(ch, to_bool(vals)),
498 (0x01, 0x00, 0x0a) => {
499 let level = if to_bool(vals) {
500 NominalSignalLevel::Professional
501 } else {
502 NominalSignalLevel::Consumer
503 };
504 InputCmd::NominalLevel(ch, level)
505 }
506 (0x01, 0x00, 0x0b) => InputCmd::Phantom(ch, to_bool(vals)),
507
508 (0x01, 0x01, 0x00) => {
509 InputCmd::Equalizer(ch, EqualizerParameter::Enable(to_bool(vals)))
510 }
511
512 (0x01, 0x02, 0x00) => {
513 InputCmd::Equalizer(ch, EqualizerParameter::HpfEnable(to_bool(vals)))
514 }
515 (0x01, 0x02, 0x01) => InputCmd::Equalizer(
516 ch,
517 EqualizerParameter::HpfSlope(RollOffLevel::from(vals[0])),
518 ),
519 (0x01, 0x02, 0x02) => {
520 InputCmd::Equalizer(ch, EqualizerParameter::HpfFreq(to_u32(vals)))
521 }
522
523 (0x01, 0x03, 0x00) => {
524 InputCmd::Equalizer(ch, EqualizerParameter::LfEnable(to_bool(vals)))
525 }
526 (0x01, 0x03, 0x01) => {
527 InputCmd::Equalizer(ch, EqualizerParameter::LfType(FilterType5::from(vals[0])))
528 }
529 (0x01, 0x03, 0x02) => InputCmd::Equalizer(ch, EqualizerParameter::LfFreq(to_u32(vals))),
530 (0x01, 0x03, 0x03) => InputCmd::Equalizer(ch, EqualizerParameter::LfGain(to_f32(vals))),
531 (0x01, 0x03, 0x04) => {
532 InputCmd::Equalizer(ch, EqualizerParameter::LfWidth(to_f32(vals)))
533 }
534
535 (0x01, 0x04, 0x00) => {
536 InputCmd::Equalizer(ch, EqualizerParameter::LmfEnable(to_bool(vals)))
537 }
538 (0x01, 0x04, 0x01) => {
539 InputCmd::Equalizer(ch, EqualizerParameter::LmfType(FilterType4::from(vals[0])))
540 }
541 (0x01, 0x04, 0x02) => {
542 InputCmd::Equalizer(ch, EqualizerParameter::LmfFreq(to_u32(vals)))
543 }
544 (0x01, 0x04, 0x03) => {
545 InputCmd::Equalizer(ch, EqualizerParameter::LmfGain(to_f32(vals)))
546 }
547 (0x01, 0x04, 0x04) => {
548 InputCmd::Equalizer(ch, EqualizerParameter::LmfWidth(to_f32(vals)))
549 }
550
551 (0x01, 0x05, 0x00) => {
552 InputCmd::Equalizer(ch, EqualizerParameter::MfEnable(to_bool(vals)))
553 }
554 (0x01, 0x05, 0x01) => {
555 InputCmd::Equalizer(ch, EqualizerParameter::MfType(FilterType4::from(vals[0])))
556 }
557 (0x01, 0x05, 0x02) => InputCmd::Equalizer(ch, EqualizerParameter::MfFreq(to_u32(vals))),
558 (0x01, 0x05, 0x03) => InputCmd::Equalizer(ch, EqualizerParameter::MfGain(to_f32(vals))),
559 (0x01, 0x05, 0x04) => {
560 InputCmd::Equalizer(ch, EqualizerParameter::MfWidth(to_f32(vals)))
561 }
562
563 (0x01, 0x06, 0x00) => {
564 InputCmd::Equalizer(ch, EqualizerParameter::HmfEnable(to_bool(vals)))
565 }
566 (0x01, 0x06, 0x01) => {
567 InputCmd::Equalizer(ch, EqualizerParameter::HmfType(FilterType4::from(vals[0])))
568 }
569 (0x01, 0x06, 0x02) => {
570 InputCmd::Equalizer(ch, EqualizerParameter::HmfFreq(to_u32(vals)))
571 }
572 (0x01, 0x06, 0x03) => {
573 InputCmd::Equalizer(ch, EqualizerParameter::HmfGain(to_f32(vals)))
574 }
575 (0x01, 0x06, 0x04) => {
576 InputCmd::Equalizer(ch, EqualizerParameter::HmfWidth(to_f32(vals)))
577 }
578
579 (0x01, 0x07, 0x00) => {
580 InputCmd::Equalizer(ch, EqualizerParameter::HfEnable(to_bool(vals)))
581 }
582 (0x01, 0x07, 0x01) => {
583 InputCmd::Equalizer(ch, EqualizerParameter::HfType(FilterType5::from(vals[0])))
584 }
585 (0x01, 0x07, 0x02) => InputCmd::Equalizer(ch, EqualizerParameter::HfFreq(to_u32(vals))),
586 (0x01, 0x07, 0x03) => InputCmd::Equalizer(ch, EqualizerParameter::HfGain(to_f32(vals))),
587 (0x01, 0x07, 0x04) => {
588 InputCmd::Equalizer(ch, EqualizerParameter::HfWidth(to_f32(vals)))
589 }
590
591 (0x01, 0x08, 0x00) => {
592 InputCmd::Equalizer(ch, EqualizerParameter::LpfEnable(to_bool(vals)))
593 }
594 (0x01, 0x08, 0x01) => InputCmd::Equalizer(
595 ch,
596 EqualizerParameter::LpfSlope(RollOffLevel::from(vals[0])),
597 ),
598 (0x01, 0x08, 0x02) => {
599 InputCmd::Equalizer(ch, EqualizerParameter::LpfFreq(to_u32(vals)))
600 }
601
602 (0x01, 0x09, 0x00) => InputCmd::Dynamics(ch, DynamicsParameter::Enable(to_bool(vals))),
603
604 (0x01, 0x0a, 0x00) => {
605 InputCmd::Dynamics(ch, DynamicsParameter::CompEnable(to_bool(vals)))
606 }
607 (0x01, 0x0a, 0x01) => {
608 InputCmd::Dynamics(ch, DynamicsParameter::CompThreshold(to_i32(vals)))
609 }
610 (0x01, 0x0a, 0x02) => {
611 InputCmd::Dynamics(ch, DynamicsParameter::CompRatio(to_f32(vals)))
612 }
613 (0x01, 0x0a, 0x03) => {
614 InputCmd::Dynamics(ch, DynamicsParameter::CompAttack(to_u32(vals)))
615 }
616 (0x01, 0x0a, 0x04) => {
617 InputCmd::Dynamics(ch, DynamicsParameter::CompRelease(to_u32(vals)))
618 }
619 (0x01, 0x0a, 0x05) => InputCmd::Dynamics(ch, DynamicsParameter::CompGain(to_f32(vals))),
620 (0x01, 0x0a, 0x06) => InputCmd::Dynamics(
621 ch,
622 DynamicsParameter::CompDetectMode(LevelDetectMode::from(vals[0])),
623 ),
624
625 (0x01, 0x0b, 0x00) => {
626 InputCmd::Dynamics(ch, DynamicsParameter::LevelerEnable(to_bool(vals)))
627 }
628 (0x01, 0x0b, 0x01) => InputCmd::Dynamics(
629 ch,
630 DynamicsParameter::LevelerMode(LevelerMode::from(vals[0])),
631 ),
632 (0x01, 0x0b, 0x02) => {
633 InputCmd::Dynamics(ch, DynamicsParameter::LevelerMakeup(to_u32(vals)))
634 }
635 (0x01, 0x0b, 0x03) => {
636 InputCmd::Dynamics(ch, DynamicsParameter::LevelerReduce(to_u32(vals)))
637 }
638
639 (0x01, 0x0c, 0x00) => InputCmd::ReverbSend(ch, to_f32(vals)),
640 (0x01, 0x0c, 0x02) => InputCmd::ReverbLrBalance(ch, to_f32(vals)),
641
642 _ => InputCmd::Reserved(identifier.to_vec(), vals.to_vec()),
648 }
649 }
650
651 fn build(&self, raw: &mut Vec<u8>) {
652 match self {
653 InputCmd::Phase(ch, enabled) => append_u8(raw, 0x01, 0x00, 0x00, *ch, *enabled),
654 InputCmd::Pair(ch, enabled) => append_u8(raw, 0x01, 0x00, 0x01, *ch, *enabled),
655 InputCmd::Gain(ch, val) => append_i32(raw, 0x01, 0x00, 0x02, *ch, *val),
656 InputCmd::Swap(ch, enabled) => append_u8(raw, 0x01, 0x00, 0x03, *ch, *enabled),
657 InputCmd::StereoMode(ch, pair_mode) => {
658 append_u8(raw, 0x01, 0x00, 0x04, *ch, *pair_mode)
659 }
660 InputCmd::Width(ch, val) => append_f32(raw, 0x01, 0x00, 0x05, *ch, *val),
661 InputCmd::Limitter(ch, enabled) => append_u8(raw, 0x01, 0x00, 0x06, *ch, *enabled),
662 InputCmd::Lookahead(ch, enabled) => append_u8(raw, 0x01, 0x00, 0x07, *ch, *enabled),
663 InputCmd::Softclip(ch, enabled) => append_u8(raw, 0x01, 0x00, 0x08, *ch, *enabled),
664 InputCmd::Pad(ch, enabled) => append_u8(raw, 0x01, 0x00, 0x09, *ch, *enabled),
665 InputCmd::NominalLevel(ch, level) => {
666 let val = if *level == NominalSignalLevel::Professional {
667 0x01
668 } else {
669 0x00
670 };
671 append_u8(raw, 0x01, 0x00, 0x0a, *ch, val)
672 }
673
674 InputCmd::Phantom(ch, enabled) => append_u8(raw, 0x01, 0x00, 0x0b, *ch, *enabled),
675
676 InputCmd::Equalizer(ch, EqualizerParameter::Enable(enabled)) => {
677 append_u8(raw, 0x01, 0x01, 0x00, *ch, *enabled)
678 }
679
680 InputCmd::Equalizer(ch, EqualizerParameter::HpfEnable(enabled)) => {
681 append_u8(raw, 0x01, 0x02, 0x00, *ch, *enabled)
682 }
683 InputCmd::Equalizer(ch, EqualizerParameter::HpfSlope(level)) => {
684 append_u8(raw, 0x01, 0x02, 0x01, *ch, *level)
685 }
686 InputCmd::Equalizer(ch, EqualizerParameter::HpfFreq(val)) => {
687 append_u32(raw, 0x01, 0x02, 0x02, *ch, *val)
688 }
689
690 InputCmd::Equalizer(ch, EqualizerParameter::LfEnable(enabled)) => {
691 append_u8(raw, 0x01, 0x03, 0x00, *ch, *enabled)
692 }
693 InputCmd::Equalizer(ch, EqualizerParameter::LfType(filter_type)) => {
694 append_u8(raw, 0x01, 0x03, 0x01, *ch, *filter_type)
695 }
696 InputCmd::Equalizer(ch, EqualizerParameter::LfFreq(val)) => {
697 append_u32(raw, 0x01, 0x03, 0x02, *ch, *val)
698 }
699 InputCmd::Equalizer(ch, EqualizerParameter::LfGain(val)) => {
700 append_f32(raw, 0x01, 0x03, 0x03, *ch, *val)
701 }
702 InputCmd::Equalizer(ch, EqualizerParameter::LfWidth(val)) => {
703 append_f32(raw, 0x01, 0x03, 0x04, *ch, *val)
704 }
705
706 InputCmd::Equalizer(ch, EqualizerParameter::LmfEnable(enabled)) => {
707 append_u8(raw, 0x01, 0x04, 0x00, *ch, *enabled)
708 }
709 InputCmd::Equalizer(ch, EqualizerParameter::LmfType(filter_type)) => {
710 append_u8(raw, 0x01, 0x04, 0x01, *ch, *filter_type)
711 }
712 InputCmd::Equalizer(ch, EqualizerParameter::LmfFreq(val)) => {
713 append_u32(raw, 0x01, 0x04, 0x02, *ch, *val)
714 }
715 InputCmd::Equalizer(ch, EqualizerParameter::LmfGain(val)) => {
716 append_f32(raw, 0x01, 0x04, 0x03, *ch, *val)
717 }
718 InputCmd::Equalizer(ch, EqualizerParameter::LmfWidth(val)) => {
719 append_f32(raw, 0x01, 0x04, 0x04, *ch, *val)
720 }
721
722 InputCmd::Equalizer(ch, EqualizerParameter::MfEnable(enabled)) => {
723 append_u8(raw, 0x01, 0x05, 0x00, *ch, *enabled)
724 }
725 InputCmd::Equalizer(ch, EqualizerParameter::MfType(filter_type)) => {
726 append_u8(raw, 0x01, 0x05, 0x01, *ch, *filter_type)
727 }
728 InputCmd::Equalizer(ch, EqualizerParameter::MfFreq(val)) => {
729 append_u32(raw, 0x01, 0x05, 0x02, *ch, *val)
730 }
731 InputCmd::Equalizer(ch, EqualizerParameter::MfGain(val)) => {
732 append_f32(raw, 0x01, 0x05, 0x03, *ch, *val)
733 }
734 InputCmd::Equalizer(ch, EqualizerParameter::MfWidth(val)) => {
735 append_f32(raw, 0x01, 0x05, 0x04, *ch, *val)
736 }
737
738 InputCmd::Equalizer(ch, EqualizerParameter::HmfEnable(enabled)) => {
739 append_u8(raw, 0x01, 0x06, 0x00, *ch, *enabled)
740 }
741 InputCmd::Equalizer(ch, EqualizerParameter::HmfType(filter_type)) => {
742 append_u8(raw, 0x01, 0x06, 0x01, *ch, *filter_type)
743 }
744 InputCmd::Equalizer(ch, EqualizerParameter::HmfFreq(val)) => {
745 append_u32(raw, 0x01, 0x06, 0x02, *ch, *val)
746 }
747 InputCmd::Equalizer(ch, EqualizerParameter::HmfGain(val)) => {
748 append_f32(raw, 0x01, 0x06, 0x03, *ch, *val)
749 }
750 InputCmd::Equalizer(ch, EqualizerParameter::HmfWidth(val)) => {
751 append_f32(raw, 0x01, 0x06, 0x04, *ch, *val)
752 }
753
754 InputCmd::Equalizer(ch, EqualizerParameter::HfEnable(enabled)) => {
755 append_u8(raw, 0x01, 0x07, 0x00, *ch, *enabled)
756 }
757 InputCmd::Equalizer(ch, EqualizerParameter::HfType(filter_type)) => {
758 append_u8(raw, 0x01, 0x07, 0x01, *ch, *filter_type)
759 }
760 InputCmd::Equalizer(ch, EqualizerParameter::HfFreq(val)) => {
761 append_u32(raw, 0x01, 0x07, 0x02, *ch, *val)
762 }
763 InputCmd::Equalizer(ch, EqualizerParameter::HfGain(val)) => {
764 append_f32(raw, 0x01, 0x07, 0x03, *ch, *val)
765 }
766 InputCmd::Equalizer(ch, EqualizerParameter::HfWidth(val)) => {
767 append_f32(raw, 0x01, 0x07, 0x04, *ch, *val)
768 }
769
770 InputCmd::Equalizer(ch, EqualizerParameter::LpfEnable(enabled)) => {
771 append_u8(raw, 0x01, 0x08, 0x00, *ch, *enabled)
772 }
773 InputCmd::Equalizer(ch, EqualizerParameter::LpfSlope(level)) => {
774 append_u8(raw, 0x01, 0x08, 0x01, *ch, *level)
775 }
776 InputCmd::Equalizer(ch, EqualizerParameter::LpfFreq(val)) => {
777 append_u32(raw, 0x01, 0x08, 0x02, *ch, *val)
778 }
779
780 InputCmd::Dynamics(ch, DynamicsParameter::Enable(enabled)) => {
781 append_u8(raw, 0x01, 0x09, 0x00, *ch, *enabled)
782 }
783
784 InputCmd::Dynamics(ch, DynamicsParameter::CompEnable(enabled)) => {
785 append_u8(raw, 0x01, 0x0a, 0x00, *ch, *enabled)
786 }
787 InputCmd::Dynamics(ch, DynamicsParameter::CompThreshold(val)) => {
788 append_i32(raw, 0x01, 0x0a, 0x01, *ch, *val)
789 }
790 InputCmd::Dynamics(ch, DynamicsParameter::CompRatio(val)) => {
791 append_f32(raw, 0x01, 0x0a, 0x02, *ch, *val)
792 }
793 InputCmd::Dynamics(ch, DynamicsParameter::CompAttack(val)) => {
794 append_u32(raw, 0x01, 0x0a, 0x03, *ch, *val)
795 }
796 InputCmd::Dynamics(ch, DynamicsParameter::CompRelease(val)) => {
797 append_u32(raw, 0x01, 0x0a, 0x04, *ch, *val)
798 }
799 InputCmd::Dynamics(ch, DynamicsParameter::CompGain(val)) => {
800 append_f32(raw, 0x01, 0x0a, 0x05, *ch, *val)
801 }
802 InputCmd::Dynamics(ch, DynamicsParameter::CompDetectMode(mode)) => {
803 append_u8(raw, 0x01, 0x0a, 0x06, *ch, *mode)
804 }
805
806 InputCmd::Dynamics(ch, DynamicsParameter::LevelerEnable(enabled)) => {
807 append_u8(raw, 0x01, 0x0b, 0x00, *ch, *enabled)
808 }
809 InputCmd::Dynamics(ch, DynamicsParameter::LevelerMode(mode)) => {
810 append_u8(raw, 0x01, 0x0b, 0x01, *ch, *mode)
811 }
812 InputCmd::Dynamics(ch, DynamicsParameter::LevelerMakeup(val)) => {
813 append_u32(raw, 0x01, 0x0b, 0x02, *ch, *val)
814 }
815 InputCmd::Dynamics(ch, DynamicsParameter::LevelerReduce(val)) => {
816 append_u32(raw, 0x01, 0x0b, 0x03, *ch, *val)
817 }
818
819 InputCmd::ReverbSend(ch, val) => append_f32(raw, 0x01, 0x0c, 0x00, *ch, *val),
820 InputCmd::ReverbLrBalance(ch, val) => append_f32(raw, 0x01, 0x0c, 0x02, *ch, *val),
821
822 InputCmd::Reserved(identifier, vals) => append_data(raw, identifier, vals),
823 }
824 }
825}
826
827#[derive(Debug, Copy, Clone, Eq, PartialEq)]
829pub enum SourceStereoPairMode {
830 Width,
831 LrBalance,
832 Reserved(u8),
833}
834
835impl Default for SourceStereoPairMode {
836 fn default() -> Self {
837 Self::Width
838 }
839}
840
841impl From<u8> for SourceStereoPairMode {
842 fn from(val: u8) -> Self {
843 match val {
844 0 => Self::Width,
845 1 => Self::LrBalance,
846 _ => Self::Reserved(val),
847 }
848 }
849}
850
851impl From<SourceStereoPairMode> for u8 {
852 fn from(mode: SourceStereoPairMode) -> Self {
853 match mode {
854 SourceStereoPairMode::Width => 0,
855 SourceStereoPairMode::LrBalance => 1,
856 SourceStereoPairMode::Reserved(val) => val,
857 }
858 }
859}
860
861#[derive(Debug, Clone, PartialEq)]
863pub enum MixerCmd {
864 OutputAssign(usize, usize),
865 OutputMute(usize, bool),
866 OutputVolume(usize, f32),
867 ReverbSend(usize, f32),
868 ReverbReturn(usize, f32),
869 SourceMute(usize, usize, bool),
870 SourceSolo(usize, usize, bool),
871 SourceMonauralLrBalance(usize, usize, f32),
872 SourceGain(usize, usize, f32),
873 SourceStereoMode(usize, usize, SourceStereoPairMode),
874 SourceStereoLrBalance(usize, usize, f32),
875 SourceStereoWidth(usize, usize, f32),
876 Reserved(Vec<u8>, Vec<u8>),
877}
878
879impl MixerCmd {
880 fn parse(identifier: &[u8], vals: &[u8]) -> Self {
881 assert_eq!(identifier.len(), 4);
882 assert!(vals.len() > 0);
883
884 let ch = identifier[0] as usize;
885 let mixer_src_ch = identifier[2] as usize;
886
887 match (identifier[3], identifier[2], identifier[1]) {
888 (0x02, 0x00, 0x00) => MixerCmd::OutputAssign(ch, to_usize(vals)),
889 (0x02, 0x00, 0x01) => MixerCmd::OutputMute(ch, to_bool(vals)),
890 (0x02, 0x00, 0x02) => MixerCmd::OutputVolume(ch, to_f32(vals)),
891
892 (0x02, 0x01, 0x00) => MixerCmd::ReverbSend(ch, to_f32(vals)),
893 (0x02, 0x01, 0x01) => MixerCmd::ReverbReturn(ch, to_f32(vals)),
894
895 (0x02, _, 0x00) => MixerCmd::SourceMute(ch, mixer_src_ch - 2, to_bool(vals)),
896 (0x02, _, 0x01) => MixerCmd::SourceSolo(ch, mixer_src_ch - 2, to_bool(vals)),
897 (0x02, _, 0x02) => {
898 MixerCmd::SourceMonauralLrBalance(ch, mixer_src_ch - 2, to_f32(vals))
899 }
900 (0x02, _, 0x03) => MixerCmd::SourceGain(ch, mixer_src_ch - 2, to_f32(vals)),
901 (0x02, _, 0x04) => MixerCmd::SourceStereoMode(
902 ch,
903 mixer_src_ch - 2,
904 SourceStereoPairMode::from(vals[0]),
905 ),
906 (0x02, _, 0x05) => MixerCmd::SourceStereoLrBalance(ch, mixer_src_ch - 2, to_f32(vals)),
907 (0x02, _, 0x06) => MixerCmd::SourceStereoWidth(ch, mixer_src_ch - 2, to_f32(vals)),
908 _ => MixerCmd::Reserved(identifier.to_vec(), vals.to_vec()),
909 }
910 }
911
912 fn build(&self, raw: &mut Vec<u8>) {
913 match self {
914 MixerCmd::OutputAssign(ch, target) => {
915 append_u8(raw, 0x02, 0x00, 0x00, *ch, *target as u8)
916 }
917 MixerCmd::OutputMute(ch, enabled) => append_u8(raw, 0x02, 0x00, 0x01, *ch, *enabled),
918 MixerCmd::OutputVolume(ch, val) => append_f32(raw, 0x02, 0x00, 0x02, *ch, *val),
919
920 MixerCmd::ReverbSend(ch, val) => append_f32(raw, 0x02, 0x01, 0x00, *ch, *val),
921 MixerCmd::ReverbReturn(ch, val) => append_f32(raw, 0x02, 0x01, 0x01, *ch, *val),
922
923 MixerCmd::SourceMute(ch, mixer_src_ch, enabled) => {
924 append_u8(raw, 0x02, (*mixer_src_ch + 2) as u8, 0x00, *ch, *enabled)
925 }
926 MixerCmd::SourceSolo(ch, mixer_src_ch, enabled) => {
927 append_u8(raw, 0x02, (*mixer_src_ch + 2) as u8, 0x01, *ch, *enabled)
928 }
929 MixerCmd::SourceMonauralLrBalance(ch, mixer_src_ch, val) => {
930 append_f32(raw, 0x02, (*mixer_src_ch + 2) as u8, 0x02, *ch, *val)
931 }
932 MixerCmd::SourceGain(ch, mixer_src_ch, val) => {
933 append_f32(raw, 0x02, (*mixer_src_ch + 2) as u8, 0x03, *ch, *val)
934 }
935 MixerCmd::SourceStereoMode(ch, mixer_src_ch, pair_mode) => {
936 append_u8(raw, 0x02, (*mixer_src_ch + 2) as u8, 0x04, *ch, *pair_mode)
937 }
938 MixerCmd::SourceStereoLrBalance(ch, mixer_src_ch, val) => {
939 append_f32(raw, 0x02, (*mixer_src_ch + 2) as u8, 0x05, *ch, *val)
940 }
941 MixerCmd::SourceStereoWidth(ch, mixer_src_ch, val) => {
942 append_f32(raw, 0x02, (*mixer_src_ch + 2) as u8, 0x06, *ch, *val)
943 }
944
945 MixerCmd::Reserved(identifier, vals) => append_data(raw, identifier, vals),
946 }
947 }
948}
949
950#[derive(Debug, Clone, PartialEq)]
952pub enum OutputCmd {
953 Equalizer(usize, EqualizerParameter),
954 Dynamics(usize, DynamicsParameter),
955 ReverbSend(usize, f32),
956 ReverbReturn(usize, f32),
957 MasterMonitor(usize, bool),
958 MasterTalkback(usize, bool),
959 MasterListenback(usize, bool),
960 Reserved(Vec<u8>, Vec<u8>),
961}
962
963impl OutputCmd {
964 fn parse(identifier: &[u8], vals: &[u8]) -> Self {
965 let ch = identifier[0] as usize;
966
967 match (identifier[3], identifier[2], identifier[1]) {
968 (0x03, 0x00, 0x00) => {
969 OutputCmd::Equalizer(ch, EqualizerParameter::Enable(to_bool(vals)))
970 }
971
972 (0x03, 0x01, 0x00) => {
973 OutputCmd::Equalizer(ch, EqualizerParameter::HpfEnable(to_bool(vals)))
974 }
975 (0x03, 0x01, 0x01) => OutputCmd::Equalizer(
976 ch,
977 EqualizerParameter::HpfSlope(RollOffLevel::from(vals[0])),
978 ),
979 (0x03, 0x01, 0x02) => {
980 OutputCmd::Equalizer(ch, EqualizerParameter::HpfFreq(to_u32(vals)))
981 }
982
983 (0x03, 0x02, 0x00) => {
984 OutputCmd::Equalizer(ch, EqualizerParameter::LfEnable(to_bool(vals)))
985 }
986 (0x03, 0x02, 0x01) => {
987 OutputCmd::Equalizer(ch, EqualizerParameter::LfType(FilterType5::from(vals[0])))
988 }
989 (0x03, 0x02, 0x02) => {
990 OutputCmd::Equalizer(ch, EqualizerParameter::LfFreq(to_u32(vals)))
991 }
992 (0x03, 0x02, 0x03) => {
993 OutputCmd::Equalizer(ch, EqualizerParameter::LfGain(to_f32(vals)))
994 }
995 (0x03, 0x02, 0x04) => {
996 OutputCmd::Equalizer(ch, EqualizerParameter::LfWidth(to_f32(vals)))
997 }
998
999 (0x03, 0x03, 0x00) => {
1000 OutputCmd::Equalizer(ch, EqualizerParameter::LmfEnable(to_bool(vals)))
1001 }
1002 (0x03, 0x03, 0x01) => {
1003 OutputCmd::Equalizer(ch, EqualizerParameter::LmfType(FilterType4::from(vals[0])))
1004 }
1005 (0x03, 0x03, 0x02) => {
1006 OutputCmd::Equalizer(ch, EqualizerParameter::LmfFreq(to_u32(vals)))
1007 }
1008 (0x03, 0x03, 0x03) => {
1009 OutputCmd::Equalizer(ch, EqualizerParameter::LmfGain(to_f32(vals)))
1010 }
1011 (0x03, 0x03, 0x04) => {
1012 OutputCmd::Equalizer(ch, EqualizerParameter::LmfWidth(to_f32(vals)))
1013 }
1014
1015 (0x03, 0x04, 0x00) => {
1016 OutputCmd::Equalizer(ch, EqualizerParameter::MfEnable(to_bool(vals)))
1017 }
1018 (0x03, 0x04, 0x01) => {
1019 OutputCmd::Equalizer(ch, EqualizerParameter::MfType(FilterType4::from(vals[0])))
1020 }
1021 (0x03, 0x04, 0x02) => {
1022 OutputCmd::Equalizer(ch, EqualizerParameter::MfFreq(to_u32(vals)))
1023 }
1024 (0x03, 0x04, 0x03) => {
1025 OutputCmd::Equalizer(ch, EqualizerParameter::MfGain(to_f32(vals)))
1026 }
1027 (0x03, 0x04, 0x04) => {
1028 OutputCmd::Equalizer(ch, EqualizerParameter::MfWidth(to_f32(vals)))
1029 }
1030
1031 (0x03, 0x05, 0x00) => {
1032 OutputCmd::Equalizer(ch, EqualizerParameter::HmfEnable(to_bool(vals)))
1033 }
1034 (0x03, 0x05, 0x01) => {
1035 OutputCmd::Equalizer(ch, EqualizerParameter::HmfType(FilterType4::from(vals[0])))
1036 }
1037 (0x03, 0x05, 0x02) => {
1038 OutputCmd::Equalizer(ch, EqualizerParameter::HmfFreq(to_u32(vals)))
1039 }
1040 (0x03, 0x05, 0x03) => {
1041 OutputCmd::Equalizer(ch, EqualizerParameter::HmfGain(to_f32(vals)))
1042 }
1043 (0x03, 0x05, 0x04) => {
1044 OutputCmd::Equalizer(ch, EqualizerParameter::HmfWidth(to_f32(vals)))
1045 }
1046
1047 (0x03, 0x06, 0x00) => {
1048 OutputCmd::Equalizer(ch, EqualizerParameter::HfEnable(to_bool(vals)))
1049 }
1050 (0x03, 0x06, 0x01) => {
1051 OutputCmd::Equalizer(ch, EqualizerParameter::HfType(FilterType5::from(vals[0])))
1052 }
1053 (0x03, 0x06, 0x02) => {
1054 OutputCmd::Equalizer(ch, EqualizerParameter::HfFreq(to_u32(vals)))
1055 }
1056 (0x03, 0x06, 0x03) => {
1057 OutputCmd::Equalizer(ch, EqualizerParameter::HfGain(to_f32(vals)))
1058 }
1059 (0x03, 0x06, 0x04) => {
1060 OutputCmd::Equalizer(ch, EqualizerParameter::HfWidth(to_f32(vals)))
1061 }
1062
1063 (0x03, 0x07, 0x00) => {
1064 OutputCmd::Equalizer(ch, EqualizerParameter::LpfEnable(to_bool(vals)))
1065 }
1066 (0x03, 0x07, 0x01) => OutputCmd::Equalizer(
1067 ch,
1068 EqualizerParameter::LpfSlope(RollOffLevel::from(vals[0])),
1069 ),
1070 (0x03, 0x07, 0x02) => {
1071 OutputCmd::Equalizer(ch, EqualizerParameter::LpfFreq(to_u32(vals)))
1072 }
1073
1074 (0x03, 0x08, 0x00) => OutputCmd::Dynamics(ch, DynamicsParameter::Enable(to_bool(vals))),
1075
1076 (0x03, 0x09, 0x00) => {
1077 OutputCmd::Dynamics(ch, DynamicsParameter::CompEnable(to_bool(vals)))
1078 }
1079 (0x03, 0x09, 0x01) => {
1080 OutputCmd::Dynamics(ch, DynamicsParameter::CompThreshold(to_i32(vals)))
1081 }
1082 (0x03, 0x09, 0x02) => {
1083 OutputCmd::Dynamics(ch, DynamicsParameter::CompRatio(to_f32(vals)))
1084 }
1085 (0x03, 0x09, 0x03) => {
1086 OutputCmd::Dynamics(ch, DynamicsParameter::CompAttack(to_u32(vals)))
1087 }
1088 (0x03, 0x09, 0x04) => {
1089 OutputCmd::Dynamics(ch, DynamicsParameter::CompRelease(to_u32(vals)))
1090 }
1091 (0x03, 0x09, 0x05) => {
1092 OutputCmd::Dynamics(ch, DynamicsParameter::CompGain(to_f32(vals)))
1093 }
1094 (0x03, 0x09, 0x06) => OutputCmd::Dynamics(
1095 ch,
1096 DynamicsParameter::CompDetectMode(LevelDetectMode::from(vals[0])),
1097 ),
1098
1099 (0x03, 0x0a, 0x00) => {
1100 OutputCmd::Dynamics(ch, DynamicsParameter::LevelerEnable(to_bool(vals)))
1101 }
1102 (0x03, 0x0a, 0x01) => OutputCmd::Dynamics(
1103 ch,
1104 DynamicsParameter::LevelerMode(LevelerMode::from(vals[0])),
1105 ),
1106 (0x03, 0x0a, 0x02) => {
1107 OutputCmd::Dynamics(ch, DynamicsParameter::LevelerMakeup(to_u32(vals)))
1108 }
1109 (0x03, 0x0a, 0x03) => {
1110 OutputCmd::Dynamics(ch, DynamicsParameter::LevelerReduce(to_u32(vals)))
1111 }
1112
1113 (0x03, 0x0b, 0x00) => OutputCmd::ReverbSend(ch, to_f32(vals)),
1114 (0x03, 0x0b, 0x01) => OutputCmd::ReverbReturn(ch, to_f32(vals)),
1115
1116 (0x03, 0x0c, 0x00) => OutputCmd::MasterMonitor(ch, to_bool(vals)),
1117 (0x03, 0x0c, 0x01) => OutputCmd::MasterTalkback(ch, to_bool(vals)),
1118 (0x03, 0x0c, 0x02) => OutputCmd::MasterListenback(ch, to_bool(vals)),
1119
1120 _ => OutputCmd::Reserved(identifier.to_vec(), vals.to_vec()),
1121 }
1122 }
1123
1124 fn build(&self, raw: &mut Vec<u8>) {
1125 match self {
1126 OutputCmd::Equalizer(ch, EqualizerParameter::Enable(enabled)) => {
1127 append_u8(raw, 0x03, 0x00, 0x00, *ch, *enabled)
1128 }
1129
1130 OutputCmd::Equalizer(ch, EqualizerParameter::HpfEnable(enabled)) => {
1131 append_u8(raw, 0x03, 0x01, 0x00, *ch, *enabled)
1132 }
1133 OutputCmd::Equalizer(ch, EqualizerParameter::HpfSlope(level)) => {
1134 append_u8(raw, 0x03, 0x01, 0x01, *ch, *level)
1135 }
1136 OutputCmd::Equalizer(ch, EqualizerParameter::HpfFreq(val)) => {
1137 append_u32(raw, 0x03, 0x01, 0x02, *ch, *val)
1138 }
1139
1140 OutputCmd::Equalizer(ch, EqualizerParameter::LfEnable(enabled)) => {
1141 append_u8(raw, 0x03, 0x02, 0x00, *ch, *enabled)
1142 }
1143 OutputCmd::Equalizer(ch, EqualizerParameter::LfType(filter_type)) => {
1144 append_u8(raw, 0x03, 0x02, 0x01, *ch, *filter_type)
1145 }
1146 OutputCmd::Equalizer(ch, EqualizerParameter::LfFreq(val)) => {
1147 append_u32(raw, 0x03, 0x02, 0x02, *ch, *val)
1148 }
1149 OutputCmd::Equalizer(ch, EqualizerParameter::LfGain(val)) => {
1150 append_f32(raw, 0x03, 0x02, 0x03, *ch, *val)
1151 }
1152 OutputCmd::Equalizer(ch, EqualizerParameter::LfWidth(val)) => {
1153 append_f32(raw, 0x03, 0x02, 0x04, *ch, *val)
1154 }
1155
1156 OutputCmd::Equalizer(ch, EqualizerParameter::LmfEnable(enabled)) => {
1157 append_u8(raw, 0x03, 0x03, 0x00, *ch, *enabled)
1158 }
1159 OutputCmd::Equalizer(ch, EqualizerParameter::LmfType(filter_type)) => {
1160 append_u8(raw, 0x03, 0x03, 0x01, *ch, *filter_type)
1161 }
1162 OutputCmd::Equalizer(ch, EqualizerParameter::LmfFreq(val)) => {
1163 append_u32(raw, 0x03, 0x03, 0x02, *ch, *val)
1164 }
1165 OutputCmd::Equalizer(ch, EqualizerParameter::LmfGain(val)) => {
1166 append_f32(raw, 0x03, 0x03, 0x03, *ch, *val)
1167 }
1168 OutputCmd::Equalizer(ch, EqualizerParameter::LmfWidth(val)) => {
1169 append_f32(raw, 0x03, 0x03, 0x04, *ch, *val)
1170 }
1171
1172 OutputCmd::Equalizer(ch, EqualizerParameter::MfEnable(enabled)) => {
1173 append_u8(raw, 0x03, 0x04, 0x00, *ch, *enabled)
1174 }
1175 OutputCmd::Equalizer(ch, EqualizerParameter::MfType(filter_type)) => {
1176 append_u8(raw, 0x03, 0x04, 0x01, *ch, *filter_type)
1177 }
1178 OutputCmd::Equalizer(ch, EqualizerParameter::MfFreq(val)) => {
1179 append_u32(raw, 0x03, 0x04, 0x02, *ch, *val)
1180 }
1181 OutputCmd::Equalizer(ch, EqualizerParameter::MfGain(val)) => {
1182 append_f32(raw, 0x03, 0x04, 0x03, *ch, *val)
1183 }
1184 OutputCmd::Equalizer(ch, EqualizerParameter::MfWidth(val)) => {
1185 append_f32(raw, 0x03, 0x04, 0x04, *ch, *val)
1186 }
1187
1188 OutputCmd::Equalizer(ch, EqualizerParameter::HmfEnable(enabled)) => {
1189 append_u8(raw, 0x03, 0x05, 0x00, *ch, *enabled)
1190 }
1191 OutputCmd::Equalizer(ch, EqualizerParameter::HmfType(filter_type)) => {
1192 append_u8(raw, 0x03, 0x05, 0x01, *ch, *filter_type)
1193 }
1194 OutputCmd::Equalizer(ch, EqualizerParameter::HmfFreq(val)) => {
1195 append_u32(raw, 0x03, 0x05, 0x02, *ch, *val)
1196 }
1197 OutputCmd::Equalizer(ch, EqualizerParameter::HmfGain(val)) => {
1198 append_f32(raw, 0x03, 0x05, 0x03, *ch, *val)
1199 }
1200 OutputCmd::Equalizer(ch, EqualizerParameter::HmfWidth(val)) => {
1201 append_f32(raw, 0x03, 0x05, 0x04, *ch, *val)
1202 }
1203
1204 OutputCmd::Equalizer(ch, EqualizerParameter::HfEnable(enabled)) => {
1205 append_u8(raw, 0x03, 0x06, 0x00, *ch, *enabled)
1206 }
1207 OutputCmd::Equalizer(ch, EqualizerParameter::HfType(filter_type)) => {
1208 append_u8(raw, 0x03, 0x06, 0x01, *ch, *filter_type)
1209 }
1210 OutputCmd::Equalizer(ch, EqualizerParameter::HfFreq(val)) => {
1211 append_u32(raw, 0x03, 0x06, 0x02, *ch, *val)
1212 }
1213 OutputCmd::Equalizer(ch, EqualizerParameter::HfGain(val)) => {
1214 append_f32(raw, 0x03, 0x06, 0x03, *ch, *val)
1215 }
1216 OutputCmd::Equalizer(ch, EqualizerParameter::HfWidth(val)) => {
1217 append_f32(raw, 0x03, 0x06, 0x04, *ch, *val)
1218 }
1219
1220 OutputCmd::Equalizer(ch, EqualizerParameter::LpfEnable(enabled)) => {
1221 append_u8(raw, 0x03, 0x07, 0x00, *ch, *enabled)
1222 }
1223 OutputCmd::Equalizer(ch, EqualizerParameter::LpfSlope(level)) => {
1224 append_u8(raw, 0x03, 0x07, 0x01, *ch, *level)
1225 }
1226 OutputCmd::Equalizer(ch, EqualizerParameter::LpfFreq(val)) => {
1227 append_u32(raw, 0x03, 0x07, 0x02, *ch, *val)
1228 }
1229
1230 OutputCmd::Dynamics(ch, DynamicsParameter::Enable(enabled)) => {
1231 append_u8(raw, 0x03, 0x08, 0x00, *ch, *enabled)
1232 }
1233
1234 OutputCmd::Dynamics(ch, DynamicsParameter::CompEnable(enabled)) => {
1235 append_u8(raw, 0x03, 0x09, 0x00, *ch, *enabled)
1236 }
1237 OutputCmd::Dynamics(ch, DynamicsParameter::CompThreshold(val)) => {
1238 append_i32(raw, 0x03, 0x09, 0x01, *ch, *val)
1239 }
1240 OutputCmd::Dynamics(ch, DynamicsParameter::CompRatio(val)) => {
1241 append_f32(raw, 0x03, 0x09, 0x02, *ch, *val)
1242 }
1243 OutputCmd::Dynamics(ch, DynamicsParameter::CompAttack(val)) => {
1244 append_u32(raw, 0x03, 0x09, 0x03, *ch, *val)
1245 }
1246 OutputCmd::Dynamics(ch, DynamicsParameter::CompRelease(val)) => {
1247 append_u32(raw, 0x03, 0x09, 0x04, *ch, *val)
1248 }
1249 OutputCmd::Dynamics(ch, DynamicsParameter::CompGain(val)) => {
1250 append_f32(raw, 0x03, 0x09, 0x05, *ch, *val)
1251 }
1252 OutputCmd::Dynamics(ch, DynamicsParameter::CompDetectMode(mode)) => {
1253 append_u8(raw, 0x03, 0x09, 0x06, *ch, *mode)
1254 }
1255
1256 OutputCmd::Dynamics(ch, DynamicsParameter::LevelerEnable(enabled)) => {
1257 append_u8(raw, 0x03, 0x0a, 0x00, *ch, *enabled)
1258 }
1259 OutputCmd::Dynamics(ch, DynamicsParameter::LevelerMode(mode)) => {
1260 append_u8(raw, 0x03, 0x0a, 0x01, *ch, *mode)
1261 }
1262 OutputCmd::Dynamics(ch, DynamicsParameter::LevelerMakeup(val)) => {
1263 append_u32(raw, 0x03, 0x0a, 0x02, *ch, *val)
1264 }
1265 OutputCmd::Dynamics(ch, DynamicsParameter::LevelerReduce(val)) => {
1266 append_u32(raw, 0x03, 0x0a, 0x03, *ch, *val)
1267 }
1268
1269 OutputCmd::ReverbSend(ch, val) => append_f32(raw, 0x03, 0x0b, 0x00, *ch, *val),
1270 OutputCmd::ReverbReturn(ch, val) => append_f32(raw, 0x03, 0x0b, 0x01, *ch, *val),
1271
1272 OutputCmd::MasterMonitor(ch, val) => append_u8(raw, 0x03, 0x0c, 0x00, *ch, *val),
1273 OutputCmd::MasterTalkback(ch, enabled) => {
1274 append_u8(raw, 0x03, 0x0c, 0x01, *ch, *enabled)
1275 }
1276 OutputCmd::MasterListenback(ch, enabled) => {
1277 append_u8(raw, 0x03, 0x0c, 0x02, *ch, *enabled)
1278 }
1279
1280 OutputCmd::Reserved(identifier, vals) => append_data(raw, identifier, vals),
1281 }
1282 }
1283}
1284
1285#[derive(Debug, Copy, Clone, Eq, PartialEq)]
1287pub enum RoomShape {
1288 A,
1289 B,
1290 C,
1291 D,
1292 E,
1293 Reserved(u8),
1294}
1295
1296impl Default for RoomShape {
1297 fn default() -> Self {
1298 Self::A
1299 }
1300}
1301
1302impl From<u8> for RoomShape {
1303 fn from(val: u8) -> Self {
1304 match val {
1305 0 => Self::A,
1306 1 => Self::B,
1307 2 => Self::C,
1308 3 => Self::D,
1309 4 => Self::E,
1310 _ => Self::Reserved(val),
1311 }
1312 }
1313}
1314
1315impl From<RoomShape> for u8 {
1316 fn from(shape: RoomShape) -> Self {
1317 match shape {
1318 RoomShape::A => 0,
1319 RoomShape::B => 1,
1320 RoomShape::C => 2,
1321 RoomShape::D => 3,
1322 RoomShape::E => 4,
1323 RoomShape::Reserved(val) => val,
1324 }
1325 }
1326}
1327
1328#[derive(Debug, Copy, Clone, Eq, PartialEq)]
1330pub enum SplitPoint {
1331 Output,
1332 Mixer,
1333 Reserved(u8),
1334}
1335
1336impl Default for SplitPoint {
1337 fn default() -> Self {
1338 Self::Output
1339 }
1340}
1341
1342impl From<u8> for SplitPoint {
1343 fn from(val: u8) -> Self {
1344 match val {
1345 0 => Self::Output,
1346 1 => Self::Mixer,
1347 _ => Self::Reserved(val),
1348 }
1349 }
1350}
1351
1352impl From<SplitPoint> for u8 {
1353 fn from(point: SplitPoint) -> Self {
1354 match point {
1355 SplitPoint::Output => 0,
1356 SplitPoint::Mixer => 1,
1357 SplitPoint::Reserved(val) => val,
1358 }
1359 }
1360}
1361
1362#[derive(Debug, Clone, PartialEq)]
1364pub enum ReverbCmd {
1365 Enable(bool),
1366 Split(SplitPoint),
1367 PreDelay(u32),
1368 ShelfFilterFreq(u32),
1369 ShelfFilterAttenuation(i32),
1370 DecayTime(u32),
1371 LowFreqTime(u32),
1372 MiddleFreqTime(u32),
1373 HighFreqTime(u32),
1374 LowFreqCrossover(u32),
1375 HighFreqCrossover(u32),
1376 Width(f32),
1377 ReflectionMode(RoomShape),
1378 ReflectionSize(u32),
1379 ReflectionLevel(f32),
1380 Reserved(Vec<u8>, Vec<u8>),
1381}
1382
1383impl ReverbCmd {
1384 fn parse(identifier: &[u8], vals: &[u8]) -> Self {
1385 assert_eq!(identifier.len(), 4);
1386 assert!(vals.len() > 0);
1387
1388 match (identifier[3], identifier[2], identifier[1]) {
1389 (0x04, 0x00, 0x00) => ReverbCmd::Enable(to_bool(vals)),
1390 (0x04, 0x00, 0x01) => ReverbCmd::Split(SplitPoint::from(vals[0])),
1391 (0x04, 0x00, 0x02) => ReverbCmd::PreDelay(to_u32(vals)),
1392 (0x04, 0x00, 0x03) => ReverbCmd::ShelfFilterFreq(to_u32(vals)),
1393 (0x04, 0x00, 0x04) => ReverbCmd::ShelfFilterAttenuation(to_i32(vals)),
1394 (0x04, 0x00, 0x05) => ReverbCmd::DecayTime(to_u32(vals)),
1395 (0x04, 0x00, 0x06) => ReverbCmd::LowFreqTime(to_u32(vals)),
1396 (0x04, 0x00, 0x07) => ReverbCmd::MiddleFreqTime(to_u32(vals)),
1397 (0x04, 0x00, 0x08) => ReverbCmd::HighFreqTime(to_u32(vals)),
1398 (0x04, 0x00, 0x09) => ReverbCmd::LowFreqCrossover(to_u32(vals)),
1399 (0x04, 0x00, 0x0a) => ReverbCmd::HighFreqCrossover(to_u32(vals)),
1400 (0x04, 0x00, 0x0b) => ReverbCmd::Width(to_f32(vals)),
1401 (0x04, 0x00, 0x0c) => ReverbCmd::ReflectionMode(RoomShape::from(vals[0])),
1402 (0x04, 0x00, 0x0d) => ReverbCmd::ReflectionSize(to_u32(vals)),
1403 (0x04, 0x00, 0x0e) => ReverbCmd::ReflectionLevel(to_f32(vals)),
1404 _ => ReverbCmd::Reserved(identifier.to_vec(), vals.to_vec()),
1405 }
1406 }
1407
1408 fn build(&self, raw: &mut Vec<u8>) {
1409 match self {
1410 ReverbCmd::Enable(enabled) => append_u8(raw, 0x04, 0x00, 0x00, 0, *enabled),
1411 ReverbCmd::Split(point) => append_u8(raw, 0x04, 0x00, 0x01, 0, *point),
1412 ReverbCmd::PreDelay(val) => append_u32(raw, 0x04, 0x00, 0x02, 0, *val),
1413 ReverbCmd::ShelfFilterFreq(val) => append_u32(raw, 0x04, 0x00, 0x03, 0, *val),
1414 ReverbCmd::ShelfFilterAttenuation(val) => append_i32(raw, 0x04, 0x00, 0x04, 0, *val),
1415 ReverbCmd::DecayTime(val) => append_u32(raw, 0x04, 0x00, 0x05, 0, *val),
1416 ReverbCmd::LowFreqTime(val) => append_u32(raw, 0x04, 0x00, 0x06, 0, *val),
1417 ReverbCmd::MiddleFreqTime(val) => append_u32(raw, 0x04, 0x00, 0x07, 0, *val),
1418 ReverbCmd::HighFreqTime(val) => append_u32(raw, 0x04, 0x00, 0x08, 0, *val),
1419 ReverbCmd::LowFreqCrossover(val) => append_u32(raw, 0x04, 0x00, 0x09, 0, *val),
1420 ReverbCmd::HighFreqCrossover(val) => append_u32(raw, 0x04, 0x00, 0x0a, 0, *val),
1421 ReverbCmd::Width(val) => append_f32(raw, 0x04, 0x00, 0x0b, 0, *val),
1422 ReverbCmd::ReflectionMode(shape) => append_u8(raw, 0x04, 0x00, 0x0c, 0, *shape),
1423 ReverbCmd::ReflectionSize(val) => append_u32(raw, 0x04, 0x00, 0x0d, 0, *val),
1424 ReverbCmd::ReflectionLevel(val) => append_f32(raw, 0x04, 0x00, 0x0e, 0, *val),
1425 ReverbCmd::Reserved(identifier, vals) => append_data(raw, identifier, vals),
1426 }
1427 }
1428}
1429
1430#[derive(Debug, Clone, PartialEq)]
1432pub enum ResourceCmd {
1433 Usage(f32, u8),
1434 Reserved(Vec<u8>),
1435}
1436
1437impl ResourceCmd {
1438 pub const USAGE_MIN: f32 = 0.0;
1439 pub const USAGE_MAX: f32 = 100.0;
1440
1441 fn parse(raw: &[u8]) -> Self {
1442 let mut quadlet = [0; 4];
1443 quadlet.copy_from_slice(&raw[1..5]);
1444 ResourceCmd::Usage(f32::from_le_bytes(quadlet), raw[5])
1445 }
1446
1447 fn build(&self, raw: &mut Vec<u8>) {
1448 match self {
1449 Self::Usage(usage, flag) => append_resource(raw, *usage, *flag),
1450 Self::Reserved(data) => raw.extend_from_slice(data),
1451 }
1452 }
1453}
1454
1455#[derive(Debug, Clone, PartialEq)]
1457pub enum DspCmd {
1458 Monitor(MonitorCmd),
1459 Input(InputCmd),
1460 Mixer(MixerCmd),
1461 Output(OutputCmd),
1462 Reverb(ReverbCmd),
1463 Resource(ResourceCmd),
1464 Reserved(Vec<u8>),
1465}
1466
1467impl DspCmd {
1468 pub fn parse(raw: &[u8], cmds: &mut Vec<DspCmd>) -> usize {
1531 match raw[0] {
1532 CMD_RESOURCE => {
1533 let r = &raw[..CMD_RESOURCE_LENGTH];
1534 let cmd = DspCmd::Resource(ResourceCmd::parse(r));
1535 cmds.push(cmd);
1536
1537 CMD_RESOURCE_LENGTH
1538 }
1539 CMD_BYTE_MULTIPLE => {
1540 let count = raw[1] as usize;
1541 let length = 6 + count;
1542
1543 let mut identifier = [0; 4];
1544 identifier.copy_from_slice(&raw[2..6]);
1545 let first_level = identifier[3];
1546
1547 if first_level <= 0x04 {
1548 (0..count).for_each(|i| {
1549 identifier[0] = i as u8;
1550 let vals = &raw[(6 + i)..(6 + i + 1)];
1551 let cmd = match first_level {
1552 0x00 => DspCmd::Monitor(MonitorCmd::parse(&identifier, vals)),
1553 0x01 => DspCmd::Input(InputCmd::parse(&identifier, vals)),
1554 0x02 => DspCmd::Mixer(MixerCmd::parse(&identifier, vals)),
1555 0x03 => DspCmd::Output(OutputCmd::parse(&identifier, vals)),
1556 0x04 => DspCmd::Reverb(ReverbCmd::parse(&identifier, vals)),
1557 _ => unreachable!(),
1558 };
1559 cmds.push(cmd);
1560 });
1561 } else {
1562 let cmd = DspCmd::Reserved(raw[..length].to_vec());
1563 cmds.push(cmd);
1564 }
1565
1566 length
1567 }
1568 CMD_QUADLET_MULTIPLE => {
1569 let count = raw[1] as usize;
1570 let length = 6 + count * 4;
1571
1572 let mut identifier = [0; 4];
1573 identifier.copy_from_slice(&raw[2..6]);
1574 let first_level = identifier[3];
1575
1576 if first_level <= 0x04 {
1577 (0..count).for_each(|i| {
1578 identifier[0] = i as u8;
1579 let vals = &raw[(6 + i * 4)..(6 + i * 4 + 4)];
1580 let cmd = match first_level {
1581 0x00 => DspCmd::Monitor(MonitorCmd::parse(&identifier, vals)),
1582 0x01 => DspCmd::Input(InputCmd::parse(&identifier, vals)),
1583 0x02 => DspCmd::Mixer(MixerCmd::parse(&identifier, vals)),
1584 0x03 => DspCmd::Output(OutputCmd::parse(&identifier, vals)),
1585 0x04 => DspCmd::Reverb(ReverbCmd::parse(&identifier, vals)),
1586 _ => unreachable!(),
1587 };
1588 cmds.push(cmd);
1589 });
1590 } else {
1591 let cmd = DspCmd::Reserved(raw[..length].to_vec());
1592 cmds.push(cmd);
1593 }
1594
1595 6 + count * 4
1596 }
1597 CMD_DRAIN => 1,
1598 CMD_END => raw.len(),
1599 CMD_BYTE_SINGLE => {
1600 let identifier = &raw[2..6];
1601 let vals = &raw[1..2];
1602
1603 let first_level = identifier[3];
1604 let r = &raw[..CMD_BYTE_SINGLE_LENGTH];
1605
1606 let cmd = match first_level {
1607 0x00 => DspCmd::Monitor(MonitorCmd::parse(identifier, vals)),
1608 0x01 => DspCmd::Input(InputCmd::parse(identifier, vals)),
1609 0x02 => DspCmd::Mixer(MixerCmd::parse(identifier, vals)),
1610 0x03 => DspCmd::Output(OutputCmd::parse(identifier, vals)),
1611 0x04 => DspCmd::Reverb(ReverbCmd::parse(identifier, vals)),
1612 _ => DspCmd::Reserved(r.to_vec()),
1613 };
1614 cmds.push(cmd);
1615
1616 CMD_BYTE_SINGLE_LENGTH
1617 }
1618 CMD_QUADLET_SINGLE => {
1619 let identifier = &raw[1..5];
1620 let vals = &raw[5..9];
1621
1622 let first_level = identifier[3];
1623 let r = &raw[..CMD_QUADLET_SINGLE_LENGTH];
1624
1625 let cmd = match first_level {
1626 0x00 => DspCmd::Monitor(MonitorCmd::parse(identifier, vals)),
1627 0x01 => DspCmd::Input(InputCmd::parse(identifier, vals)),
1628 0x02 => DspCmd::Mixer(MixerCmd::parse(identifier, vals)),
1629 0x03 => DspCmd::Output(OutputCmd::parse(identifier, vals)),
1630 0x04 => DspCmd::Reverb(ReverbCmd::parse(identifier, vals)),
1631 _ => DspCmd::Reserved(r.to_vec()),
1632 };
1633 cmds.push(cmd);
1634
1635 CMD_QUADLET_SINGLE_LENGTH
1636 }
1637 _ => 0,
1638 }
1639 }
1640
1641 pub fn build(&self, raw: &mut Vec<u8>) {
1642 match self {
1643 DspCmd::Monitor(cmd) => cmd.build(raw),
1644 DspCmd::Input(cmd) => cmd.build(raw),
1645 DspCmd::Mixer(cmd) => cmd.build(raw),
1646 DspCmd::Output(cmd) => cmd.build(raw),
1647 DspCmd::Reverb(cmd) => cmd.build(raw),
1648 DspCmd::Resource(cmd) => cmd.build(raw),
1649 DspCmd::Reserved(data) => raw.extend_from_slice(data),
1650 }
1651 }
1652}
1653
1654fn append_u8<T>(
1655 raw: &mut Vec<u8>,
1656 first_level: u8,
1657 second_level: u8,
1658 third_level: u8,
1659 ch: usize,
1660 val: T,
1661) where
1662 u8: From<T>,
1663{
1664 raw.push(CMD_BYTE_SINGLE);
1665 raw.push(u8::from(val));
1666 raw.push(ch as u8);
1667 raw.push(third_level);
1668 raw.push(second_level);
1669 raw.push(first_level);
1670}
1671
1672fn append_i32(
1673 raw: &mut Vec<u8>,
1674 first_level: u8,
1675 second_level: u8,
1676 third_level: u8,
1677 ch: usize,
1678 val: i32,
1679) {
1680 append_f32(raw, first_level, second_level, third_level, ch, val as f32)
1681}
1682
1683fn append_f32(
1684 raw: &mut Vec<u8>,
1685 first_level: u8,
1686 second_level: u8,
1687 third_level: u8,
1688 ch: usize,
1689 val: f32,
1690) {
1691 raw.push(CMD_QUADLET_SINGLE);
1692 raw.push(ch as u8);
1693 raw.push(third_level);
1694 raw.push(second_level);
1695 raw.push(first_level);
1696 raw.extend_from_slice(&val.to_le_bytes());
1697}
1698
1699fn append_u32(
1700 raw: &mut Vec<u8>,
1701 first_level: u8,
1702 second_level: u8,
1703 third_level: u8,
1704 ch: usize,
1705 val: u32,
1706) {
1707 append_f32(raw, first_level, second_level, third_level, ch, val as f32)
1708}
1709
1710fn append_resource(raw: &mut Vec<u8>, usage: f32, flag: u8) {
1711 raw.push(CMD_RESOURCE);
1712 raw.extend_from_slice(&usage.to_le_bytes());
1713 raw.push(flag);
1714}
1715
1716fn send_message(
1722 req: &mut FwReq,
1723 node: &mut FwNode,
1724 tag: u8,
1725 sequence_number: &mut u8,
1726 mut msg: &[u8],
1727 timeout_ms: u32,
1728) -> Result<(), Error> {
1729 while msg.len() > 0 {
1730 let length = std::cmp::min(msg.len(), MAXIMUM_DSP_FRAME_SIZE - 2);
1731 let mut frame = Vec::with_capacity(2 + length);
1732 frame.push(tag);
1733 frame.push(*sequence_number);
1734 frame.extend_from_slice(&msg[..length]);
1735
1736 while frame.len() % 4 > 0 {
1739 frame.push(0x00);
1740 }
1741
1742 req.transaction_sync(
1743 node,
1744 FwTcode::WriteBlockRequest,
1745 DSP_CMD_OFFSET,
1746 frame.len(),
1747 &mut frame,
1748 timeout_ms,
1749 )?;
1750
1751 *sequence_number += 1;
1752 *sequence_number %= 0xff;
1753
1754 msg = &msg[length..];
1755 }
1756
1757 Ok(())
1758}
1759
1760pub trait CommandDspOperation {
1762 fn send_commands(
1763 req: &mut FwReq,
1764 node: &mut FwNode,
1765 sequence_number: &mut u8,
1766 cmds: &[DspCmd],
1767 timeout_ms: u32,
1768 ) -> Result<(), Error> {
1769 let mut frame = Vec::new();
1770 cmds.iter().for_each(|cmd| cmd.build(&mut frame));
1771 send_message(req, node, 0x02, sequence_number, &mut frame, timeout_ms)
1772 }
1773
1774 fn register_message_destination_address(
1775 resp: &mut FwResp,
1776 req: &mut FwReq,
1777 node: &mut FwNode,
1778 timeout_ms: u32,
1779 ) -> Result<(), Error> {
1780 if !resp.is_reserved() {
1781 resp.reserve_within_region(
1782 node,
1783 MSG_DST_OFFSET_BEGIN,
1784 MSG_DST_OFFSET_END,
1785 8 + MAXIMUM_DSP_FRAME_SIZE as u32,
1786 )?;
1787 }
1788
1789 let local_node_id = node.local_node_id() as u64;
1790 let addr = (local_node_id << 48) | resp.offset();
1791
1792 let high = (addr >> 32) as u32;
1793 write_quad(req, node, DSP_MSG_DST_HIGH_OFFSET, high, timeout_ms)?;
1794
1795 let low = (addr & 0xffffffff) as u32;
1796 write_quad(req, node, DSP_MSG_DST_LOW_OFFSET, low, timeout_ms)?;
1797
1798 Ok(())
1799 }
1800
1801 fn begin_messaging(
1802 req: &mut FwReq,
1803 node: &mut FwNode,
1804 sequence_number: &mut u8,
1805 timeout_ms: u32,
1806 ) -> Result<(), Error> {
1807 let frame = [0x00, 0x00];
1808 send_message(req, node, 0x01, sequence_number, &frame, timeout_ms)?;
1809
1810 let frame = [0x00, 0x00];
1811 send_message(req, node, 0x02, sequence_number, &frame, timeout_ms)?;
1812
1813 Ok(())
1814 }
1815
1816 fn cancel_messaging(
1817 req: &mut FwReq,
1818 node: &mut FwNode,
1819 sequence_number: &mut u8,
1820 timeout_ms: u32,
1821 ) -> Result<(), Error> {
1822 let frame = [0x00, 0x00];
1823 send_message(req, node, 0x00, sequence_number, &frame, timeout_ms)
1824 }
1825
1826 fn release_message_destination_address(
1827 resp: &mut FwResp,
1828 req: &mut FwReq,
1829 node: &mut FwNode,
1830 timeout_ms: u32,
1831 ) -> Result<(), Error> {
1832 write_quad(req, node, DSP_MSG_DST_HIGH_OFFSET, 0, timeout_ms)?;
1833 write_quad(req, node, DSP_MSG_DST_LOW_OFFSET, 0, timeout_ms)?;
1834
1835 if resp.is_reserved() {
1836 resp.release();
1837 }
1838
1839 Ok(())
1840 }
1841}
1842
1843#[derive(Debug)]
1845pub struct CommandDspMessageHandler {
1846 state: ParserState,
1847 cache: Vec<u8>,
1848 seq_num: u8,
1849}
1850
1851#[derive(Debug, Eq, PartialEq)]
1852enum ParserState {
1853 Initialized,
1854 Prepared,
1855 InTruncatedMessage,
1856}
1857
1858impl Default for CommandDspMessageHandler {
1859 fn default() -> Self {
1860 Self {
1861 state: ParserState::Initialized,
1862 cache: Vec::with_capacity(MAXIMUM_DSP_FRAME_SIZE + 6),
1863 seq_num: 0,
1864 }
1865 }
1866}
1867
1868fn remove_padding(cache: &mut Vec<u8>) {
1869 let mut buf = &cache[..];
1870 let mut count = 0;
1871
1872 while buf.len() > 4 {
1873 let length = match buf[0] {
1874 CMD_RESOURCE => CMD_RESOURCE_LENGTH,
1875 CMD_QUADLET_MULTIPLE => 6 + 4 * buf[1] as usize,
1876 CMD_BYTE_MULTIPLE => 6 + buf[1] as usize,
1877 CMD_DRAIN => 1,
1878 CMD_END => 0,
1879 CMD_QUADLET_SINGLE => CMD_QUADLET_SINGLE_LENGTH,
1880 CMD_BYTE_SINGLE => CMD_BYTE_SINGLE_LENGTH,
1881 _ => 0,
1882 };
1883 if length == 0 {
1884 break;
1885 }
1886
1887 count += length;
1888 buf = &buf[length..];
1889 }
1890
1891 let _ = cache.drain(count..);
1892}
1893
1894fn increment_seq_num(seq_num: u8) -> u8 {
1895 if seq_num == u8::MAX {
1896 0
1897 } else {
1898 seq_num + 1
1899 }
1900}
1901
1902impl CommandDspMessageHandler {
1903 pub fn cache_dsp_messages(&mut self, frame: &[u8]) {
1918 let seq_num = frame[1];
1919
1920 if self.state == ParserState::Initialized {
1921 self.seq_num = seq_num;
1922 self.state = ParserState::Prepared;
1923 }
1924
1925 if self.seq_num == seq_num {
1926 self.seq_num = increment_seq_num(seq_num);
1927
1928 if self.state == ParserState::Prepared {
1929 if frame.len() > 4 && frame[2] != 0x00 {
1931 self.cache.extend_from_slice(&frame[2..]);
1932
1933 if frame.len() == MAXIMUM_DSP_FRAME_SIZE {
1934 self.state = ParserState::InTruncatedMessage;
1935 } else {
1936 remove_padding(&mut self.cache);
1937 }
1938 }
1939 } else if self.state == ParserState::InTruncatedMessage {
1940 self.cache.extend_from_slice(&frame[2..]);
1941
1942 if frame.len() < MAXIMUM_DSP_FRAME_SIZE {
1943 remove_padding(&mut self.cache);
1944 self.state = ParserState::Prepared;
1945 }
1946 }
1947 } else {
1948 self.cache.clear();
1949 self.state = ParserState::Prepared;
1950 }
1951 }
1952
1953 pub fn has_dsp_message(&self) -> bool {
1954 self.cache.len() > 0 && (self.state == ParserState::Prepared)
1955 }
1956
1957 pub fn decode_messages(&mut self) -> Vec<DspCmd> {
1958 let mut cmds = Vec::new();
1959
1960 while self.cache.len() > 0 {
1961 let consumed = DspCmd::parse(&self.cache, &mut cmds);
1962 if consumed == 0 {
1963 break;
1964 }
1965
1966 let _ = self.cache.drain(..consumed);
1967 }
1968
1969 cmds
1970 }
1971}
1972
1973pub trait MotuCommandDspParametersOperation<T> {
1975 fn build_commands(params: &T) -> Vec<DspCmd>;
1977 fn parse_command(params: &mut T, command: &DspCmd) -> bool;
1979}
1980
1981pub trait MotuCommandDspImageOperation<T, U> {
1983 fn parse_image(params: &mut T, image: &U);
1985}
1986
1987pub trait MotuCommandDspUpdatableParamsOperation<T> {
1989 fn update_partially(
1991 req: &mut FwReq,
1992 node: &mut FwNode,
1993 sequence_number: &mut u8,
1994 params: &mut T,
1995 updates: T,
1996 timeout_ms: u32,
1997 ) -> Result<(), Error>;
1998}
1999
2000impl<O, T> MotuCommandDspUpdatableParamsOperation<T> for O
2001where
2002 O: CommandDspOperation + MotuCommandDspParametersOperation<T>,
2003{
2004 fn update_partially(
2005 req: &mut FwReq,
2006 node: &mut FwNode,
2007 sequence_number: &mut u8,
2008 params: &mut T,
2009 updates: T,
2010 timeout_ms: u32,
2011 ) -> Result<(), Error> {
2012 let mut new_cmds = O::build_commands(&updates);
2013 let old_cmds = O::build_commands(params);
2014 new_cmds.retain(|cmd| old_cmds.iter().find(|c| c.eq(&cmd)).is_none());
2015 Self::send_commands(req, node, sequence_number, &new_cmds, timeout_ms)
2016 .map(|_| *params = updates)
2017 }
2018}
2019
2020#[derive(Default, Debug, Copy, Clone, PartialEq)]
2022pub struct CommandDspReverbState {
2023 pub enable: bool,
2025 pub split_point: SplitPoint,
2027 pub pre_delay: u32,
2029 pub shelf_filter_freq: u32,
2031 pub shelf_filter_attenuation: i32,
2033 pub decay_time: u32,
2035 pub freq_time: [u32; 3],
2037 pub freq_crossover: [u32; 2],
2039 pub width: f32,
2041 pub reflection_mode: RoomShape,
2043 pub reflection_size: u32,
2045 pub reflection_level: f32,
2047}
2048
2049pub trait MotuCommandDspReverbSpecification {
2051 const DECAY_TIME_MIN: u32 = 100;
2053 const DECAY_TIME_MAX: u32 = 60000;
2055 const DECAY_TIME_STEP: u32 = 1;
2057
2058 const PRE_DELAY_MIN: u32 = 0;
2060 const PRE_DELAY_MAX: u32 = 100;
2062 const PRE_DELAY_STEP: u32 = 1;
2064
2065 const SHELF_FILTER_FREQ_MIN: u32 = 1000;
2067 const SHELF_FILTER_FREQ_MAX: u32 = 20000;
2069 const SHELF_FILTER_FREQ_STEP: u32 = 1;
2071
2072 const SHELF_FILTER_ATTR_MIN: i32 = -40;
2074 const SHELF_FILTER_ATTR_MAX: i32 = 0;
2076 const SHELF_FILTER_ATTR_STEP: i32 = 0;
2078
2079 const FREQ_TIME_COUNT: usize = 3;
2081 const FREQ_TIME_MIN: u32 = 0;
2083 const FREQ_TIME_MAX: u32 = 100;
2085 const FREQ_TIME_STEP: u32 = 1;
2087
2088 const FREQ_CROSSOVER_COUNT: usize = 2;
2090 const FREQ_CROSSOVER_MIN: u32 = 100;
2092 const FREQ_CROSSOVER_MAX: u32 = 20000;
2094 const FREQ_CROSSOVER_STEP: u32 = 1;
2096
2097 const WIDTH_MIN: f32 = -1.0;
2099 const WIDTH_MAX: f32 = 1.0;
2101
2102 const REFLECTION_SIZE_MIN: u32 = 50;
2104 const REFLECTION_SIZE_MAX: u32 = 400;
2106 const REFLECTION_SIZE_STEP: u32 = 1;
2108
2109 const REFLECTION_LEVEL_MIN: f32 = 0.0;
2111 const REFLECTION_LEVEL_MAX: f32 = 1.0;
2113}
2114
2115impl<O> MotuCommandDspParametersOperation<CommandDspReverbState> for O
2116where
2117 O: MotuCommandDspReverbSpecification,
2118{
2119 fn build_commands(params: &CommandDspReverbState) -> Vec<DspCmd> {
2120 vec![
2121 DspCmd::Reverb(ReverbCmd::Enable(params.enable)),
2122 DspCmd::Reverb(ReverbCmd::Split(params.split_point)),
2123 DspCmd::Reverb(ReverbCmd::PreDelay(params.pre_delay)),
2124 DspCmd::Reverb(ReverbCmd::ShelfFilterFreq(params.shelf_filter_freq)),
2125 DspCmd::Reverb(ReverbCmd::ShelfFilterAttenuation(
2126 params.shelf_filter_attenuation,
2127 )),
2128 DspCmd::Reverb(ReverbCmd::DecayTime(params.decay_time)),
2129 DspCmd::Reverb(ReverbCmd::LowFreqTime(params.freq_time[0])),
2130 DspCmd::Reverb(ReverbCmd::MiddleFreqTime(params.freq_time[1])),
2131 DspCmd::Reverb(ReverbCmd::HighFreqTime(params.freq_time[2])),
2132 DspCmd::Reverb(ReverbCmd::LowFreqCrossover(params.freq_crossover[0])),
2133 DspCmd::Reverb(ReverbCmd::HighFreqCrossover(params.freq_crossover[1])),
2134 DspCmd::Reverb(ReverbCmd::Width(params.width)),
2135 DspCmd::Reverb(ReverbCmd::ReflectionMode(params.reflection_mode)),
2136 DspCmd::Reverb(ReverbCmd::ReflectionSize(params.reflection_size)),
2137 DspCmd::Reverb(ReverbCmd::ReflectionLevel(params.reflection_level)),
2138 ]
2139 }
2140
2141 fn parse_command(params: &mut CommandDspReverbState, command: &DspCmd) -> bool {
2142 if let DspCmd::Reverb(cmd) = command {
2143 match cmd {
2144 ReverbCmd::Enable(val) => params.enable = *val,
2145 ReverbCmd::Split(val) => params.split_point = *val,
2146 ReverbCmd::PreDelay(val) => params.pre_delay = *val,
2147 ReverbCmd::ShelfFilterFreq(val) => params.shelf_filter_freq = *val,
2148 ReverbCmd::ShelfFilterAttenuation(val) => params.shelf_filter_attenuation = *val,
2149 ReverbCmd::DecayTime(val) => params.decay_time = *val,
2150 ReverbCmd::LowFreqTime(val) => params.freq_time[0] = *val,
2151 ReverbCmd::MiddleFreqTime(val) => params.freq_time[1] = *val,
2152 ReverbCmd::HighFreqTime(val) => params.freq_time[2] = *val,
2153 ReverbCmd::LowFreqCrossover(val) => params.freq_crossover[0] = *val,
2154 ReverbCmd::HighFreqCrossover(val) => params.freq_crossover[1] = *val,
2155 ReverbCmd::Width(val) => params.width = *val,
2156 ReverbCmd::ReflectionMode(val) => params.reflection_mode = *val,
2157 ReverbCmd::ReflectionSize(val) => params.reflection_size = *val,
2158 ReverbCmd::ReflectionLevel(val) => params.reflection_level = *val,
2159 _ => (),
2160 };
2161 true
2162 } else {
2163 false
2164 }
2165 }
2166}
2167
2168#[derive(Default, Debug, Copy, Clone, PartialEq)]
2170pub struct CommandDspMonitorState {
2171 pub main_volume: f32,
2173 pub talkback_enable: bool,
2175 pub listenback_enable: bool,
2177 pub talkback_volume: f32,
2179 pub listenback_volume: f32,
2181 pub focus: FocusTarget,
2183 pub assign_target: TargetPort,
2185}
2186
2187pub trait MotuCommandDspMonitorSpecification {
2189 const RETURN_ASSIGN_TARGETS: &'static [TargetPort];
2191
2192 const VOLUME_MIN: f32 = 0.0;
2194 const VOLUME_MAX: f32 = 1.0;
2196}
2197
2198impl<O> MotuCommandDspParametersOperation<CommandDspMonitorState> for O
2199where
2200 O: MotuCommandDspMonitorSpecification,
2201{
2202 fn build_commands(params: &CommandDspMonitorState) -> Vec<DspCmd> {
2203 let pos = Self::RETURN_ASSIGN_TARGETS
2204 .iter()
2205 .position(|p| params.assign_target.eq(p))
2206 .unwrap_or_default();
2207
2208 vec![
2209 DspCmd::Monitor(MonitorCmd::Volume(params.main_volume)),
2210 DspCmd::Monitor(MonitorCmd::TalkbackEnable(params.talkback_enable)),
2211 DspCmd::Monitor(MonitorCmd::ListenbackEnable(params.listenback_enable)),
2212 DspCmd::Monitor(MonitorCmd::TalkbackVolume(params.talkback_volume)),
2213 DspCmd::Monitor(MonitorCmd::ListenbackVolume(params.listenback_volume)),
2214 DspCmd::Monitor(MonitorCmd::Focus(params.focus)),
2215 DspCmd::Monitor(MonitorCmd::ReturnAssign(pos)),
2216 ]
2217 }
2218
2219 fn parse_command(params: &mut CommandDspMonitorState, command: &DspCmd) -> bool {
2220 if let DspCmd::Monitor(cmd) = command {
2221 match cmd {
2222 MonitorCmd::Volume(val) => params.main_volume = *val,
2223 MonitorCmd::TalkbackEnable(val) => params.talkback_enable = *val,
2224 MonitorCmd::ListenbackEnable(val) => params.listenback_enable = *val,
2225 MonitorCmd::TalkbackVolume(val) => params.talkback_volume = *val,
2226 MonitorCmd::ListenbackVolume(val) => params.listenback_volume = *val,
2227 MonitorCmd::Focus(val) => params.focus = *val,
2228 MonitorCmd::ReturnAssign(val) => {
2229 params.assign_target = Self::RETURN_ASSIGN_TARGETS
2230 .iter()
2231 .nth(*val as usize)
2232 .map(|&p| p)
2233 .unwrap_or_default();
2234 }
2235 _ => (),
2236 };
2237 true
2238 } else {
2239 false
2240 }
2241 }
2242}
2243
2244#[derive(Default, Debug, Clone, PartialEq)]
2246pub struct CommandDspMixerSourceState {
2247 pub mute: Vec<bool>,
2249 pub solo: Vec<bool>,
2251 pub gain: Vec<f32>,
2253 pub pan: Vec<f32>,
2255 pub stereo_mode: Vec<SourceStereoPairMode>,
2257 pub stereo_balance: Vec<f32>,
2259 pub stereo_width: Vec<f32>,
2261}
2262
2263const MIXER_COUNT: usize = 8;
2264
2265#[derive(Default, Debug, Clone, PartialEq)]
2267pub struct CommandDspMixerState {
2268 pub output_assign: [TargetPort; MIXER_COUNT],
2270 pub output_mute: [bool; MIXER_COUNT],
2272 pub output_volume: [f32; MIXER_COUNT],
2274 pub reverb_send: [f32; MIXER_COUNT],
2276 pub reverb_return: [f32; MIXER_COUNT],
2278 pub source: [CommandDspMixerSourceState; MIXER_COUNT],
2280}
2281
2282pub trait MotuCommandDspMixerSpecification {
2284 const SOURCE_PORTS: &'static [TargetPort];
2286 const OUTPUT_PORTS: &'static [TargetPort];
2288
2289 const MIXER_COUNT: usize = MIXER_COUNT;
2291
2292 const OUTPUT_VOLUME_MIN: f32 = 0.0;
2294 const OUTPUT_VOLUME_MAX: f32 = 1.0;
2296
2297 const SOURCE_GAIN_MIN: f32 = 0.0;
2299 const SOURCE_GAIN_MAX: f32 = 1.0;
2301
2302 const SOURCE_PAN_MIN: f32 = -1.0;
2304 const SOURCE_PAN_MAX: f32 = 1.0;
2306
2307 fn create_mixer_state() -> CommandDspMixerState {
2308 let mut state = CommandDspMixerState::default();
2309
2310 state.source.iter_mut().for_each(|src| {
2311 src.mute = vec![Default::default(); Self::SOURCE_PORTS.len()];
2312 src.solo = vec![Default::default(); Self::SOURCE_PORTS.len()];
2313 src.gain = vec![Default::default(); Self::SOURCE_PORTS.len()];
2314 src.pan = vec![Default::default(); Self::SOURCE_PORTS.len()];
2315 src.stereo_mode = vec![Default::default(); Self::SOURCE_PORTS.len()];
2316 src.stereo_balance = vec![Default::default(); Self::SOURCE_PORTS.len()];
2317 src.stereo_width = vec![Default::default(); Self::SOURCE_PORTS.len()];
2318 });
2319
2320 state
2321 }
2322}
2323
2324impl<O> MotuCommandDspParametersOperation<CommandDspMixerState> for O
2325where
2326 O: MotuCommandDspMixerSpecification,
2327{
2328 fn build_commands(params: &CommandDspMixerState) -> Vec<DspCmd> {
2329 let mut cmds = Vec::new();
2330
2331 (0..MIXER_COUNT).for_each(|mixer| {
2332 let pos = Self::OUTPUT_PORTS
2333 .iter()
2334 .position(|p| params.output_assign[mixer].eq(p))
2335 .unwrap_or_default();
2336 cmds.push(DspCmd::Mixer(MixerCmd::OutputAssign(mixer, pos)));
2337 cmds.push(DspCmd::Mixer(MixerCmd::OutputMute(
2338 mixer,
2339 params.output_mute[mixer],
2340 )));
2341 cmds.push(DspCmd::Mixer(MixerCmd::OutputVolume(
2342 mixer,
2343 params.output_volume[mixer],
2344 )));
2345 cmds.push(DspCmd::Mixer(MixerCmd::ReverbSend(
2346 mixer,
2347 params.reverb_send[mixer],
2348 )));
2349 cmds.push(DspCmd::Mixer(MixerCmd::ReverbReturn(
2350 mixer,
2351 params.reverb_return[mixer],
2352 )));
2353
2354 let src = ¶ms.source[mixer];
2355 (0..Self::SOURCE_PORTS.len()).for_each(|ch| {
2356 cmds.push(DspCmd::Mixer(MixerCmd::SourceMute(mixer, ch, src.mute[ch])));
2357 cmds.push(DspCmd::Mixer(MixerCmd::SourceSolo(mixer, ch, src.solo[ch])));
2358 cmds.push(DspCmd::Mixer(MixerCmd::SourceGain(mixer, ch, src.gain[ch])));
2359 cmds.push(DspCmd::Mixer(MixerCmd::SourceMonauralLrBalance(
2360 mixer,
2361 ch,
2362 src.pan[ch],
2363 )));
2364 cmds.push(DspCmd::Mixer(MixerCmd::SourceStereoMode(
2365 mixer,
2366 ch,
2367 src.stereo_mode[ch],
2368 )));
2369 cmds.push(DspCmd::Mixer(MixerCmd::SourceStereoLrBalance(
2370 mixer,
2371 ch,
2372 src.stereo_balance[ch],
2373 )));
2374 cmds.push(DspCmd::Mixer(MixerCmd::SourceStereoWidth(
2375 mixer,
2376 ch,
2377 src.stereo_width[ch],
2378 )));
2379 });
2380 });
2381
2382 cmds
2383 }
2384
2385 fn parse_command(params: &mut CommandDspMixerState, command: &DspCmd) -> bool {
2386 if let DspCmd::Mixer(cmd) = command {
2387 match cmd {
2388 MixerCmd::OutputAssign(mixer, val) => {
2389 params.output_assign[*mixer] = Self::OUTPUT_PORTS
2390 .iter()
2391 .nth(*val)
2392 .map(|&p| p)
2393 .unwrap_or_else(|| Self::OUTPUT_PORTS[0]);
2394 }
2395 MixerCmd::OutputMute(mixer, val) => params.output_mute[*mixer] = *val,
2396 MixerCmd::OutputVolume(mixer, val) => params.output_volume[*mixer] = *val,
2397 MixerCmd::ReverbSend(mixer, val) => params.reverb_send[*mixer] = *val,
2398 MixerCmd::ReverbReturn(mixer, val) => params.reverb_return[*mixer] = *val,
2399 MixerCmd::SourceMute(mixer, src, val) => params.source[*mixer].mute[*src] = *val,
2400 MixerCmd::SourceSolo(mixer, src, val) => params.source[*mixer].solo[*src] = *val,
2401 MixerCmd::SourceGain(mixer, src, val) => params.source[*mixer].gain[*src] = *val,
2402 MixerCmd::SourceMonauralLrBalance(mixer, src, val) => {
2403 params.source[*mixer].pan[*src] = *val
2404 }
2405 MixerCmd::SourceStereoMode(mixer, src, val) => {
2406 params.source[*mixer].stereo_mode[*src] = *val
2407 }
2408 MixerCmd::SourceStereoLrBalance(mixer, src, val) => {
2409 params.source[*mixer].stereo_balance[*src] = *val
2410 }
2411 MixerCmd::SourceStereoWidth(mixer, src, val) => {
2412 params.source[*mixer].stereo_width[*src] = *val
2413 }
2414 _ => (),
2415 };
2416 true
2417 } else {
2418 false
2419 }
2420 }
2421}
2422
2423#[derive(Default, Debug, Clone, PartialEq)]
2425pub struct CommandDspEqualizerState {
2426 pub enable: Vec<bool>,
2428
2429 pub hpf_enable: Vec<bool>,
2431 pub hpf_slope: Vec<RollOffLevel>,
2433 pub hpf_freq: Vec<u32>,
2435
2436 pub lpf_enable: Vec<bool>,
2438 pub lpf_slope: Vec<RollOffLevel>,
2440 pub lpf_freq: Vec<u32>,
2442
2443 pub lf_enable: Vec<bool>,
2445 pub lf_type: Vec<FilterType5>,
2447 pub lf_freq: Vec<u32>,
2449 pub lf_gain: Vec<f32>,
2451 pub lf_width: Vec<f32>,
2453
2454 pub lmf_enable: Vec<bool>,
2456 pub lmf_type: Vec<FilterType4>,
2458 pub lmf_freq: Vec<u32>,
2460 pub lmf_gain: Vec<f32>,
2462 pub lmf_width: Vec<f32>,
2464
2465 pub mf_enable: Vec<bool>,
2467 pub mf_type: Vec<FilterType4>,
2469 pub mf_freq: Vec<u32>,
2471 pub mf_gain: Vec<f32>,
2473 pub mf_width: Vec<f32>,
2475
2476 pub hmf_enable: Vec<bool>,
2478 pub hmf_type: Vec<FilterType4>,
2480 pub hmf_freq: Vec<u32>,
2482 pub hmf_gain: Vec<f32>,
2484 pub hmf_width: Vec<f32>,
2486
2487 pub hf_enable: Vec<bool>,
2489 pub hf_type: Vec<FilterType5>,
2491 pub hf_freq: Vec<u32>,
2493 pub hf_gain: Vec<f32>,
2495 pub hf_width: Vec<f32>,
2497}
2498
2499pub trait MotuCommandDspEqualizerSpecification {
2501 const EQUALIZER_FREQ_MIN: u32 = 20;
2503 const EQUALIZER_FREQ_MAX: u32 = 20000;
2505 const EQUALIZER_FREQ_STEP: u32 = 1;
2507
2508 const EQUALIZER_GAIN_MIN: f32 = -20.0;
2510 const EQUALIZER_GAIN_MAX: f32 = 20.0;
2512
2513 const EQUALIZER_WIDTH_MIN: f32 = 0.01;
2515 const EQUALIZER_WIDTH_MAX: f32 = 3.0;
2517
2518 fn create_equalizer_parameters(
2519 state: &CommandDspEqualizerState,
2520 ch: usize,
2521 ) -> Vec<EqualizerParameter> {
2522 let mut params = Vec::new();
2523
2524 params.push(EqualizerParameter::Enable(state.enable[ch]));
2525
2526 params.push(EqualizerParameter::HpfEnable(state.hpf_enable[ch]));
2527 params.push(EqualizerParameter::HpfSlope(state.hpf_slope[ch]));
2528 params.push(EqualizerParameter::HpfFreq(state.hpf_freq[ch]));
2529
2530 params.push(EqualizerParameter::LpfEnable(state.lpf_enable[ch]));
2531 params.push(EqualizerParameter::LpfSlope(state.lpf_slope[ch]));
2532 params.push(EqualizerParameter::LpfFreq(state.lpf_freq[ch]));
2533
2534 params.push(EqualizerParameter::LfEnable(state.lf_enable[ch]));
2535 params.push(EqualizerParameter::LfType(state.lf_type[ch]));
2536 params.push(EqualizerParameter::LfFreq(state.lf_freq[ch]));
2537 params.push(EqualizerParameter::LfGain(state.lf_gain[ch]));
2538 params.push(EqualizerParameter::LfWidth(state.lf_width[ch]));
2539
2540 params.push(EqualizerParameter::LmfEnable(state.lmf_enable[ch]));
2541 params.push(EqualizerParameter::LmfType(state.lmf_type[ch]));
2542 params.push(EqualizerParameter::LmfFreq(state.lmf_freq[ch]));
2543 params.push(EqualizerParameter::LmfGain(state.lmf_gain[ch]));
2544 params.push(EqualizerParameter::LmfWidth(state.lmf_width[ch]));
2545
2546 params.push(EqualizerParameter::MfEnable(state.mf_enable[ch]));
2547 params.push(EqualizerParameter::MfType(state.mf_type[ch]));
2548 params.push(EqualizerParameter::MfFreq(state.mf_freq[ch]));
2549 params.push(EqualizerParameter::MfGain(state.mf_gain[ch]));
2550 params.push(EqualizerParameter::MfWidth(state.mf_width[ch]));
2551
2552 params.push(EqualizerParameter::HmfEnable(state.hmf_enable[ch]));
2553 params.push(EqualizerParameter::HmfType(state.hmf_type[ch]));
2554 params.push(EqualizerParameter::HmfFreq(state.hmf_freq[ch]));
2555 params.push(EqualizerParameter::HmfGain(state.hmf_gain[ch]));
2556 params.push(EqualizerParameter::HmfWidth(state.hmf_width[ch]));
2557
2558 params.push(EqualizerParameter::HfEnable(state.hf_enable[ch]));
2559 params.push(EqualizerParameter::HfType(state.hf_type[ch]));
2560 params.push(EqualizerParameter::HfFreq(state.hf_freq[ch]));
2561 params.push(EqualizerParameter::HfGain(state.hf_gain[ch]));
2562 params.push(EqualizerParameter::HfWidth(state.hf_width[ch]));
2563
2564 params
2565 }
2566
2567 fn parse_equalizer_parameter(
2568 state: &mut CommandDspEqualizerState,
2569 param: &EqualizerParameter,
2570 ch: usize,
2571 ) {
2572 match param {
2573 EqualizerParameter::Enable(val) => state.enable[ch] = *val,
2574
2575 EqualizerParameter::HpfEnable(val) => state.hpf_enable[ch] = *val,
2576 EqualizerParameter::HpfSlope(val) => state.hpf_slope[ch] = *val,
2577 EqualizerParameter::HpfFreq(val) => state.hpf_freq[ch] = *val,
2578
2579 EqualizerParameter::LpfEnable(val) => state.lpf_enable[ch] = *val,
2580 EqualizerParameter::LpfSlope(val) => state.lpf_slope[ch] = *val,
2581 EqualizerParameter::LpfFreq(val) => state.lpf_freq[ch] = *val,
2582
2583 EqualizerParameter::LfEnable(val) => state.lf_enable[ch] = *val,
2584 EqualizerParameter::LfType(val) => state.lf_type[ch] = *val,
2585 EqualizerParameter::LfFreq(val) => state.lf_freq[ch] = *val,
2586 EqualizerParameter::LfGain(val) => state.lf_gain[ch] = *val,
2587 EqualizerParameter::LfWidth(val) => state.lf_width[ch] = *val,
2588
2589 EqualizerParameter::LmfEnable(val) => state.lmf_enable[ch] = *val,
2590 EqualizerParameter::LmfType(val) => state.lmf_type[ch] = *val,
2591 EqualizerParameter::LmfFreq(val) => state.lmf_freq[ch] = *val,
2592 EqualizerParameter::LmfGain(val) => state.lmf_gain[ch] = *val,
2593 EqualizerParameter::LmfWidth(val) => state.lmf_width[ch] = *val,
2594
2595 EqualizerParameter::MfEnable(val) => state.mf_enable[ch] = *val,
2596 EqualizerParameter::MfType(val) => state.mf_type[ch] = *val,
2597 EqualizerParameter::MfFreq(val) => state.mf_freq[ch] = *val,
2598 EqualizerParameter::MfGain(val) => state.mf_gain[ch] = *val,
2599 EqualizerParameter::MfWidth(val) => state.mf_width[ch] = *val,
2600
2601 EqualizerParameter::HmfEnable(val) => state.hmf_enable[ch] = *val,
2602 EqualizerParameter::HmfType(val) => state.hmf_type[ch] = *val,
2603 EqualizerParameter::HmfFreq(val) => state.hmf_freq[ch] = *val,
2604 EqualizerParameter::HmfGain(val) => state.hmf_gain[ch] = *val,
2605 EqualizerParameter::HmfWidth(val) => state.hmf_width[ch] = *val,
2606
2607 EqualizerParameter::HfEnable(val) => state.hf_enable[ch] = *val,
2608 EqualizerParameter::HfType(val) => state.hf_type[ch] = *val,
2609 EqualizerParameter::HfFreq(val) => state.hf_freq[ch] = *val,
2610 EqualizerParameter::HfGain(val) => state.hf_gain[ch] = *val,
2611 EqualizerParameter::HfWidth(val) => state.hf_width[ch] = *val,
2612 }
2613 }
2614}
2615
2616#[derive(Default, Debug, Clone, PartialEq)]
2618pub struct CommandDspDynamicsState {
2619 pub enable: Vec<bool>,
2621
2622 pub comp_enable: Vec<bool>,
2624 pub comp_detect_mode: Vec<LevelDetectMode>,
2626 pub comp_threshold: Vec<i32>,
2628 pub comp_ratio: Vec<f32>,
2630 pub comp_attack: Vec<u32>,
2632 pub comp_release: Vec<u32>,
2634 pub comp_gain: Vec<f32>,
2636
2637 pub leveler_enable: Vec<bool>,
2639 pub leveler_mode: Vec<LevelerMode>,
2641 pub leveler_makeup: Vec<u32>,
2643 pub leveler_reduce: Vec<u32>,
2645}
2646
2647pub trait MotuCommandDspDynamicsSpecification {
2649 const COMP_THRESHOLD_MIN: i32 = -48;
2651 const COMP_THRESHOLD_MAX: i32 = 0;
2653 const COMP_THRESHOLD_STEP: i32 = 1;
2655
2656 const COMP_RATIO_MIN: f32 = 1.0;
2658 const COMP_RATIO_MAX: f32 = 10.0;
2660
2661 const COMP_ATTACK_MIN: i32 = 10;
2663 const COMP_ATTACK_MAX: i32 = 100;
2665 const COMP_ATTACK_STEP: i32 = 1;
2667
2668 const COMP_RELEASE_MIN: i32 = 10;
2670 const COMP_RELEASE_MAX: i32 = 100;
2672 const COMP_RELEASE_STEP: i32 = 1;
2674
2675 const COMP_GAIN_MIN: f32 = -6.0;
2677 const COMP_GAIN_MAX: f32 = 0.0;
2679
2680 const LEVELER_PERCENTAGE_MIN: u32 = 0;
2682 const LEVELER_PERCENTAGE_MAX: u32 = 100;
2684 const LEVELER_PERCENTAGE_STEP: u32 = 1;
2686
2687 fn create_dynamics_parameters(
2688 state: &CommandDspDynamicsState,
2689 ch: usize,
2690 ) -> Vec<DynamicsParameter> {
2691 let mut params = Vec::new();
2692
2693 params.push(DynamicsParameter::Enable(state.enable[ch]));
2694
2695 params.push(DynamicsParameter::CompEnable(state.comp_enable[ch]));
2696 params.push(DynamicsParameter::CompDetectMode(
2697 state.comp_detect_mode[ch],
2698 ));
2699 params.push(DynamicsParameter::CompThreshold(state.comp_threshold[ch]));
2700 params.push(DynamicsParameter::CompRatio(state.comp_ratio[ch]));
2701 params.push(DynamicsParameter::CompAttack(state.comp_attack[ch]));
2702 params.push(DynamicsParameter::CompRelease(state.comp_release[ch]));
2703 params.push(DynamicsParameter::CompGain(state.comp_gain[ch]));
2704
2705 params.push(DynamicsParameter::LevelerEnable(state.leveler_enable[ch]));
2706 params.push(DynamicsParameter::LevelerMode(state.leveler_mode[ch]));
2707 params.push(DynamicsParameter::LevelerMakeup(state.leveler_makeup[ch]));
2708 params.push(DynamicsParameter::LevelerReduce(state.leveler_reduce[ch]));
2709
2710 params
2711 }
2712
2713 fn parse_dynamics_parameter(
2714 state: &mut CommandDspDynamicsState,
2715 param: &DynamicsParameter,
2716 ch: usize,
2717 ) {
2718 match param {
2719 DynamicsParameter::Enable(val) => state.enable[ch] = *val,
2720
2721 DynamicsParameter::CompEnable(val) => state.comp_enable[ch] = *val,
2722 DynamicsParameter::CompDetectMode(val) => state.comp_detect_mode[ch] = *val,
2723 DynamicsParameter::CompThreshold(val) => state.comp_threshold[ch] = *val,
2724 DynamicsParameter::CompRatio(val) => state.comp_ratio[ch] = *val,
2725 DynamicsParameter::CompAttack(val) => state.comp_attack[ch] = *val,
2726 DynamicsParameter::CompRelease(val) => state.comp_release[ch] = *val,
2727 DynamicsParameter::CompGain(val) => state.comp_gain[ch] = *val,
2728
2729 DynamicsParameter::LevelerEnable(val) => state.leveler_enable[ch] = *val,
2730 DynamicsParameter::LevelerMode(val) => state.leveler_mode[ch] = *val,
2731 DynamicsParameter::LevelerMakeup(val) => state.leveler_makeup[ch] = *val,
2732 DynamicsParameter::LevelerReduce(val) => state.leveler_reduce[ch] = *val,
2733 }
2734 }
2735}
2736
2737#[derive(Default, Debug, Clone, PartialEq)]
2739pub struct CommandDspInputState {
2740 pub phase: Vec<bool>,
2742 pub pair: Vec<bool>,
2744 pub gain: Vec<i32>,
2746 pub swap: Vec<bool>,
2748 pub stereo_mode: Vec<InputStereoPairMode>,
2750 pub width: Vec<f32>,
2752
2753 pub reverb_send: Vec<f32>,
2755 pub reverb_balance: Vec<f32>,
2757
2758 pub pad: Vec<bool>,
2760 pub nominal_level: Vec<NominalSignalLevel>,
2762 pub phantom: Vec<bool>,
2764 pub limitter: Vec<bool>,
2766 pub lookahead: Vec<bool>,
2768 pub soft_clip: Vec<bool>,
2770}
2771
2772pub trait MotuCommandDspInputSpecification {
2774 const INPUT_PORTS: &'static [TargetPort];
2776 const MIC_COUNT: usize;
2778 const LINE_INPUT_COUNT: usize;
2780
2781 const INPUT_GAIN_MIN: i32 = -96;
2783 const INPUT_GAIN_MAX: i32 = 22;
2785 const INPUT_GAIN_STEP: i32 = 1;
2787
2788 const INPUT_WIDTH_MIN: f32 = 0.0;
2790 const INPUT_WIDTH_MAX: f32 = 1.0;
2792
2793 const INPUT_REVERB_GAIN_MIN: f32 = 0.0;
2795 const INPUT_REVERB_GAIN_MAX: f32 = 1.0;
2797
2798 const INPUT_REVERB_BALANCE_MIN: f32 = -1.0;
2800 const INPUT_REVERB_BALANCE_MAX: f32 = 1.0;
2802
2803 fn create_input_state() -> CommandDspInputState {
2805 CommandDspInputState {
2806 phase: vec![Default::default(); Self::INPUT_PORTS.len()],
2807 pair: vec![Default::default(); Self::INPUT_PORTS.len()],
2808 gain: vec![Default::default(); Self::INPUT_PORTS.len()],
2809 swap: vec![Default::default(); Self::INPUT_PORTS.len()],
2810 stereo_mode: vec![Default::default(); Self::INPUT_PORTS.len()],
2811 width: vec![Default::default(); Self::INPUT_PORTS.len()],
2812 reverb_send: vec![Default::default(); Self::INPUT_PORTS.len()],
2813 reverb_balance: vec![Default::default(); Self::INPUT_PORTS.len()],
2814 pad: vec![Default::default(); Self::MIC_COUNT],
2815 phantom: vec![Default::default(); Self::MIC_COUNT],
2816 limitter: vec![Default::default(); Self::MIC_COUNT],
2817 lookahead: vec![Default::default(); Self::MIC_COUNT],
2818 soft_clip: vec![Default::default(); Self::MIC_COUNT],
2819 nominal_level: vec![Default::default(); Self::LINE_INPUT_COUNT],
2820 }
2821 }
2822
2823 fn create_input_equalizer_state() -> CommandDspInputEqualizerState {
2825 CommandDspInputEqualizerState(CommandDspEqualizerState {
2826 enable: vec![Default::default(); Self::INPUT_PORTS.len()],
2827
2828 hpf_enable: vec![Default::default(); Self::INPUT_PORTS.len()],
2829 hpf_slope: vec![Default::default(); Self::INPUT_PORTS.len()],
2830 hpf_freq: vec![Default::default(); Self::INPUT_PORTS.len()],
2831
2832 lpf_enable: vec![Default::default(); Self::INPUT_PORTS.len()],
2833 lpf_slope: vec![Default::default(); Self::INPUT_PORTS.len()],
2834 lpf_freq: vec![Default::default(); Self::INPUT_PORTS.len()],
2835
2836 lf_enable: vec![Default::default(); Self::INPUT_PORTS.len()],
2837 lf_type: vec![Default::default(); Self::INPUT_PORTS.len()],
2838 lf_freq: vec![Default::default(); Self::INPUT_PORTS.len()],
2839 lf_gain: vec![Default::default(); Self::INPUT_PORTS.len()],
2840 lf_width: vec![Default::default(); Self::INPUT_PORTS.len()],
2841
2842 lmf_enable: vec![Default::default(); Self::INPUT_PORTS.len()],
2843 lmf_type: vec![Default::default(); Self::INPUT_PORTS.len()],
2844 lmf_freq: vec![Default::default(); Self::INPUT_PORTS.len()],
2845 lmf_gain: vec![Default::default(); Self::INPUT_PORTS.len()],
2846 lmf_width: vec![Default::default(); Self::INPUT_PORTS.len()],
2847
2848 mf_enable: vec![Default::default(); Self::INPUT_PORTS.len()],
2849 mf_type: vec![Default::default(); Self::INPUT_PORTS.len()],
2850 mf_freq: vec![Default::default(); Self::INPUT_PORTS.len()],
2851 mf_gain: vec![Default::default(); Self::INPUT_PORTS.len()],
2852 mf_width: vec![Default::default(); Self::INPUT_PORTS.len()],
2853
2854 hmf_enable: vec![Default::default(); Self::INPUT_PORTS.len()],
2855 hmf_type: vec![Default::default(); Self::INPUT_PORTS.len()],
2856 hmf_freq: vec![Default::default(); Self::INPUT_PORTS.len()],
2857 hmf_gain: vec![Default::default(); Self::INPUT_PORTS.len()],
2858 hmf_width: vec![Default::default(); Self::INPUT_PORTS.len()],
2859
2860 hf_enable: vec![Default::default(); Self::INPUT_PORTS.len()],
2861 hf_type: vec![Default::default(); Self::INPUT_PORTS.len()],
2862 hf_freq: vec![Default::default(); Self::INPUT_PORTS.len()],
2863 hf_gain: vec![Default::default(); Self::INPUT_PORTS.len()],
2864 hf_width: vec![Default::default(); Self::INPUT_PORTS.len()],
2865 })
2866 }
2867
2868 fn create_input_dynamics_state() -> CommandDspInputDynamicsState {
2870 CommandDspInputDynamicsState(CommandDspDynamicsState {
2871 enable: vec![Default::default(); Self::INPUT_PORTS.len()],
2872
2873 comp_enable: vec![Default::default(); Self::INPUT_PORTS.len()],
2874 comp_detect_mode: vec![Default::default(); Self::INPUT_PORTS.len()],
2875 comp_threshold: vec![Default::default(); Self::INPUT_PORTS.len()],
2876 comp_ratio: vec![Default::default(); Self::INPUT_PORTS.len()],
2877 comp_attack: vec![Default::default(); Self::INPUT_PORTS.len()],
2878 comp_release: vec![Default::default(); Self::INPUT_PORTS.len()],
2879 comp_gain: vec![Default::default(); Self::INPUT_PORTS.len()],
2880
2881 leveler_enable: vec![Default::default(); Self::INPUT_PORTS.len()],
2882 leveler_mode: vec![Default::default(); Self::INPUT_PORTS.len()],
2883 leveler_makeup: vec![Default::default(); Self::INPUT_PORTS.len()],
2884 leveler_reduce: vec![Default::default(); Self::INPUT_PORTS.len()],
2885 })
2886 }
2887}
2888
2889impl<O> MotuCommandDspParametersOperation<CommandDspInputState> for O
2890where
2891 O: MotuCommandDspInputSpecification,
2892{
2893 fn build_commands(params: &CommandDspInputState) -> Vec<DspCmd> {
2894 let mut cmds = Vec::new();
2895
2896 (0..Self::INPUT_PORTS.len()).for_each(|ch| {
2897 cmds.push(DspCmd::Input(InputCmd::Phase(ch, params.phase[ch])));
2898 cmds.push(DspCmd::Input(InputCmd::Pair(ch, params.pair[ch])));
2899 cmds.push(DspCmd::Input(InputCmd::Gain(ch, params.gain[ch])));
2900 cmds.push(DspCmd::Input(InputCmd::Swap(ch, params.swap[ch])));
2901 cmds.push(DspCmd::Input(InputCmd::StereoMode(
2902 ch,
2903 params.stereo_mode[ch],
2904 )));
2905 cmds.push(DspCmd::Input(InputCmd::Width(ch, params.width[ch])));
2906
2907 cmds.push(DspCmd::Input(InputCmd::ReverbSend(
2908 ch,
2909 params.reverb_send[ch],
2910 )));
2911 cmds.push(DspCmd::Input(InputCmd::ReverbLrBalance(
2912 ch,
2913 params.reverb_balance[ch],
2914 )));
2915 });
2916
2917 (0..Self::MIC_COUNT).for_each(|ch| {
2918 cmds.push(DspCmd::Input(InputCmd::Pad(ch, params.pad[ch])));
2919 cmds.push(DspCmd::Input(InputCmd::Phantom(ch, params.phantom[ch])));
2920 cmds.push(DspCmd::Input(InputCmd::Limitter(ch, params.limitter[ch])));
2921 cmds.push(DspCmd::Input(InputCmd::Lookahead(ch, params.lookahead[ch])));
2922 cmds.push(DspCmd::Input(InputCmd::Softclip(ch, params.soft_clip[ch])));
2923 });
2924
2925 (0..Self::LINE_INPUT_COUNT).for_each(|ch| {
2926 cmds.push(DspCmd::Input(InputCmd::NominalLevel(
2927 Self::MIC_COUNT + ch,
2928 params.nominal_level[ch],
2929 )));
2930 });
2931
2932 cmds
2933 }
2934
2935 fn parse_command(params: &mut CommandDspInputState, command: &DspCmd) -> bool {
2936 if let DspCmd::Input(cmd) = command {
2937 match cmd {
2938 InputCmd::Phase(ch, val) => {
2939 params.phase[*ch] = *val;
2940 true
2941 }
2942 InputCmd::Pair(ch, val) => {
2943 params.pair[*ch] = *val;
2944 true
2945 }
2946 InputCmd::Gain(ch, val) => {
2947 params.gain[*ch] = *val;
2948 true
2949 }
2950 InputCmd::Swap(ch, val) => {
2951 params.swap[*ch] = *val;
2952 true
2953 }
2954 InputCmd::StereoMode(ch, val) => {
2955 params.stereo_mode[*ch] = *val;
2956 true
2957 }
2958 InputCmd::Width(ch, val) => {
2959 params.width[*ch] = *val;
2960 true
2961 }
2962 InputCmd::ReverbSend(ch, val) => {
2963 params.reverb_send[*ch] = *val;
2964 true
2965 }
2966 InputCmd::ReverbLrBalance(ch, val) => {
2967 params.reverb_balance[*ch] = *val;
2968 true
2969 }
2970 InputCmd::NominalLevel(ch, val) => {
2971 if *ch >= params.pad.len()
2972 && *ch < params.pad.len() + params.nominal_level.len()
2973 {
2974 params.nominal_level[*ch - params.pad.len()] = *val;
2975 true
2976 } else {
2977 false
2978 }
2979 }
2980 _ => false,
2981 }
2982 } else {
2983 false
2984 }
2985 }
2986}
2987
2988#[derive(Default, Debug, Clone, PartialEq)]
2990pub struct CommandDspInputEqualizerState(pub CommandDspEqualizerState);
2991
2992impl AsRef<CommandDspEqualizerState> for CommandDspInputEqualizerState {
2993 fn as_ref(&self) -> &CommandDspEqualizerState {
2994 &self.0
2995 }
2996}
2997
2998impl AsMut<CommandDspEqualizerState> for CommandDspInputEqualizerState {
2999 fn as_mut(&mut self) -> &mut CommandDspEqualizerState {
3000 &mut self.0
3001 }
3002}
3003
3004impl<O> MotuCommandDspParametersOperation<CommandDspInputEqualizerState> for O
3005where
3006 O: MotuCommandDspInputSpecification + MotuCommandDspEqualizerSpecification,
3007{
3008 fn build_commands(params: &CommandDspInputEqualizerState) -> Vec<DspCmd> {
3009 let mut cmds = Vec::new();
3010
3011 (0..Self::INPUT_PORTS.len()).for_each(|ch| {
3012 Self::create_equalizer_parameters(¶ms.0, ch)
3013 .into_iter()
3014 .for_each(|param| {
3015 let cmd = DspCmd::Input(InputCmd::Equalizer(ch, param));
3016 cmds.push(cmd);
3017 });
3018 });
3019
3020 cmds
3021 }
3022
3023 fn parse_command(params: &mut CommandDspInputEqualizerState, command: &DspCmd) -> bool {
3024 if let DspCmd::Input(InputCmd::Equalizer(ch, param)) = command {
3025 Self::parse_equalizer_parameter(&mut params.0, param, *ch);
3026 true
3027 } else {
3028 false
3029 }
3030 }
3031}
3032
3033#[derive(Default, Debug, Clone, PartialEq)]
3035pub struct CommandDspInputDynamicsState(pub CommandDspDynamicsState);
3036
3037impl AsRef<CommandDspDynamicsState> for CommandDspInputDynamicsState {
3038 fn as_ref(&self) -> &CommandDspDynamicsState {
3039 &self.0
3040 }
3041}
3042
3043impl AsMut<CommandDspDynamicsState> for CommandDspInputDynamicsState {
3044 fn as_mut(&mut self) -> &mut CommandDspDynamicsState {
3045 &mut self.0
3046 }
3047}
3048
3049impl<O> MotuCommandDspParametersOperation<CommandDspInputDynamicsState> for O
3050where
3051 O: MotuCommandDspInputSpecification + MotuCommandDspDynamicsSpecification,
3052{
3053 fn build_commands(params: &CommandDspInputDynamicsState) -> Vec<DspCmd> {
3054 let mut cmds = Vec::new();
3055
3056 (0..Self::INPUT_PORTS.len()).for_each(|ch| {
3057 Self::create_dynamics_parameters(¶ms.0, ch)
3058 .into_iter()
3059 .for_each(|param| {
3060 let cmd = DspCmd::Input(InputCmd::Dynamics(ch, param));
3061 cmds.push(cmd);
3062 });
3063 });
3064
3065 cmds
3066 }
3067
3068 fn parse_command(params: &mut CommandDspInputDynamicsState, command: &DspCmd) -> bool {
3069 if let DspCmd::Input(InputCmd::Dynamics(ch, param)) = command {
3070 Self::parse_dynamics_parameter(&mut params.0, param, *ch);
3071 true
3072 } else {
3073 false
3074 }
3075 }
3076}
3077
3078#[derive(Default, Debug, Clone, PartialEq)]
3080pub struct CommandDspOutputState {
3081 pub reverb_send: Vec<f32>,
3083 pub reverb_return: Vec<f32>,
3085
3086 pub master_monitor: Vec<bool>,
3088 pub master_talkback: Vec<bool>,
3090 pub master_listenback: Vec<bool>,
3092}
3093
3094pub trait MotuCommandDspOutputSpecification {
3096 const OUTPUT_PORTS: &'static [TargetPort];
3098
3099 const OUTPUT_GAIN_MIN: f32 = 0.0;
3101 const OUTPUT_GAIN_MAX: f32 = 1.0;
3103
3104 const OUTPUT_VOLUME_MIN: f32 = 0.0;
3106 const OUTPUT_VOLUME_MAX: f32 = 1.0;
3108
3109 fn create_output_state() -> CommandDspOutputState {
3110 CommandDspOutputState {
3111 reverb_send: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3112 reverb_return: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3113 master_monitor: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3114 master_talkback: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3115 master_listenback: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3116 }
3117 }
3118
3119 fn create_output_equalizer_state() -> CommandDspOutputEqualizerState {
3120 CommandDspOutputEqualizerState(CommandDspEqualizerState {
3121 enable: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3122
3123 hpf_enable: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3124 hpf_slope: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3125 hpf_freq: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3126
3127 lpf_enable: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3128 lpf_slope: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3129 lpf_freq: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3130
3131 lf_enable: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3132 lf_type: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3133 lf_freq: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3134 lf_gain: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3135 lf_width: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3136
3137 lmf_enable: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3138 lmf_type: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3139 lmf_freq: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3140 lmf_gain: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3141 lmf_width: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3142
3143 mf_enable: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3144 mf_type: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3145 mf_freq: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3146 mf_gain: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3147 mf_width: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3148
3149 hmf_enable: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3150 hmf_type: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3151 hmf_freq: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3152 hmf_gain: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3153 hmf_width: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3154
3155 hf_enable: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3156 hf_type: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3157 hf_freq: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3158 hf_gain: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3159 hf_width: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3160 })
3161 }
3162
3163 fn create_output_dynamics_state() -> CommandDspOutputDynamicsState {
3164 CommandDspOutputDynamicsState(CommandDspDynamicsState {
3165 enable: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3166
3167 comp_enable: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3168 comp_detect_mode: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3169 comp_threshold: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3170 comp_ratio: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3171 comp_attack: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3172 comp_release: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3173 comp_gain: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3174
3175 leveler_enable: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3176 leveler_mode: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3177 leveler_makeup: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3178 leveler_reduce: vec![Default::default(); Self::OUTPUT_PORTS.len()],
3179 })
3180 }
3181}
3182
3183impl<O> MotuCommandDspParametersOperation<CommandDspOutputState> for O
3184where
3185 O: MotuCommandDspOutputSpecification,
3186{
3187 fn build_commands(params: &CommandDspOutputState) -> Vec<DspCmd> {
3188 let mut cmds = Vec::new();
3189
3190 (0..Self::OUTPUT_PORTS.len()).for_each(|ch| {
3191 cmds.push(DspCmd::Output(OutputCmd::ReverbSend(
3192 ch,
3193 params.reverb_send[ch],
3194 )));
3195 cmds.push(DspCmd::Output(OutputCmd::ReverbReturn(
3196 ch,
3197 params.reverb_return[ch],
3198 )));
3199
3200 cmds.push(DspCmd::Output(OutputCmd::MasterMonitor(
3201 ch,
3202 params.master_monitor[ch],
3203 )));
3204 cmds.push(DspCmd::Output(OutputCmd::MasterTalkback(
3205 ch,
3206 params.master_talkback[ch],
3207 )));
3208 cmds.push(DspCmd::Output(OutputCmd::MasterListenback(
3209 ch,
3210 params.master_listenback[ch],
3211 )));
3212 });
3213
3214 cmds
3215 }
3216
3217 fn parse_command(params: &mut CommandDspOutputState, command: &DspCmd) -> bool {
3218 if let DspCmd::Output(cmd) = command {
3219 match cmd {
3220 OutputCmd::ReverbSend(ch, val) => {
3221 params.reverb_send[*ch] = *val;
3222 true
3223 }
3224 OutputCmd::ReverbReturn(ch, val) => {
3225 params.reverb_return[*ch] = *val;
3226 true
3227 }
3228 OutputCmd::MasterMonitor(ch, val) => {
3229 params.master_monitor[*ch] = *val;
3230 true
3231 }
3232 OutputCmd::MasterTalkback(ch, val) => {
3233 params.master_talkback[*ch] = *val;
3234 true
3235 }
3236 OutputCmd::MasterListenback(ch, val) => {
3237 params.master_listenback[*ch] = *val;
3238 true
3239 }
3240 _ => false,
3241 }
3242 } else {
3243 false
3244 }
3245 }
3246}
3247
3248#[derive(Default, Debug, Clone, PartialEq)]
3250pub struct CommandDspOutputEqualizerState(pub CommandDspEqualizerState);
3251
3252impl AsRef<CommandDspEqualizerState> for CommandDspOutputEqualizerState {
3253 fn as_ref(&self) -> &CommandDspEqualizerState {
3254 &self.0
3255 }
3256}
3257
3258impl AsMut<CommandDspEqualizerState> for CommandDspOutputEqualizerState {
3259 fn as_mut(&mut self) -> &mut CommandDspEqualizerState {
3260 &mut self.0
3261 }
3262}
3263
3264impl<O> MotuCommandDspParametersOperation<CommandDspOutputEqualizerState> for O
3265where
3266 O: MotuCommandDspOutputSpecification + MotuCommandDspEqualizerSpecification,
3267{
3268 fn build_commands(params: &CommandDspOutputEqualizerState) -> Vec<DspCmd> {
3269 let mut cmds = Vec::new();
3270
3271 (0..Self::OUTPUT_PORTS.len()).for_each(|ch| {
3272 Self::create_equalizer_parameters(¶ms.0, ch)
3273 .into_iter()
3274 .for_each(|param| {
3275 let cmd = DspCmd::Output(OutputCmd::Equalizer(ch, param));
3276 cmds.push(cmd);
3277 });
3278 });
3279
3280 cmds
3281 }
3282
3283 fn parse_command(params: &mut CommandDspOutputEqualizerState, command: &DspCmd) -> bool {
3284 if let DspCmd::Output(OutputCmd::Equalizer(ch, param)) = command {
3285 Self::parse_equalizer_parameter(&mut params.0, param, *ch);
3286 true
3287 } else {
3288 false
3289 }
3290 }
3291}
3292
3293#[derive(Default, Debug, Clone, PartialEq)]
3295pub struct CommandDspOutputDynamicsState(pub CommandDspDynamicsState);
3296
3297impl AsRef<CommandDspDynamicsState> for CommandDspOutputDynamicsState {
3298 fn as_ref(&self) -> &CommandDspDynamicsState {
3299 &self.0
3300 }
3301}
3302
3303impl AsMut<CommandDspDynamicsState> for CommandDspOutputDynamicsState {
3304 fn as_mut(&mut self) -> &mut CommandDspDynamicsState {
3305 &mut self.0
3306 }
3307}
3308
3309impl<O> MotuCommandDspParametersOperation<CommandDspOutputDynamicsState> for O
3310where
3311 O: MotuCommandDspOutputSpecification + MotuCommandDspDynamicsSpecification,
3312{
3313 fn build_commands(params: &CommandDspOutputDynamicsState) -> Vec<DspCmd> {
3314 let mut cmds = Vec::new();
3315
3316 (0..Self::OUTPUT_PORTS.len()).for_each(|ch| {
3317 Self::create_dynamics_parameters(¶ms.0, ch)
3318 .into_iter()
3319 .for_each(|param| {
3320 let cmd = DspCmd::Output(OutputCmd::Dynamics(ch, param));
3321 cmds.push(cmd);
3322 });
3323 });
3324
3325 cmds
3326 }
3327
3328 fn parse_command(params: &mut CommandDspOutputDynamicsState, command: &DspCmd) -> bool {
3329 if let DspCmd::Output(OutputCmd::Dynamics(ch, param)) = command {
3330 Self::parse_dynamics_parameter(&mut params.0, param, *ch);
3331 true
3332 } else {
3333 false
3334 }
3335 }
3336}
3337
3338#[derive(Default, Debug, Clone, PartialEq)]
3340pub struct CommandDspMeterState {
3341 pub inputs: Vec<f32>,
3342 pub outputs: Vec<f32>,
3343 }
3345
3346const METER_IMAGE_SIZE: usize = 400;
3347
3348pub trait MotuCommandDspMeterSpecification {
3350 const INPUT_PORTS: &'static [(TargetPort, usize)];
3351 const OUTPUT_PORTS: &'static [(TargetPort, usize)];
3352
3353 const LEVEL_MIN: f32 = 0.0;
3354 const LEVEL_MAX: f32 = 1.0;
3355
3356 const METER_IMAGE_SIZE: usize = 400;
3357
3358 fn create_meter_state() -> CommandDspMeterState {
3359 CommandDspMeterState {
3360 inputs: vec![0.0; Self::INPUT_PORTS.len()],
3361 outputs: vec![0.0; Self::OUTPUT_PORTS.len()],
3362 }
3363 }
3364}
3365
3366impl<O> MotuCommandDspImageOperation<CommandDspMeterState, [f32; METER_IMAGE_SIZE]> for O
3367where
3368 O: MotuCommandDspMeterSpecification,
3369{
3370 fn parse_image(params: &mut CommandDspMeterState, image: &[f32; METER_IMAGE_SIZE]) {
3371 params
3372 .inputs
3373 .iter_mut()
3374 .zip(Self::INPUT_PORTS)
3375 .for_each(|(m, &(_, pos))| *m = image[pos]);
3376 params
3377 .outputs
3378 .iter_mut()
3379 .zip(Self::OUTPUT_PORTS)
3380 .for_each(|(m, &(_, pos))| *m = image[pos]);
3381 }
3382}
3383
3384#[cfg(test)]
3385mod test {
3386 use super::*;
3387
3388 #[test]
3389 fn test_u8_cmds() {
3390 [
3391 DspCmd::Monitor(MonitorCmd::ReturnAssign(0x69)),
3392 DspCmd::Monitor(MonitorCmd::TalkbackEnable(true)),
3393 DspCmd::Monitor(MonitorCmd::ListenbackEnable(true)),
3394 DspCmd::Input(InputCmd::Phase(0x59, true)),
3395 DspCmd::Input(InputCmd::Pair(0x0, false)),
3396 DspCmd::Input(InputCmd::Swap(0x24, false)),
3397 DspCmd::Input(InputCmd::StereoMode(
3398 0x35,
3399 InputStereoPairMode::MonauralStereo,
3400 )),
3401 DspCmd::Input(InputCmd::Limitter(0xad, true)),
3402 DspCmd::Input(InputCmd::Lookahead(0xdd, true)),
3403 DspCmd::Input(InputCmd::Softclip(0xfc, false)),
3404 DspCmd::Input(InputCmd::Pad(0x91, true)),
3405 DspCmd::Input(InputCmd::NominalLevel(
3406 0x91,
3407 NominalSignalLevel::Professional,
3408 )),
3409 DspCmd::Input(InputCmd::Phantom(0x13, false)),
3410 DspCmd::Input(InputCmd::Equalizer(0x14, EqualizerParameter::Enable(false))),
3411 DspCmd::Input(InputCmd::Equalizer(
3412 0x23,
3413 EqualizerParameter::HpfEnable(true),
3414 )),
3415 DspCmd::Input(InputCmd::Equalizer(
3416 0x32,
3417 EqualizerParameter::HpfSlope(RollOffLevel::L30),
3418 )),
3419 DspCmd::Input(InputCmd::Equalizer(
3420 0x41,
3421 EqualizerParameter::LfEnable(false),
3422 )),
3423 DspCmd::Input(InputCmd::Equalizer(
3424 0x59,
3425 EqualizerParameter::LfType(FilterType5::Shelf),
3426 )),
3427 DspCmd::Input(InputCmd::Equalizer(
3428 0x68,
3429 EqualizerParameter::LmfEnable(true),
3430 )),
3431 DspCmd::Input(InputCmd::Equalizer(
3432 0x77,
3433 EqualizerParameter::LmfType(FilterType4::T4),
3434 )),
3435 DspCmd::Input(InputCmd::Equalizer(
3436 0x86,
3437 EqualizerParameter::MfEnable(false),
3438 )),
3439 DspCmd::Input(InputCmd::Equalizer(
3440 0x95,
3441 EqualizerParameter::MfType(FilterType4::T3),
3442 )),
3443 DspCmd::Input(InputCmd::Equalizer(
3444 0xaf,
3445 EqualizerParameter::HmfEnable(true),
3446 )),
3447 DspCmd::Input(InputCmd::Equalizer(
3448 0xbe,
3449 EqualizerParameter::HmfType(FilterType4::T2),
3450 )),
3451 DspCmd::Input(InputCmd::Equalizer(
3452 0xcd,
3453 EqualizerParameter::HfEnable(false),
3454 )),
3455 DspCmd::Input(InputCmd::Equalizer(
3456 0xdc,
3457 EqualizerParameter::HfType(FilterType5::T1),
3458 )),
3459 DspCmd::Input(InputCmd::Equalizer(
3460 0xeb,
3461 EqualizerParameter::LpfEnable(true),
3462 )),
3463 DspCmd::Input(InputCmd::Equalizer(
3464 0xfa,
3465 EqualizerParameter::LpfSlope(RollOffLevel::L24),
3466 )),
3467 DspCmd::Input(InputCmd::Dynamics(0xf0, DynamicsParameter::Enable(false))),
3468 DspCmd::Input(InputCmd::Dynamics(
3469 0xe1,
3470 DynamicsParameter::CompEnable(true),
3471 )),
3472 DspCmd::Input(InputCmd::Dynamics(
3473 0xd2,
3474 DynamicsParameter::CompDetectMode(LevelDetectMode::Rms),
3475 )),
3476 DspCmd::Input(InputCmd::Dynamics(
3477 0xc3,
3478 DynamicsParameter::LevelerEnable(false),
3479 )),
3480 DspCmd::Input(InputCmd::Dynamics(
3481 0xb4,
3482 DynamicsParameter::LevelerMode(LevelerMode::Limit),
3483 )),
3484 DspCmd::Mixer(MixerCmd::OutputAssign(0xa5, 0x91)),
3485 DspCmd::Mixer(MixerCmd::OutputMute(0x96, true)),
3486 DspCmd::Mixer(MixerCmd::SourceMute(0x87, 0x13, false)),
3487 DspCmd::Mixer(MixerCmd::SourceSolo(0x78, 0x31, true)),
3488 DspCmd::Mixer(MixerCmd::SourceStereoMode(
3489 0x69,
3490 0x11,
3491 SourceStereoPairMode::LrBalance,
3492 )),
3493 DspCmd::Output(OutputCmd::Equalizer(
3494 0x5a,
3495 EqualizerParameter::Enable(false),
3496 )),
3497 DspCmd::Output(OutputCmd::Equalizer(
3498 0x4b,
3499 EqualizerParameter::HpfEnable(true),
3500 )),
3501 DspCmd::Output(OutputCmd::Equalizer(
3502 0x3c,
3503 EqualizerParameter::HpfSlope(RollOffLevel::L6),
3504 )),
3505 DspCmd::Output(OutputCmd::Equalizer(
3506 0x2d,
3507 EqualizerParameter::LfEnable(false),
3508 )),
3509 DspCmd::Output(OutputCmd::Equalizer(
3510 0x1e,
3511 EqualizerParameter::LfType(FilterType5::Shelf),
3512 )),
3513 DspCmd::Output(OutputCmd::Equalizer(
3514 0x0f,
3515 EqualizerParameter::LmfEnable(true),
3516 )),
3517 DspCmd::Output(OutputCmd::Equalizer(
3518 0xf1,
3519 EqualizerParameter::LmfType(FilterType4::T4),
3520 )),
3521 DspCmd::Output(OutputCmd::Equalizer(
3522 0xe2,
3523 EqualizerParameter::MfEnable(false),
3524 )),
3525 DspCmd::Output(OutputCmd::Equalizer(
3526 0xd3,
3527 EqualizerParameter::MfType(FilterType4::T3),
3528 )),
3529 DspCmd::Output(OutputCmd::Equalizer(
3530 0xc4,
3531 EqualizerParameter::HmfEnable(true),
3532 )),
3533 DspCmd::Output(OutputCmd::Equalizer(
3534 0xb5,
3535 EqualizerParameter::HmfType(FilterType4::T2),
3536 )),
3537 DspCmd::Output(OutputCmd::Equalizer(
3538 0xa6,
3539 EqualizerParameter::HfEnable(false),
3540 )),
3541 DspCmd::Output(OutputCmd::Equalizer(
3542 0x97,
3543 EqualizerParameter::HfType(FilterType5::T1),
3544 )),
3545 DspCmd::Output(OutputCmd::Equalizer(
3546 0x88,
3547 EqualizerParameter::LpfEnable(true),
3548 )),
3549 DspCmd::Output(OutputCmd::Equalizer(
3550 0x79,
3551 EqualizerParameter::LpfSlope(RollOffLevel::L18),
3552 )),
3553 DspCmd::Output(OutputCmd::Dynamics(0xff, DynamicsParameter::Enable(false))),
3554 DspCmd::Output(OutputCmd::Dynamics(
3555 0xee,
3556 DynamicsParameter::CompEnable(true),
3557 )),
3558 DspCmd::Output(OutputCmd::Dynamics(
3559 0xdd,
3560 DynamicsParameter::CompDetectMode(LevelDetectMode::Peak),
3561 )),
3562 DspCmd::Output(OutputCmd::Dynamics(
3563 0xcc,
3564 DynamicsParameter::LevelerEnable(false),
3565 )),
3566 DspCmd::Output(OutputCmd::Dynamics(
3567 0xbb,
3568 DynamicsParameter::LevelerMode(LevelerMode::Compress),
3569 )),
3570 DspCmd::Output(OutputCmd::MasterMonitor(0x97, true)),
3571 DspCmd::Output(OutputCmd::MasterTalkback(0xec, false)),
3572 DspCmd::Output(OutputCmd::MasterListenback(0xd5, true)),
3573 DspCmd::Reverb(ReverbCmd::Enable(false)),
3574 DspCmd::Reverb(ReverbCmd::Split(SplitPoint::Mixer)),
3575 DspCmd::Reverb(ReverbCmd::ReflectionMode(RoomShape::D)),
3576 DspCmd::Reserved(vec![0x69, 0xed, 0xba, 0x98, 0xec, 0x75]),
3577 ]
3578 .iter()
3579 .for_each(|cmd| {
3580 let mut raw = Vec::new();
3581 cmd.build(&mut raw);
3582 let mut c = Vec::new();
3583 assert_eq!(DspCmd::parse(&raw, &mut c), CMD_BYTE_SINGLE_LENGTH);
3584 assert_eq!(&c[0], cmd);
3585 });
3586 }
3587
3588 #[test]
3589 fn test_i32_cmds() {
3590 [
3591 DspCmd::Monitor(MonitorCmd::Focus(FocusTarget::Output(11))),
3592 DspCmd::Input(InputCmd::Gain(0xe4, 0x01)),
3593 DspCmd::Input(InputCmd::Dynamics(
3594 0xb1,
3595 DynamicsParameter::CompThreshold(97531),
3596 )),
3597 DspCmd::Output(OutputCmd::Dynamics(
3598 0x45,
3599 DynamicsParameter::CompThreshold(86420),
3600 )),
3601 DspCmd::Reverb(ReverbCmd::ShelfFilterAttenuation(98765)),
3602 ]
3603 .iter()
3604 .for_each(|cmd| {
3605 let mut raw = Vec::new();
3606 cmd.build(&mut raw);
3607 let mut c = Vec::new();
3608 assert_eq!(DspCmd::parse(&raw, &mut c), CMD_QUADLET_SINGLE_LENGTH);
3609 assert_eq!(&c[0], cmd);
3610 });
3611 }
3612
3613 #[test]
3614 fn test_u32_cmds() {
3615 [
3616 DspCmd::Input(InputCmd::Equalizer(0xc2, EqualizerParameter::HpfFreq(10))),
3617 DspCmd::Input(InputCmd::Equalizer(0xb1, EqualizerParameter::LfFreq(20))),
3618 DspCmd::Input(InputCmd::Equalizer(0x8e, EqualizerParameter::LmfFreq(30))),
3619 DspCmd::Input(InputCmd::Equalizer(0x5b, EqualizerParameter::MfFreq(40))),
3620 DspCmd::Input(InputCmd::Equalizer(0x28, EqualizerParameter::HmfFreq(50))),
3621 DspCmd::Input(InputCmd::Equalizer(0xf5, EqualizerParameter::HfFreq(60))),
3622 DspCmd::Input(InputCmd::Equalizer(0xc2, EqualizerParameter::LpfFreq(70))),
3623 DspCmd::Input(InputCmd::Dynamics(0x9f, DynamicsParameter::CompAttack(100))),
3624 DspCmd::Input(InputCmd::Dynamics(
3625 0x8e,
3626 DynamicsParameter::CompRelease(200),
3627 )),
3628 DspCmd::Output(OutputCmd::Dynamics(
3629 0x7f,
3630 DynamicsParameter::LevelerMakeup(1000),
3631 )),
3632 DspCmd::Output(OutputCmd::Dynamics(
3633 0xf2,
3634 DynamicsParameter::LevelerReduce(2000),
3635 )),
3636 DspCmd::Output(OutputCmd::Equalizer(0xa8, EqualizerParameter::HpfFreq(103))),
3637 DspCmd::Output(OutputCmd::Equalizer(0x39, EqualizerParameter::LfFreq(105))),
3638 DspCmd::Output(OutputCmd::Equalizer(0x5b, EqualizerParameter::LmfFreq(107))),
3639 DspCmd::Output(OutputCmd::Equalizer(0xbc, EqualizerParameter::MfFreq(109))),
3640 DspCmd::Output(OutputCmd::Equalizer(0xf7, EqualizerParameter::HmfFreq(111))),
3641 DspCmd::Output(OutputCmd::Equalizer(0xc0, EqualizerParameter::HfFreq(113))),
3642 DspCmd::Output(OutputCmd::Equalizer(0x29, EqualizerParameter::LpfFreq(115))),
3643 DspCmd::Output(OutputCmd::Dynamics(
3644 0x1b,
3645 DynamicsParameter::CompAttack(111),
3646 )),
3647 DspCmd::Output(OutputCmd::Dynamics(
3648 0x49,
3649 DynamicsParameter::CompRelease(113),
3650 )),
3651 DspCmd::Input(InputCmd::Dynamics(
3652 0x6c,
3653 DynamicsParameter::LevelerMakeup(1111),
3654 )),
3655 DspCmd::Input(InputCmd::Dynamics(
3656 0x5b,
3657 DynamicsParameter::LevelerReduce(1113),
3658 )),
3659 DspCmd::Reverb(ReverbCmd::PreDelay(11111)),
3660 DspCmd::Reverb(ReverbCmd::ShelfFilterFreq(111113)),
3661 DspCmd::Reverb(ReverbCmd::DecayTime(111115)),
3662 DspCmd::Reverb(ReverbCmd::LowFreqTime(111117)),
3663 DspCmd::Reverb(ReverbCmd::MiddleFreqTime(111119)),
3664 DspCmd::Reverb(ReverbCmd::HighFreqTime(111121)),
3665 DspCmd::Reverb(ReverbCmd::LowFreqCrossover(111123)),
3666 DspCmd::Reverb(ReverbCmd::HighFreqCrossover(111125)),
3667 DspCmd::Reverb(ReverbCmd::ReflectionSize(111127)),
3668 DspCmd::Reserved(vec![0x66, 0x00, 0x01, 0x02, 0x80, 0x04, 0x05, 0x06, 0x07]),
3669 ]
3670 .iter()
3671 .for_each(|cmd| {
3672 let mut raw = Vec::new();
3673 cmd.build(&mut raw);
3674 let mut c = Vec::new();
3675 assert_eq!(DspCmd::parse(&raw, &mut c), CMD_QUADLET_SINGLE_LENGTH);
3676 assert_eq!(&c[0], cmd);
3677 });
3678 }
3679
3680 #[test]
3681 fn test_f32_cmds() {
3682 [
3683 DspCmd::Monitor(MonitorCmd::Volume(9.012345678)),
3684 DspCmd::Monitor(MonitorCmd::ListenbackVolume(9.234567891)),
3685 DspCmd::Monitor(MonitorCmd::TalkbackVolume(9.345678912)),
3686 DspCmd::Input(InputCmd::Width(0xd3, 0.0987654321)),
3687 DspCmd::Input(InputCmd::Equalizer(
3688 0xa0,
3689 EqualizerParameter::LfGain(0.123456789),
3690 )),
3691 DspCmd::Input(InputCmd::Equalizer(
3692 0x9f,
3693 EqualizerParameter::LfWidth(0.987654321),
3694 )),
3695 DspCmd::Input(InputCmd::Equalizer(
3696 0x7d,
3697 EqualizerParameter::LmfGain(0.234567891),
3698 )),
3699 DspCmd::Input(InputCmd::Equalizer(
3700 0x6c,
3701 EqualizerParameter::LmfWidth(0.876543219),
3702 )),
3703 DspCmd::Input(InputCmd::Equalizer(
3704 0x4a,
3705 EqualizerParameter::MfGain(0.345678912),
3706 )),
3707 DspCmd::Input(InputCmd::Equalizer(
3708 0x39,
3709 EqualizerParameter::MfWidth(0.765432198),
3710 )),
3711 DspCmd::Input(InputCmd::Equalizer(
3712 0x17,
3713 EqualizerParameter::HmfGain(0.456789123),
3714 )),
3715 DspCmd::Input(InputCmd::Equalizer(
3716 0x06,
3717 EqualizerParameter::HmfWidth(0.654321987),
3718 )),
3719 DspCmd::Input(InputCmd::Equalizer(
3720 0xe4,
3721 EqualizerParameter::HfGain(0.567891234),
3722 )),
3723 DspCmd::Input(InputCmd::Equalizer(
3724 0xd3,
3725 EqualizerParameter::HfWidth(0.543219876),
3726 )),
3727 DspCmd::Input(InputCmd::Dynamics(
3728 0xa0,
3729 DynamicsParameter::CompRatio(0.678912345),
3730 )),
3731 DspCmd::Input(InputCmd::Dynamics(
3732 0x7d,
3733 DynamicsParameter::CompGain(0.432198765),
3734 )),
3735 DspCmd::Input(InputCmd::ReverbSend(0x33, 0.789123456)),
3736 DspCmd::Input(InputCmd::ReverbLrBalance(0xcc, 0.891234567)),
3737 DspCmd::Mixer(MixerCmd::OutputVolume(0x4a, 1.2345678)),
3738 DspCmd::Mixer(MixerCmd::ReverbSend(0x39, 1.3456789)),
3739 DspCmd::Mixer(MixerCmd::ReverbReturn(0x28, 1.456789)),
3740 DspCmd::Mixer(MixerCmd::SourceMonauralLrBalance(0x17, 0xc8, 1.987654)),
3741 DspCmd::Mixer(MixerCmd::SourceGain(0x06, 0x11, 1.876543)),
3742 DspCmd::Mixer(MixerCmd::SourceStereoLrBalance(0xe5, 0x13, 1.7654321)),
3743 DspCmd::Mixer(MixerCmd::SourceStereoWidth(0xd4, 0x1a, 1.654321)),
3744 DspCmd::Output(OutputCmd::Equalizer(
3745 0x11,
3746 EqualizerParameter::LfGain(2.123456789),
3747 )),
3748 DspCmd::Output(OutputCmd::Equalizer(
3749 0x5a,
3750 EqualizerParameter::LfWidth(2.987654321),
3751 )),
3752 DspCmd::Output(OutputCmd::Equalizer(
3753 0x98,
3754 EqualizerParameter::LmfGain(2.234567891),
3755 )),
3756 DspCmd::Output(OutputCmd::Equalizer(
3757 0x74,
3758 EqualizerParameter::LmfWidth(2.876543219),
3759 )),
3760 DspCmd::Output(OutputCmd::Equalizer(
3761 0x32,
3762 EqualizerParameter::MfGain(2.345678912),
3763 )),
3764 DspCmd::Output(OutputCmd::Equalizer(
3765 0x20,
3766 EqualizerParameter::MfWidth(2.765432198),
3767 )),
3768 DspCmd::Output(OutputCmd::Equalizer(
3769 0xc0,
3770 EqualizerParameter::HmfGain(2.456789123),
3771 )),
3772 DspCmd::Output(OutputCmd::Equalizer(
3773 0xf5,
3774 EqualizerParameter::HmfWidth(2.654321987),
3775 )),
3776 DspCmd::Output(OutputCmd::Equalizer(
3777 0x01,
3778 EqualizerParameter::HfGain(2.567891234),
3779 )),
3780 DspCmd::Output(OutputCmd::Equalizer(
3781 0xdb,
3782 EqualizerParameter::HfWidth(2.543219876),
3783 )),
3784 DspCmd::Output(OutputCmd::Dynamics(
3785 0x5e,
3786 DynamicsParameter::CompRatio(2.678912345),
3787 )),
3788 DspCmd::Output(OutputCmd::Dynamics(
3789 0xba,
3790 DynamicsParameter::CompGain(2.432198765),
3791 )),
3792 DspCmd::Output(OutputCmd::ReverbSend(0x99, 2.78912345)),
3793 DspCmd::Output(OutputCmd::ReverbReturn(0x88, 2.321987654)),
3794 DspCmd::Reverb(ReverbCmd::Width(123.456)),
3795 DspCmd::Reverb(ReverbCmd::ReflectionLevel(234.561)),
3796 ]
3797 .iter()
3798 .for_each(|cmd| {
3799 let mut raw = Vec::new();
3800 cmd.build(&mut raw);
3801 let mut c = Vec::new();
3802 assert_eq!(DspCmd::parse(&raw, &mut c), CMD_QUADLET_SINGLE_LENGTH);
3803 assert_eq!(&c[0], cmd);
3804 });
3805 }
3806
3807 #[test]
3808 fn test_resource() {
3809 let cmd = DspCmd::Resource(ResourceCmd::Usage(99.99999, 0x17));
3810 let mut raw = Vec::new();
3811 cmd.build(&mut raw);
3812 let mut c = Vec::new();
3813 assert_eq!(DspCmd::parse(&raw, &mut c), CMD_RESOURCE_LENGTH);
3814 assert_eq!(c[0], cmd);
3815 }
3816
3817 #[test]
3818 fn message_decode_test() {
3819 let raw = [
3820 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x69, 0x00, 0x00, 0x0a, 0x00,
3821 0x00, 0x69, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x66, 0x00, 0x07, 0x00, 0xff, 0x00, 0x00,
3822 0x00, 0x01, 0x62, 0x46, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x49,
3823 0x07, 0x00, 0x02, 0x0c, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x02,
3824 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x46,
3825 0x00, 0xa0, 0x8c, 0x46, 0x00, 0xa0, 0x8c,
3826 ];
3827 let mut handler = CommandDspMessageHandler::default();
3828 handler.cache.extend_from_slice(&raw);
3829 let cmds = handler.decode_messages();
3830 assert_eq!(cmds[0], DspCmd::Monitor(MonitorCmd::Volume(1.0)));
3831 assert_eq!(
3832 cmds[1],
3833 DspCmd::Monitor(MonitorCmd::Reserved(
3834 vec![0x00, 0x0a, 0x00, 0x00],
3835 vec![0x00]
3836 ))
3837 );
3838 assert_eq!(
3839 cmds[2],
3840 DspCmd::Monitor(MonitorCmd::Reserved(
3841 vec![0x00, 0x0b, 0x00, 0x00],
3842 vec![0x00]
3843 ))
3844 );
3845 assert_eq!(
3846 cmds[3],
3847 DspCmd::Reserved(vec![0x66, 0x00, 0x07, 0x00, 0xff, 0x00, 0x00, 0x00, 0x01])
3848 );
3849 assert_eq!(cmds[4], DspCmd::Monitor(MonitorCmd::Volume(1.0)));
3850 assert_eq!(
3851 cmds[5],
3852 DspCmd::Output(OutputCmd::MasterListenback(0, false))
3853 );
3854 assert_eq!(
3855 cmds[6],
3856 DspCmd::Output(OutputCmd::MasterListenback(1, false))
3857 );
3858 assert_eq!(
3859 cmds[7],
3860 DspCmd::Output(OutputCmd::MasterListenback(2, false))
3861 );
3862 assert_eq!(
3863 cmds[8],
3864 DspCmd::Output(OutputCmd::MasterListenback(3, false))
3865 );
3866 assert_eq!(
3867 cmds[9],
3868 DspCmd::Output(OutputCmd::MasterListenback(4, false))
3869 );
3870 assert_eq!(
3871 cmds[10],
3872 DspCmd::Output(OutputCmd::MasterListenback(5, false))
3873 );
3874 assert_eq!(
3875 cmds[11],
3876 DspCmd::Output(OutputCmd::MasterListenback(6, false))
3877 );
3878 assert_eq!(cmds[12], DspCmd::Input(InputCmd::Width(0, 0.0)));
3879 assert_eq!(cmds[13], DspCmd::Input(InputCmd::Width(1, 0.0)));
3880 assert_eq!(cmds.len(), 14);
3881 }
3882}