1use {super::*, hitaki::SndMotuRegisterDspParameter};
16
17const EV_TYPE_MIXER_SRC_GAIN: u8 = 0x02;
18const EV_TYPE_MIXER_SRC_PAN: u8 = 0x03;
19const EV_TYPE_MIXER_SRC_FLAG: u8 = 0x04;
20const EV_TYPE_MIXER_OUTPUT_PAIRED_VOLUME: u8 = 0x05;
21const EV_TYPE_MIXER_OUTPUT_PAIRED_FLAG: u8 = 0x06;
22const EV_TYPE_MAIN_OUTPUT_PAIRED_VOLUME: u8 = 0x07;
23const EV_TYPE_HP_OUTPUT_PAIRED_VOLUME: u8 = 0x08;
24const EV_TYPE_HP_OUTPUT_PAIRED_SOURCE: u8 = 0x09;
25const EV_TYPE_LINE_INPUT_BOOST: u8 = 0x0d;
26const EV_TYPE_LINE_INPUT_NOMINAL_LEVEL: u8 = 0x0e;
27const EV_TYPE_INPUT_GAIN_AND_INVERT: u8 = 0x15;
28const EV_TYPE_INPUT_FLAG: u8 = 0x16;
29const EV_TYPE_MIXER_SRC_PAIRED_BALANCE: u8 = 0x17;
30const EV_TYPE_MIXER_SRC_PAIRED_WIDTH: u8 = 0x18;
31
32#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
34pub struct RegisterDspEvent {
35 pub ev_type: u8,
37 pub identifier0: u8,
39 pub identifier1: u8,
41 pub value: u8,
43}
44
45impl From<u32> for RegisterDspEvent {
46 fn from(val: u32) -> Self {
47 Self {
48 ev_type: ((val & 0xff000000) >> 24) as u8,
49 identifier0: ((val & 0x00ff0000) >> 16) as u8,
50 identifier1: ((val & 0x0000ff00) >> 8) as u8,
51 value: (val & 0x000000ff) as u8,
52 }
53 }
54}
55
56pub trait MotuRegisterDspSpecification {
58 const MIXER_OUTPUT_DESTINATIONS: &'static [TargetPort];
60
61 const MIXER_COUNT: usize = 4;
63
64 const MIXER_OUTPUT_VOLUME_MIN: u8 = 0x00;
66 const MIXER_OUTPUT_VOLUME_MAX: u8 = 0x80;
68 const MIXER_OUTPUT_VOLUME_STEP: u8 = 0x01;
70
71 const OUTPUT_VOLUME_MIN: u8 = 0x00;
73 const OUTPUT_VOLUME_MAX: u8 = 0x80;
75 const OUTPUT_VOLUME_STEP: u8 = 0x01;
77}
78
79pub trait MotuRegisterDspImageOperation<T, U> {
81 fn parse_image(params: &mut T, image: &U);
83}
84
85pub trait MotuRegisterDspEventOperation<T> {
87 fn parse_event(params: &mut T, event: &RegisterDspEvent) -> bool;
89}
90
91impl<O> MotuRegisterDspImageOperation<PhoneAssignParameters, SndMotuRegisterDspParameter> for O
92where
93 O: MotuRegisterDspSpecification + MotuPortAssignSpecification,
94{
95 fn parse_image(params: &mut PhoneAssignParameters, image: &SndMotuRegisterDspParameter) {
96 let val = image.headphone_output_paired_assignment();
97 let _ = Self::ASSIGN_PORT_TARGETS
98 .iter()
99 .zip(Self::ASSIGN_PORT_VALS)
100 .find(|(_, v)| val.eq(v))
101 .map(|(&p, _)| params.0 = p);
102 }
103}
104
105impl<O> MotuRegisterDspEventOperation<PhoneAssignParameters> for O
106where
107 O: MotuRegisterDspSpecification + MotuPortAssignSpecification,
108{
109 fn parse_event(params: &mut PhoneAssignParameters, event: &RegisterDspEvent) -> bool {
110 match event.ev_type {
111 EV_TYPE_HP_OUTPUT_PAIRED_SOURCE => {
112 let val = event.value;
113 let _ = Self::ASSIGN_PORT_TARGETS
114 .iter()
115 .zip(Self::ASSIGN_PORT_VALS)
116 .find(|(_, v)| val.eq(v))
117 .map(|(&p, _)| params.0 = p);
118 true
119 }
120 _ => false,
121 }
122 }
123}
124
125const MIXER_COUNT: usize = 4;
126
127const MIXER_OUTPUT_OFFSETS: [usize; MIXER_COUNT] = [0x0c20, 0x0c24, 0x0c28, 0x0c2c];
128const MIXER_OUTPUT_MUTE_FLAG: u32 = 0x00001000;
129const MIXER_OUTPUT_DESTINATION_MASK: u32 = 0x00000f00;
130const MIXER_OUTPUT_VOLUME_MASK: u32 = 0x000000ff;
131
132#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
134pub struct RegisterDspMixerReturnParameters(pub bool);
135
136impl<O> MotuWhollyCacheableParamsOperation<RegisterDspMixerReturnParameters> for O
137where
138 O: MotuRegisterDspSpecification,
139{
140 fn cache_wholly(
141 req: &mut FwReq,
142 node: &mut FwNode,
143 params: &mut RegisterDspMixerReturnParameters,
144 timeout_ms: u32,
145 ) -> Result<(), Error> {
146 read_quad(req, node, MIXER_RETURN_ENABLE_OFFSET as u32, timeout_ms)
147 .map(|val| params.0 = val > 0)
148 }
149}
150
151impl<O> MotuWhollyUpdatableParamsOperation<RegisterDspMixerReturnParameters> for O
152where
153 O: MotuRegisterDspSpecification,
154{
155 fn update_wholly(
156 req: &mut FwReq,
157 node: &mut FwNode,
158 params: &RegisterDspMixerReturnParameters,
159 timeout_ms: u32,
160 ) -> Result<(), Error> {
161 write_quad(
162 req,
163 node,
164 MIXER_RETURN_ENABLE_OFFSET as u32,
165 params.0 as u32,
166 timeout_ms,
167 )
168 }
169}
170
171#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
173pub struct RegisterDspMixerOutputState {
174 pub volume: [u8; MIXER_COUNT],
175 pub mute: [bool; MIXER_COUNT],
176 pub destination: [TargetPort; MIXER_COUNT],
177}
178
179impl<O> MotuWhollyCacheableParamsOperation<RegisterDspMixerOutputState> for O
180where
181 O: MotuRegisterDspSpecification,
182{
183 fn cache_wholly(
184 req: &mut FwReq,
185 node: &mut FwNode,
186 params: &mut RegisterDspMixerOutputState,
187 timeout_ms: u32,
188 ) -> Result<(), Error> {
189 MIXER_OUTPUT_OFFSETS
190 .iter()
191 .enumerate()
192 .try_for_each(|(i, &offset)| {
193 read_quad(req, node, offset as u32, timeout_ms).map(|val| {
194 params.volume[i] = (val & MIXER_OUTPUT_VOLUME_MASK) as u8;
195 params.mute[i] = (val & MIXER_OUTPUT_MUTE_FLAG) > 0;
196
197 let src = ((val & MIXER_OUTPUT_DESTINATION_MASK) >> 8) as usize;
198 params.destination[i] = Self::MIXER_OUTPUT_DESTINATIONS
199 .iter()
200 .nth(src)
201 .map(|&p| p)
202 .unwrap_or_default();
203 })
204 })
205 }
206}
207
208impl<O> MotuPartiallyUpdatableParamsOperation<RegisterDspMixerOutputState> for O
209where
210 O: MotuRegisterDspSpecification,
211{
212 fn update_partially(
213 req: &mut FwReq,
214 node: &mut FwNode,
215 params: &mut RegisterDspMixerOutputState,
216 updates: RegisterDspMixerOutputState,
217 timeout_ms: u32,
218 ) -> Result<(), Error> {
219 MIXER_OUTPUT_OFFSETS
220 .iter()
221 .enumerate()
222 .try_for_each(|(i, &offset)| {
223 if params.volume[i] != updates.volume[i]
224 || params.mute[i] != updates.mute[i]
225 || params.destination[i] != updates.destination[i]
226 {
227 let quad = read_quad(req, node, offset as u32, timeout_ms)?;
228 let mut change = quad;
229 if params.volume[i] != updates.volume[i] {
230 change &= !MIXER_OUTPUT_VOLUME_MASK;
231 change |= updates.volume[i] as u32;
232 }
233 if params.mute[i] != updates.mute[i] {
234 change &= !MIXER_OUTPUT_MUTE_FLAG;
235 if updates.mute[i] {
236 change |= MIXER_OUTPUT_MUTE_FLAG;
237 }
238 }
239 if params.destination[i] != updates.destination[i] {
240 let pos = Self::MIXER_OUTPUT_DESTINATIONS
241 .iter()
242 .position(|d| updates.destination[i].eq(d))
243 .unwrap_or_default();
244 change &= !MIXER_OUTPUT_DESTINATION_MASK;
245 change |= (pos as u32) << 8;
246 }
247 if quad != change {
248 write_quad(req, node, offset as u32, change, timeout_ms)
249 } else {
250 Ok(())
251 }
252 } else {
253 Ok(())
254 }
255 })
256 }
257}
258
259impl<O> MotuRegisterDspImageOperation<RegisterDspMixerOutputState, SndMotuRegisterDspParameter>
260 for O
261where
262 O: MotuRegisterDspSpecification,
263{
264 fn parse_image(params: &mut RegisterDspMixerOutputState, image: &SndMotuRegisterDspParameter) {
265 let vols = image.mixer_output_paired_volume();
266 params.volume.copy_from_slice(vols);
267
268 let flags = image.mixer_output_paired_flag();
269 params.mute.iter_mut().zip(flags).for_each(|(mute, &flag)| {
270 let val = (flag as u32) << 8;
271 *mute = val & MIXER_OUTPUT_MUTE_FLAG > 0;
272 });
273 params
274 .destination
275 .iter_mut()
276 .zip(flags)
277 .for_each(|(dest, &flag)| {
278 let val = (flag as u32) << 8;
279 let idx = ((val & MIXER_OUTPUT_DESTINATION_MASK) >> 8) as usize;
280 *dest = Self::MIXER_OUTPUT_DESTINATIONS
281 .iter()
282 .nth(idx)
283 .map(|&port| port)
284 .unwrap_or_default();
285 });
286 }
287}
288
289impl<O> MotuRegisterDspEventOperation<RegisterDspMixerOutputState> for O
290where
291 O: MotuRegisterDspSpecification,
292{
293 fn parse_event(params: &mut RegisterDspMixerOutputState, event: &RegisterDspEvent) -> bool {
294 match event.ev_type {
295 EV_TYPE_MIXER_OUTPUT_PAIRED_VOLUME => {
296 let mixer = event.identifier0 as usize;
297 if mixer < MIXER_COUNT {
298 params.volume[mixer] = event.value;
299 true
300 } else {
301 false
302 }
303 }
304 EV_TYPE_MIXER_OUTPUT_PAIRED_FLAG => {
305 let mixer = event.identifier0 as usize;
306 if mixer < MIXER_COUNT {
307 let val = (event.value as u32) << 8;
308
309 params.mute[mixer] = val & MIXER_OUTPUT_MUTE_FLAG > 0;
310
311 let assign = ((val & MIXER_OUTPUT_DESTINATION_MASK) >> 8) as usize;
312 params.destination[mixer] = Self::MIXER_OUTPUT_DESTINATIONS
313 .iter()
314 .nth(assign)
315 .map(|&port| port)
316 .unwrap_or_default();
317
318 true
319 } else {
320 false
321 }
322 }
323 _ => false,
324 }
325 }
326}
327
328const MIXER_RETURN_ENABLE_OFFSET: usize = 0x0c18;
329
330#[derive(Debug, Clone, PartialEq, Eq)]
332pub struct RegisterDspMixerMonauralSourceEntry {
333 pub gain: Vec<u8>,
335 pub pan: Vec<u8>,
337 pub mute: Vec<bool>,
339 pub solo: Vec<bool>,
341}
342
343#[derive(Debug, Clone, PartialEq, Eq)]
345pub struct RegisterDspMixerMonauralSourceState(
346 pub [RegisterDspMixerMonauralSourceEntry; MIXER_COUNT],
347);
348
349const MIXER_SOURCE_OFFSETS: [usize; MIXER_COUNT] = [0x4000, 0x4100, 0x4200, 0x4300];
350const MIXER_SOURCE_PAN_CHANGE_FLAG: u32 = 0x80000000;
351const MIXER_SOURCE_GAIN_CHANGE_FLAG: u32 = 0x40000000;
352const MIXER_SOURCE_MUTE_FLAG: u32 = 0x00010000;
353const MIXER_SOURCE_SOLO_FLAG: u32 = 0x00020000;
354const MIXER_SOURCE_PAN_MASK: u32 = 0x0000ff00;
355const MIXER_SOURCE_GAIN_MASK: u32 = 0x000000ff;
356
357pub trait MotuRegisterDspMixerMonauralSourceSpecification: MotuRegisterDspSpecification {
359 const MIXER_SOURCES: &'static [TargetPort];
361
362 const SOURCE_GAIN_MIN: u8 = 0x00;
364 const SOURCE_GAIN_MAX: u8 = 0x80;
366 const SOURCE_GAIN_STEP: u8 = 0x01;
368
369 const SOURCE_PAN_MIN: u8 = 0x00;
371 const SOURCE_PAN_MAX: u8 = 0x80;
373 const SOURCE_PAN_STEP: u8 = 0x01;
375
376 fn create_mixer_monaural_source_state() -> RegisterDspMixerMonauralSourceState {
377 let entry = RegisterDspMixerMonauralSourceEntry {
378 gain: vec![Default::default(); Self::MIXER_SOURCES.len()],
379 pan: vec![Default::default(); Self::MIXER_SOURCES.len()],
380 mute: vec![Default::default(); Self::MIXER_SOURCES.len()],
381 solo: vec![Default::default(); Self::MIXER_SOURCES.len()],
382 };
383 RegisterDspMixerMonauralSourceState([
384 entry.clone(),
385 entry.clone(),
386 entry.clone(),
387 entry.clone(),
388 ])
389 }
390}
391
392impl<O> MotuWhollyCacheableParamsOperation<RegisterDspMixerMonauralSourceState> for O
393where
394 O: MotuRegisterDspMixerMonauralSourceSpecification,
395{
396 fn cache_wholly(
397 req: &mut FwReq,
398 node: &mut FwNode,
399 params: &mut RegisterDspMixerMonauralSourceState,
400 timeout_ms: u32,
401 ) -> Result<(), Error> {
402 params
403 .0
404 .iter_mut()
405 .zip(MIXER_SOURCE_OFFSETS)
406 .try_for_each(|(entry, offset)| {
407 (0..Self::MIXER_SOURCES.len()).try_for_each(|i| {
408 read_quad(req, node, (offset + i * 4) as u32, timeout_ms).map(|quad| {
409 entry.gain[i] = (quad & MIXER_SOURCE_GAIN_MASK) as u8;
410 entry.pan[i] = ((quad & MIXER_SOURCE_PAN_MASK) >> 8) as u8;
411 entry.mute[i] = quad & MIXER_SOURCE_MUTE_FLAG > 0;
412 entry.solo[i] = quad & MIXER_SOURCE_SOLO_FLAG > 0;
413 })
414 })
415 })
416 }
417}
418
419impl<O> MotuPartiallyUpdatableParamsOperation<RegisterDspMixerMonauralSourceState> for O
420where
421 O: MotuRegisterDspMixerMonauralSourceSpecification,
422{
423 fn update_partially(
424 req: &mut FwReq,
425 node: &mut FwNode,
426 params: &mut RegisterDspMixerMonauralSourceState,
427 updates: RegisterDspMixerMonauralSourceState,
428 timeout_ms: u32,
429 ) -> Result<(), Error> {
430 params
431 .0
432 .iter_mut()
433 .zip(&updates.0)
434 .zip(MIXER_SOURCE_OFFSETS)
435 .try_for_each(|((current, update), mixer_offset)| {
436 (0..Self::MIXER_SOURCES.len()).try_for_each(|i| {
437 if current.gain[i] != update.gain[i]
438 || current.pan[i] != update.pan[i]
439 || current.mute[i] != update.mute[i]
440 || current.solo[i] != update.solo[i]
441 {
442 let offset = (mixer_offset + i * 4) as u32;
443 let mut quad = read_quad(req, node, offset, timeout_ms)?;
444 if current.gain[i] != update.gain[i] {
445 quad &= !MIXER_SOURCE_GAIN_MASK;
446 quad |= update.gain[i] as u32;
447 quad |= MIXER_SOURCE_GAIN_CHANGE_FLAG;
448 }
449 if current.pan[i] != update.pan[i] {
450 quad &= !MIXER_SOURCE_PAN_MASK;
451 quad |= (update.pan[i] as u32) << 8;
452 quad |= MIXER_SOURCE_PAN_CHANGE_FLAG;
453 }
454 if current.mute[i] != update.mute[i] {
455 quad &= !MIXER_SOURCE_MUTE_FLAG;
456 if update.mute[i] {
457 quad |= MIXER_SOURCE_MUTE_FLAG;
458 }
459 }
460 if current.solo[i] != update.solo[i] {
461 quad &= !MIXER_SOURCE_SOLO_FLAG;
462 if update.solo[i] {
463 quad |= MIXER_SOURCE_SOLO_FLAG;
464 }
465 }
466 write_quad(req, node, offset, quad, timeout_ms).map(|_| {
467 current.gain[i] = update.gain[i];
468 current.pan[i] = update.pan[i];
469 current.mute[i] = update.mute[i];
470 current.solo[i] = update.solo[i];
471 })
472 } else {
473 Ok(())
474 }
475 })
476 })
477 }
478}
479
480impl<O>
481 MotuRegisterDspImageOperation<RegisterDspMixerMonauralSourceState, SndMotuRegisterDspParameter>
482 for O
483where
484 O: MotuRegisterDspMixerMonauralSourceSpecification,
485{
486 fn parse_image(
487 params: &mut RegisterDspMixerMonauralSourceState,
488 image: &SndMotuRegisterDspParameter,
489 ) {
490 params.0.iter_mut().enumerate().for_each(|(i, src)| {
491 let gains = image.mixer_source_gain(i);
492 src.gain
493 .iter_mut()
494 .zip(gains)
495 .for_each(|(dst, src)| *dst = *src);
496
497 let pans = image.mixer_source_pan(i);
498 src.pan
499 .iter_mut()
500 .zip(pans)
501 .for_each(|(dst, src)| *dst = *src);
502
503 let flags: Vec<u32> = image
504 .mixer_source_flag(i)
505 .iter()
506 .map(|&flag| (flag as u32) << 16)
507 .collect();
508
509 src.mute
510 .iter_mut()
511 .zip(&flags)
512 .for_each(|(mute, flag)| *mute = flag & MIXER_SOURCE_MUTE_FLAG > 0);
513 src.solo
514 .iter_mut()
515 .zip(&flags)
516 .for_each(|(solo, flag)| *solo = flag & MIXER_SOURCE_SOLO_FLAG > 0);
517 });
518 }
519}
520
521impl<O> MotuRegisterDspEventOperation<RegisterDspMixerMonauralSourceState> for O
522where
523 O: MotuRegisterDspMixerMonauralSourceSpecification,
524{
525 fn parse_event(
526 params: &mut RegisterDspMixerMonauralSourceState,
527 event: &RegisterDspEvent,
528 ) -> bool {
529 match event.ev_type {
530 EV_TYPE_MIXER_SRC_GAIN => {
531 let mixer = event.identifier0 as usize;
532 let src = event.identifier1 as usize;
533 let val = event.value;
534
535 if mixer < MIXER_COUNT && src < Self::MIXER_SOURCES.len() {
536 params.0[mixer].gain[src] = val;
537 true
538 } else {
539 false
540 }
541 }
542 EV_TYPE_MIXER_SRC_PAN => {
543 let mixer = event.identifier0 as usize;
544 let src = event.identifier1 as usize;
545 let val = event.value;
546
547 if mixer < MIXER_COUNT && src < Self::MIXER_SOURCES.len() {
548 params.0[mixer].pan[src] = val;
549 true
550 } else {
551 false
552 }
553 }
554 EV_TYPE_MIXER_SRC_FLAG => {
555 let mixer = event.identifier0 as usize;
556 let src = event.identifier1 as usize;
557 let val = (event.value as u32) << 16;
558
559 if mixer < MIXER_COUNT && src < Self::MIXER_SOURCES.len() {
560 params.0[mixer].mute[src] = val & MIXER_SOURCE_MUTE_FLAG > 0;
561 params.0[mixer].solo[src] = val & MIXER_SOURCE_SOLO_FLAG > 0;
562 true
563 } else {
564 false
565 }
566 }
567 _ => false,
568 }
569 }
570}
571
572const MIXER_STEREO_SOURCE_COUNT: usize = 6;
573const MIXER_STEREO_SOURCE_PAIR_COUNT: usize = MIXER_STEREO_SOURCE_COUNT / 2;
574
575#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
577pub struct RegisterDspMixerStereoSourceEntry {
578 pub gain: [u8; MIXER_STEREO_SOURCE_COUNT],
580 pub pan: [u8; MIXER_STEREO_SOURCE_COUNT],
582 pub mute: [bool; MIXER_STEREO_SOURCE_COUNT],
584 pub solo: [bool; MIXER_STEREO_SOURCE_COUNT],
586 pub balance: [u8; MIXER_STEREO_SOURCE_PAIR_COUNT],
588 pub width: [u8; MIXER_STEREO_SOURCE_PAIR_COUNT],
590}
591
592#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
594pub struct RegisterDspMixerStereoSourceState(pub [RegisterDspMixerStereoSourceEntry; MIXER_COUNT]);
595
596const MIXER_SOURCE_PAIRED_WIDTH_FLAG: u32 = 0x00400000;
597const MIXER_SOURCE_PAIRED_BALANCE_FLAG: u32 = 0x00800000;
598
599const EV_MIXER_SOURCE_PAIRED_CH_MAP: [usize; MIXER_STEREO_SOURCE_COUNT] = [0, 1, 2, 3, 8, 9];
600
601pub trait MotuRegisterDspMixerStereoSourceSpecification: MotuRegisterDspSpecification {
603 const MIXER_SOURCES: [TargetPort; MIXER_STEREO_SOURCE_COUNT] = [
605 TargetPort::Analog(0),
606 TargetPort::Analog(1),
607 TargetPort::Analog(2),
608 TargetPort::Analog(3),
609 TargetPort::Spdif(0),
610 TargetPort::Spdif(1),
611 ];
612
613 const MIXER_SOURCE_PAIR_COUNT: usize = Self::MIXER_SOURCES.len() / 2;
615
616 const SOURCE_GAIN_MIN: u8 = 0x00;
618 const SOURCE_GAIN_MAX: u8 = 0x80;
620 const SOURCE_GAIN_STEP: u8 = 0x01;
622
623 const SOURCE_PAN_MIN: u8 = 0x00;
625 const SOURCE_PAN_MAX: u8 = 0x80;
627 const SOURCE_PAN_STEP: u8 = 0x01;
629
630 const SOURCE_STEREO_BALANCE_MIN: u8 = 0x00;
632 const SOURCE_STEREO_BALANCE_MAX: u8 = 0x80;
634 const SOURCE_STEREO_BALANCE_STEP: u8 = 0x01;
636
637 const SOURCE_STEREO_WIDTH_MIN: u8 = 0x00;
639 const SOURCE_STEREO_WIDTH_MAX: u8 = 0x80;
641 const SOURCE_STEREO_WIDTH_STEP: u8 = 0x01;
643}
644
645fn compute_mixer_stereo_source_offset(base_offset: usize, src_idx: usize) -> usize {
646 base_offset + 4 * if src_idx < 4 { src_idx } else { src_idx + 4 }
647}
648
649impl<O> MotuWhollyCacheableParamsOperation<RegisterDspMixerStereoSourceState> for O
652where
653 O: MotuRegisterDspMixerStereoSourceSpecification,
654{
655 fn cache_wholly(
656 req: &mut FwReq,
657 node: &mut FwNode,
658 params: &mut RegisterDspMixerStereoSourceState,
659 timeout_ms: u32,
660 ) -> Result<(), Error> {
661 params.0.iter_mut().enumerate().try_for_each(|(i, entry)| {
662 let base_offset = MIXER_SOURCE_OFFSETS[i];
663 (0..Self::MIXER_SOURCES.len()).try_for_each(|j| {
664 let offset = compute_mixer_stereo_source_offset(base_offset, j) as u32;
665 read_quad(req, node, offset, timeout_ms).map(|val| {
666 entry.gain[j] = (val & MIXER_SOURCE_GAIN_MASK) as u8;
667 entry.mute[j] = ((val & MIXER_SOURCE_MUTE_FLAG) >> 8) > 0;
668 entry.solo[j] = ((val & MIXER_SOURCE_SOLO_FLAG) >> 16) > 0;
669 })
670 })
671 })?;
672
673 Ok(())
674 }
675}
676
677impl<O> MotuPartiallyUpdatableParamsOperation<RegisterDspMixerStereoSourceState> for O
678where
679 O: MotuRegisterDspMixerStereoSourceSpecification,
680{
681 fn update_partially(
682 req: &mut FwReq,
683 node: &mut FwNode,
684 params: &mut RegisterDspMixerStereoSourceState,
685 updates: RegisterDspMixerStereoSourceState,
686 timeout_ms: u32,
687 ) -> Result<(), Error> {
688 params
689 .0
690 .iter_mut()
691 .zip(&updates.0)
692 .zip(MIXER_SOURCE_OFFSETS)
693 .try_for_each(|((current, update), base_offset)| {
694 (0..Self::MIXER_SOURCES.len()).try_for_each(|i| {
695 if current.gain[i] != update.gain[i]
696 || current.pan[i] != update.pan[i]
697 || current.mute[i] != update.mute[i]
698 || current.solo[i] != update.solo[i]
699 {
700 let offset = compute_mixer_stereo_source_offset(base_offset, i) as u32;
701 let mut quad = read_quad(req, node, offset, timeout_ms)?;
702
703 if current.gain[i] != update.gain[i] {
704 quad &= !MIXER_SOURCE_GAIN_MASK;
705 quad |= update.gain[i] as u32;
706 }
707
708 if current.pan[i] != update.pan[i] {
709 quad &= !MIXER_SOURCE_PAN_MASK;
710 quad |= (update.pan[i] as u32) << 8;
711 quad |= MIXER_SOURCE_PAN_CHANGE_FLAG;
712 }
713
714 if current.mute[i] != update.mute[i] {
715 quad &= !MIXER_SOURCE_MUTE_FLAG;
716 if update.mute[i] {
717 quad |= MIXER_SOURCE_MUTE_FLAG;
718 }
719 }
720
721 if current.solo[i] != update.solo[i] {
722 quad &= !MIXER_SOURCE_SOLO_FLAG;
723 if update.solo[i] {
724 quad |= MIXER_SOURCE_SOLO_FLAG;
725 }
726 }
727
728 write_quad(req, node, offset, quad, timeout_ms).map(|_| {
729 current.gain[i] = update.gain[i];
730 current.pan[i] = update.pan[i];
731 current.mute[i] = update.mute[i];
732 current.solo[i] = update.solo[i];
733 })
734 } else {
735 Ok(())
736 }
737 })?;
738
739 (0..Self::MIXER_SOURCE_PAIR_COUNT).try_for_each(|i| {
740 if current.balance[i] != update.balance[i]
741 || current.width[i] != update.width[i]
742 {
743 let offset = compute_mixer_stereo_source_offset(base_offset, i) as u32;
744 let mut quad = 0;
745
746 if current.balance[i] != update.balance[i] {
747 quad |= MIXER_SOURCE_PAN_CHANGE_FLAG;
748 quad |= MIXER_SOURCE_PAIRED_WIDTH_FLAG;
749 quad |= (update.balance[i] as u32) << 8;
750 }
751
752 if current.width[i] != update.width[i] {
753 quad |= MIXER_SOURCE_PAN_CHANGE_FLAG;
754 quad |= MIXER_SOURCE_PAIRED_BALANCE_FLAG;
755 quad |= (update.width[i] as u32) << 8;
756 }
757
758 write_quad(req, node, offset, quad, timeout_ms).map(|_| {
759 current.balance[i] = update.balance[i];
760 current.width[i] = update.width[i];
761 })
762 } else {
763 Ok(())
764 }
765 })
766 })
767 }
768}
769
770impl<O>
771 MotuRegisterDspImageOperation<RegisterDspMixerStereoSourceState, SndMotuRegisterDspParameter>
772 for O
773where
774 O: MotuRegisterDspMixerStereoSourceSpecification,
775{
776 fn parse_image(
777 params: &mut RegisterDspMixerStereoSourceState,
778 image: &SndMotuRegisterDspParameter,
779 ) {
780 params.0.iter_mut().enumerate().for_each(|(i, src)| {
781 let gains = image.mixer_source_gain(i);
782 src.gain
783 .iter_mut()
784 .zip(gains)
785 .for_each(|(dst, src)| *dst = *src);
786
787 let pans = image.mixer_source_pan(i);
788 src.pan
789 .iter_mut()
790 .zip(pans)
791 .for_each(|(dst, src)| *dst = *src);
792
793 let flags: Vec<u32> = image
794 .mixer_source_flag(i)
795 .iter()
796 .map(|&flag| (flag as u32) << 16)
797 .collect();
798
799 src.mute
800 .iter_mut()
801 .zip(&flags)
802 .for_each(|(mute, flag)| *mute = flag & MIXER_SOURCE_MUTE_FLAG > 0);
803 src.solo
804 .iter_mut()
805 .zip(&flags)
806 .for_each(|(solo, flag)| *solo = flag & MIXER_SOURCE_SOLO_FLAG > 0);
807 });
808 }
809}
810
811impl<O> MotuRegisterDspEventOperation<RegisterDspMixerStereoSourceState> for O
812where
813 O: MotuRegisterDspMixerStereoSourceSpecification,
814{
815 fn parse_event(
816 params: &mut RegisterDspMixerStereoSourceState,
817 event: &RegisterDspEvent,
818 ) -> bool {
819 match event.ev_type {
820 EV_TYPE_MIXER_SRC_GAIN => {
821 let mixer = event.identifier0 as usize;
822 let src = event.identifier1 as usize;
823 let val = event.value;
824
825 if mixer < MIXER_COUNT && src < Self::MIXER_SOURCES.len() {
826 params.0[mixer].gain[src] = val;
827 true
828 } else {
829 false
830 }
831 }
832 EV_TYPE_MIXER_SRC_PAN => {
833 let mixer = event.identifier0 as usize;
834 let src = event.identifier1 as usize;
835 let val = event.value;
836
837 if mixer < MIXER_COUNT && src < Self::MIXER_SOURCES.len() {
838 params.0[mixer].pan[src] = val;
839 true
840 } else {
841 false
842 }
843 }
844 EV_TYPE_MIXER_SRC_FLAG => {
845 let mixer = event.identifier0 as usize;
846 let src = event.identifier1 as usize;
847 let val = (event.value as u32) << 16;
848
849 if mixer < MIXER_COUNT && src < Self::MIXER_SOURCES.len() {
850 params.0[mixer].mute[src] = val & MIXER_SOURCE_MUTE_FLAG > 0;
851 params.0[mixer].solo[src] = val & MIXER_SOURCE_SOLO_FLAG > 0;
852 true
853 } else {
854 false
855 }
856 }
857 EV_TYPE_MIXER_SRC_PAIRED_BALANCE => {
858 let mixer = event.identifier0 as usize;
859 let src = event.identifier1 as usize;
860 let val = event.value;
861
862 if let Some(idx) = EV_MIXER_SOURCE_PAIRED_CH_MAP.iter().position(|&p| p == src) {
863 params.0[mixer].balance[idx / 2] = val;
864 true
865 } else {
866 false
867 }
868 }
869 EV_TYPE_MIXER_SRC_PAIRED_WIDTH => {
870 let mixer = event.identifier0 as usize;
871 let src = event.identifier1 as usize;
872 let val = event.value;
873
874 if let Some(idx) = EV_MIXER_SOURCE_PAIRED_CH_MAP.iter().position(|&p| p == src) {
875 params.0[mixer].width[idx / 2] = val;
876 true
877 } else {
878 false
879 }
880 }
881 _ => false,
882 }
883 }
884}
885
886const MASTER_VOLUME_OFFSET: usize = 0x0c0c;
887const PHONE_VOLUME_OFFSET: usize = 0x0c10;
888
889#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
891pub struct RegisterDspOutputState {
892 pub master_volume: u8,
894 pub phone_volume: u8,
896}
897
898impl<O> MotuWhollyCacheableParamsOperation<RegisterDspOutputState> for O
899where
900 O: MotuRegisterDspSpecification,
901{
902 fn cache_wholly(
903 req: &mut FwReq,
904 node: &mut FwNode,
905 params: &mut RegisterDspOutputState,
906 timeout_ms: u32,
907 ) -> Result<(), Error> {
908 read_quad(req, node, MASTER_VOLUME_OFFSET as u32, timeout_ms).map(|val| {
909 params.master_volume = val as u8;
910 })?;
911 read_quad(req, node, PHONE_VOLUME_OFFSET as u32, timeout_ms).map(|val| {
912 params.phone_volume = val as u8;
913 })?;
914 Ok(())
915 }
916}
917
918impl<O> MotuPartiallyUpdatableParamsOperation<RegisterDspOutputState> for O
919where
920 O: MotuRegisterDspSpecification,
921{
922 fn update_partially(
923 req: &mut FwReq,
924 node: &mut FwNode,
925 params: &mut RegisterDspOutputState,
926 updates: RegisterDspOutputState,
927 timeout_ms: u32,
928 ) -> Result<(), Error> {
929 if params.master_volume != updates.master_volume {
930 write_quad(
931 req,
932 node,
933 MASTER_VOLUME_OFFSET as u32,
934 updates.master_volume as u32,
935 timeout_ms,
936 )?;
937 params.master_volume = updates.master_volume;
938 }
939
940 if params.phone_volume != updates.phone_volume {
941 write_quad(
942 req,
943 node,
944 PHONE_VOLUME_OFFSET as u32,
945 updates.phone_volume as u32,
946 timeout_ms,
947 )?;
948 params.phone_volume = updates.phone_volume;
949 }
950
951 Ok(())
952 }
953}
954
955impl<O> MotuRegisterDspImageOperation<RegisterDspOutputState, SndMotuRegisterDspParameter> for O
956where
957 O: MotuRegisterDspSpecification,
958{
959 fn parse_image(params: &mut RegisterDspOutputState, image: &SndMotuRegisterDspParameter) {
960 params.master_volume = image.main_output_paired_volume();
961 params.phone_volume = image.headphone_output_paired_volume();
962 }
963}
964
965impl<O> MotuRegisterDspEventOperation<RegisterDspOutputState> for O
966where
967 O: MotuRegisterDspSpecification,
968{
969 fn parse_event(params: &mut RegisterDspOutputState, event: &RegisterDspEvent) -> bool {
970 match event.ev_type {
971 EV_TYPE_MAIN_OUTPUT_PAIRED_VOLUME => {
972 params.master_volume = event.value;
973 true
974 }
975 EV_TYPE_HP_OUTPUT_PAIRED_VOLUME => {
976 params.phone_volume = event.value;
977 true
978 }
979 _ => false,
980 }
981 }
982}
983
984#[derive(Default, Debug, Clone, PartialEq, Eq)]
986pub struct RegisterDspLineInputState {
987 pub level: Vec<NominalSignalLevel>,
989 pub boost: Vec<bool>,
991}
992
993const LINE_INPUT_LEVEL_OFFSET: usize = 0x0c08;
994const LINE_INPUT_BOOST_OFFSET: usize = 0x0c14;
995
996pub trait MotuRegisterDspLineInputSpecification: MotuRegisterDspSpecification {
998 const LINE_INPUT_COUNT: usize;
999 const CH_OFFSET: usize;
1000
1001 fn create_line_input_state() -> RegisterDspLineInputState {
1002 RegisterDspLineInputState {
1003 level: vec![Default::default(); Self::LINE_INPUT_COUNT],
1004 boost: vec![Default::default(); Self::LINE_INPUT_COUNT],
1005 }
1006 }
1007}
1008
1009impl<O> MotuWhollyCacheableParamsOperation<RegisterDspLineInputState> for O
1010where
1011 O: MotuRegisterDspLineInputSpecification,
1012{
1013 fn cache_wholly(
1014 req: &mut FwReq,
1015 node: &mut FwNode,
1016 params: &mut RegisterDspLineInputState,
1017 timeout_ms: u32,
1018 ) -> Result<(), Error> {
1019 read_quad(req, node, LINE_INPUT_LEVEL_OFFSET as u32, timeout_ms).map(|val| {
1020 params
1021 .level
1022 .iter_mut()
1023 .enumerate()
1024 .for_each(|(mut i, level)| {
1025 i += Self::CH_OFFSET;
1026 *level = if val & (1 << i) > 0 {
1027 NominalSignalLevel::Professional
1028 } else {
1029 NominalSignalLevel::Consumer
1030 };
1031 });
1032 })?;
1033
1034 read_quad(req, node, LINE_INPUT_BOOST_OFFSET as u32, timeout_ms).map(|val| {
1035 params
1036 .boost
1037 .iter_mut()
1038 .enumerate()
1039 .for_each(|(mut i, boost)| {
1040 i += Self::CH_OFFSET;
1041 *boost = val & (1 << i) > 0
1042 });
1043 })?;
1044
1045 Ok(())
1046 }
1047}
1048
1049impl<O> MotuPartiallyUpdatableParamsOperation<RegisterDspLineInputState> for O
1050where
1051 O: MotuRegisterDspLineInputSpecification,
1052{
1053 fn update_partially(
1054 req: &mut FwReq,
1055 node: &mut FwNode,
1056 params: &mut RegisterDspLineInputState,
1057 updates: RegisterDspLineInputState,
1058 timeout_ms: u32,
1059 ) -> Result<(), Error> {
1060 if params.level != updates.level {
1061 let quad = updates
1062 .level
1063 .iter()
1064 .enumerate()
1065 .fold(0u32, |mut quad, (i, l)| {
1066 if NominalSignalLevel::Professional.eq(l) {
1067 quad |= 1 << (i + Self::CH_OFFSET);
1068 }
1069 quad
1070 });
1071 write_quad(req, node, LINE_INPUT_LEVEL_OFFSET as u32, quad, timeout_ms)?;
1072 params.level.copy_from_slice(&updates.level);
1073 }
1074
1075 if params.boost != updates.boost {
1076 let quad = updates
1077 .boost
1078 .iter()
1079 .enumerate()
1080 .fold(0u32, |mut quad, (mut i, b)| {
1081 i += Self::CH_OFFSET;
1082 if *b {
1083 quad |= 1 << i;
1084 }
1085 quad
1086 });
1087
1088 write_quad(req, node, LINE_INPUT_BOOST_OFFSET as u32, quad, timeout_ms)?;
1089 params.boost.copy_from_slice(&updates.boost);
1090 }
1091
1092 Ok(())
1093 }
1094}
1095
1096impl<O> MotuRegisterDspImageOperation<RegisterDspLineInputState, SndMotuRegisterDspParameter> for O
1097where
1098 O: MotuRegisterDspLineInputSpecification,
1099{
1100 fn parse_image(params: &mut RegisterDspLineInputState, image: &SndMotuRegisterDspParameter) {
1101 let flags = image.line_input_nominal_level_flag();
1102 params.level.iter_mut().enumerate().for_each(|(i, level)| {
1103 let shift = i + Self::CH_OFFSET;
1104 *level = if flags & (1 << shift) > 0 {
1105 NominalSignalLevel::Professional
1106 } else {
1107 NominalSignalLevel::Consumer
1108 };
1109 });
1110
1111 let flags = image.line_input_boost_flag();
1112 params.boost.iter_mut().enumerate().for_each(|(i, boost)| {
1113 let shift = i + Self::CH_OFFSET;
1114 *boost = flags & (1 << shift) > 0;
1115 });
1116 }
1117}
1118
1119impl<O> MotuRegisterDspEventOperation<RegisterDspLineInputState> for O
1120where
1121 O: MotuRegisterDspLineInputSpecification,
1122{
1123 fn parse_event(params: &mut RegisterDspLineInputState, event: &RegisterDspEvent) -> bool {
1124 match event.ev_type {
1125 EV_TYPE_LINE_INPUT_NOMINAL_LEVEL => {
1126 params.level.iter_mut().enumerate().for_each(|(i, level)| {
1127 let shift = i + Self::CH_OFFSET;
1128 *level = if event.value & (1 << shift) > 0 {
1129 NominalSignalLevel::Professional
1130 } else {
1131 NominalSignalLevel::Consumer
1132 };
1133 });
1134 true
1135 }
1136 EV_TYPE_LINE_INPUT_BOOST => {
1137 params.boost.iter_mut().enumerate().for_each(|(i, boost)| {
1138 let shift = i + Self::CH_OFFSET;
1139 *boost = event.value & (1 << shift) > 0;
1140 });
1141 true
1142 }
1143 _ => false,
1144 }
1145 }
1146}
1147
1148const MONAURAL_INPUT_COUNT: usize = 10;
1149
1150#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
1152pub struct RegisterDspMonauralInputState {
1153 pub gain: [u8; MONAURAL_INPUT_COUNT],
1155 pub invert: [bool; MONAURAL_INPUT_COUNT],
1157}
1158
1159const STEREO_INPUT_COUNT: usize = 6;
1160
1161#[derive(Default, Debug, Clone, PartialEq, Eq)]
1163pub struct RegisterDspStereoInputState {
1164 pub gain: [u8; STEREO_INPUT_COUNT],
1166 pub invert: [bool; STEREO_INPUT_COUNT],
1168 pub paired: [bool; STEREO_INPUT_COUNT / 2],
1170 pub phantom: Vec<bool>,
1172 pub pad: Vec<bool>,
1174 pub jack: Vec<bool>,
1176}
1177
1178const INPUT_GAIN_INVERT_OFFSET: usize = 0x0c70;
1179const MONAURAL_INPUT_GAIN_MASK: u8 = 0x1f;
1180const MONAURAL_INPUT_INVERT_FLAG: u8 = 0x20;
1181const STEREO_INPUT_GAIN_MASK: u8 = 0x3f;
1182const STEREO_INPUT_INVERT_FLAG: u8 = 0x40;
1183const INPUT_CHANGE_FLAG: u8 = 0x80;
1184const MIC_PARAM_OFFSET: usize = 0x0c80;
1185const MIC_PARAM_PAD_FLAG: u8 = 0x02;
1186const MIC_PARAM_PHANTOM_FLAG: u8 = 0x01;
1187const MIC_PARAM_CHANGE_FLAG: u8 = 0x80;
1188const INPUT_PAIRED_OFFSET: usize = 0x0c84;
1189const INPUT_PAIRED_FLAG: u8 = 0x01;
1190const INPUT_PAIRED_CHANGE_FLAG: u8 = 0x80;
1191const INPUT_PAIRED_CH_MAP: [usize; STEREO_INPUT_COUNT / 2] = [0, 1, 3];
1192
1193const EV_INPUT_PAIRED_FLAG: u8 = 0x01;
1194const EV_MIC_PHANTOM_FLAG: u8 = 0x02;
1195const EV_MIC_PAD_FLAG: u8 = 0x04;
1196const EV_INPUT_JACK_FLAG: u8 = 0x08;
1197const EV_INPUT_PAIRED_CH_MAP: [usize; STEREO_INPUT_COUNT] = [0, 1, 2, 3, 8, 9];
1198
1199pub trait MotuRegisterDspMonauralInputSpecification {
1201 const INPUT_COUNT: usize = MONAURAL_INPUT_COUNT;
1203
1204 const INPUT_GAIN_MIN: u8 = 0x00;
1206 const INPUT_MIC_GAIN_MAX: u8 = 0x18;
1208 const INPUT_LINE_GAIN_MAX: u8 = 0x12;
1210 const INPUT_SPDIF_GAIN_MAX: u8 = 0x0c;
1212 const INPUT_GAIN_STEP: u8 = 0x01;
1214}
1215
1216impl<O> MotuWhollyCacheableParamsOperation<RegisterDspMonauralInputState> for O
1217where
1218 O: MotuRegisterDspMonauralInputSpecification,
1219{
1220 fn cache_wholly(
1221 req: &mut FwReq,
1222 node: &mut FwNode,
1223 params: &mut RegisterDspMonauralInputState,
1224 timeout_ms: u32,
1225 ) -> Result<(), Error> {
1226 let mut quads = [0; (MONAURAL_INPUT_COUNT + 3) / 4];
1227 quads.iter_mut().enumerate().try_for_each(|(i, quad)| {
1228 let offset = INPUT_GAIN_INVERT_OFFSET + i * 4;
1229 read_quad(req, node, offset as u32, timeout_ms).map(|val| *quad = val)
1230 })?;
1231
1232 (0..MONAURAL_INPUT_COUNT).for_each(|i| {
1233 let pos = i / 4;
1234 let shift = (i % 4) * 8;
1235 let val = ((quads[pos] >> shift) as u8) & 0xff;
1236
1237 params.gain[i] = val & MONAURAL_INPUT_GAIN_MASK;
1238 params.invert[i] = val & MONAURAL_INPUT_INVERT_FLAG > 0;
1239 });
1240
1241 Ok(())
1242 }
1243}
1244
1245impl<O> MotuPartiallyUpdatableParamsOperation<RegisterDspMonauralInputState> for O
1246where
1247 O: MotuRegisterDspMonauralInputSpecification,
1248{
1249 fn update_partially(
1250 req: &mut FwReq,
1251 node: &mut FwNode,
1252 params: &mut RegisterDspMonauralInputState,
1253 updates: RegisterDspMonauralInputState,
1254 timeout_ms: u32,
1255 ) -> Result<(), Error> {
1256 (0..MONAURAL_INPUT_COUNT).try_for_each(|i| {
1257 if params.gain[i] != updates.gain[i] || params.invert[i] != updates.invert[i] {
1258 let pos = i / 4;
1259 let shift = (i % 4) * 8;
1260 let mut byte = INPUT_CHANGE_FLAG;
1261 if params.gain[i] != updates.gain[i] {
1262 byte |= updates.gain[i];
1263 }
1264 if params.invert[i] != updates.invert[i] {
1265 if updates.invert[i] {
1266 byte |= MONAURAL_INPUT_INVERT_FLAG;
1267 }
1268 }
1269 let quad = (byte as u32) << shift;
1270 let offset = (INPUT_GAIN_INVERT_OFFSET + pos * 4) as u32;
1271 write_quad(req, node, offset, quad, timeout_ms).map(|_| {
1272 params.gain[i] = updates.gain[i];
1273 params.invert[i] = updates.invert[i];
1274 })
1275 } else {
1276 Ok(())
1277 }
1278 })
1279 }
1280}
1281
1282impl<O> MotuRegisterDspImageOperation<RegisterDspMonauralInputState, SndMotuRegisterDspParameter>
1283 for O
1284where
1285 O: MotuRegisterDspMonauralInputSpecification,
1286{
1287 fn parse_image(
1288 params: &mut RegisterDspMonauralInputState,
1289 image: &SndMotuRegisterDspParameter,
1290 ) {
1291 let vals = image.input_gain_and_invert();
1292 params
1293 .gain
1294 .iter_mut()
1295 .zip(vals)
1296 .for_each(|(gain, val)| *gain = val & MONAURAL_INPUT_GAIN_MASK);
1297 params
1298 .invert
1299 .iter_mut()
1300 .zip(vals)
1301 .for_each(|(invert, val)| *invert = val & MONAURAL_INPUT_INVERT_FLAG > 0);
1302 }
1303}
1304
1305impl<O> MotuRegisterDspEventOperation<RegisterDspMonauralInputState> for O
1306where
1307 O: MotuRegisterDspMonauralInputSpecification,
1308{
1309 fn parse_event(params: &mut RegisterDspMonauralInputState, event: &RegisterDspEvent) -> bool {
1310 match event.ev_type {
1311 EV_TYPE_INPUT_GAIN_AND_INVERT => {
1312 let ch = event.identifier0 as usize;
1313 if ch < MONAURAL_INPUT_COUNT {
1314 params.gain[ch] = event.value & MONAURAL_INPUT_GAIN_MASK;
1315 params.invert[ch] = event.value & MONAURAL_INPUT_INVERT_FLAG > 0;
1316 true
1317 } else {
1318 false
1319 }
1320 }
1321 _ => false,
1322 }
1323 }
1324}
1325
1326pub trait MotuRegisterDspStereoInputSpecification: MotuRegisterDspSpecification {
1328 const INPUT_COUNT: usize = STEREO_INPUT_COUNT;
1330
1331 const INPUT_PAIR_COUNT: usize = STEREO_INPUT_COUNT / 2;
1333
1334 const MIC_COUNT: usize;
1336
1337 const INPUT_GAIN_MIN: u8 = 0x00;
1339 const INPUT_MIC_GAIN_MAX: u8 = 0x3c;
1341 const INPUT_LINE_GAIN_MAX: u8 = 0x16;
1343 const INPUT_SPDIF_GAIN_MAX: u8 = 0x0c;
1345 const INPUT_GAIN_STEP: u8 = 0x01;
1347
1348 fn create_stereo_input_state() -> RegisterDspStereoInputState {
1349 RegisterDspStereoInputState {
1350 gain: Default::default(),
1351 invert: Default::default(),
1352 paired: Default::default(),
1353 phantom: vec![Default::default(); Self::MIC_COUNT],
1354 pad: vec![Default::default(); Self::MIC_COUNT],
1355 jack: vec![Default::default(); Self::MIC_COUNT],
1356 }
1357 }
1358}
1359
1360impl<O> MotuWhollyCacheableParamsOperation<RegisterDspStereoInputState> for O
1361where
1362 O: MotuRegisterDspStereoInputSpecification,
1363{
1364 fn cache_wholly(
1365 req: &mut FwReq,
1366 node: &mut FwNode,
1367 params: &mut RegisterDspStereoInputState,
1368 timeout_ms: u32,
1369 ) -> Result<(), Error> {
1370 (0..Self::INPUT_COUNT).step_by(4).try_for_each(|i| {
1371 let offset = (INPUT_GAIN_INVERT_OFFSET + i) as u32;
1372 read_quad(req, node, offset, timeout_ms).map(|quad| {
1373 params.gain[i..]
1374 .iter_mut()
1375 .take(4)
1376 .enumerate()
1377 .for_each(|(j, gain)| {
1378 let shift = j * 8;
1379 let val = ((quad >> shift) as u8) & 0xff;
1380 *gain = val & STEREO_INPUT_GAIN_MASK;
1381 });
1382 params.invert[i..]
1383 .iter_mut()
1384 .take(4)
1385 .enumerate()
1386 .for_each(|(j, invert)| {
1387 let shift = j * 8;
1388 let val = ((quad >> shift) as u8) & 0xff;
1389 *invert = val & STEREO_INPUT_INVERT_FLAG > 0;
1390 });
1391 })
1392 })?;
1393
1394 read_quad(req, node, MIC_PARAM_OFFSET as u32, timeout_ms).map(|quad| {
1395 (0..Self::MIC_COUNT).for_each(|i| {
1396 let val = (quad >> (i * 8)) as u8;
1397 params.phantom[i] = val & MIC_PARAM_PHANTOM_FLAG > 0;
1398 params.pad[i] = val & MIC_PARAM_PAD_FLAG > 0;
1399 });
1400 })?;
1401
1402 read_quad(req, node, INPUT_PAIRED_OFFSET as u32, timeout_ms).map(|quad| {
1403 params
1405 .paired
1406 .iter_mut()
1407 .enumerate()
1408 .for_each(|(i, paired)| {
1409 *paired = ((quad >> (i * 8)) as u8) & INPUT_PAIRED_FLAG > 0
1410 });
1411 })?;
1412
1413 Ok(())
1414 }
1415}
1416
1417impl<O> MotuPartiallyUpdatableParamsOperation<RegisterDspStereoInputState> for O
1418where
1419 O: MotuRegisterDspStereoInputSpecification,
1420{
1421 fn update_partially(
1422 req: &mut FwReq,
1423 node: &mut FwNode,
1424 params: &mut RegisterDspStereoInputState,
1425 updates: RegisterDspStereoInputState,
1426 timeout_ms: u32,
1427 ) -> Result<(), Error> {
1428 (0..Self::INPUT_COUNT).try_for_each(|i| {
1429 if params.gain[i] != updates.gain[i] || params.invert[i] != updates.invert[i] {
1430 let pos = i / 4;
1431 let shift = (i % 4) * 8;
1432
1433 let mut byte = 0;
1434 if params.gain[i] != updates.gain[i] {
1435 byte |= updates.gain[i] | INPUT_CHANGE_FLAG;
1436 }
1437
1438 if params.invert[i] != updates.invert[i] {
1439 if updates.invert[i] {
1440 byte |= STEREO_INPUT_INVERT_FLAG;
1441 }
1442 }
1443
1444 let quad = (byte as u32) << shift;
1445 let offset = (INPUT_GAIN_INVERT_OFFSET + pos * 4) as u32;
1446 write_quad(req, node, offset, quad, timeout_ms)
1447 } else {
1448 Ok(())
1449 }
1450 })?;
1451
1452 if params.paired != updates.paired {
1453 let quad = params
1454 .paired
1455 .iter_mut()
1456 .zip(&updates.paired)
1457 .zip(INPUT_PAIRED_CH_MAP)
1458 .filter(|((o, n), _)| !o.eq(n))
1459 .fold(0, |quad, ((_, &paired), ch_map)| {
1460 let shift = ch_map * 8;
1462 let mut val = INPUT_PAIRED_CHANGE_FLAG;
1463 if paired {
1464 val |= INPUT_PAIRED_FLAG;
1465 }
1466 quad | ((val as u32) << shift)
1467 });
1468 write_quad(req, node, INPUT_PAIRED_OFFSET as u32, quad, timeout_ms)
1469 .map(|_| params.paired.copy_from_slice(&updates.paired))?;
1470 }
1471
1472 if params.phantom != updates.phantom || params.pad != updates.pad {
1473 let quad = (0..Self::MIC_COUNT).fold(0, |quad, i| {
1474 let shift = i * 8;
1475 let mut val = MIC_PARAM_CHANGE_FLAG;
1476
1477 if updates.phantom[i] {
1478 val |= MIC_PARAM_PHANTOM_FLAG;
1479 }
1480
1481 if updates.pad[i] {
1482 val |= MIC_PARAM_PAD_FLAG;
1483 }
1484
1485 quad | ((val as u32) << shift)
1486 });
1487
1488 write_quad(req, node, MIC_PARAM_OFFSET as u32, quad, timeout_ms).map(|_| {
1489 params.phantom.copy_from_slice(&updates.phantom);
1490 params.pad.copy_from_slice(&updates.pad);
1491 })?;
1492 }
1493
1494 Ok(())
1495 }
1496}
1497
1498impl<O> MotuRegisterDspImageOperation<RegisterDspStereoInputState, SndMotuRegisterDspParameter>
1499 for O
1500where
1501 O: MotuRegisterDspStereoInputSpecification,
1502{
1503 fn parse_image(params: &mut RegisterDspStereoInputState, image: &SndMotuRegisterDspParameter) {
1504 let vals = image.input_gain_and_invert();
1505 params
1506 .gain
1507 .iter_mut()
1508 .zip(vals)
1509 .for_each(|(gain, val)| *gain = val & STEREO_INPUT_GAIN_MASK);
1510 params
1511 .invert
1512 .iter_mut()
1513 .zip(vals)
1514 .for_each(|(invert, val)| *invert = val & STEREO_INPUT_INVERT_FLAG > 0);
1515
1516 let flags = image.input_flag();
1517 params
1518 .phantom
1519 .iter_mut()
1520 .zip(flags)
1521 .for_each(|(phantom, val)| *phantom = val & EV_MIC_PHANTOM_FLAG > 0);
1522 params
1523 .pad
1524 .iter_mut()
1525 .zip(flags)
1526 .for_each(|(pad, val)| *pad = val & EV_MIC_PAD_FLAG > 0);
1527 params
1528 .jack
1529 .iter_mut()
1530 .zip(flags)
1531 .for_each(|(jack, val)| *jack = val & EV_INPUT_JACK_FLAG > 0);
1532 params
1533 .paired
1534 .iter_mut()
1535 .enumerate()
1536 .for_each(|(i, paired)| {
1537 let pos = EV_INPUT_PAIRED_CH_MAP[i * 2];
1538 *paired = flags[pos] & EV_INPUT_PAIRED_FLAG > 0;
1539 });
1540 }
1541}
1542
1543impl<O> MotuRegisterDspEventOperation<RegisterDspStereoInputState> for O
1544where
1545 O: MotuRegisterDspStereoInputSpecification,
1546{
1547 fn parse_event(params: &mut RegisterDspStereoInputState, event: &RegisterDspEvent) -> bool {
1548 match event.ev_type {
1549 EV_TYPE_INPUT_GAIN_AND_INVERT => {
1550 let ch = event.identifier0 as usize;
1551 if ch < STEREO_INPUT_COUNT {
1552 params.gain[ch] = event.value & STEREO_INPUT_GAIN_MASK;
1553 params.invert[ch] = event.value & STEREO_INPUT_INVERT_FLAG > 0;
1554 true
1555 } else {
1556 false
1557 }
1558 }
1559 EV_TYPE_INPUT_FLAG => {
1560 let ch = event.identifier0 as usize;
1561 if let Some(pos) = EV_INPUT_PAIRED_CH_MAP.iter().position(|&p| p == ch) {
1562 if pos % 2 == 0 {
1563 params.paired[pos / 2] = event.value & EV_INPUT_PAIRED_FLAG > 0;
1564 }
1565 if pos < Self::MIC_COUNT {
1566 params.phantom[ch] = event.value & EV_MIC_PHANTOM_FLAG > 0;
1567 params.pad[ch] = event.value & EV_MIC_PAD_FLAG > 0;
1568 params.jack[ch] = event.value & EV_INPUT_JACK_FLAG > 0;
1569 }
1570 true
1571 } else {
1572 false
1573 }
1574 }
1575 _ => false,
1576 }
1577 }
1578}
1579
1580#[derive(Debug, Clone, PartialEq, Eq)]
1582pub struct RegisterDspMeterState {
1583 pub inputs: Vec<u8>,
1585 pub outputs: Vec<u8>,
1587}
1588
1589const METER_OUTPUT_SELECT_OFFSET: usize = 0x0b2c;
1591const METER_OUTPUT_SELECT_TARGET_MASK: u32 = 0x000000ff;
1592const METER_OUTPUT_SELECT_CHANGE_FLAG: u32 = 0x00000b00;
1593
1594const MAX_METER_INPUT_COUNT: usize = 24;
1596const MAX_METER_OUTPUT_COUNT: usize = 48;
1597
1598const METER_IMAGE_SIZE: usize = 48;
1599
1600pub trait MotuRegisterDspMeterSpecification: MotuRegisterDspSpecification {
1602 const INPUT_PORTS: &'static [TargetPort];
1604 const OUTPUT_PORT_PAIRS: &'static [TargetPort];
1606 const OUTPUT_PORT_PAIR_POS: &'static [[usize; 2]];
1607 const OUTPUT_PORT_COUNT: usize = Self::OUTPUT_PORT_PAIRS.len() * 2;
1609
1610 const LEVEL_MIN: u8 = 0;
1612 const LEVEL_MAX: u8 = 0x7f;
1614 const LEVEL_STEP: u8 = 1;
1616
1617 const METER_IMAGE_SIZE: usize = METER_IMAGE_SIZE;
1619
1620 fn create_meter_state() -> RegisterDspMeterState {
1621 assert!(Self::INPUT_PORTS.len() <= MAX_METER_INPUT_COUNT);
1623 assert!(Self::OUTPUT_PORT_PAIRS.len() <= MAX_METER_OUTPUT_COUNT);
1624 assert_eq!(
1625 Self::OUTPUT_PORT_PAIRS.len(),
1626 Self::OUTPUT_PORT_PAIR_POS.len()
1627 );
1628
1629 RegisterDspMeterState {
1630 inputs: vec![0; Self::INPUT_PORTS.len()],
1631 outputs: vec![0; Self::OUTPUT_PORT_COUNT],
1632 }
1633 }
1634}
1635
1636impl<O> MotuRegisterDspImageOperation<RegisterDspMeterState, [u8; METER_IMAGE_SIZE]> for O
1637where
1638 O: MotuRegisterDspMeterSpecification,
1639{
1640 fn parse_image(params: &mut RegisterDspMeterState, image: &[u8; METER_IMAGE_SIZE]) {
1641 params
1642 .inputs
1643 .copy_from_slice(&image[..Self::INPUT_PORTS.len()]);
1644
1645 Self::OUTPUT_PORT_PAIR_POS
1646 .iter()
1647 .flatten()
1648 .zip(&mut params.outputs)
1649 .for_each(|(pos, m)| *m = image[MAX_METER_INPUT_COUNT + pos]);
1650 }
1651}
1652
1653#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
1655pub struct RegisterDspMeterOutputTarget(pub usize);
1656
1657pub trait MotuRegisterDspMeterOutputTargetSpecification: MotuRegisterDspMeterSpecification {}
1659
1660impl<O> MotuWhollyUpdatableParamsOperation<RegisterDspMeterOutputTarget> for O
1661where
1662 O: MotuRegisterDspMeterOutputTargetSpecification,
1663{
1664 fn update_wholly(
1665 req: &mut FwReq,
1666 node: &mut FwNode,
1667 params: &RegisterDspMeterOutputTarget,
1668 timeout_ms: u32,
1669 ) -> Result<(), Error> {
1670 if params.0 >= Self::OUTPUT_PORT_PAIRS.len() {
1671 Err(Error::new(
1672 FileError::Inval,
1673 "Invalid argument for output metering target",
1674 ))?;
1675 }
1676
1677 let mut quad = ((params.0 + 1) as u32) & METER_OUTPUT_SELECT_TARGET_MASK;
1678 quad |= METER_OUTPUT_SELECT_CHANGE_FLAG;
1679 write_quad(
1680 req,
1681 node,
1682 METER_OUTPUT_SELECT_OFFSET as u32,
1683 quad,
1684 timeout_ms,
1685 )
1686 }
1687}