firewire_fireface_protocols/
latter.rs

1// SPDX-License-Identifier: LGPL-3.0-or-later
2// Copyright (c) 2021 Takashi Sakamoto
3
4//! Protocol defined by RME GmbH for latter models of Fireface series.
5
6pub mod ff802;
7pub mod ucx;
8
9use super::*;
10
11const CFG_OFFSET: u64 = 0xffff00000014;
12const DSP_OFFSET: u64 = 0xffff0000001c;
13const METER_OFFSET: u64 = 0xffffff000000;
14
15// For configuration register (0x'ffff'0000'0014).
16const CFG_MIDI_TX_LOW_OFFSET_MASK: u32 = 0x0001e000;
17const CFG_MIDI_TX_LOW_OFFSET_0180_FLAG: u32 = 0x00010000;
18const CFG_MIDI_TX_LOW_OFFSET_0100_FLAG: u32 = 0x00008000;
19const CFG_MIDI_TX_LOW_OFFSET_0080_FLAG: u32 = 0x00004000;
20const CFG_MIDI_TX_LOW_OFFSET_0000_FLAG: u32 = 0x00002000;
21
22/// Low offset of destination address for MIDI messages.
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24enum FfLatterMidiTxLowOffset {
25    /// Between 0x0000 to 0x007c.
26    A0000,
27    /// Between 0x0080 to 0x00fc.
28    A0080,
29    /// Between 0x0100 to 0x017c.
30    A0100,
31    /// Between 0x0180 to 0x01fc.
32    A0180,
33}
34
35impl Default for FfLatterMidiTxLowOffset {
36    fn default() -> Self {
37        Self::A0000
38    }
39}
40
41fn serialize_midi_tx_low_offset(offset: &FfLatterMidiTxLowOffset, quad: &mut u32) {
42    *quad &= !CFG_MIDI_TX_LOW_OFFSET_MASK;
43    *quad |= match offset {
44        FfLatterMidiTxLowOffset::A0000 => CFG_MIDI_TX_LOW_OFFSET_0000_FLAG,
45        FfLatterMidiTxLowOffset::A0080 => CFG_MIDI_TX_LOW_OFFSET_0080_FLAG,
46        FfLatterMidiTxLowOffset::A0100 => CFG_MIDI_TX_LOW_OFFSET_0100_FLAG,
47        FfLatterMidiTxLowOffset::A0180 => CFG_MIDI_TX_LOW_OFFSET_0180_FLAG,
48    };
49}
50
51fn deserialize_midi_tx_low_offset(offset: &mut FfLatterMidiTxLowOffset, quad: &u32) {
52    *offset = match *quad & CFG_MIDI_TX_LOW_OFFSET_MASK {
53        CFG_MIDI_TX_LOW_OFFSET_0180_FLAG => FfLatterMidiTxLowOffset::A0180,
54        CFG_MIDI_TX_LOW_OFFSET_0100_FLAG => FfLatterMidiTxLowOffset::A0100,
55        CFG_MIDI_TX_LOW_OFFSET_0080_FLAG => FfLatterMidiTxLowOffset::A0080,
56        CFG_MIDI_TX_LOW_OFFSET_0000_FLAG => FfLatterMidiTxLowOffset::A0000,
57        _ => unreachable!(),
58    }
59}
60
61const LATTER_CONFIG_SIZE: usize = 4;
62
63fn write_config<T: RmeFfOffsetParamsSerialize<U>, U>(
64    req: &mut FwReq,
65    node: &mut FwNode,
66    config: &U,
67    timeout_ms: u32,
68) -> Result<(), Error> {
69    let mut raw = T::serialize_offsets(config);
70
71    req.transaction_sync(
72        node,
73        FwTcode::WriteQuadletRequest,
74        CFG_OFFSET,
75        raw.len(),
76        &mut raw,
77        timeout_ms,
78    )
79}
80
81// For status register (0x'ffff'0000'001c).
82const STATUS_CLK_RATE_32000: u32 = 0x00;
83const STATUS_CLK_RATE_44100: u32 = 0x01;
84const STATUS_CLK_RATE_48000: u32 = 0x02;
85const STATUS_CLK_RATE_64000: u32 = 0x04;
86const STATUS_CLK_RATE_88200: u32 = 0x05;
87const STATUS_CLK_RATE_96000: u32 = 0x06;
88const STATUS_CLK_RATE_128000: u32 = 0x08;
89const STATUS_CLK_RATE_176400: u32 = 0x09;
90const STATUS_CLK_RATE_192000: u32 = 0x0a;
91const STATUS_CLK_RATE_NONE: u32 = 0x0f;
92
93fn serialize_clock_rate(clock_rate: &ClkNominalRate, quad: &mut u32, shift: usize) {
94    let val = match clock_rate {
95        ClkNominalRate::R32000 => STATUS_CLK_RATE_32000,
96        ClkNominalRate::R44100 => STATUS_CLK_RATE_44100,
97        ClkNominalRate::R48000 => STATUS_CLK_RATE_48000,
98        ClkNominalRate::R64000 => STATUS_CLK_RATE_64000,
99        ClkNominalRate::R88200 => STATUS_CLK_RATE_88200,
100        ClkNominalRate::R96000 => STATUS_CLK_RATE_96000,
101        ClkNominalRate::R128000 => STATUS_CLK_RATE_128000,
102        ClkNominalRate::R176400 => STATUS_CLK_RATE_176400,
103        ClkNominalRate::R192000 => STATUS_CLK_RATE_192000,
104    };
105    *quad |= val << shift;
106}
107
108fn deserialize_clock_rate(clock_rate: &mut ClkNominalRate, quad: &u32, shift: usize) {
109    *clock_rate = match (*quad >> shift) & 0x0000000f {
110        STATUS_CLK_RATE_32000 => ClkNominalRate::R32000,
111        STATUS_CLK_RATE_44100 => ClkNominalRate::R44100,
112        STATUS_CLK_RATE_48000 => ClkNominalRate::R48000,
113        STATUS_CLK_RATE_64000 => ClkNominalRate::R64000,
114        STATUS_CLK_RATE_88200 => ClkNominalRate::R88200,
115        STATUS_CLK_RATE_96000 => ClkNominalRate::R96000,
116        STATUS_CLK_RATE_128000 => ClkNominalRate::R128000,
117        STATUS_CLK_RATE_176400 => ClkNominalRate::R176400,
118        STATUS_CLK_RATE_192000 => ClkNominalRate::R192000,
119        _ => unreachable!(),
120    };
121}
122
123fn serialize_clock_rate_optional(
124    clock_rate: &Option<ClkNominalRate>,
125    quad: &mut u32,
126    shift: usize,
127) {
128    if let Some(r) = clock_rate {
129        serialize_clock_rate(r, quad, shift)
130    } else {
131        *quad |= STATUS_CLK_RATE_NONE << shift;
132    }
133}
134
135fn deserialize_clock_rate_optional(
136    clock_rate: &mut Option<ClkNominalRate>,
137    quad: &u32,
138    shift: usize,
139) {
140    if (*quad >> shift) & 0x0000000f != STATUS_CLK_RATE_NONE {
141        let mut r = ClkNominalRate::default();
142        deserialize_clock_rate(&mut r, quad, shift);
143        *clock_rate = Some(r);
144    } else {
145        *clock_rate = None;
146    };
147}
148
149const LATTER_STATUS_SIZE: usize = 4;
150
151fn read_status<T: RmeFfOffsetParamsDeserialize<U>, U>(
152    req: &mut FwReq,
153    node: &mut FwNode,
154    status: &mut U,
155    timeout_ms: u32,
156) -> Result<(), Error> {
157    let mut raw = [0; 4];
158    req.transaction_sync(
159        node,
160        FwTcode::ReadQuadletRequest,
161        DSP_OFFSET as u64,
162        raw.len(),
163        &mut raw,
164        timeout_ms,
165    )
166    .map(|_| T::deserialize_offsets(status, &raw))
167}
168
169/// The specification of latter model.
170pub trait RmeFfLatterSpecification {
171    /// The number of line inputs.
172    const LINE_INPUT_COUNT: usize;
173    /// The number of microphone inputs.
174    const MIC_INPUT_COUNT: usize;
175    /// The number of S/PDIF inputs.
176    const SPDIF_INPUT_COUNT: usize;
177    /// The number of ADAT inputs.
178    const ADAT_INPUT_COUNT: usize;
179    /// The number of stream inputs.
180    const STREAM_INPUT_COUNT: usize;
181
182    /// The number of line outputs.
183    const LINE_OUTPUT_COUNT: usize;
184    /// The number of headphone outputs.
185    const HP_OUTPUT_COUNT: usize;
186    /// The number of S/PDIF outputs.
187    const SPDIF_OUTPUT_COUNT: usize;
188    /// The number of ADAT outputs.
189    const ADAT_OUTPUT_COUNT: usize;
190}
191
192/// State of meters.
193///
194/// Each value is between 0x'0000'0000'0000'0000 and 0x'3fff'ffff'ffff'ffff. 0x'0000'0000'0000'001f
195/// represents negative infinite.
196#[derive(Default, Debug, Clone, PartialEq, Eq)]
197pub struct FfLatterMeterState {
198    /// The number of line inputs.
199    pub line_inputs: Vec<i32>,
200    /// The number of microphone inputs.
201    pub mic_inputs: Vec<i32>,
202    /// The number of S/PDIF inputs.
203    pub spdif_inputs: Vec<i32>,
204    /// The number of ADAT inputs.
205    pub adat_inputs: Vec<i32>,
206    /// The number of stream inputs.
207    pub stream_inputs: Vec<i32>,
208    /// The number of line outputs.
209    pub line_outputs: Vec<i32>,
210    /// The number of headphone outputs.
211    pub hp_outputs: Vec<i32>,
212    /// The number of S/PDIF outputs.
213    pub spdif_outputs: Vec<i32>,
214    /// The number of ADAT outputs.
215    pub adat_outputs: Vec<i32>,
216}
217
218const METER_CHUNK_SIZE: usize = 392;
219const METER_CHUNK_COUNT: usize = 5;
220const METER32_MASK: i32 = 0x07fffff0;
221
222/// The specification of hardware meter.
223pub trait RmeFfLatterMeterSpecification: RmeFfLatterSpecification {
224    const LEVEL_MIN: i32 = 0x0;
225    const LEVEL_MAX: i32 = 0x07fffff0;
226    const LEVEL_STEP: i32 = 0x10;
227
228    fn create_meter_state() -> FfLatterMeterState {
229        FfLatterMeterState {
230            line_inputs: vec![Default::default(); Self::LINE_INPUT_COUNT],
231            mic_inputs: vec![Default::default(); Self::MIC_INPUT_COUNT],
232            spdif_inputs: vec![Default::default(); Self::SPDIF_INPUT_COUNT],
233            adat_inputs: vec![Default::default(); Self::ADAT_INPUT_COUNT],
234            stream_inputs: vec![Default::default(); Self::STREAM_INPUT_COUNT],
235            line_outputs: vec![Default::default(); Self::LINE_OUTPUT_COUNT],
236            hp_outputs: vec![Default::default(); Self::HP_OUTPUT_COUNT],
237            spdif_outputs: vec![Default::default(); Self::SPDIF_OUTPUT_COUNT],
238            adat_outputs: vec![Default::default(); Self::ADAT_OUTPUT_COUNT],
239        }
240    }
241}
242
243impl<O: RmeFfLatterSpecification> RmeFfLatterMeterSpecification for O {}
244
245// Read data retrieved by each block read transaction consists of below chunks in the order:
246//  32 octlets for meters detected by DSP.
247//  32 quadlets for meters detected by DSP.
248//  2 quadlets for unknown meters.
249//  2 quadlets for tags.
250//
251// The first tag represents the set of content:
252//  0x11111111 - hardware outputs
253//  0x22222222 - channel strip for hardware inputs
254//  0x33333333 - stream inputs
255//  0x55555555 - fx bus
256//  0x66666666 - hardware inputs
257//
258//  The maximum value for quadlet is 0x07fffff0. The byte in LSB is 0xf at satulated.
259impl<O: RmeFfLatterMeterSpecification> RmeFfOffsetParamsDeserialize<FfLatterMeterState> for O {
260    fn deserialize_offsets(state: &mut FfLatterMeterState, raw: &[u8]) {
261        assert_eq!(raw.len(), METER_CHUNK_SIZE);
262
263        let mut quadlet = [0; 4];
264        quadlet.copy_from_slice(&raw[(METER_CHUNK_SIZE - 4)..]);
265        let target = u32::from_le_bytes(quadlet);
266
267        match target {
268            // For phys outputs.
269            0x11111111 => {
270                [
271                    (state.line_outputs.iter_mut(), 0),
272                    (state.hp_outputs.iter_mut(), Self::LINE_OUTPUT_COUNT),
273                    (
274                        state.spdif_outputs.iter_mut(),
275                        Self::LINE_OUTPUT_COUNT + Self::HP_OUTPUT_COUNT,
276                    ),
277                    (
278                        state.adat_outputs.iter_mut(),
279                        Self::LINE_OUTPUT_COUNT + Self::HP_OUTPUT_COUNT + Self::SPDIF_OUTPUT_COUNT,
280                    ),
281                ]
282                .iter_mut()
283                .for_each(|(iter, offset)| {
284                    iter.enumerate().for_each(|(i, meter)| {
285                        let pos = 256 + (*offset + i) * 4;
286                        quadlet.copy_from_slice(&raw[pos..(pos + 4)]);
287                        *meter = i32::from_le_bytes(quadlet) & METER32_MASK;
288                    });
289                });
290            }
291            // For stream inputs.
292            0x33333333 => {
293                state
294                    .stream_inputs
295                    .iter_mut()
296                    .enumerate()
297                    .for_each(|(i, meter)| {
298                        let pos = 256 + i * 4;
299                        quadlet.copy_from_slice(&raw[pos..(pos + 4)]);
300                        *meter = i32::from_le_bytes(quadlet) & METER32_MASK;
301                    });
302            }
303            // For phys inputs.
304            0x66666666 => {
305                [
306                    (state.line_inputs.iter_mut(), 0),
307                    (state.mic_inputs.iter_mut(), Self::LINE_INPUT_COUNT),
308                    (
309                        state.spdif_inputs.iter_mut(),
310                        Self::LINE_INPUT_COUNT + Self::MIC_INPUT_COUNT,
311                    ),
312                    (
313                        state.adat_inputs.iter_mut(),
314                        Self::LINE_INPUT_COUNT + Self::MIC_INPUT_COUNT + Self::SPDIF_INPUT_COUNT,
315                    ),
316                ]
317                .iter_mut()
318                .for_each(|(iter, offset)| {
319                    iter.enumerate().for_each(|(i, meter)| {
320                        let pos = 256 + (*offset + i) * 4;
321                        quadlet.copy_from_slice(&raw[pos..(pos + 4)]);
322                        *meter = i32::from_le_bytes(quadlet) & METER32_MASK;
323                    });
324                });
325            }
326            _ => (),
327        }
328    }
329}
330
331impl<O> RmeFfCacheableParamsOperation<FfLatterMeterState> for O
332where
333    O: RmeFfOffsetParamsDeserialize<FfLatterMeterState>,
334{
335    fn cache_wholly(
336        req: &mut FwReq,
337        node: &mut FwNode,
338        state: &mut FfLatterMeterState,
339        timeout_ms: u32,
340    ) -> Result<(), Error> {
341        (0..METER_CHUNK_COUNT).try_for_each(|_| {
342            let mut raw = vec![0; METER_CHUNK_SIZE];
343            req.transaction_sync(
344                node,
345                FwTcode::ReadBlockRequest,
346                METER_OFFSET as u64,
347                raw.len(),
348                &mut raw,
349                timeout_ms,
350            )
351            .map(|_| Self::deserialize_offsets(state, &raw))
352        })
353    }
354}
355
356const VIRT_PORT_CMD_FLAG: u32 = 0x40000000;
357const ODD_PARITY_FLAG: u32 = 0x80000000;
358
359fn create_phys_port_cmd(ch: u8, cmd: u8, coef: i16) -> u32 {
360    ((ch as u32) << 24) | ((cmd as u32) << 16) | (u16::from_le_bytes(coef.to_le_bytes()) as u32)
361}
362
363fn create_virt_port_cmd(mixer_step: u16, mixer: u16, ch: u16, coef: u16) -> u32 {
364    VIRT_PORT_CMD_FLAG | (((mixer_step * mixer + ch) as u32) << 16) | (coef as u32)
365}
366
367fn write_dsp_cmd(
368    req: &mut FwReq,
369    node: &mut FwNode,
370    mut cmd: u32,
371    timeout_ms: u32,
372) -> Result<(), Error> {
373    // Add odd parity.
374    if (0..32).fold(0x01, |count, shift| count ^ (cmd >> shift) & 0x1) > 0 {
375        cmd |= ODD_PARITY_FLAG;
376    }
377    let mut raw = cmd.to_le_bytes();
378    req.transaction_sync(
379        node,
380        FwTcode::WriteQuadletRequest,
381        DSP_OFFSET as u64,
382        raw.len(),
383        &mut raw,
384        timeout_ms,
385    )
386}
387
388fn write_dsp_cmds(
389    req: &mut FwReq,
390    node: &mut FwNode,
391    curr: &[u32],
392    cmds: &[u32],
393    timeout_ms: u32,
394) -> Result<(), Error> {
395    cmds.iter()
396        .zip(curr)
397        .filter(|(n, o)| !n.eq(o))
398        .try_for_each(|(&cmd, _)| write_dsp_cmd(req, node, cmd, timeout_ms))
399}
400
401/// Serialize commands for parameters.
402pub trait RmeFfCommandParamsSerialize<T> {
403    /// Serialize parameters into commands.
404    fn serialize_commands(params: &T) -> Vec<u32>;
405}
406
407/// Deserialize commands for parameters.
408pub trait RmeFfCommandParamsDeserialize<T> {
409    /// Derialize parameters from commands.
410    fn deserialize_commands(params: &mut T, raw: &[u32]);
411}
412
413/// Operation for parameters which can be updated wholly at once.
414pub trait RmeFfWhollyCommandableParamsOperation<T> {
415    /// Update registers for whole parameters.
416    fn command_wholly(
417        req: &mut FwReq,
418        node: &mut FwNode,
419        params: &T,
420        timeout_ms: u32,
421    ) -> Result<(), Error>;
422}
423
424impl<O, T> RmeFfWhollyCommandableParamsOperation<T> for O
425where
426    O: RmeFfCommandParamsSerialize<T>,
427{
428    fn command_wholly(
429        req: &mut FwReq,
430        node: &mut FwNode,
431        params: &T,
432        timeout_ms: u32,
433    ) -> Result<(), Error> {
434        let cmds = Self::serialize_commands(params);
435        cmds.iter()
436            .try_for_each(|&cmd| write_dsp_cmd(req, node, cmd, timeout_ms))
437    }
438}
439
440/// Operation for parameters which can be updated partially.
441pub trait RmeFfPartiallyCommandableParamsOperation<T> {
442    fn command_partially(
443        req: &mut FwReq,
444        node: &mut FwNode,
445        params: &mut T,
446        update: T,
447        timeout_ms: u32,
448    ) -> Result<(), Error>;
449}
450
451impl<O, T> RmeFfPartiallyCommandableParamsOperation<T> for O
452where
453    O: RmeFfCommandParamsSerialize<T>,
454{
455    fn command_partially(
456        req: &mut FwReq,
457        node: &mut FwNode,
458        params: &mut T,
459        update: T,
460        timeout_ms: u32,
461    ) -> Result<(), Error> {
462        let old = Self::serialize_commands(params);
463        let new = Self::serialize_commands(&update);
464
465        write_dsp_cmds(req, node, &old, &new, timeout_ms).map(|_| *params = update)
466    }
467}
468
469/// The specification of DSP.
470///
471/// DSP is configurable by quadlet write request with command aligned to little endian, which
472/// consists of two parts; 16 bit target and 16 bit coefficient. The command has odd parity
473/// bit in its most significant bit against the rest of bits.
474pub trait RmeFfLatterDspSpecification: RmeFfLatterSpecification {
475    const PHYS_INPUT_COUNT: usize = Self::LINE_INPUT_COUNT
476        + Self::MIC_INPUT_COUNT
477        + Self::SPDIF_INPUT_COUNT
478        + Self::ADAT_INPUT_COUNT;
479    const INPUT_COUNT: usize = Self::PHYS_INPUT_COUNT + Self::STREAM_INPUT_COUNT;
480    const OUTPUT_COUNT: usize = Self::LINE_OUTPUT_COUNT
481        + Self::HP_OUTPUT_COUNT
482        + Self::SPDIF_OUTPUT_COUNT
483        + Self::ADAT_OUTPUT_COUNT;
484
485    const STREAM_OFFSET: u16 = 0x0020;
486    const MIXER_STEP: u16 = Self::STREAM_OFFSET * 2;
487}
488
489impl<O: RmeFfLatterSpecification> RmeFfLatterDspSpecification for O {}
490
491const INPUT_TO_FX_CMD: u8 = 0x01;
492const INPUT_STEREO_LINK_CMD: u8 = 0x02;
493const INPUT_INVERT_PHASE_CMD: u8 = 0x06;
494const INPUT_LINE_GAIN_CMD: u8 = 0x07;
495const INPUT_LINE_LEVEL_CMD: u8 = 0x08;
496const INPUT_MIC_POWER_CMD: u8 = 0x08;
497const INPUT_MIC_INST_CMD: u8 = 0x09;
498
499const OUTPUT_VOL_CMD: u8 = 0x00;
500const OUTPUT_STEREO_BALANCE_CMD: u8 = 0x01;
501const OUTPUT_FROM_FX_CMD: u8 = 0x03;
502const OUTPUT_STEREO_LINK_CMD: u8 = 0x04;
503const OUTPUT_INVERT_PHASE_CMD: u8 = 0x07;
504const OUTPUT_LINE_LEVEL_CMD: u8 = 0x08;
505
506const HPF_ACTIVATE_CMD: u8 = 0x20;
507const HPF_CUT_OFF_CMD: u8 = 0x21;
508const HPF_ROLL_OFF_CMD: u8 = 0x22;
509const EQ_ACTIVATE_CMD: u8 = 0x40;
510const EQ_LOW_TYPE_CMD: u8 = 0x41;
511const EQ_LOW_GAIN_CMD: u8 = 0x42;
512const EQ_LOW_FREQ_CMD: u8 = 0x43;
513const EQ_LOW_QUALITY_CMD: u8 = 0x44;
514const EQ_MIDDLE_GAIN_CMD: u8 = 0x45;
515const EQ_MIDDLE_FREQ_CMD: u8 = 0x46;
516const EQ_MIDDLE_QUALITY_CMD: u8 = 0x47;
517const EQ_HIGH_TYPE_CMD: u8 = 0x48;
518const EQ_HIGH_GAIN_CMD: u8 = 0x49;
519const EQ_HIGH_FREQ_CMD: u8 = 0x4a;
520const EQ_HIGH_QUALITY_CMD: u8 = 0x4b;
521const DYN_ACTIVATE_CMD: u8 = 0x60;
522const DYN_GAIN_CMD: u8 = 0x61;
523const DYN_ATTACK_CMD: u8 = 0x62;
524const DYN_RELEASE_CMD: u8 = 0x63;
525const DYN_COMPR_THRESHOLD_CMD: u8 = 0x64;
526const DYN_COMPR_RATIO_CMD: u8 = 0x65;
527const DYN_EXPANDER_THRESHOLD_CMD: u8 = 0x66;
528const DYN_EXPANDER_RATIO_CMD: u8 = 0x67;
529const AUTOLEVEL_ACTIVATE_CMD: u8 = 0x80;
530const AUTOLEVEL_MAX_GAIN_CMD: u8 = 0x81;
531const AUTOLEVEL_HEADROOM_CMD: u8 = 0x82;
532const AUTOLEVEL_RISE_TIME_CMD: u8 = 0x83;
533
534const FX_REVERB_ACTIVATE_CMD: u8 = 0x00;
535const FX_REVERB_TYPE_CMD: u8 = 0x01;
536const FX_REVERB_PRE_DELAY_CMD: u8 = 0x02;
537const FX_REVERB_PRE_HPF_FREQ_CMD: u8 = 0x03;
538const FX_REVERB_ROOM_SCALE_CMD: u8 = 0x04;
539const FX_REVERB_ATTACK_CMD: u8 = 0x05;
540const FX_REVERB_HOLD_CMD: u8 = 0x06;
541const FX_REVERB_RELEASE_CMD: u8 = 0x07;
542const FX_REVERB_POST_LPF_FREQ_CMD: u8 = 0x08;
543const FX_REVERB_TIME_CMD: u8 = 0x09;
544const FX_REVERB_DAMPING_FREQ_CMD: u8 = 0x0a;
545const FX_REVERB_SMOOTH_CMD: u8 = 0x0b;
546const FX_REVERB_VOLUME_CMD: u8 = 0x0c;
547const FX_REVERB_STEREO_WIDTH_CMD: u8 = 0x0d;
548
549const FX_ECHO_ACTIVATE_CMD: u8 = 0x20;
550const FX_ECHO_TYPE_CMD: u8 = 0x21;
551const FX_ECHO_DELAY_CMD: u8 = 0x22;
552const FX_ECHO_FEEDBACK_CMD: u8 = 0x23;
553const FX_ECHO_LPF_FREQ_CMD: u8 = 0x24;
554const FX_ECHO_VOLUME_CMD: u8 = 0x25;
555const FX_ECHO_STEREO_WIDTH_CMD: u8 = 0x26;
556
557/// Nominal level of analog input.
558#[derive(Debug, Clone, Copy, PartialEq, Eq)]
559pub enum LatterInNominalLevel {
560    Low,
561    /// +4 dBu.
562    Professional,
563}
564
565impl Default for LatterInNominalLevel {
566    fn default() -> Self {
567        Self::Low
568    }
569}
570
571fn deserialize_input_nominal_level(level: &LatterInNominalLevel) -> i16 {
572    match level {
573        LatterInNominalLevel::Low => 0x0000,
574        LatterInNominalLevel::Professional => 0x0001,
575    }
576}
577
578/// State of inputs.
579#[derive(Debug, Clone, PartialEq, Eq)]
580pub struct FfLatterInputState {
581    /// Whether to link each pair of left and right ports.
582    pub stereo_links: Vec<bool>,
583    /// Whether to inverse the phase of analog, spdif, and adat inputs.
584    pub invert_phases: Vec<bool>,
585    /// The gain of analog line input. The value is between 0 and 120 to represent 0.00 dB and 12.00 dB.
586    pub line_gains: Vec<i16>,
587    /// The nominal level of analog line input.
588    pub line_levels: Vec<LatterInNominalLevel>,
589    /// Whether to enable powering for mic input. This setting has no effect when the microphone is
590    /// used for instrument.
591    pub mic_powers: Vec<bool>,
592    /// Whether to use mic input for instrument.
593    pub mic_insts: Vec<bool>,
594}
595
596/// The specification of inputs.
597pub trait RmeFfLatterInputSpecification: RmeFfLatterDspSpecification {
598    /// The minimum value of physical inputs.
599    const PHYS_INPUT_GAIN_MIN: i32 = 0;
600    /// The maximum value of physical inputs.
601    const PHYS_INPUT_GAIN_MAX: i32 = 120;
602    /// The step value of physical inputs.
603    const PHYS_INPUT_GAIN_STEP: i32 = 1;
604
605    /// Instantiate input parameters.
606    fn create_input_parameters() -> FfLatterInputState {
607        FfLatterInputState {
608            stereo_links: vec![Default::default(); Self::PHYS_INPUT_COUNT / 2],
609            invert_phases: vec![Default::default(); Self::PHYS_INPUT_COUNT],
610            line_gains: vec![Default::default(); Self::LINE_INPUT_COUNT],
611            line_levels: vec![Default::default(); Self::LINE_INPUT_COUNT],
612            mic_powers: vec![Default::default(); Self::MIC_INPUT_COUNT],
613            mic_insts: vec![Default::default(); Self::MIC_INPUT_COUNT],
614        }
615    }
616
617    /// Instantiate input equalizer parameters.
618    fn create_input_hpf_parameters() -> FfLatterInputHpfParameters {
619        FfLatterInputHpfParameters(FfLatterHpfState {
620            activates: vec![Default::default(); Self::PHYS_INPUT_COUNT],
621            cut_offs: vec![Default::default(); Self::PHYS_INPUT_COUNT],
622            roll_offs: vec![Default::default(); Self::PHYS_INPUT_COUNT],
623        })
624    }
625
626    /// Instantiate input equalizer parameters.
627    fn create_input_equalizer_parameters() -> FfLatterInputEqualizerParameters {
628        FfLatterInputEqualizerParameters(FfLatterEqState {
629            activates: vec![Default::default(); Self::PHYS_INPUT_COUNT],
630            low_types: vec![Default::default(); Self::PHYS_INPUT_COUNT],
631            low_gains: vec![Default::default(); Self::PHYS_INPUT_COUNT],
632            low_freqs: vec![Default::default(); Self::PHYS_INPUT_COUNT],
633            low_qualities: vec![Default::default(); Self::PHYS_INPUT_COUNT],
634            middle_gains: vec![Default::default(); Self::PHYS_INPUT_COUNT],
635            middle_freqs: vec![Default::default(); Self::PHYS_INPUT_COUNT],
636            middle_qualities: vec![Default::default(); Self::PHYS_INPUT_COUNT],
637            high_types: vec![Default::default(); Self::PHYS_INPUT_COUNT],
638            high_gains: vec![Default::default(); Self::PHYS_INPUT_COUNT],
639            high_freqs: vec![Default::default(); Self::PHYS_INPUT_COUNT],
640            high_qualities: vec![Default::default(); Self::PHYS_INPUT_COUNT],
641        })
642    }
643
644    /// Instantiate input dynamics parameters.
645    fn create_input_dynamics_parameters() -> FfLatterInputDynamicsParameters {
646        FfLatterInputDynamicsParameters(FfLatterDynState {
647            activates: vec![Default::default(); Self::PHYS_INPUT_COUNT],
648            gains: vec![Default::default(); Self::PHYS_INPUT_COUNT],
649            attacks: vec![Default::default(); Self::PHYS_INPUT_COUNT],
650            releases: vec![Default::default(); Self::PHYS_INPUT_COUNT],
651            compressor_thresholds: vec![Default::default(); Self::PHYS_INPUT_COUNT],
652            compressor_ratios: vec![Default::default(); Self::PHYS_INPUT_COUNT],
653            expander_thresholds: vec![Default::default(); Self::PHYS_INPUT_COUNT],
654            expander_ratios: vec![Default::default(); Self::PHYS_INPUT_COUNT],
655        })
656    }
657
658    /// Instantiate input autolevel parameters.
659    fn create_input_autolevel_parameters() -> FfLatterInputAutolevelParameters {
660        FfLatterInputAutolevelParameters(FfLatterAutolevelState {
661            activates: vec![Default::default(); Self::PHYS_INPUT_COUNT],
662            max_gains: vec![Default::default(); Self::PHYS_INPUT_COUNT],
663            headrooms: vec![Default::default(); Self::PHYS_INPUT_COUNT],
664            rise_times: vec![Default::default(); Self::PHYS_INPUT_COUNT],
665        })
666    }
667}
668
669impl<O: RmeFfLatterDspSpecification> RmeFfLatterInputSpecification for O {}
670
671impl<O: RmeFfLatterInputSpecification> RmeFfCommandParamsSerialize<FfLatterInputState> for O {
672    fn serialize_commands(state: &FfLatterInputState) -> Vec<u32> {
673        assert_eq!(state.stereo_links.len(), Self::PHYS_INPUT_COUNT / 2);
674        assert_eq!(state.invert_phases.len(), Self::PHYS_INPUT_COUNT);
675        assert_eq!(state.line_gains.len(), Self::LINE_INPUT_COUNT);
676        assert_eq!(state.line_levels.len(), Self::LINE_INPUT_COUNT);
677        assert_eq!(state.mic_powers.len(), Self::MIC_INPUT_COUNT);
678        assert_eq!(state.mic_insts.len(), Self::MIC_INPUT_COUNT);
679
680        let mut cmds = Vec::new();
681
682        state
683            .stereo_links
684            .iter()
685            .enumerate()
686            .for_each(|(i, &link)| {
687                let ch = (i * 2) as u8;
688                cmds.push(create_phys_port_cmd(ch, INPUT_STEREO_LINK_CMD, link as i16));
689            });
690
691        state
692            .invert_phases
693            .iter()
694            .enumerate()
695            .for_each(|(i, &invert_phase)| {
696                let ch = i as u8;
697                cmds.push(create_phys_port_cmd(
698                    ch,
699                    INPUT_INVERT_PHASE_CMD,
700                    invert_phase as i16,
701                ));
702            });
703
704        state.line_gains.iter().enumerate().for_each(|(i, &gain)| {
705            let ch = i as u8;
706            cmds.push(create_phys_port_cmd(ch, INPUT_LINE_GAIN_CMD, gain as i16));
707        });
708
709        state.line_levels.iter().enumerate().for_each(|(i, level)| {
710            let ch = i as u8;
711            cmds.push(create_phys_port_cmd(
712                ch,
713                INPUT_LINE_LEVEL_CMD,
714                deserialize_input_nominal_level(level),
715            ));
716        });
717
718        (0..Self::MIC_INPUT_COUNT).for_each(|i| {
719            // NOTE: The offset is required for microphone inputs.
720            let ch = (Self::LINE_INPUT_COUNT + i) as u8;
721
722            let cmd = create_phys_port_cmd(ch, INPUT_MIC_INST_CMD, state.mic_insts[i] as i16);
723            cmds.push(cmd);
724
725            // NOTE: When enabling the setting for instrument, the setting for phantom powering is
726            // disabled automatically.
727            let powering = state.mic_powers[i] && !state.mic_insts[i];
728            let cmd = create_phys_port_cmd(ch, INPUT_MIC_POWER_CMD, powering as i16);
729            cmds.push(cmd);
730        });
731
732        cmds
733    }
734}
735
736fn deserialize_output_nominal_level(level: &LineOutNominalLevel) -> i16 {
737    match level {
738        LineOutNominalLevel::Consumer => 0x0000,
739        LineOutNominalLevel::Professional => 0x0001,
740        LineOutNominalLevel::High => 0x0002,
741    }
742}
743
744/// The specification of output.
745#[derive(Debug, Clone, PartialEq, Eq)]
746pub struct FfLatterOutputState {
747    /// The level of volume. Each value is between -650 (0xfd76) and 60 (0x003c) to represent
748    /// -65.00 dB and 6.00 dB.
749    pub vols: Vec<i16>,
750    /// The balance between left and right. The value is between -100 (0xff9c) and 100 (0x0064).
751    pub stereo_balance: Vec<i16>,
752    /// Whether to link each pair of left and right ports.
753    pub stereo_links: Vec<bool>,
754    /// Whether to inverse the phase of analog, spdif, and adat outputs.
755    pub invert_phases: Vec<bool>,
756    /// The nominal level of analog line output.
757    pub line_levels: Vec<LineOutNominalLevel>,
758}
759
760/// The specification of output.
761pub trait RmeFfLatterOutputSpecification: RmeFfLatterDspSpecification {
762    /// The minimum value for volume of physical output.
763    const PHYS_OUTPUT_VOL_MIN: i32 = -650;
764    /// The maximum value for volume of physical output.
765    const PHYS_OUTPUT_VOL_MAX: i32 = 60;
766    /// The step value of for volume physical output.
767    const PHYS_OUTPUT_VOL_STEP: i32 = 1;
768
769    /// The minimum value for left and right balance of physical output.
770    const PHYS_OUTPUT_BALANCE_MIN: i32 = -100;
771    /// The maximum value for left and right balance of physical output.
772    const PHYS_OUTPUT_BALANCE_MAX: i32 = 100;
773    /// The step value for left and right balance of physical output.
774    const PHYS_OUTPUT_BALANCE_STEP: i32 = 1;
775
776    /// The number of physical outputs.
777    const CH_OFFSET: u8 = Self::PHYS_INPUT_COUNT as u8;
778    /// The number of physical output pairs.
779    const OUTPUT_PAIR_COUNT: usize = Self::OUTPUT_COUNT / 2;
780
781    /// Instantiate output parameters.
782    fn create_output_parameters() -> FfLatterOutputState {
783        FfLatterOutputState {
784            vols: vec![Default::default(); Self::OUTPUT_COUNT],
785            stereo_balance: vec![Default::default(); Self::OUTPUT_COUNT / 2],
786            stereo_links: vec![Default::default(); Self::OUTPUT_COUNT / 2],
787            invert_phases: vec![Default::default(); Self::OUTPUT_COUNT],
788            line_levels: vec![Default::default(); Self::LINE_OUTPUT_COUNT],
789        }
790    }
791
792    /// Instantiate output equalizer parameters.
793    fn create_output_hpf_parameters() -> FfLatterOutputHpfParameters {
794        FfLatterOutputHpfParameters(FfLatterHpfState {
795            activates: vec![Default::default(); Self::OUTPUT_COUNT],
796            cut_offs: vec![Default::default(); Self::OUTPUT_COUNT],
797            roll_offs: vec![Default::default(); Self::OUTPUT_COUNT],
798        })
799    }
800
801    /// Instantiate output equalizer parameters.
802    fn create_output_equalizer_parameters() -> FfLatterOutputEqualizerParameters {
803        FfLatterOutputEqualizerParameters(FfLatterEqState {
804            activates: vec![Default::default(); Self::OUTPUT_COUNT],
805            low_types: vec![Default::default(); Self::OUTPUT_COUNT],
806            low_gains: vec![Default::default(); Self::OUTPUT_COUNT],
807            low_freqs: vec![Default::default(); Self::OUTPUT_COUNT],
808            low_qualities: vec![Default::default(); Self::OUTPUT_COUNT],
809            middle_gains: vec![Default::default(); Self::OUTPUT_COUNT],
810            middle_freqs: vec![Default::default(); Self::OUTPUT_COUNT],
811            middle_qualities: vec![Default::default(); Self::OUTPUT_COUNT],
812            high_types: vec![Default::default(); Self::OUTPUT_COUNT],
813            high_gains: vec![Default::default(); Self::OUTPUT_COUNT],
814            high_freqs: vec![Default::default(); Self::OUTPUT_COUNT],
815            high_qualities: vec![Default::default(); Self::OUTPUT_COUNT],
816        })
817    }
818
819    /// Instantiate output dynamics parameters.
820    fn create_output_dynamics_parameters() -> FfLatterOutputDynamicsParameters {
821        FfLatterOutputDynamicsParameters(FfLatterDynState {
822            activates: vec![Default::default(); Self::OUTPUT_COUNT],
823            gains: vec![Default::default(); Self::OUTPUT_COUNT],
824            attacks: vec![Default::default(); Self::OUTPUT_COUNT],
825            releases: vec![Default::default(); Self::OUTPUT_COUNT],
826            compressor_thresholds: vec![Default::default(); Self::OUTPUT_COUNT],
827            compressor_ratios: vec![Default::default(); Self::OUTPUT_COUNT],
828            expander_thresholds: vec![Default::default(); Self::OUTPUT_COUNT],
829            expander_ratios: vec![Default::default(); Self::OUTPUT_COUNT],
830        })
831    }
832
833    /// Instantiate output autolevel parameters.
834    fn create_output_autolevel_parameters() -> FfLatterOutputAutolevelParameters {
835        FfLatterOutputAutolevelParameters(FfLatterAutolevelState {
836            activates: vec![Default::default(); Self::OUTPUT_COUNT],
837            max_gains: vec![Default::default(); Self::OUTPUT_COUNT],
838            headrooms: vec![Default::default(); Self::OUTPUT_COUNT],
839            rise_times: vec![Default::default(); Self::OUTPUT_COUNT],
840        })
841    }
842}
843
844impl<O: RmeFfLatterDspSpecification> RmeFfLatterOutputSpecification for O {}
845
846impl<O: RmeFfLatterOutputSpecification> RmeFfCommandParamsSerialize<FfLatterOutputState> for O {
847    fn serialize_commands(state: &FfLatterOutputState) -> Vec<u32> {
848        assert_eq!(state.vols.len(), Self::OUTPUT_COUNT);
849        assert_eq!(state.stereo_balance.len(), Self::OUTPUT_COUNT / 2);
850        assert_eq!(state.stereo_links.len(), Self::OUTPUT_COUNT / 2);
851        assert_eq!(state.invert_phases.len(), Self::OUTPUT_COUNT);
852        assert_eq!(state.line_levels.len(), Self::LINE_OUTPUT_COUNT);
853
854        let mut cmds = Vec::new();
855        let ch_offset = Self::PHYS_INPUT_COUNT as u8;
856
857        state.vols.iter().enumerate().for_each(|(i, &vol)| {
858            let ch = ch_offset + i as u8;
859            cmds.push(create_phys_port_cmd(ch, OUTPUT_VOL_CMD, vol));
860        });
861
862        state
863            .stereo_balance
864            .iter()
865            .enumerate()
866            .for_each(|(i, &balance)| {
867                let ch = ch_offset + i as u8;
868                cmds.push(create_phys_port_cmd(ch, OUTPUT_STEREO_BALANCE_CMD, balance));
869            });
870
871        state
872            .stereo_links
873            .iter()
874            .enumerate()
875            .for_each(|(i, &link)| {
876                let ch = ch_offset + i as u8;
877                cmds.push(create_phys_port_cmd(
878                    ch,
879                    OUTPUT_STEREO_LINK_CMD,
880                    link as i16,
881                ));
882            });
883
884        state
885            .invert_phases
886            .iter()
887            .enumerate()
888            .for_each(|(i, &invert_phase)| {
889                let ch = ch_offset + i as u8;
890                cmds.push(create_phys_port_cmd(
891                    ch,
892                    OUTPUT_INVERT_PHASE_CMD,
893                    invert_phase as i16,
894                ));
895            });
896
897        state
898            .line_levels
899            .iter()
900            .enumerate()
901            .for_each(|(i, line_level)| {
902                let ch = ch_offset + i as u8;
903                cmds.push(create_phys_port_cmd(
904                    ch,
905                    OUTPUT_LINE_LEVEL_CMD,
906                    deserialize_output_nominal_level(line_level),
907                ));
908            });
909
910        cmds
911    }
912}
913
914/// State of sources for mixer.
915///
916/// Each value is between 0x0000 and 0xa000 through 0x9000 to represent -65.00 dB and 6.00 dB
917/// through 0.00 dB.
918#[derive(Debug, Clone, PartialEq, Eq)]
919pub struct FfLatterMixer {
920    /// The gain of sources from line inputs.
921    pub line_gains: Vec<u16>,
922    /// The gain of sources from microphone inputs.
923    pub mic_gains: Vec<u16>,
924    /// The gain of sources from S/PDIF inputs.
925    pub spdif_gains: Vec<u16>,
926    /// The gain of sources from ADAT inputs.
927    pub adat_gains: Vec<u16>,
928    /// The gain of sources from stream inputs.
929    pub stream_gains: Vec<u16>,
930}
931
932/// State of mixers.
933#[derive(Debug, Clone, PartialEq, Eq)]
934pub struct FfLatterMixerState(pub Vec<FfLatterMixer>);
935
936/// The specification of mixer.
937pub trait RmeFfLatterMixerSpecification: RmeFfLatterDspSpecification {
938    /// The minimum value of gain for source of mixer.
939    const MIXER_INPUT_GAIN_MIN: i32 = 0x0000;
940    /// The zero value of gain for source of mixer.
941    const MIXER_INPUT_GAIN_ZERO: i32 = 0x9000;
942    /// The maximum value of gain for source of mixer.
943    const MIXER_INPUT_GAIN_MAX: i32 = 0xa000;
944    /// The step value of gain for source of mixer.
945    const MIXER_INPUT_GAIN_STEP: i32 = 1;
946
947    fn create_mixer_parameters() -> FfLatterMixerState {
948        FfLatterMixerState(vec![
949            FfLatterMixer {
950                line_gains: vec![Default::default(); Self::LINE_INPUT_COUNT],
951                mic_gains: vec![Default::default(); Self::MIC_INPUT_COUNT],
952                spdif_gains: vec![Default::default(); Self::SPDIF_INPUT_COUNT],
953                adat_gains: vec![Default::default(); Self::ADAT_INPUT_COUNT],
954                stream_gains: vec![Default::default(); Self::STREAM_INPUT_COUNT],
955            };
956            Self::OUTPUT_COUNT
957        ])
958    }
959}
960
961impl<O: RmeFfLatterDspSpecification> RmeFfLatterMixerSpecification for O {}
962
963impl<O: RmeFfLatterMixerSpecification> RmeFfCommandParamsSerialize<FfLatterMixerState> for O {
964    fn serialize_commands(state: &FfLatterMixerState) -> Vec<u32> {
965        state
966            .0
967            .iter()
968            .enumerate()
969            .flat_map(|(i, mixer)| {
970                let index = i as u16;
971                mixer
972                    .line_gains
973                    .iter()
974                    .chain(&mixer.mic_gains)
975                    .chain(&mixer.spdif_gains)
976                    .chain(&mixer.adat_gains)
977                    .enumerate()
978                    .map(|(j, &gain)| {
979                        let ch = j as u16;
980                        create_virt_port_cmd(Self::MIXER_STEP, index, ch, gain)
981                    })
982                    .collect::<Vec<u32>>()
983            })
984            .collect()
985    }
986}
987
988/// Level of roll off in high pass filter.
989#[derive(Debug, Clone, Copy, PartialEq, Eq)]
990pub enum FfLatterHpfRollOffLevel {
991    L6,
992    L12,
993    L18,
994    L24,
995}
996
997impl Default for FfLatterHpfRollOffLevel {
998    fn default() -> Self {
999        Self::L6
1000    }
1001}
1002
1003fn deserialize_hpf_roll_off_level(freq: &FfLatterHpfRollOffLevel) -> i16 {
1004    match freq {
1005        FfLatterHpfRollOffLevel::L6 => 0,
1006        FfLatterHpfRollOffLevel::L12 => 1,
1007        FfLatterHpfRollOffLevel::L18 => 2,
1008        FfLatterHpfRollOffLevel::L24 => 3,
1009    }
1010}
1011
1012/// State of high pass filter in channel strip effect.
1013#[derive(Debug, Clone, PartialEq, Eq)]
1014pub struct FfLatterHpfState {
1015    /// Whether to activate high pass filter.
1016    pub activates: Vec<bool>,
1017    /// The frequency to cut between 20 and 500 Hz.
1018    pub cut_offs: Vec<u16>,
1019    /// The ratio to decline gain.
1020    pub roll_offs: Vec<FfLatterHpfRollOffLevel>,
1021}
1022
1023fn hpf_state_to_cmds(state: &FfLatterHpfState, ch_offset: u8) -> Vec<u32> {
1024    assert_eq!(state.cut_offs.len(), state.activates.len());
1025    assert_eq!(state.roll_offs.len(), state.activates.len());
1026
1027    let mut cmds = Vec::new();
1028
1029    (0..state.activates.len()).for_each(|i| {
1030        let ch = ch_offset + i as u8;
1031        cmds.push(create_phys_port_cmd(
1032            ch,
1033            HPF_ACTIVATE_CMD,
1034            state.activates[i] as i16,
1035        ));
1036        cmds.push(create_phys_port_cmd(
1037            ch,
1038            HPF_CUT_OFF_CMD,
1039            state.cut_offs[i] as i16,
1040        ));
1041        cmds.push(create_phys_port_cmd(
1042            ch,
1043            HPF_ROLL_OFF_CMD,
1044            deserialize_hpf_roll_off_level(&state.roll_offs[i]),
1045        ));
1046    });
1047
1048    cmds
1049}
1050
1051/// Parameters of input high pass filter.
1052#[derive(Debug, Clone, PartialEq, Eq)]
1053pub struct FfLatterInputHpfParameters(pub FfLatterHpfState);
1054
1055impl AsRef<FfLatterHpfState> for FfLatterInputHpfParameters {
1056    fn as_ref(&self) -> &FfLatterHpfState {
1057        &self.0
1058    }
1059}
1060
1061impl AsMut<FfLatterHpfState> for FfLatterInputHpfParameters {
1062    fn as_mut(&mut self) -> &mut FfLatterHpfState {
1063        &mut self.0
1064    }
1065}
1066
1067/// Parameters of output high pass filter.
1068#[derive(Debug, Clone, PartialEq, Eq)]
1069pub struct FfLatterOutputHpfParameters(pub FfLatterHpfState);
1070
1071impl AsRef<FfLatterHpfState> for FfLatterOutputHpfParameters {
1072    fn as_ref(&self) -> &FfLatterHpfState {
1073        &self.0
1074    }
1075}
1076
1077impl AsMut<FfLatterHpfState> for FfLatterOutputHpfParameters {
1078    fn as_mut(&mut self) -> &mut FfLatterHpfState {
1079        &mut self.0
1080    }
1081}
1082
1083/// The trait for specification of high pass filter.
1084pub trait RmeFfLatterHpfSpecification {
1085    /// The minimum value of cut off.
1086    const HPF_CUT_OFF_MIN: i32 = 20;
1087    /// The maximum value of cut off.
1088    const HPF_CUT_OFF_MAX: i32 = 500;
1089    /// The step value of cut off.
1090    const HPF_CUT_OFF_STEP: i32 = 1;
1091}
1092
1093impl<O: RmeFfLatterDspSpecification> RmeFfLatterHpfSpecification for O {}
1094
1095impl<O> RmeFfCommandParamsSerialize<FfLatterInputHpfParameters> for O
1096where
1097    O: RmeFfLatterHpfSpecification + RmeFfLatterInputSpecification,
1098{
1099    fn serialize_commands(params: &FfLatterInputHpfParameters) -> Vec<u32> {
1100        hpf_state_to_cmds(&params.0, 0)
1101    }
1102}
1103
1104impl<O> RmeFfCommandParamsSerialize<FfLatterOutputHpfParameters> for O
1105where
1106    O: RmeFfLatterHpfSpecification + RmeFfLatterOutputSpecification,
1107{
1108    fn serialize_commands(params: &FfLatterOutputHpfParameters) -> Vec<u32> {
1109        hpf_state_to_cmds(&params.0, Self::PHYS_INPUT_COUNT as u8)
1110    }
1111}
1112
1113/// Type of bandwidth equalizing.
1114#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1115pub enum FfLatterChStripEqType {
1116    Peak,
1117    Shelf,
1118    LowPass,
1119}
1120
1121impl Default for FfLatterChStripEqType {
1122    fn default() -> Self {
1123        Self::Peak
1124    }
1125}
1126
1127fn deserialize_eq_type(eq_type: &FfLatterChStripEqType) -> i16 {
1128    match eq_type {
1129        FfLatterChStripEqType::Peak => 0x0000,
1130        FfLatterChStripEqType::Shelf => 0x0001,
1131        FfLatterChStripEqType::LowPass => 0x0002,
1132    }
1133}
1134
1135/// State of equalizer in channel strip effect.
1136#[derive(Debug, Clone, PartialEq, Eq)]
1137pub struct FfLatterEqState {
1138    /// Whether to activate equalizer.
1139    pub activates: Vec<bool>,
1140    /// The type of equalizer at low bandwidth.
1141    pub low_types: Vec<FfLatterChStripEqType>,
1142    /// The gain of equalizer at low bandwidth between -20 and 20.
1143    pub low_gains: Vec<i16>,
1144    /// The frequency of equalizer at low bandwidth between 20 and 20000.
1145    pub low_freqs: Vec<u16>,
1146    /// The quality of equalizer at low bandwidth between 7 and 50, displayed by 1/10.
1147    pub low_qualities: Vec<u16>,
1148    /// The gain of equalizer at middle bandwidth between -20 and 20.
1149    pub middle_gains: Vec<i16>,
1150    /// The frequency of equalizer at middle bandwidth between 20 and 20000.
1151    pub middle_freqs: Vec<u16>,
1152    /// The quality of equalizer at middle bandwidth between 7 and 50, displayed by 1/10.
1153    pub middle_qualities: Vec<u16>,
1154    /// The type of equalizer at high bandwidth.
1155    pub high_types: Vec<FfLatterChStripEqType>,
1156    /// The gain of equalizer at high bandwidth between -20 and 20.
1157    pub high_gains: Vec<i16>,
1158    /// The frequency of equalizer at high bandwidth between 20 and 20000.
1159    pub high_freqs: Vec<u16>,
1160    /// The quality of equalizer at high bandwidth between 7 and 50, displayed by 1/10.
1161    pub high_qualities: Vec<u16>,
1162}
1163
1164fn eq_state_to_cmds(state: &FfLatterEqState, ch_offset: u8) -> Vec<u32> {
1165    assert_eq!(state.low_types.len(), state.activates.len());
1166    assert_eq!(state.low_gains.len(), state.activates.len());
1167    assert_eq!(state.low_freqs.len(), state.activates.len());
1168    assert_eq!(state.low_qualities.len(), state.activates.len());
1169    assert_eq!(state.middle_gains.len(), state.activates.len());
1170    assert_eq!(state.middle_freqs.len(), state.activates.len());
1171    assert_eq!(state.middle_qualities.len(), state.activates.len());
1172    assert_eq!(state.high_types.len(), state.activates.len());
1173    assert_eq!(state.high_gains.len(), state.activates.len());
1174    assert_eq!(state.high_freqs.len(), state.activates.len());
1175    assert_eq!(state.high_qualities.len(), state.activates.len());
1176
1177    let mut cmds = Vec::new();
1178
1179    (0..state.activates.len()).for_each(|i| {
1180        let ch = ch_offset + i as u8;
1181        cmds.push(create_phys_port_cmd(
1182            ch,
1183            EQ_ACTIVATE_CMD,
1184            state.activates[i] as i16,
1185        ));
1186        cmds.push(create_phys_port_cmd(
1187            ch,
1188            EQ_LOW_TYPE_CMD,
1189            deserialize_eq_type(&state.low_types[i]),
1190        ));
1191        cmds.push(create_phys_port_cmd(
1192            ch,
1193            EQ_LOW_GAIN_CMD,
1194            state.low_gains[i] as i16,
1195        ));
1196        cmds.push(create_phys_port_cmd(
1197            ch,
1198            EQ_LOW_FREQ_CMD,
1199            state.low_freqs[i] as i16,
1200        ));
1201        cmds.push(create_phys_port_cmd(
1202            ch,
1203            EQ_LOW_QUALITY_CMD,
1204            state.low_qualities[i] as i16,
1205        ));
1206        cmds.push(create_phys_port_cmd(
1207            ch,
1208            EQ_MIDDLE_GAIN_CMD,
1209            state.middle_gains[i] as i16,
1210        ));
1211        cmds.push(create_phys_port_cmd(
1212            ch,
1213            EQ_MIDDLE_FREQ_CMD,
1214            state.middle_freqs[i] as i16,
1215        ));
1216        cmds.push(create_phys_port_cmd(
1217            ch,
1218            EQ_MIDDLE_QUALITY_CMD,
1219            state.middle_qualities[i] as i16,
1220        ));
1221        cmds.push(create_phys_port_cmd(
1222            ch,
1223            EQ_HIGH_TYPE_CMD,
1224            deserialize_eq_type(&state.high_types[i]),
1225        ));
1226        cmds.push(create_phys_port_cmd(
1227            ch,
1228            EQ_HIGH_GAIN_CMD,
1229            state.high_gains[i] as i16,
1230        ));
1231        cmds.push(create_phys_port_cmd(
1232            ch,
1233            EQ_HIGH_FREQ_CMD,
1234            state.high_freqs[i] as i16,
1235        ));
1236        cmds.push(create_phys_port_cmd(
1237            ch,
1238            EQ_HIGH_QUALITY_CMD,
1239            state.high_qualities[i] as i16,
1240        ));
1241    });
1242
1243    cmds
1244}
1245
1246/// Parameters of input equalizer.
1247#[derive(Debug, Clone, PartialEq, Eq)]
1248pub struct FfLatterInputEqualizerParameters(pub FfLatterEqState);
1249
1250impl AsRef<FfLatterEqState> for FfLatterInputEqualizerParameters {
1251    fn as_ref(&self) -> &FfLatterEqState {
1252        &self.0
1253    }
1254}
1255
1256impl AsMut<FfLatterEqState> for FfLatterInputEqualizerParameters {
1257    fn as_mut(&mut self) -> &mut FfLatterEqState {
1258        &mut self.0
1259    }
1260}
1261
1262/// Parameters of output equalizer.
1263#[derive(Debug, Clone, PartialEq, Eq)]
1264pub struct FfLatterOutputEqualizerParameters(pub FfLatterEqState);
1265
1266impl AsRef<FfLatterEqState> for FfLatterOutputEqualizerParameters {
1267    fn as_ref(&self) -> &FfLatterEqState {
1268        &self.0
1269    }
1270}
1271
1272impl AsMut<FfLatterEqState> for FfLatterOutputEqualizerParameters {
1273    fn as_mut(&mut self) -> &mut FfLatterEqState {
1274        &mut self.0
1275    }
1276}
1277
1278/// The trait for specification of equalizer.
1279pub trait RmeFfLatterEqualizerSpecification {
1280    /// The minimum value of gain.
1281    const EQ_GAIN_MIN: i32 = -20;
1282    /// The maximum value of gain.
1283    const EQ_GAIN_MAX: i32 = 20;
1284    /// The step value of gain.
1285    const EQ_GAIN_STEP: i32 = 1;
1286
1287    /// The minimum value of frequency.
1288    const EQ_FREQ_MIN: i32 = 20;
1289    /// The maximum value of frequency.
1290    const EQ_FREQ_MAX: i32 = 20000;
1291    /// The step value of frequency.
1292    const EQ_FREQ_STEP: i32 = 1;
1293
1294    /// The minimum value of quality.
1295    const EQ_QUALITY_MIN: i32 = 7;
1296    /// The maximum value of quality.
1297    const EQ_QUALITY_MAX: i32 = 50;
1298    /// The step value of quality.
1299    const EQ_QUALITY_STEP: i32 = 1;
1300}
1301
1302impl<O: RmeFfLatterDspSpecification> RmeFfLatterEqualizerSpecification for O {}
1303
1304impl<O> RmeFfCommandParamsSerialize<FfLatterInputEqualizerParameters> for O
1305where
1306    O: RmeFfLatterEqualizerSpecification + RmeFfLatterInputSpecification,
1307{
1308    fn serialize_commands(params: &FfLatterInputEqualizerParameters) -> Vec<u32> {
1309        eq_state_to_cmds(&params.0, 0)
1310    }
1311}
1312
1313impl<O> RmeFfCommandParamsSerialize<FfLatterOutputEqualizerParameters> for O
1314where
1315    O: RmeFfLatterEqualizerSpecification + RmeFfLatterOutputSpecification,
1316{
1317    fn serialize_commands(params: &FfLatterOutputEqualizerParameters) -> Vec<u32> {
1318        eq_state_to_cmds(&params.0, Self::PHYS_INPUT_COUNT as u8)
1319    }
1320}
1321
1322/// State of dynamics in channel strip effect.
1323#[derive(Debug, Clone, PartialEq, Eq)]
1324pub struct FfLatterDynState {
1325    /// Whether to activate dynamics.
1326    pub activates: Vec<bool>,
1327    /// The gain of dynamics between -300 and 300, displayed by 1/10.
1328    pub gains: Vec<i16>,
1329    /// The rise time of dynamics between 0 and 200 ms.
1330    pub attacks: Vec<u16>,
1331    /// The release time of dynamics between 100 and 999 ms.
1332    pub releases: Vec<u16>,
1333    /// The threshold of compressor between -600 and 0, displayed by 1/10.
1334    pub compressor_thresholds: Vec<i16>,
1335    /// The ratio of compressor between 10 and 100.
1336    pub compressor_ratios: Vec<u16>,
1337    /// The threshold of expander between -990 and -200, displayed by 1/10.
1338    pub expander_thresholds: Vec<i16>,
1339    /// The ratio of expander between 10 and 100.
1340    pub expander_ratios: Vec<u16>,
1341}
1342
1343fn dyn_state_to_cmds(state: &FfLatterDynState, ch_offset: u8) -> Vec<u32> {
1344    assert_eq!(state.gains.len(), state.activates.len());
1345    assert_eq!(state.attacks.len(), state.activates.len());
1346    assert_eq!(state.releases.len(), state.activates.len());
1347    assert_eq!(state.compressor_thresholds.len(), state.activates.len());
1348    assert_eq!(state.compressor_ratios.len(), state.activates.len());
1349    assert_eq!(state.expander_thresholds.len(), state.activates.len());
1350    assert_eq!(state.expander_ratios.len(), state.activates.len());
1351
1352    let mut cmds = Vec::new();
1353
1354    (0..state.activates.len()).for_each(|i| {
1355        let ch = ch_offset + i as u8;
1356        cmds.push(create_phys_port_cmd(
1357            ch,
1358            DYN_ACTIVATE_CMD,
1359            state.activates[i] as i16,
1360        ));
1361        cmds.push(create_phys_port_cmd(
1362            ch,
1363            DYN_GAIN_CMD,
1364            state.gains[i] as i16,
1365        ));
1366        cmds.push(create_phys_port_cmd(
1367            ch,
1368            DYN_ATTACK_CMD,
1369            state.attacks[i] as i16,
1370        ));
1371        cmds.push(create_phys_port_cmd(
1372            ch,
1373            DYN_RELEASE_CMD,
1374            state.releases[i] as i16,
1375        ));
1376        cmds.push(create_phys_port_cmd(
1377            ch,
1378            DYN_COMPR_THRESHOLD_CMD,
1379            state.compressor_thresholds[i],
1380        ));
1381        cmds.push(create_phys_port_cmd(
1382            ch,
1383            DYN_COMPR_RATIO_CMD,
1384            state.compressor_ratios[i] as i16,
1385        ));
1386        cmds.push(create_phys_port_cmd(
1387            ch,
1388            DYN_EXPANDER_THRESHOLD_CMD,
1389            state.expander_thresholds[i],
1390        ));
1391        cmds.push(create_phys_port_cmd(
1392            ch,
1393            DYN_EXPANDER_RATIO_CMD,
1394            state.expander_ratios[i] as i16,
1395        ));
1396    });
1397
1398    cmds
1399}
1400
1401/// Parameters of input dynamics.
1402#[derive(Debug, Clone, PartialEq, Eq)]
1403pub struct FfLatterInputDynamicsParameters(pub FfLatterDynState);
1404
1405impl AsRef<FfLatterDynState> for FfLatterInputDynamicsParameters {
1406    fn as_ref(&self) -> &FfLatterDynState {
1407        &self.0
1408    }
1409}
1410
1411impl AsMut<FfLatterDynState> for FfLatterInputDynamicsParameters {
1412    fn as_mut(&mut self) -> &mut FfLatterDynState {
1413        &mut self.0
1414    }
1415}
1416
1417/// Parameters of output dynamics.
1418#[derive(Debug, Clone, PartialEq, Eq)]
1419pub struct FfLatterOutputDynamicsParameters(pub FfLatterDynState);
1420
1421impl AsRef<FfLatterDynState> for FfLatterOutputDynamicsParameters {
1422    fn as_ref(&self) -> &FfLatterDynState {
1423        &self.0
1424    }
1425}
1426
1427impl AsMut<FfLatterDynState> for FfLatterOutputDynamicsParameters {
1428    fn as_mut(&mut self) -> &mut FfLatterDynState {
1429        &mut self.0
1430    }
1431}
1432
1433/// The specification of channel strip.
1434pub trait RmeFfLatterDynamicsSpecification {
1435    /// The minimum value of gain.
1436    const DYN_GAIN_MIN: i32 = -300;
1437    /// The maximum value of gain.
1438    const DYN_GAIN_MAX: i32 = 300;
1439    /// The step value of gain.
1440    const DYN_GAIN_STEP: i32 = 1;
1441
1442    /// The minimum value of attack.
1443    const DYN_ATTACK_MIN: i32 = 0;
1444    /// The maximum value of attack.
1445    const DYN_ATTACK_MAX: i32 = 200;
1446    /// The step value of attack.
1447    const DYN_ATTACK_STEP: i32 = 1;
1448
1449    /// The minimum value of release.
1450    const DYN_RELEASE_MIN: i32 = 100;
1451    /// The maximum value of release.
1452    const DYN_RELEASE_MAX: i32 = 999;
1453    /// The step value of release.
1454    const DYN_RELEASE_STEP: i32 = 1;
1455
1456    /// The minimum value of compressor threshold.
1457    const DYN_COMP_THRESHOLD_MIN: i32 = -600;
1458    /// The maximum value of compressor threshold.
1459    const DYN_COMP_THRESHOLD_MAX: i32 = 0;
1460    /// The step value of compressor threshold.
1461    const DYN_COMP_THRESHOLD_STEP: i32 = 1;
1462
1463    /// The minimum value of ratio.
1464    const DYN_RATIO_MIN: i32 = 10;
1465    /// The maximum value of ratio.
1466    const DYN_RATIO_MAX: i32 = 100;
1467    /// The step value of ratio.
1468    const DYN_RATIO_STEP: i32 = 1;
1469
1470    /// The minimum value of extra threshold.
1471    const DYN_EX_THRESHOLD_MIN: i32 = -999;
1472    /// The maximum value of extra .
1473    const DYN_EX_THRESHOLD_MAX: i32 = -200;
1474    /// The step value of extra .
1475    const DYN_EX_THRESHOLD_STEP: i32 = 1;
1476}
1477
1478impl<O: RmeFfLatterDspSpecification> RmeFfLatterDynamicsSpecification for O {}
1479
1480impl<O> RmeFfCommandParamsSerialize<FfLatterInputDynamicsParameters> for O
1481where
1482    O: RmeFfLatterDynamicsSpecification + RmeFfLatterInputSpecification,
1483{
1484    fn serialize_commands(params: &FfLatterInputDynamicsParameters) -> Vec<u32> {
1485        dyn_state_to_cmds(&params.0, 0)
1486    }
1487}
1488
1489impl<O> RmeFfCommandParamsSerialize<FfLatterOutputDynamicsParameters> for O
1490where
1491    O: RmeFfLatterDynamicsSpecification + RmeFfLatterOutputSpecification,
1492{
1493    fn serialize_commands(params: &FfLatterOutputDynamicsParameters) -> Vec<u32> {
1494        dyn_state_to_cmds(&params.0, Self::PHYS_INPUT_COUNT as u8)
1495    }
1496}
1497
1498/// State of autolevel in channel strip effects.
1499#[derive(Debug, Clone, PartialEq, Eq)]
1500pub struct FfLatterAutolevelState {
1501    /// Whether to activate auto level.
1502    pub activates: Vec<bool>,
1503    /// The maximum level of amplification between 0 and 180, displayed by 1/10 for dB.
1504    pub max_gains: Vec<u16>,
1505    /// The level of head room to decline signal peak between 30 and 120, displayed by 1/10 for dB.
1506    pub headrooms: Vec<u16>,
1507    /// The speed of level increase between 1 and 99, displayed by 1/10 for seconds.
1508    pub rise_times: Vec<u16>,
1509}
1510
1511fn autolevel_state_to_cmds(state: &FfLatterAutolevelState, ch_offset: u8) -> Vec<u32> {
1512    assert_eq!(state.max_gains.len(), state.activates.len());
1513    assert_eq!(state.headrooms.len(), state.activates.len());
1514    assert_eq!(state.rise_times.len(), state.activates.len());
1515
1516    let mut cmds = Vec::new();
1517
1518    (0..state.activates.len()).for_each(|i| {
1519        let ch = ch_offset + i as u8;
1520        cmds.push(create_phys_port_cmd(
1521            ch,
1522            AUTOLEVEL_ACTIVATE_CMD,
1523            state.activates[i] as i16,
1524        ));
1525        cmds.push(create_phys_port_cmd(
1526            ch,
1527            AUTOLEVEL_MAX_GAIN_CMD,
1528            state.max_gains[i] as i16,
1529        ));
1530        cmds.push(create_phys_port_cmd(
1531            ch,
1532            AUTOLEVEL_HEADROOM_CMD,
1533            state.headrooms[i] as i16,
1534        ));
1535        cmds.push(create_phys_port_cmd(
1536            ch,
1537            AUTOLEVEL_RISE_TIME_CMD,
1538            state.rise_times[i] as i16,
1539        ));
1540    });
1541
1542    cmds
1543}
1544
1545/// Parameters of input autolevel.
1546#[derive(Debug, Clone, PartialEq, Eq)]
1547pub struct FfLatterInputAutolevelParameters(pub FfLatterAutolevelState);
1548
1549impl AsRef<FfLatterAutolevelState> for FfLatterInputAutolevelParameters {
1550    fn as_ref(&self) -> &FfLatterAutolevelState {
1551        &self.0
1552    }
1553}
1554
1555impl AsMut<FfLatterAutolevelState> for FfLatterInputAutolevelParameters {
1556    fn as_mut(&mut self) -> &mut FfLatterAutolevelState {
1557        &mut self.0
1558    }
1559}
1560
1561/// Parameters of output autolevel.
1562#[derive(Debug, Clone, PartialEq, Eq)]
1563pub struct FfLatterOutputAutolevelParameters(pub FfLatterAutolevelState);
1564
1565impl AsRef<FfLatterAutolevelState> for FfLatterOutputAutolevelParameters {
1566    fn as_ref(&self) -> &FfLatterAutolevelState {
1567        &self.0
1568    }
1569}
1570
1571impl AsMut<FfLatterAutolevelState> for FfLatterOutputAutolevelParameters {
1572    fn as_mut(&mut self) -> &mut FfLatterAutolevelState {
1573        &mut self.0
1574    }
1575}
1576
1577/// The specification of autolevel in channel strip effects.
1578pub trait RmeFfLatterAutolevelSpecification {
1579    /// The minimum value of max gain.
1580    const AUTOLEVEL_MAX_GAIN_MIN: i32 = 0;
1581    /// The maximum value of max gain.
1582    const AUTOLEVEL_MAX_GAIN_MAX: i32 = 180;
1583    /// The step value of max gain.
1584    const AUTOLEVEL_MAX_GAIN_STEP: i32 = 1;
1585
1586    /// The minimum value of head room.
1587    const AUTOLEVEL_HEAD_ROOM_MIN: i32 = 30;
1588    /// The maximum value of head room.
1589    const AUTOLEVEL_HEAD_ROOM_MAX: i32 = 120;
1590    /// The step value of head room.
1591    const AUTOLEVEL_HEAD_ROOM_STEP: i32 = 1;
1592
1593    /// The minimum value of rise time.
1594    const AUTOLEVEL_RISE_TIME_MIN: i32 = 1;
1595    /// The maximum value of rise time.
1596    const AUTOLEVEL_RISE_TIME_MAX: i32 = 99;
1597    /// The step value of rise time.
1598    const AUTOLEVEL_RISE_TIME_STEP: i32 = 1;
1599}
1600
1601impl<O: RmeFfLatterDspSpecification> RmeFfLatterAutolevelSpecification for O {}
1602
1603impl<O> RmeFfCommandParamsSerialize<FfLatterInputAutolevelParameters> for O
1604where
1605    O: RmeFfLatterAutolevelSpecification + RmeFfLatterInputSpecification,
1606{
1607    fn serialize_commands(params: &FfLatterInputAutolevelParameters) -> Vec<u32> {
1608        autolevel_state_to_cmds(&params.0, 0)
1609    }
1610}
1611
1612impl<O> RmeFfCommandParamsSerialize<FfLatterOutputAutolevelParameters> for O
1613where
1614    O: RmeFfLatterAutolevelSpecification + RmeFfLatterOutputSpecification,
1615{
1616    fn serialize_commands(params: &FfLatterOutputAutolevelParameters) -> Vec<u32> {
1617        autolevel_state_to_cmds(&params.0, Self::PHYS_INPUT_COUNT as u8)
1618    }
1619}
1620
1621/// Parameters of sources to fx component.
1622#[derive(Default, Debug, Clone, PartialEq, Eq)]
1623pub struct FfLatterFxSourceParameters {
1624    /// The gain of line inputs. Each value is between 0xfd76 (-65.0 dB) and 0x0000 (0.0 dB).
1625    pub line_input_gains: Vec<i16>,
1626    /// The gain of mic inputs. Each value is between 0xfd76 (-65.0 dB) and 0x0000 (0.0 dB).
1627    pub mic_input_gains: Vec<i16>,
1628    /// The gain of S/PDIF inputs. Each value is between 0xfd76 (-65.0 dB) and 0x0000 (0.0 dB).
1629    pub spdif_input_gains: Vec<i16>,
1630    /// The gain of ADAT inputs. Each value is between 0xfd76 (-65.0 dB) and 0x0000 (0.0 dB).
1631    pub adat_input_gains: Vec<i16>,
1632    /// The gain of stream inputs. Each value is between 0x0000 (-65.0 dB) and 0x8b5c (0.0 dB).
1633    pub stream_input_gains: Vec<u16>,
1634}
1635
1636const FX_MIXER_0: u16 = 0x1e;
1637const FX_MIXER_1: u16 = 0x1f;
1638
1639impl<O> RmeFfCommandParamsSerialize<FfLatterFxSourceParameters> for O
1640where
1641    O: RmeFfLatterFxSpecification,
1642{
1643    fn serialize_commands(params: &FfLatterFxSourceParameters) -> Vec<u32> {
1644        let mut cmds = Vec::new();
1645
1646        params
1647            .line_input_gains
1648            .iter()
1649            .chain(&params.mic_input_gains)
1650            .chain(&params.spdif_input_gains)
1651            .chain(&params.adat_input_gains)
1652            .enumerate()
1653            .for_each(|(i, &gain)| {
1654                let ch = i as u8;
1655                cmds.push(create_phys_port_cmd(ch, INPUT_TO_FX_CMD, gain));
1656            });
1657
1658        params
1659            .stream_input_gains
1660            .iter()
1661            .enumerate()
1662            .for_each(|(i, &gain)| {
1663                cmds.push(create_virt_port_cmd(
1664                    Self::MIXER_STEP,
1665                    FX_MIXER_0,
1666                    Self::STREAM_OFFSET + i as u16,
1667                    gain,
1668                ));
1669                cmds.push(create_virt_port_cmd(
1670                    Self::MIXER_STEP,
1671                    FX_MIXER_1,
1672                    Self::STREAM_OFFSET + i as u16,
1673                    gain,
1674                ));
1675            });
1676
1677        cmds
1678    }
1679}
1680
1681/// Parameters of outputs from fx component.
1682#[derive(Default, Debug, Clone, PartialEq, Eq)]
1683pub struct FfLatterFxOutputParameters {
1684    /// The volume to line outputs. Each value is between 0xfd76 (-65.0 dB) and 0x0000 (0.0 dB).
1685    pub line_output_vols: Vec<i16>,
1686    /// The volume to hp outputs. Each value is between 0xfd76 (-65.0 dB) and 0x0000 (0.0 dB).
1687    pub hp_output_vols: Vec<i16>,
1688    /// The volume to S/PDIF outputs. Each value is between 0xfd76 (-65.0 dB) and 0x0000 (0.0 dB).
1689    pub spdif_output_vols: Vec<i16>,
1690    /// The volume to ADAT outputs. Each value is between 0xfd76 (-65.0 dB) and 0x0000 (0.0 dB).
1691    pub adat_output_vols: Vec<i16>,
1692}
1693
1694impl<O: RmeFfLatterFxSpecification> RmeFfCommandParamsSerialize<FfLatterFxOutputParameters> for O {
1695    fn serialize_commands(params: &FfLatterFxOutputParameters) -> Vec<u32> {
1696        params
1697            .line_output_vols
1698            .iter()
1699            .chain(&params.hp_output_vols)
1700            .chain(&params.spdif_output_vols)
1701            .chain(&params.adat_output_vols)
1702            .enumerate()
1703            .map(|(i, &gain)| {
1704                let ch = (Self::PHYS_INPUT_COUNT + i) as u8;
1705                create_phys_port_cmd(ch, OUTPUT_FROM_FX_CMD, gain)
1706            })
1707            .collect()
1708    }
1709}
1710
1711/// Type of reverb effect.
1712#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1713pub enum FfLatterFxReverbType {
1714    SmallRoom,
1715    MediumRoom,
1716    LargeRoom,
1717    Walls,
1718    Shorty,
1719    Attack,
1720    Swagger,
1721    OldSchool,
1722    Echoistic,
1723    EightPlusNine,
1724    GrandWide,
1725    Thicker,
1726    Envelope,
1727    Gated,
1728    Space,
1729}
1730
1731impl Default for FfLatterFxReverbType {
1732    fn default() -> Self {
1733        Self::SmallRoom
1734    }
1735}
1736
1737fn deserialize_fx_reverb_type(reverb_type: &FfLatterFxReverbType) -> i16 {
1738    match reverb_type {
1739        FfLatterFxReverbType::SmallRoom => 0x0000,
1740        FfLatterFxReverbType::MediumRoom => 0x0001,
1741        FfLatterFxReverbType::LargeRoom => 0x0002,
1742        FfLatterFxReverbType::Walls => 0x0003,
1743        FfLatterFxReverbType::Shorty => 0x0004,
1744        FfLatterFxReverbType::Attack => 0x0005,
1745        FfLatterFxReverbType::Swagger => 0x0006,
1746        FfLatterFxReverbType::OldSchool => 0x0007,
1747        FfLatterFxReverbType::Echoistic => 0x0008,
1748        FfLatterFxReverbType::EightPlusNine => 0x0009,
1749        FfLatterFxReverbType::GrandWide => 0x000a,
1750        FfLatterFxReverbType::Thicker => 0x000b,
1751        FfLatterFxReverbType::Envelope => 0x000c,
1752        FfLatterFxReverbType::Gated => 0x000d,
1753        FfLatterFxReverbType::Space => 0x000e,
1754    }
1755}
1756
1757/// Type of echo effect.
1758#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1759pub enum FfLatterFxEchoType {
1760    StereoEcho,
1761    StereoCross,
1762    PongEcho,
1763}
1764
1765impl Default for FfLatterFxEchoType {
1766    fn default() -> Self {
1767        Self::StereoEcho
1768    }
1769}
1770
1771fn deserialize_fx_echo_type(echo_type: &FfLatterFxEchoType) -> i16 {
1772    match echo_type {
1773        FfLatterFxEchoType::StereoEcho => 0x0000,
1774        FfLatterFxEchoType::StereoCross => 0x0001,
1775        FfLatterFxEchoType::PongEcho => 0x0002,
1776    }
1777}
1778
1779/// Frequency of low pass filter for echo effect.
1780#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1781pub enum FfLatterFxEchoLpfFreq {
1782    Off,
1783    H2000,
1784    H4000,
1785    H8000,
1786    H12000,
1787    H16000,
1788}
1789
1790impl Default for FfLatterFxEchoLpfFreq {
1791    fn default() -> Self {
1792        Self::Off
1793    }
1794}
1795
1796fn deserialize_fx_echo_lpf_freq(freq: &FfLatterFxEchoLpfFreq) -> i16 {
1797    match freq {
1798        FfLatterFxEchoLpfFreq::Off => 0x0000,
1799        FfLatterFxEchoLpfFreq::H2000 => 0x0005,
1800        FfLatterFxEchoLpfFreq::H4000 => 0x0004,
1801        FfLatterFxEchoLpfFreq::H8000 => 0x0003,
1802        FfLatterFxEchoLpfFreq::H12000 => 0x0002,
1803        FfLatterFxEchoLpfFreq::H16000 => 0x0001,
1804    }
1805}
1806
1807/// State of reverb in send effect.
1808#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
1809pub struct FfLatterFxReverbState {
1810    /// Whether to activate reverb effect.
1811    pub activate: bool,
1812    /// The type of reverb effect.
1813    pub reverb_type: FfLatterFxReverbType,
1814    /// The pre-delay of reverb effect between 0 and 999.
1815    pub pre_delay: u16,
1816    /// The frequency of high pass filter before reverb generation between 20 and 500 Hz.
1817    pub pre_hpf: u16,
1818    /// The scale of room between 50 and 300, displayed by 1/10.
1819    pub room_scale: u16,
1820    /// The time for increase volume between 5 and 400 ms.
1821    pub attack: u16,
1822    /// The time for fixed volume between 5 and 400 ms.
1823    pub hold: u16,
1824    /// The time for volume decrease between 5 and 500 ms.
1825    pub release: u16,
1826    /// The frequency of low pass filter after reverb generation between 200 and 20000 Hz.
1827    pub post_lpf: u16,
1828    /// The time for volume drop between 1 and 49, displayed by 1/10 sec.
1829    pub time: u16,
1830    /// The frequency of treble dampling for reverb generation between 2000 and 20000 Hz.
1831    pub damping: u16,
1832    /// The level of softener between 0 and 100.
1833    pub smooth: u16,
1834    /// The level of output between -650 and 60, displayed by 1/10.
1835    pub volume: i16,
1836    /// The stereo width between 0(monaural) and 100(stereo).
1837    pub stereo_width: u16,
1838}
1839
1840const FX_CH: u8 = 0x3c;
1841
1842fn reverb_state_to_cmds(state: &FfLatterFxReverbState) -> Vec<u32> {
1843    let mut cmds = Vec::new();
1844
1845    cmds.push(create_phys_port_cmd(
1846        FX_CH,
1847        FX_REVERB_ACTIVATE_CMD,
1848        state.activate as i16,
1849    ));
1850    cmds.push(create_phys_port_cmd(
1851        FX_CH,
1852        FX_REVERB_TYPE_CMD,
1853        deserialize_fx_reverb_type(&state.reverb_type),
1854    ));
1855    cmds.push(create_phys_port_cmd(
1856        FX_CH,
1857        FX_REVERB_PRE_DELAY_CMD,
1858        state.pre_delay as i16,
1859    ));
1860    cmds.push(create_phys_port_cmd(
1861        FX_CH,
1862        FX_REVERB_PRE_HPF_FREQ_CMD,
1863        state.pre_hpf as i16,
1864    ));
1865    cmds.push(create_phys_port_cmd(
1866        FX_CH,
1867        FX_REVERB_ROOM_SCALE_CMD,
1868        state.room_scale as i16,
1869    ));
1870    cmds.push(create_phys_port_cmd(
1871        FX_CH,
1872        FX_REVERB_ATTACK_CMD,
1873        state.attack as i16,
1874    ));
1875    cmds.push(create_phys_port_cmd(
1876        FX_CH,
1877        FX_REVERB_HOLD_CMD,
1878        state.hold as i16,
1879    ));
1880    cmds.push(create_phys_port_cmd(
1881        FX_CH,
1882        FX_REVERB_RELEASE_CMD,
1883        state.release as i16,
1884    ));
1885    cmds.push(create_phys_port_cmd(
1886        FX_CH,
1887        FX_REVERB_POST_LPF_FREQ_CMD,
1888        state.post_lpf as i16,
1889    ));
1890    cmds.push(create_phys_port_cmd(
1891        FX_CH,
1892        FX_REVERB_TIME_CMD,
1893        state.time as i16,
1894    ));
1895    cmds.push(create_phys_port_cmd(
1896        FX_CH,
1897        FX_REVERB_DAMPING_FREQ_CMD,
1898        state.damping as i16,
1899    ));
1900    cmds.push(create_phys_port_cmd(
1901        FX_CH,
1902        FX_REVERB_SMOOTH_CMD,
1903        state.smooth as i16,
1904    ));
1905    cmds.push(create_phys_port_cmd(
1906        FX_CH,
1907        FX_REVERB_VOLUME_CMD,
1908        state.volume,
1909    ));
1910    cmds.push(create_phys_port_cmd(
1911        FX_CH,
1912        FX_REVERB_STEREO_WIDTH_CMD,
1913        state.stereo_width as i16,
1914    ));
1915
1916    cmds
1917}
1918
1919impl<O: RmeFfLatterFxSpecification> RmeFfCommandParamsSerialize<FfLatterFxReverbState> for O {
1920    fn serialize_commands(params: &FfLatterFxReverbState) -> Vec<u32> {
1921        reverb_state_to_cmds(params)
1922    }
1923}
1924
1925/// State of echo in send effect.
1926#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
1927pub struct FfLatterFxEchoState {
1928    /// Whether to activate echo effect.
1929    pub activate: bool,
1930    /// The type of echo effect.
1931    pub echo_type: FfLatterFxEchoType,
1932    /// The time to delay for echo between 0 and 100.
1933    pub delay: u16,
1934    /// The level of feedback for further echo between 0 and 100.
1935    pub feedback: u16,
1936    /// The frequency of low pass filter.
1937    pub lpf: FfLatterFxEchoLpfFreq,
1938    /// The level of output between -650 and 0, displayed by 1/10.
1939    pub volume: i16,
1940    /// The stereo width between 0(monaural) and 100(stereo).
1941    pub stereo_width: u16,
1942}
1943
1944fn echo_state_to_cmds(state: &FfLatterFxEchoState) -> Vec<u32> {
1945    let mut cmds = Vec::new();
1946
1947    cmds.push(create_phys_port_cmd(
1948        FX_CH,
1949        FX_ECHO_ACTIVATE_CMD,
1950        state.activate as i16,
1951    ));
1952    cmds.push(create_phys_port_cmd(
1953        FX_CH,
1954        FX_ECHO_TYPE_CMD,
1955        deserialize_fx_echo_type(&state.echo_type),
1956    ));
1957    cmds.push(create_phys_port_cmd(
1958        FX_CH,
1959        FX_ECHO_DELAY_CMD,
1960        state.delay as i16,
1961    ));
1962    cmds.push(create_phys_port_cmd(
1963        FX_CH,
1964        FX_ECHO_FEEDBACK_CMD,
1965        state.feedback as i16,
1966    ));
1967    cmds.push(create_phys_port_cmd(
1968        FX_CH,
1969        FX_ECHO_LPF_FREQ_CMD,
1970        deserialize_fx_echo_lpf_freq(&state.lpf),
1971    ));
1972    cmds.push(create_phys_port_cmd(
1973        FX_CH,
1974        FX_ECHO_VOLUME_CMD,
1975        state.volume,
1976    ));
1977    cmds.push(create_phys_port_cmd(
1978        FX_CH,
1979        FX_ECHO_STEREO_WIDTH_CMD,
1980        state.stereo_width as i16,
1981    ));
1982
1983    cmds
1984}
1985
1986impl<O: RmeFfLatterFxSpecification> RmeFfCommandParamsSerialize<FfLatterFxEchoState> for O {
1987    fn serialize_commands(params: &FfLatterFxEchoState) -> Vec<u32> {
1988        echo_state_to_cmds(params)
1989    }
1990}
1991
1992/// The specification of FX.
1993pub trait RmeFfLatterFxSpecification: RmeFfLatterDspSpecification {
1994    /// The minimum value for .
1995    const FX_PHYS_LEVEL_MIN: i32 = -650;
1996    /// The maximum value for .
1997    const FX_PHYS_LEVEL_MAX: i32 = 0;
1998    /// The step value for .
1999    const FX_PHYS_LEVEL_STEP: i32 = 1;
2000
2001    /// The minimum value for .
2002    const FX_VIRT_LEVEL_MIN: i32 = 0;
2003    /// The maximum value for .
2004    const FX_VIRT_LEVEL_MAX: i32 = 35676;
2005    /// The step value for .
2006    const FX_VIRT_LEVEL_STEP: i32 = 1;
2007
2008    /// The minimum value for pre delay.
2009    const REVERB_PRE_DELAY_MIN: i32 = 0;
2010    /// The maximum value for pre delay.
2011    const REVERB_PRE_DELAY_MAX: i32 = 999;
2012    /// The step value for pre delay.
2013    const REVERB_PRE_DELAY_STEP: i32 = 1;
2014
2015    /// The minimum value for attack.
2016    const REVERB_ATTACK_MIN: i32 = 5;
2017    /// The maximum value for attack.
2018    const REVERB_ATTACK_MAX: i32 = 400;
2019    /// The step value for attack.
2020    const REVERB_ATTACK_STEP: i32 = 1;
2021
2022    /// The minimum value for hold.
2023    const REVERB_HOLD_MIN: i32 = 5;
2024    /// The maximum value for hold.
2025    const REVERB_HOLD_MAX: i32 = 400;
2026    /// The step value for hold.
2027    const REVERB_HOLD_STEP: i32 = 1;
2028
2029    /// The minimum value for release.
2030    const REVERB_RELEASE_MIN: i32 = 5;
2031    /// The maximum value for release.
2032    const REVERB_RELEASE_MAX: i32 = 500;
2033    /// The step value for release.
2034    const REVERB_RELEASE_STEP: i32 = 1;
2035
2036    /// The minimum value for post low pass filter.
2037    const REVERB_POST_LPF_FREQ_MIN: i32 = 200;
2038    /// The maximum value for post low pass filter.
2039    const REVERB_POST_LPF_FREQ_MAX: i32 = 20000;
2040    /// The step value for post low pass filter.
2041    const REVERB_POST_LPF_FREQ_STEP: i32 = 1;
2042
2043    /// The minimum value for decay time.
2044    const REVERB_TIME_MIN: i32 = 1;
2045    /// The maximum value for decay time.
2046    const REVERB_TIME_MAX: i32 = 49;
2047    /// The step value for decay time.
2048    const REVERB_TIME_STEP: i32 = 1;
2049
2050    /// The minimum value for damping.
2051    const REVERB_DAMPING_MIN: i32 = 2000;
2052    /// The maximum value for damping.
2053    const REVERB_DAMPING_MAX: i32 = 20000;
2054    /// The step value for damping.
2055    const REVERB_DAMPING_STEP: i32 = 1;
2056
2057    /// The minimum value for smooth.
2058    const REVERB_SMOOTH_MIN: i32 = 0;
2059    /// The maximum value for smooth.
2060    const REVERB_SMOOTH_MAX: i32 = 100;
2061    /// The step value for smooth.
2062    const REVERB_SMOOTH_STEP: i32 = 1;
2063
2064    /// The minimum value for volume.
2065    const REVERB_VOL_MIN: i32 = -650;
2066    /// The maximum value for volume.
2067    const REVERB_VOL_MAX: i32 = 60;
2068    /// The step value for volume.
2069    const REVERB_VOL_STEP: i32 = 1;
2070
2071    /// The minimum value for stereo width.
2072    const REVERB_STEREO_WIDTH_MIN: i32 = 0;
2073    /// The maximum value for stereo width.
2074    const REVERB_STEREO_WIDTH_MAX: i32 = 100;
2075    /// The step value for stereo width.
2076    const REVERB_STEREO_WIDTH_STEP: i32 = 1;
2077
2078    /// The minimum value for echo delay.
2079    const ECHO_DELAY_MIN: i32 = 0;
2080    /// The maximum value for echo delay.
2081    const ECHO_DELAY_MAX: i32 = 100;
2082    /// The step value for echo delay.
2083    const ECHO_DELAY_STEP: i32 = 1;
2084
2085    /// The minimum value for echo feedback.
2086    const ECHO_FEEDBACK_MIN: i32 = 0;
2087    /// The maximum value for echo feedback.
2088    const ECHO_FEEDBACK_MAX: i32 = 100;
2089    /// The step value for echo feedback.
2090    const ECHO_FEEDBACK_STEP: i32 = 1;
2091
2092    /// The minimum value for echo volume.
2093    const ECHO_VOL_MIN: i32 = -650;
2094    /// The maximum value for echo volume.
2095    const ECHO_VOL_MAX: i32 = 0;
2096    /// The step value for echo volume.
2097    const ECHO_VOL_STEP: i32 = 1;
2098
2099    /// The minimum value for echo stereo width.
2100    const ECHO_STEREO_WIDTH_MIN: i32 = 0;
2101    /// The maximum value for echo stereo width.
2102    const ECHO_STEREO_WIDTH_MAX: i32 = 100;
2103    /// The step value for echo stereo width.
2104    const ECHO_STEREO_WIDTH_STEP: i32 = 1;
2105
2106    /// Instantiate fx source parameters.
2107    fn create_fx_sources_parameters() -> FfLatterFxSourceParameters {
2108        FfLatterFxSourceParameters {
2109            line_input_gains: vec![0; Self::LINE_INPUT_COUNT],
2110            mic_input_gains: vec![0; Self::MIC_INPUT_COUNT],
2111            spdif_input_gains: vec![0; Self::SPDIF_INPUT_COUNT],
2112            adat_input_gains: vec![0; Self::ADAT_INPUT_COUNT],
2113            stream_input_gains: vec![0; Self::STREAM_INPUT_COUNT],
2114        }
2115    }
2116
2117    /// Instantiate fx output parameters.
2118    fn create_fx_output_parameters() -> FfLatterFxOutputParameters {
2119        FfLatterFxOutputParameters {
2120            line_output_vols: vec![0; Self::LINE_OUTPUT_COUNT],
2121            hp_output_vols: vec![0; Self::HP_OUTPUT_COUNT],
2122            spdif_output_vols: vec![0; Self::SPDIF_OUTPUT_COUNT],
2123            adat_output_vols: vec![0; Self::ADAT_OUTPUT_COUNT],
2124        }
2125    }
2126}
2127
2128impl<O: RmeFfLatterDspSpecification> RmeFfLatterFxSpecification for O {}
2129
2130#[cfg(test)]
2131mod test {
2132    use super::*;
2133
2134    #[test]
2135    fn midi_tx_low_offset_serdes() {
2136        [
2137            FfLatterMidiTxLowOffset::A0000,
2138            FfLatterMidiTxLowOffset::A0080,
2139            FfLatterMidiTxLowOffset::A0100,
2140            FfLatterMidiTxLowOffset::A0180,
2141        ]
2142        .iter()
2143        .for_each(|orig| {
2144            let mut quad = 0;
2145            serialize_midi_tx_low_offset(orig, &mut quad);
2146            let mut target = FfLatterMidiTxLowOffset::default();
2147            deserialize_midi_tx_low_offset(&mut target, &quad);
2148
2149            assert_eq!(&target, orig);
2150        });
2151    }
2152
2153    #[test]
2154    fn clock_rate_serdes() {
2155        [
2156            ClkNominalRate::R32000,
2157            ClkNominalRate::R44100,
2158            ClkNominalRate::R48000,
2159            ClkNominalRate::R64000,
2160            ClkNominalRate::R88200,
2161            ClkNominalRate::R96000,
2162            ClkNominalRate::R128000,
2163            ClkNominalRate::R176400,
2164            ClkNominalRate::R192000,
2165        ]
2166        .iter()
2167        .for_each(|orig| {
2168            let mut quad = 0;
2169            serialize_clock_rate(orig, &mut quad, 0);
2170            let mut target = ClkNominalRate::default();
2171            deserialize_clock_rate(&mut target, &quad, 0);
2172
2173            assert_eq!(&target, orig);
2174        });
2175    }
2176}