firewire_motu_protocols/
register_dsp.rs

1// SPDX-License-Identifier: LGPL-3.0-or-later
2// Copyright (c) 2021 Takashi Sakamoto
3
4//! Protocol for hardware mixer function expressed in registers.
5//!
6//! The module includes structure, enumeration, and trait for hardware mixer function expressed
7//! in registers.
8//!
9//! The hardware transfers isochronous packets in which its state, PCM frames, and MIDI messages
10//! are multiplexed. ALSA firewire-motu driver caches the state, and allow userspace application
11//! to read the cache from kernel space as `SndMotuRegisterDspParameter` structure. Additionally,
12//! when changing the cache, the driver generates notification to the application.
13//! `RegisterDspEvent` is available to parse the notification.
14
15use {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/// The event emitted from ALSA firewire-motu driver for register DSP.
33#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
34pub struct RegisterDspEvent {
35    /// The numeric type of event.
36    pub ev_type: u8,
37    /// The first identifier specific to the event.
38    pub identifier0: u8,
39    /// The second identifier specific to the event.
40    pub identifier1: u8,
41    /// The value of event.
42    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
56/// The specification for register DSP.
57pub trait MotuRegisterDspSpecification {
58    /// The destinations of mixer outputs.
59    const MIXER_OUTPUT_DESTINATIONS: &'static [TargetPort];
60
61    /// The number of mixers.
62    const MIXER_COUNT: usize = 4;
63
64    /// The minimum value of mixer output volume.
65    const MIXER_OUTPUT_VOLUME_MIN: u8 = 0x00;
66    /// The maximum value of mixer output volume.
67    const MIXER_OUTPUT_VOLUME_MAX: u8 = 0x80;
68    /// The step value of mixer output volume.
69    const MIXER_OUTPUT_VOLUME_STEP: u8 = 0x01;
70
71    /// The minimum value of physical output volume.
72    const OUTPUT_VOLUME_MIN: u8 = 0x00;
73    /// The maximum value of physical output volume.
74    const OUTPUT_VOLUME_MAX: u8 = 0x80;
75    /// The step value of physical output volume.
76    const OUTPUT_VOLUME_STEP: u8 = 0x01;
77}
78
79/// The trait for DSP image operations.
80pub trait MotuRegisterDspImageOperation<T, U> {
81    /// Parse image transferred in the series of isochronous packets.
82    fn parse_image(params: &mut T, image: &U);
83}
84
85/// The trait for DSP event operation.
86pub trait MotuRegisterDspEventOperation<T> {
87    /// Parse event.
88    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/// The parameters of mixer return.
133#[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/// State of mixer output.
172#[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/// State of sources in mixer entiry which can be operated as monaural channel.
331#[derive(Debug, Clone, PartialEq, Eq)]
332pub struct RegisterDspMixerMonauralSourceEntry {
333    /// The gain of source. The value is between 0x00 and 0x80.
334    pub gain: Vec<u8>,
335    /// The left and right balance of source to stereo mixer. The value is between 0x00 and 0x80.
336    pub pan: Vec<u8>,
337    /// Whether to mute the source.
338    pub mute: Vec<bool>,
339    /// Whether to mute the other sources.
340    pub solo: Vec<bool>,
341}
342
343/// State of mixer sources which can be operated as monaural channel.
344#[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
357/// The trait for specification of mixer sources which can be operated as monaural channel.
358pub trait MotuRegisterDspMixerMonauralSourceSpecification: MotuRegisterDspSpecification {
359    /// The port of mixer sources.
360    const MIXER_SOURCES: &'static [TargetPort];
361
362    /// The minimum value of gain for mixer source.
363    const SOURCE_GAIN_MIN: u8 = 0x00;
364    /// The maximum value of gain for mixer source.
365    const SOURCE_GAIN_MAX: u8 = 0x80;
366    /// The step value of gain for mixer source.
367    const SOURCE_GAIN_STEP: u8 = 0x01;
368
369    /// The minimum value of left and right balance for mixer source.
370    const SOURCE_PAN_MIN: u8 = 0x00;
371    /// The maximum value of left and right balance for mixer source.
372    const SOURCE_PAN_MAX: u8 = 0x80;
373    /// The step value of left and right balance for mixer source.
374    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/// State of sources in mixer entiry.
576#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
577pub struct RegisterDspMixerStereoSourceEntry {
578    /// The gain of mixer sources.
579    pub gain: [u8; MIXER_STEREO_SOURCE_COUNT],
580    /// The left and right panning of mixer sources.
581    pub pan: [u8; MIXER_STEREO_SOURCE_COUNT],
582    /// Whether to mute mixer sources.
583    pub mute: [bool; MIXER_STEREO_SOURCE_COUNT],
584    /// Whether to mute the other mixer sources.
585    pub solo: [bool; MIXER_STEREO_SOURCE_COUNT],
586    /// The left and right balance of paired mixer sources.
587    pub balance: [u8; MIXER_STEREO_SOURCE_PAIR_COUNT],
588    /// The left and right width of paired mixer sources.
589    pub width: [u8; MIXER_STEREO_SOURCE_PAIR_COUNT],
590}
591
592/// State of mixer sources.
593#[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
601/// The trait for specification of mixer sources.
602pub trait MotuRegisterDspMixerStereoSourceSpecification: MotuRegisterDspSpecification {
603    /// The ports of mixer sources.
604    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    /// The number of paired mixer sources.
614    const MIXER_SOURCE_PAIR_COUNT: usize = Self::MIXER_SOURCES.len() / 2;
615
616    /// The minimum value of gain for mixer source.
617    const SOURCE_GAIN_MIN: u8 = 0x00;
618    /// The maximum value of gain for mixer source.
619    const SOURCE_GAIN_MAX: u8 = 0x80;
620    /// The step value of gain for mixer source.
621    const SOURCE_GAIN_STEP: u8 = 0x01;
622
623    /// The minimum value of left and right balance for mixer source.
624    const SOURCE_PAN_MIN: u8 = 0x00;
625    /// The maximum value of left and right balance for mixer source.
626    const SOURCE_PAN_MAX: u8 = 0x80;
627    /// The step value of left and right balance for mixer source.
628    const SOURCE_PAN_STEP: u8 = 0x01;
629
630    /// The minimum value of left and right balance for paired mixer source.
631    const SOURCE_STEREO_BALANCE_MIN: u8 = 0x00;
632    /// The maximum value of left and right balance for paired mixer source.
633    const SOURCE_STEREO_BALANCE_MAX: u8 = 0x80;
634    /// The step value of left and right balance for paired mixer source.
635    const SOURCE_STEREO_BALANCE_STEP: u8 = 0x01;
636
637    /// The minimum value of left and right width for paired mixer source.
638    const SOURCE_STEREO_WIDTH_MIN: u8 = 0x00;
639    /// The maximum value of left and right width for paired mixer source.
640    const SOURCE_STEREO_WIDTH_MAX: u8 = 0x80;
641    /// The step value of left and right width for paired mixer source.
642    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
649// MEMO: no register to read balance and width of mixer source. They are just expressed in DSP
650// events.
651impl<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/// State of output.
890#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
891pub struct RegisterDspOutputState {
892    /// The volume of master output.
893    pub master_volume: u8,
894    /// The volume of headphone output.
895    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/// State of inputs in 828mkII and Traveler.
985#[derive(Default, Debug, Clone, PartialEq, Eq)]
986pub struct RegisterDspLineInputState {
987    /// The nominal level of input signal.
988    pub level: Vec<NominalSignalLevel>,
989    /// Apply +6dB.
990    pub boost: Vec<bool>,
991}
992
993const LINE_INPUT_LEVEL_OFFSET: usize = 0x0c08;
994const LINE_INPUT_BOOST_OFFSET: usize = 0x0c14;
995
996/// The trait for specification of line input.
997pub 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/// State of input in Ultralite.
1151#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
1152pub struct RegisterDspMonauralInputState {
1153    /// The gain of inputs.
1154    pub gain: [u8; MONAURAL_INPUT_COUNT],
1155    /// Whether to invert signal of inputs.
1156    pub invert: [bool; MONAURAL_INPUT_COUNT],
1157}
1158
1159const STEREO_INPUT_COUNT: usize = 6;
1160
1161/// State of input in Audio Express, and 4 pre.
1162#[derive(Default, Debug, Clone, PartialEq, Eq)]
1163pub struct RegisterDspStereoInputState {
1164    /// The gain of inputs.
1165    pub gain: [u8; STEREO_INPUT_COUNT],
1166    /// Whether to invert signal of inputs.
1167    pub invert: [bool; STEREO_INPUT_COUNT],
1168    /// Whether the stereo channels are paired.
1169    pub paired: [bool; STEREO_INPUT_COUNT / 2],
1170    /// Whether to enable phantom powering.
1171    pub phantom: Vec<bool>,
1172    /// Whether to attenate inputs.
1173    pub pad: Vec<bool>,
1174    /// Whether jack is inserted.
1175    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
1199/// The trait for specification of monaural inputs.
1200pub trait MotuRegisterDspMonauralInputSpecification {
1201    /// The number of inputs.
1202    const INPUT_COUNT: usize = MONAURAL_INPUT_COUNT;
1203
1204    /// The minimum value of gain.
1205    const INPUT_GAIN_MIN: u8 = 0x00;
1206    /// The maximum value of gain for microphone inputs.
1207    const INPUT_MIC_GAIN_MAX: u8 = 0x18;
1208    /// The maximum value of gain for line inputs.
1209    const INPUT_LINE_GAIN_MAX: u8 = 0x12;
1210    /// The maximum value of gain for S/PDIF inputs.
1211    const INPUT_SPDIF_GAIN_MAX: u8 = 0x0c;
1212    /// The step value of gain.
1213    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
1326/// The trait for specification of stereo inputs in Audio Express and 4 pre.
1327pub trait MotuRegisterDspStereoInputSpecification: MotuRegisterDspSpecification {
1328    /// The number of inputs.
1329    const INPUT_COUNT: usize = STEREO_INPUT_COUNT;
1330
1331    /// The number of input pairs.
1332    const INPUT_PAIR_COUNT: usize = STEREO_INPUT_COUNT / 2;
1333
1334    /// The number of microphone inputs.
1335    const MIC_COUNT: usize;
1336
1337    /// The minimum value of gain.
1338    const INPUT_GAIN_MIN: u8 = 0x00;
1339    /// The maximum value of gain for microphone inputs.
1340    const INPUT_MIC_GAIN_MAX: u8 = 0x3c;
1341    /// The maximum value of gain for line inputs.
1342    const INPUT_LINE_GAIN_MAX: u8 = 0x16;
1343    /// The maximum value of gain for S/PDIF inputs.
1344    const INPUT_SPDIF_GAIN_MAX: u8 = 0x0c;
1345    /// The step value of gain.
1346    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            // MEMO: The flag is put from LSB to MSB in its order.
1404            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                    // MEMO: 0x00ff0000 mask is absent.
1461                    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/// Information of meter.
1581#[derive(Debug, Clone, PartialEq, Eq)]
1582pub struct RegisterDspMeterState {
1583    /// The detected level of signal in inputs.
1584    pub inputs: Vec<u8>,
1585    /// The detected level of signal in outputs.
1586    pub outputs: Vec<u8>,
1587}
1588
1589// Read-only.
1590const METER_OUTPUT_SELECT_OFFSET: usize = 0x0b2c;
1591const METER_OUTPUT_SELECT_TARGET_MASK: u32 = 0x000000ff;
1592const METER_OUTPUT_SELECT_CHANGE_FLAG: u32 = 0x00000b00;
1593
1594// Assertion from UAPI of ALSA firewire stack.
1595const MAX_METER_INPUT_COUNT: usize = 24;
1596const MAX_METER_OUTPUT_COUNT: usize = 48;
1597
1598const METER_IMAGE_SIZE: usize = 48;
1599
1600/// The trait for specification of hardware metering.
1601pub trait MotuRegisterDspMeterSpecification: MotuRegisterDspSpecification {
1602    /// The input ports.
1603    const INPUT_PORTS: &'static [TargetPort];
1604    /// The output pairs.
1605    const OUTPUT_PORT_PAIRS: &'static [TargetPort];
1606    const OUTPUT_PORT_PAIR_POS: &'static [[usize; 2]];
1607    /// The number of outputs.
1608    const OUTPUT_PORT_COUNT: usize = Self::OUTPUT_PORT_PAIRS.len() * 2;
1609
1610    /// The minimum value of detected signal level.
1611    const LEVEL_MIN: u8 = 0;
1612    /// The maximum value of detected signal level.
1613    const LEVEL_MAX: u8 = 0x7f;
1614    /// The step value of detected signal level.
1615    const LEVEL_STEP: u8 = 1;
1616
1617    /// The size of image.
1618    const METER_IMAGE_SIZE: usize = METER_IMAGE_SIZE;
1619
1620    fn create_meter_state() -> RegisterDspMeterState {
1621        // Assertion from UAPI of ALSA firewire stack.
1622        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/// The target of output metering.
1654#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
1655pub struct RegisterDspMeterOutputTarget(pub usize);
1656
1657/// The specification of meter for output target.
1658pub 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}