1pub 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
15const 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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24enum FfLatterMidiTxLowOffset {
25 A0000,
27 A0080,
29 A0100,
31 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
81const 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
169pub trait RmeFfLatterSpecification {
171 const LINE_INPUT_COUNT: usize;
173 const MIC_INPUT_COUNT: usize;
175 const SPDIF_INPUT_COUNT: usize;
177 const ADAT_INPUT_COUNT: usize;
179 const STREAM_INPUT_COUNT: usize;
181
182 const LINE_OUTPUT_COUNT: usize;
184 const HP_OUTPUT_COUNT: usize;
186 const SPDIF_OUTPUT_COUNT: usize;
188 const ADAT_OUTPUT_COUNT: usize;
190}
191
192#[derive(Default, Debug, Clone, PartialEq, Eq)]
197pub struct FfLatterMeterState {
198 pub line_inputs: Vec<i32>,
200 pub mic_inputs: Vec<i32>,
202 pub spdif_inputs: Vec<i32>,
204 pub adat_inputs: Vec<i32>,
206 pub stream_inputs: Vec<i32>,
208 pub line_outputs: Vec<i32>,
210 pub hp_outputs: Vec<i32>,
212 pub spdif_outputs: Vec<i32>,
214 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
222pub 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
245impl<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 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 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 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 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
401pub trait RmeFfCommandParamsSerialize<T> {
403 fn serialize_commands(params: &T) -> Vec<u32>;
405}
406
407pub trait RmeFfCommandParamsDeserialize<T> {
409 fn deserialize_commands(params: &mut T, raw: &[u32]);
411}
412
413pub trait RmeFfWhollyCommandableParamsOperation<T> {
415 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
440pub 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
469pub 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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
559pub enum LatterInNominalLevel {
560 Low,
561 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#[derive(Debug, Clone, PartialEq, Eq)]
580pub struct FfLatterInputState {
581 pub stereo_links: Vec<bool>,
583 pub invert_phases: Vec<bool>,
585 pub line_gains: Vec<i16>,
587 pub line_levels: Vec<LatterInNominalLevel>,
589 pub mic_powers: Vec<bool>,
592 pub mic_insts: Vec<bool>,
594}
595
596pub trait RmeFfLatterInputSpecification: RmeFfLatterDspSpecification {
598 const PHYS_INPUT_GAIN_MIN: i32 = 0;
600 const PHYS_INPUT_GAIN_MAX: i32 = 120;
602 const PHYS_INPUT_GAIN_STEP: i32 = 1;
604
605 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 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 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 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 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 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 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#[derive(Debug, Clone, PartialEq, Eq)]
746pub struct FfLatterOutputState {
747 pub vols: Vec<i16>,
750 pub stereo_balance: Vec<i16>,
752 pub stereo_links: Vec<bool>,
754 pub invert_phases: Vec<bool>,
756 pub line_levels: Vec<LineOutNominalLevel>,
758}
759
760pub trait RmeFfLatterOutputSpecification: RmeFfLatterDspSpecification {
762 const PHYS_OUTPUT_VOL_MIN: i32 = -650;
764 const PHYS_OUTPUT_VOL_MAX: i32 = 60;
766 const PHYS_OUTPUT_VOL_STEP: i32 = 1;
768
769 const PHYS_OUTPUT_BALANCE_MIN: i32 = -100;
771 const PHYS_OUTPUT_BALANCE_MAX: i32 = 100;
773 const PHYS_OUTPUT_BALANCE_STEP: i32 = 1;
775
776 const CH_OFFSET: u8 = Self::PHYS_INPUT_COUNT as u8;
778 const OUTPUT_PAIR_COUNT: usize = Self::OUTPUT_COUNT / 2;
780
781 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 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 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 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 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#[derive(Debug, Clone, PartialEq, Eq)]
919pub struct FfLatterMixer {
920 pub line_gains: Vec<u16>,
922 pub mic_gains: Vec<u16>,
924 pub spdif_gains: Vec<u16>,
926 pub adat_gains: Vec<u16>,
928 pub stream_gains: Vec<u16>,
930}
931
932#[derive(Debug, Clone, PartialEq, Eq)]
934pub struct FfLatterMixerState(pub Vec<FfLatterMixer>);
935
936pub trait RmeFfLatterMixerSpecification: RmeFfLatterDspSpecification {
938 const MIXER_INPUT_GAIN_MIN: i32 = 0x0000;
940 const MIXER_INPUT_GAIN_ZERO: i32 = 0x9000;
942 const MIXER_INPUT_GAIN_MAX: i32 = 0xa000;
944 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#[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#[derive(Debug, Clone, PartialEq, Eq)]
1014pub struct FfLatterHpfState {
1015 pub activates: Vec<bool>,
1017 pub cut_offs: Vec<u16>,
1019 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#[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#[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
1083pub trait RmeFfLatterHpfSpecification {
1085 const HPF_CUT_OFF_MIN: i32 = 20;
1087 const HPF_CUT_OFF_MAX: i32 = 500;
1089 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(¶ms.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(¶ms.0, Self::PHYS_INPUT_COUNT as u8)
1110 }
1111}
1112
1113#[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#[derive(Debug, Clone, PartialEq, Eq)]
1137pub struct FfLatterEqState {
1138 pub activates: Vec<bool>,
1140 pub low_types: Vec<FfLatterChStripEqType>,
1142 pub low_gains: Vec<i16>,
1144 pub low_freqs: Vec<u16>,
1146 pub low_qualities: Vec<u16>,
1148 pub middle_gains: Vec<i16>,
1150 pub middle_freqs: Vec<u16>,
1152 pub middle_qualities: Vec<u16>,
1154 pub high_types: Vec<FfLatterChStripEqType>,
1156 pub high_gains: Vec<i16>,
1158 pub high_freqs: Vec<u16>,
1160 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#[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#[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
1278pub trait RmeFfLatterEqualizerSpecification {
1280 const EQ_GAIN_MIN: i32 = -20;
1282 const EQ_GAIN_MAX: i32 = 20;
1284 const EQ_GAIN_STEP: i32 = 1;
1286
1287 const EQ_FREQ_MIN: i32 = 20;
1289 const EQ_FREQ_MAX: i32 = 20000;
1291 const EQ_FREQ_STEP: i32 = 1;
1293
1294 const EQ_QUALITY_MIN: i32 = 7;
1296 const EQ_QUALITY_MAX: i32 = 50;
1298 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(¶ms.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(¶ms.0, Self::PHYS_INPUT_COUNT as u8)
1319 }
1320}
1321
1322#[derive(Debug, Clone, PartialEq, Eq)]
1324pub struct FfLatterDynState {
1325 pub activates: Vec<bool>,
1327 pub gains: Vec<i16>,
1329 pub attacks: Vec<u16>,
1331 pub releases: Vec<u16>,
1333 pub compressor_thresholds: Vec<i16>,
1335 pub compressor_ratios: Vec<u16>,
1337 pub expander_thresholds: Vec<i16>,
1339 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#[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#[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
1433pub trait RmeFfLatterDynamicsSpecification {
1435 const DYN_GAIN_MIN: i32 = -300;
1437 const DYN_GAIN_MAX: i32 = 300;
1439 const DYN_GAIN_STEP: i32 = 1;
1441
1442 const DYN_ATTACK_MIN: i32 = 0;
1444 const DYN_ATTACK_MAX: i32 = 200;
1446 const DYN_ATTACK_STEP: i32 = 1;
1448
1449 const DYN_RELEASE_MIN: i32 = 100;
1451 const DYN_RELEASE_MAX: i32 = 999;
1453 const DYN_RELEASE_STEP: i32 = 1;
1455
1456 const DYN_COMP_THRESHOLD_MIN: i32 = -600;
1458 const DYN_COMP_THRESHOLD_MAX: i32 = 0;
1460 const DYN_COMP_THRESHOLD_STEP: i32 = 1;
1462
1463 const DYN_RATIO_MIN: i32 = 10;
1465 const DYN_RATIO_MAX: i32 = 100;
1467 const DYN_RATIO_STEP: i32 = 1;
1469
1470 const DYN_EX_THRESHOLD_MIN: i32 = -999;
1472 const DYN_EX_THRESHOLD_MAX: i32 = -200;
1474 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(¶ms.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(¶ms.0, Self::PHYS_INPUT_COUNT as u8)
1495 }
1496}
1497
1498#[derive(Debug, Clone, PartialEq, Eq)]
1500pub struct FfLatterAutolevelState {
1501 pub activates: Vec<bool>,
1503 pub max_gains: Vec<u16>,
1505 pub headrooms: Vec<u16>,
1507 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#[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#[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
1577pub trait RmeFfLatterAutolevelSpecification {
1579 const AUTOLEVEL_MAX_GAIN_MIN: i32 = 0;
1581 const AUTOLEVEL_MAX_GAIN_MAX: i32 = 180;
1583 const AUTOLEVEL_MAX_GAIN_STEP: i32 = 1;
1585
1586 const AUTOLEVEL_HEAD_ROOM_MIN: i32 = 30;
1588 const AUTOLEVEL_HEAD_ROOM_MAX: i32 = 120;
1590 const AUTOLEVEL_HEAD_ROOM_STEP: i32 = 1;
1592
1593 const AUTOLEVEL_RISE_TIME_MIN: i32 = 1;
1595 const AUTOLEVEL_RISE_TIME_MAX: i32 = 99;
1597 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(¶ms.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(¶ms.0, Self::PHYS_INPUT_COUNT as u8)
1618 }
1619}
1620
1621#[derive(Default, Debug, Clone, PartialEq, Eq)]
1623pub struct FfLatterFxSourceParameters {
1624 pub line_input_gains: Vec<i16>,
1626 pub mic_input_gains: Vec<i16>,
1628 pub spdif_input_gains: Vec<i16>,
1630 pub adat_input_gains: Vec<i16>,
1632 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(¶ms.mic_input_gains)
1650 .chain(¶ms.spdif_input_gains)
1651 .chain(¶ms.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#[derive(Default, Debug, Clone, PartialEq, Eq)]
1683pub struct FfLatterFxOutputParameters {
1684 pub line_output_vols: Vec<i16>,
1686 pub hp_output_vols: Vec<i16>,
1688 pub spdif_output_vols: Vec<i16>,
1690 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(¶ms.hp_output_vols)
1700 .chain(¶ms.spdif_output_vols)
1701 .chain(¶ms.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#[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#[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#[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#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
1809pub struct FfLatterFxReverbState {
1810 pub activate: bool,
1812 pub reverb_type: FfLatterFxReverbType,
1814 pub pre_delay: u16,
1816 pub pre_hpf: u16,
1818 pub room_scale: u16,
1820 pub attack: u16,
1822 pub hold: u16,
1824 pub release: u16,
1826 pub post_lpf: u16,
1828 pub time: u16,
1830 pub damping: u16,
1832 pub smooth: u16,
1834 pub volume: i16,
1836 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#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
1927pub struct FfLatterFxEchoState {
1928 pub activate: bool,
1930 pub echo_type: FfLatterFxEchoType,
1932 pub delay: u16,
1934 pub feedback: u16,
1936 pub lpf: FfLatterFxEchoLpfFreq,
1938 pub volume: i16,
1940 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
1992pub trait RmeFfLatterFxSpecification: RmeFfLatterDspSpecification {
1994 const FX_PHYS_LEVEL_MIN: i32 = -650;
1996 const FX_PHYS_LEVEL_MAX: i32 = 0;
1998 const FX_PHYS_LEVEL_STEP: i32 = 1;
2000
2001 const FX_VIRT_LEVEL_MIN: i32 = 0;
2003 const FX_VIRT_LEVEL_MAX: i32 = 35676;
2005 const FX_VIRT_LEVEL_STEP: i32 = 1;
2007
2008 const REVERB_PRE_DELAY_MIN: i32 = 0;
2010 const REVERB_PRE_DELAY_MAX: i32 = 999;
2012 const REVERB_PRE_DELAY_STEP: i32 = 1;
2014
2015 const REVERB_ATTACK_MIN: i32 = 5;
2017 const REVERB_ATTACK_MAX: i32 = 400;
2019 const REVERB_ATTACK_STEP: i32 = 1;
2021
2022 const REVERB_HOLD_MIN: i32 = 5;
2024 const REVERB_HOLD_MAX: i32 = 400;
2026 const REVERB_HOLD_STEP: i32 = 1;
2028
2029 const REVERB_RELEASE_MIN: i32 = 5;
2031 const REVERB_RELEASE_MAX: i32 = 500;
2033 const REVERB_RELEASE_STEP: i32 = 1;
2035
2036 const REVERB_POST_LPF_FREQ_MIN: i32 = 200;
2038 const REVERB_POST_LPF_FREQ_MAX: i32 = 20000;
2040 const REVERB_POST_LPF_FREQ_STEP: i32 = 1;
2042
2043 const REVERB_TIME_MIN: i32 = 1;
2045 const REVERB_TIME_MAX: i32 = 49;
2047 const REVERB_TIME_STEP: i32 = 1;
2049
2050 const REVERB_DAMPING_MIN: i32 = 2000;
2052 const REVERB_DAMPING_MAX: i32 = 20000;
2054 const REVERB_DAMPING_STEP: i32 = 1;
2056
2057 const REVERB_SMOOTH_MIN: i32 = 0;
2059 const REVERB_SMOOTH_MAX: i32 = 100;
2061 const REVERB_SMOOTH_STEP: i32 = 1;
2063
2064 const REVERB_VOL_MIN: i32 = -650;
2066 const REVERB_VOL_MAX: i32 = 60;
2068 const REVERB_VOL_STEP: i32 = 1;
2070
2071 const REVERB_STEREO_WIDTH_MIN: i32 = 0;
2073 const REVERB_STEREO_WIDTH_MAX: i32 = 100;
2075 const REVERB_STEREO_WIDTH_STEP: i32 = 1;
2077
2078 const ECHO_DELAY_MIN: i32 = 0;
2080 const ECHO_DELAY_MAX: i32 = 100;
2082 const ECHO_DELAY_STEP: i32 = 1;
2084
2085 const ECHO_FEEDBACK_MIN: i32 = 0;
2087 const ECHO_FEEDBACK_MAX: i32 = 100;
2089 const ECHO_FEEDBACK_STEP: i32 = 1;
2091
2092 const ECHO_VOL_MIN: i32 = -650;
2094 const ECHO_VOL_MAX: i32 = 0;
2096 const ECHO_VOL_STEP: i32 = 1;
2098
2099 const ECHO_STEREO_WIDTH_MIN: i32 = 0;
2101 const ECHO_STEREO_WIDTH_MAX: i32 = 100;
2103 const ECHO_STEREO_WIDTH_STEP: i32 = 1;
2105
2106 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 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}