firewire_dice_protocols/presonus/
fstudio.rs

1// SPDX-License-Identifier: LGPL-3.0-or-later
2// Copyright (c) 2021 Takashi Sakamoto
3
4//! Protocol implementation for PreSonus FireStudio.
5//!
6//! ## Diagram of internal signal flow
7//!
8//! ```text
9//!
10//! analog-input-1/2 ---------------------------> stream-output-A-1/2
11//! analog-input-3/4 ---------------------------> stream-output-A-3/4
12//! analog-input-5/6 ---------------------------> stream-output-A-5/6
13//! analog-input-7/8 ---------------------------> stream-output-A-7/8
14//! adat-input-1/2 -----------------------------> stream-output-A-9/10
15//! adat-input-3/4 -----------------------------> stream-output-A-11/12
16//! adat-input-5/6 -----------------------------> stream-output-A-13/14
17//! adat-input-7/8 -----------------------------> stream-output-A-15/16
18//! adat-input-9/10 ----------------------------> stream-output-B-1/2
19//! adat-input-11/12 ---------------------------> stream-output-B-3/4
20//! adat-input-13/14 ---------------------------> stream-output-B-5/6
21//! adat-input-15/16 ---------------------------> stream-output-B-7/8
22//! spdif-input-1/2 ----------------------------> stream-output-B-9/10
23//!
24//! analog-input-1/2 ---------------------------> mixer-source-1/2
25//! analog-input-3/4 ---------------------------> mixer-source-3/4
26//! analog-input-5/6 ---------------------------> mixer-source-5/6
27//! analog-input-7/8 ---------------------------> mixer-source-7/8
28//! adat-input-1/2 -----------------------------> mixer-source-9/10
29//! adat-input-3/4 -----------------------------> mixer-source-11/12
30//! adat-input-5/6 -----------------------------> mixer-source-13/14
31//! adat-input-7/8 -----------------------------> mixer-source-15/16
32//! spdif-input-1/2 ----------------------------> mixer-source-17/18
33//! stream-input-A-1/2 -------------------------> mixer-source-19/20
34//! stream-input-A-3/4 -------------------------> mixer-source-21/22
35//! stream-input-A-5/6 -------------------------> mixer-source-23/24
36//! stream-input-A-7/8 -------------------------> mixer-source-25/26
37//! stream-input-B-9/10 ------------------------> mixer-source-27/28
38//! adat-input-9..16 --------------or-----------> mixer-source-29..36
39//! stream-input-A-9..16 ----------+
40//!
41//!                           ++===========++
42//! mixer-source-1/2 -------> ||           ||
43//! mixer-source-3/4 -------> ||           ||
44//! mixer-source-5/6 -------> ||           ||
45//! mixer-source-7/8 -------> ||           ||
46//! mixer-source-9/10 ------> ||           ||
47//! mixer-source-11/12 -----> ||           || --> mixer-output-1/2
48//! mixer-source-13/14 -----> ||           || --> mixer-output-3/4
49//! mixer-source-15/16 -----> ||           || --> mixer-output-5/6
50//! mixer-source-17/18 -----> ||  36 x 18  || --> mixer-output-7/8
51//! mixer-source-19/20 -----> ||           || --> mixer-output-9/10
52//! mixer-source-21/22 -----> ||   mixer   || --> mixer-output-11/12
53//! mixer-source-23/24 -----> ||           || --> mixer-output-13/14
54//! mixer-source-25/26 -----> ||           || --> mixer-output-15/15
55//! mixer-source-27/28 -----> ||           || --> mixer-output-17/18
56//! mixer-source-29/30 -----> ||           ||
57//! mixer-source-31/32 -----> ||           ||
58//! mixer-source-33/34 -----> ||           ||
59//! mixer-source-35/36 -----> ||           ||
60//!                           ++===========++
61//!
62//!                           ++===========++
63//! mixer-source-1/2 -------> ||           ||
64//! mixer-source-3/4 -------> ||           ||
65//! mixer-source-5/6 -------> ||           ||
66//! mixer-source-7/8 -------> ||           ||
67//! mixer-source-9/10 ------> ||           ||
68//! mixer-source-11/12 -----> ||           ||
69//! mixer-source-13/14 -----> ||           ||
70//! mixer-source-15/16 -----> ||           ||
71//! mixer-source-17/18 -----> ||           ||
72//! mixer-source-19/20 -----> ||           || --> analog-output-1/2
73//! mixer-source-21/22 -----> ||           || --> analog-output-3/4
74//! mixer-source-23/24 -----> ||           || --> analog-output-5/6
75//! mixer-source-25/27 -----> ||  54 x 18  || --> analog-output-7/8
76//! mixer-source-27/28 -----> ||           || --> adat-output-1/2
77//! mixer-source-29/30 -----> ||           || --> adat-output-3/4
78//! mixer-source-31/32 -----> ||  router   || --> adat-output-5/6
79//! mixer-source-33/34 -----> ||           || --> adat-output-7/8
80//! mixer-source-35/36 -----> ||           || --> spdif-output-1/2
81//! mixer-output-1/2 -------> ||           ||
82//! mixer-output-3/4 -------> ||           ||
83//! mixer-output-5/6 -------> ||           ||
84//! mixer-output-7/8 -------> ||           ||
85//! mixer-output-9/10 ------> ||           ||
86//! mixer-output-11/12 -----> ||           ||
87//! mixer-output-13/14 -----> ||           ||
88//! mixer-output-15/15 -----> ||           ||
89//! mixer-output-17/18 -----> ||           ||
90//!                           ++===========++
91//!
92//! stream-input-B-1/2 -------------------------> adat-output-9/10
93//! stream-input-B-3/4 -------------------------> adat-output-11/12
94//! stream-input-B-5/6 -------------------------> adat-output-13/14
95//! stream-input-B-7/8 -------------------------> adat-output-15/16
96//!
97//!                           ++===========++
98//! analog-output-1/2 ------> ||           ||
99//! analog-output-3/4 ------> ||           ||
100//! analog-output-5/6 ------> ||           || --> main-output-1/2
101//! analog-output-7/8 ------> ||  18 x 8   || --> headphone-output-1/2
102//! adat-output-1/2 --------> ||           || --> headphone-output-3/4
103//! adat-output-3/4 --------> ||  router   || --> headphone-output-5/6
104//! adat-output-5/6 --------> ||           ||
105//! adat-output-7/8 --------> ||           ||
106//! spdif-output-1/2 -------> ||           ||
107//!                           ++===========++
108//!
109
110use {
111    super::{super::tcat::global_section::*, *},
112    std::ops::Range,
113};
114
115/// Protocol implementation specific to FireStudio.
116#[derive(Default, Debug)]
117pub struct FStudioProtocol;
118
119impl TcatOperation for FStudioProtocol {}
120
121// MEMO: the device returns 'SPDIF\ADAT\Word Clock\Unused\Unused\Unused\Unused\Internal\\'.
122impl TcatGlobalSectionSpecification for FStudioProtocol {
123    const CLOCK_SOURCE_LABEL_TABLE: &'static [ClockSource] = &[
124        ClockSource::Aes1,
125        ClockSource::Adat,
126        ClockSource::WordClock,
127        ClockSource::Arx1,
128        ClockSource::Arx2,
129        ClockSource::Arx3,
130        ClockSource::Arx4,
131        ClockSource::Internal,
132    ];
133}
134
135impl FStudioOperation for FStudioProtocol {}
136
137const OFFSET: usize = 0x00700000;
138
139const MIXER_PHYS_SRC_PARAMS_OFFSET: usize = 0x0038;
140const MIXER_STREAM_SRC_PARAMS_OFFSET: usize = 0x07d0;
141const MIXER_SELECTABLE_SRC_PARAMS_OFFSET: usize = 0x0c08;
142const OUTPUT_PARAMS_OFFSET: usize = 0x0f68;
143const MIXER_OUTPUT_PARAMS_OFFSET: usize = 0x1040;
144const OUTPUT_SRC_OFFSET: usize = 0x10ac;
145const OUTPUT_ASSIGN_OFFSET: usize = 0x10f4;
146const OUTPUT_BNC_TERMINATE_OFFSET: usize = 0x1118;
147const MIXER_EXPANSION_MODE_OFFSET: usize = 0x1128;
148const MIXER_SRC_LINK_OFFSET: usize = 0x112c;
149const OUTPUT_LINK_OFFSET: usize = 0x1150;
150const METER_OFFSET: usize = 0x13e8;
151
152// For volume, unused, mute of 8 analog outputs, 8 ADAT0 outputs, and 2 S/PDIF outputs.
153const OUTPUT_PARAMS_SIZE: usize = 4 * 3 * (8 + 8 + 2);
154// For source of 8 analog outputs, 8 ADAT0 outputs, and 2 S/PDIF outputs.
155const OUTPUT_SRC_SIZE: usize = 4 * (8 + 8 + 2);
156// Assignment to main and 3 headphone outputs.
157const OUTPUT_ASSIGN_SIZE: usize = 4 * 4;
158const OUTPUT_BNC_TERMINATE_SIZE: usize = 4;
159// Link bit flags for 8 analog outputs, 8 ADAT0 outputs, and 2 S/PDIF outputs.
160const OUTPUT_LINK_SIZE: usize = 4;
161
162// For gain, pan, mute of 8 analog inputs, 8 Adat0 inputs, and 2 S/PDIF inputs in 9 stereo mixers.
163const MIXER_PHYS_SRC_PARAMS_SIZE: usize = 4 * 9 * 3 * (8 + 8 + 2);
164// For gain, pan, mute of 10 stream inputs in 9 stereo mixers.
165const MIXER_STREAM_SRC_PARAMS_SIZE: usize = 4 * 9 * 3 * 10;
166// For gain, pan, mute of 8 selectable inputs in 9 stereo mixers.
167const MIXER_SELECTABLE_SRC_PARAMS_SIZE: usize = 4 * 9 * 3 * 8;
168// For gain, unused, mute of output pairs from 9 stereo mixers.
169const MIXER_OUTPUT_PARAMS_SIZE: usize = 4 * 9 * 3;
170const MIXER_EXPANSION_MODE_SIZE: usize = 4;
171// For pair link of source pairs in 9 stereo mixers.
172const MIXER_SRC_LINK_SIZE: usize = 4 * 9;
173
174/// Serialize and deserialize parameters for FireStudio.
175pub trait FStudioParametersSerdes<T> {
176    /// The representative name of parameters.
177    const NAME: &'static str;
178
179    /// The list of ranges for offset and size.
180    const OFFSET_RANGES: &'static [Range<usize>];
181
182    /// Serialize for raw data.
183    fn serialize_params(params: &T, raw: &mut [u8]) -> Result<(), String>;
184
185    /// Deserialize for raw data.
186    fn deserialize_params(params: &mut T, raw: &[u8]) -> Result<(), String>;
187}
188
189fn compute_params_size(ranges: &[Range<usize>]) -> usize {
190    ranges
191        .iter()
192        .fold(0usize, |size, range| size + range.end - range.start)
193}
194
195fn generate_err(name: &str, cause: &str, raw: &[u8]) -> Error {
196    let msg = format!("params: {}, cause: {}, raw: {:02x?}", name, cause, raw);
197    Error::new(GeneralProtocolError::VendorDependent, &msg)
198}
199
200/// Operation for parameters in FireStudio.
201pub trait FStudioOperation: TcatOperation {
202    fn read_parameters(
203        req: &FwReq,
204        node: &FwNode,
205        offset: usize,
206        raw: &mut [u8],
207        timeout_ms: u32,
208    ) -> Result<(), Error> {
209        Self::read(req, node, OFFSET + offset, raw, timeout_ms)
210    }
211
212    fn write_parameters(
213        req: &FwReq,
214        node: &FwNode,
215        offset: usize,
216        raw: &mut [u8],
217        timeout_ms: u32,
218    ) -> Result<(), Error> {
219        Self::write(req, node, OFFSET + offset, raw, timeout_ms)
220    }
221}
222
223/// Operation for parameters to cache state of hardware.
224pub trait FStudioParametersOperation<T>: FStudioOperation + FStudioParametersSerdes<T> {
225    /// Cache state of hardware for whole parameters.
226    fn cache_whole_parameters(
227        req: &FwReq,
228        node: &FwNode,
229        params: &mut T,
230        timeout_ms: u32,
231    ) -> Result<(), Error> {
232        let size = compute_params_size(Self::OFFSET_RANGES);
233        let mut raw = vec![0u8; size];
234
235        let mut pos = 0;
236
237        Self::OFFSET_RANGES.iter().try_for_each(|range| {
238            let size = range.end - range.start;
239            Self::read_parameters(
240                req,
241                node,
242                range.start,
243                &mut raw[pos..(pos + size)],
244                timeout_ms,
245            )
246            .map(|_| pos += size)
247        })?;
248
249        Self::deserialize_params(params, &raw)
250            .map_err(|cause| generate_err(Self::NAME, &cause, &raw))
251    }
252}
253
254impl<O: FStudioOperation + FStudioParametersSerdes<T>, T> FStudioParametersOperation<T> for O {}
255
256/// Operation for parameters to update state of hardware.
257pub trait FStudioMutableParametersOperation<T>:
258    FStudioOperation + FStudioParametersSerdes<T>
259{
260    /// Update the hardware partially for any change of parameter.
261    fn update_partial_parameters(
262        req: &FwReq,
263        node: &FwNode,
264        params: &T,
265        prev: &mut T,
266        timeout_ms: u32,
267    ) -> Result<(), Error> {
268        let size = compute_params_size(Self::OFFSET_RANGES);
269
270        let mut new = vec![0u8; size];
271        let mut old = vec![0u8; size];
272        Self::serialize_params(params, &mut new)
273            .map_err(|cause| generate_err(Self::NAME, &cause, &new))?;
274        Self::serialize_params(prev, &mut old)
275            .map_err(|cause| generate_err(Self::NAME, &cause, &old))?;
276
277        let mut pos = 0;
278
279        Self::OFFSET_RANGES.iter().try_for_each(|range| {
280            let size = range.end - range.start;
281
282            if new[pos..(pos + size)] != old[pos..(pos + size)] {
283                (0..size).step_by(4).try_for_each(|offset| {
284                    let p = pos + offset;
285                    if new[p..(p + 4)] != old[p..(p + 4)] {
286                        Self::write_parameters(
287                            req,
288                            node,
289                            range.start + offset,
290                            &mut new[p..(p + 4)],
291                            timeout_ms,
292                        )
293                    } else {
294                        Ok(())
295                    }
296                })
297            } else {
298                Ok(())
299            }
300            .map(|_| pos += size)
301        })?;
302
303        Self::deserialize_params(prev, &new).map_err(|cause| generate_err(Self::NAME, &cause, &new))
304    }
305}
306
307/// Hardware meter.
308#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
309pub struct FStudioMeter {
310    /// Detected levels for analog inputs.
311    pub analog_inputs: [u8; 8],
312    /// Detected levels for stream inputs.
313    pub stream_inputs: [u8; 18],
314    /// Detected levels for mixer outputs.
315    pub mixer_outputs: [u8; 18],
316}
317
318impl FStudioMeter {
319    const SIZE: usize = 64;
320}
321
322impl FStudioParametersSerdes<FStudioMeter> for FStudioProtocol {
323    const NAME: &'static str = "meter";
324
325    const OFFSET_RANGES: &'static [Range<usize>] = &[Range {
326        start: METER_OFFSET,
327        end: METER_OFFSET + FStudioMeter::SIZE,
328    }];
329
330    fn serialize_params(params: &FStudioMeter, raw: &mut [u8]) -> Result<(), String> {
331        [
332            (8, &params.analog_inputs[..]),
333            (16, &params.stream_inputs[..]),
334            (40, &params.mixer_outputs[..]),
335        ]
336        .iter()
337        .for_each(|(offset, meters)| {
338            meters.iter().enumerate().for_each(|(i, &meter)| {
339                let pos = *offset + (i / 4) * 4 + (3 - i % 4);
340                raw[pos] = meter;
341            });
342        });
343
344        Ok(())
345    }
346
347    fn deserialize_params(params: &mut FStudioMeter, raw: &[u8]) -> Result<(), String> {
348        [
349            (8, &mut params.analog_inputs[..]),
350            (16, &mut params.stream_inputs[..]),
351            (40, &mut params.mixer_outputs[..]),
352        ]
353        .iter_mut()
354        .for_each(|(offset, meters)| {
355            meters.iter_mut().enumerate().for_each(|(i, meter)| {
356                let pos = *offset + (i / 4) * 4 + (3 - i % 4);
357                *meter = raw[pos];
358            });
359        });
360
361        Ok(())
362    }
363}
364
365/// Source of output.
366#[derive(Debug, Copy, Clone, PartialEq, Eq)]
367pub enum OutputSrc {
368    /// Analog input 1..8.
369    Analog(usize),
370    /// ADAT input 1..8 in 1st optical interface.
371    Adat0(usize),
372    /// S/PDIF input 1/2 in coaxial interface.
373    Spdif(usize),
374    /// Stream input A 1..8 and stream input 9/10.
375    Stream(usize),
376    /// Either stream input A 9..16, or ADAT input 9..16 in 2nd optical interface.
377    StreamAdat1(usize),
378    /// Outputs from stereo mixer 1..9.
379    MixerOut(usize),
380}
381
382impl Default for OutputSrc {
383    fn default() -> Self {
384        Self::Analog(0)
385    }
386}
387
388fn serialize_output_source(src: &OutputSrc, raw: &mut [u8]) -> Result<(), String> {
389    assert!(raw.len() >= 4);
390
391    let val = (match src {
392        OutputSrc::Analog(val) => *val,
393        OutputSrc::Adat0(val) => *val + 0x08,
394        OutputSrc::Spdif(val) => *val + 0x10,
395        OutputSrc::Stream(val) => *val + 0x12,
396        OutputSrc::StreamAdat1(val) => *val + 0x1c,
397        OutputSrc::MixerOut(val) => *val + 0x24,
398    }) as u32;
399
400    serialize_u32(&val, raw);
401
402    Ok(())
403}
404
405fn deserialize_output_source(src: &mut OutputSrc, raw: &[u8]) -> Result<(), String> {
406    assert!(raw.len() >= 4);
407
408    let mut val = 0usize;
409    deserialize_usize(&mut val, raw);
410
411    *src = match val {
412        0x00..=0x07 => OutputSrc::Analog(val),
413        0x08..=0x0f => OutputSrc::Adat0(val - 0x08),
414        0x10..=0x11 => OutputSrc::Spdif(val - 0x10),
415        0x12..=0x1b => OutputSrc::Stream(val - 0x12),
416        0x1c..=0x23 => OutputSrc::StreamAdat1(val - 0x1c),
417        0x24..=0x35 => OutputSrc::MixerOut(val - 0x24),
418        _ => Err(format!("Output source not found for value {}", val))?,
419    };
420
421    Ok(())
422}
423
424/// Parameters for left and right channels of output.
425#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
426pub struct OutputPair {
427    /// Volume of each channel, between 0x00 and 0xff.
428    pub volumes: [u8; 2],
429    /// Whether to be muted for each channel.
430    pub mutes: [bool; 2],
431    /// Source of both channels.
432    pub src: OutputSrc,
433    /// Whether to link both channels.
434    pub link: bool,
435}
436
437/// Parameters for outputs.
438#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
439pub struct OutputParameters {
440    /// Pair of outputs.
441    pub pairs: [OutputPair; 9],
442    /// Source of main output.
443    pub main_assign: AssignTarget,
444    /// Source of 3 headphones.
445    pub headphone_assigns: [AssignTarget; 3],
446    /// Whether to suppress generation of word clock signal in BNC output interface.
447    pub bnc_terminate: bool,
448}
449
450impl FStudioParametersSerdes<OutputParameters> for FStudioProtocol {
451    const NAME: &'static str = "output-state";
452
453    const OFFSET_RANGES: &'static [Range<usize>] = &[
454        Range {
455            start: OUTPUT_PARAMS_OFFSET,
456            end: OUTPUT_PARAMS_OFFSET + OUTPUT_PARAMS_SIZE,
457        },
458        Range {
459            start: OUTPUT_SRC_OFFSET,
460            end: OUTPUT_SRC_OFFSET + OUTPUT_SRC_SIZE,
461        },
462        Range {
463            start: OUTPUT_ASSIGN_OFFSET,
464            end: OUTPUT_ASSIGN_OFFSET + OUTPUT_ASSIGN_SIZE,
465        },
466        Range {
467            start: OUTPUT_BNC_TERMINATE_OFFSET,
468            end: OUTPUT_BNC_TERMINATE_OFFSET + OUTPUT_BNC_TERMINATE_SIZE,
469        },
470        Range {
471            start: OUTPUT_LINK_OFFSET,
472            end: OUTPUT_LINK_OFFSET + OUTPUT_LINK_SIZE,
473        },
474    ];
475
476    fn serialize_params(params: &OutputParameters, raw: &mut [u8]) -> Result<(), String> {
477        params.pairs.iter().enumerate().try_for_each(|(i, pair)| {
478            pair.volumes.iter().enumerate().for_each(|(j, vol)| {
479                let pos = 4 * 3 * (i * 2 + j);
480                serialize_u8(vol, &mut raw[pos..(pos + 4)]);
481            });
482
483            pair.mutes.iter().enumerate().for_each(|(j, mute)| {
484                let pos = 4 * (3 * (i * 2 + j) + 2);
485                serialize_bool(mute, &mut raw[pos..(pos + 4)]);
486            });
487
488            let pos = 216 + 4 * i;
489            serialize_output_source(&pair.src, &mut raw[pos..(pos + 4)])
490        })?;
491
492        serialize_assign_target(&params.main_assign, &mut raw[288..292])?;
493        serialize_assign_target(&params.headphone_assigns[0], &mut raw[292..296])?;
494        serialize_assign_target(&params.headphone_assigns[1], &mut raw[296..300])?;
495        serialize_assign_target(&params.headphone_assigns[2], &mut raw[300..304])?;
496
497        serialize_bool(&params.bnc_terminate, &mut raw[304..308]);
498
499        let mut val = 0u32;
500        params
501            .pairs
502            .iter()
503            .enumerate()
504            .filter(|(_, pair)| pair.link)
505            .for_each(|(i, _)| {
506                val |= 1 << i;
507            });
508        serialize_u32(&val, &mut raw[308..312]);
509
510        Ok(())
511    }
512
513    fn deserialize_params(params: &mut OutputParameters, raw: &[u8]) -> Result<(), String> {
514        params
515            .pairs
516            .iter_mut()
517            .enumerate()
518            .try_for_each(|(i, pair)| {
519                pair.volumes.iter_mut().enumerate().for_each(|(j, vol)| {
520                    let pos = 4 * 3 * (i * 2 + j);
521                    deserialize_u8(vol, &raw[pos..(pos + 4)]);
522                });
523
524                pair.mutes.iter_mut().enumerate().for_each(|(j, mute)| {
525                    let pos = 4 * (3 * (i * 2 + j) + 2);
526                    deserialize_bool(mute, &raw[pos..(pos + 4)]);
527                });
528
529                let pos = 216 + 4 * i;
530                deserialize_output_source(&mut pair.src, &raw[pos..(pos + 4)])
531            })?;
532
533        deserialize_assign_target(&mut params.main_assign, &raw[288..292])?;
534        deserialize_assign_target(&mut params.headphone_assigns[0], &raw[292..296])?;
535        deserialize_assign_target(&mut params.headphone_assigns[1], &raw[296..300])?;
536        deserialize_assign_target(&mut params.headphone_assigns[2], &raw[300..304])?;
537
538        deserialize_bool(&mut params.bnc_terminate, &raw[304..308]);
539
540        let mut val = 0u32;
541        deserialize_u32(&mut val, &raw[308..312]);
542        params.pairs.iter_mut().enumerate().for_each(|(i, pair)| {
543            pair.link = (val & (1 << i)) > 0;
544        });
545
546        Ok(())
547    }
548}
549
550impl<O: FStudioOperation + FStudioParametersSerdes<OutputParameters>>
551    FStudioMutableParametersOperation<OutputParameters> for O
552{
553}
554
555/// Target of output assignment.
556#[derive(Debug, Copy, Clone, PartialEq, Eq)]
557pub enum AssignTarget {
558    /// Audio signal to analog output 1/2.
559    Analog01,
560    /// Audio signal to analog output 3/4.
561    Analog23,
562    /// Audio signal to analog output 5/6.
563    Analog56,
564    /// Audio signal to analog output 7/8.
565    Analog78,
566    /// Audio signal to ADAT output 1/2.
567    AdatA01,
568    /// Audio signal to ADAT output 3/4.
569    AdatA23,
570    /// Audio signal to ADAT output 5/6.
571    AdatA45,
572    /// Audio signal to ADAT output 7/8.
573    AdatA67,
574    /// Audio signal to S/PDIF output 1/2.
575    Spdif01,
576}
577
578impl Default for AssignTarget {
579    fn default() -> Self {
580        Self::Analog01
581    }
582}
583
584fn serialize_assign_target(target: &AssignTarget, raw: &mut [u8]) -> Result<(), String> {
585    let val = match target {
586        AssignTarget::Analog01 => 0x00u32,
587        AssignTarget::Analog23 => 0x02,
588        AssignTarget::Analog56 => 0x04,
589        AssignTarget::Analog78 => 0x06,
590        AssignTarget::AdatA01 => 0x08,
591        AssignTarget::AdatA23 => 0x0a,
592        AssignTarget::AdatA45 => 0x0c,
593        AssignTarget::AdatA67 => 0x0e,
594        AssignTarget::Spdif01 => 0x10,
595    };
596
597    serialize_u32(&val, raw);
598
599    Ok(())
600}
601
602fn deserialize_assign_target(target: &mut AssignTarget, raw: &[u8]) -> Result<(), String> {
603    assert!(raw.len() >= 4);
604
605    let mut val = 0u32;
606    deserialize_u32(&mut val, raw);
607
608    *target = match val {
609        0x00 => AssignTarget::Analog01,
610        0x02 => AssignTarget::Analog23,
611        0x04 => AssignTarget::Analog56,
612        0x06 => AssignTarget::Analog78,
613        0x08 => AssignTarget::AdatA01,
614        0x0a => AssignTarget::AdatA23,
615        0x0c => AssignTarget::AdatA45,
616        0x0e => AssignTarget::AdatA67,
617        0x10 => AssignTarget::Spdif01,
618        _ => Err(format!("Assign target not found for value {}", val))?,
619    };
620
621    Ok(())
622}
623
624/// Mode of mixer expansion.
625#[derive(Debug, Copy, Clone, PartialEq, Eq)]
626pub enum ExpansionMode {
627    /// Stream input B 1..8.
628    StreamB0_7,
629    /// ADAT input 9..16 in 2nd optical interface.
630    AdatB0_7,
631}
632
633impl Default for ExpansionMode {
634    fn default() -> Self {
635        Self::StreamB0_7
636    }
637}
638
639fn serialize_expansion_mode(mode: &ExpansionMode, raw: &mut [u8]) -> Result<(), String> {
640    assert!(raw.len() >= 4);
641
642    let val = match mode {
643        ExpansionMode::StreamB0_7 => 0u32,
644        ExpansionMode::AdatB0_7 => 1,
645    };
646
647    serialize_u32(&val, raw);
648
649    Ok(())
650}
651
652fn deserialize_expansion_mode(mode: &mut ExpansionMode, raw: &[u8]) -> Result<(), String> {
653    assert!(raw.len() >= 4);
654
655    let mut val = 0u32;
656    deserialize_u32(&mut val, raw);
657
658    *mode = match val {
659        0 => ExpansionMode::StreamB0_7,
660        1 => ExpansionMode::AdatB0_7,
661        _ => Err(format!("Expansion mode not found for value {}", val))?,
662    };
663
664    Ok(())
665}
666
667/// Parameters for channels (left and right) in a pair of source to mixer.
668#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
669pub struct MixerSourcePair {
670    /// Gain for each channel, between 0x00 and 0xff.
671    pub gains: [u8; 2],
672    /// Left and right balance for each channel, between 0x00 and 0x7f.
673    pub balances: [u8; 2],
674    /// Whether to be muted for each channel.
675    pub mutes: [bool; 2],
676    /// Whether to link both channels.
677    pub link: bool,
678}
679
680fn serialize_mixer_source_pair(pair: &MixerSourcePair, raw: &mut [u8]) -> Result<(), String> {
681    assert!(raw.len() >= 24);
682
683    serialize_u8(&pair.gains[0], &mut raw[..4]);
684    serialize_u8(&pair.balances[0], &mut raw[4..8]);
685    serialize_bool(&pair.mutes[0], &mut raw[8..12]);
686    serialize_u8(&pair.gains[1], &mut raw[12..16]);
687    serialize_u8(&pair.balances[1], &mut raw[16..20]);
688    serialize_bool(&pair.mutes[1], &mut raw[20..24]);
689
690    Ok(())
691}
692
693fn deserialize_mixer_source_pair(pair: &mut MixerSourcePair, raw: &[u8]) -> Result<(), String> {
694    assert!(raw.len() >= 24);
695
696    deserialize_u8(&mut pair.gains[0], &raw[..4]);
697    deserialize_u8(&mut pair.balances[0], &raw[4..8]);
698    deserialize_bool(&mut pair.mutes[0], &raw[8..12]);
699    deserialize_u8(&mut pair.gains[1], &raw[12..16]);
700    deserialize_u8(&mut pair.balances[1], &raw[16..20]);
701    deserialize_bool(&mut pair.mutes[1], &raw[20..24]);
702
703    Ok(())
704}
705
706/// Parameters for pairs of source to single mixer.
707#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
708pub struct MixerSources {
709    /// Pairs of analog input 1-8.
710    pub analog_pairs: [MixerSourcePair; 4],
711    /// Pairs of ADAT input 1-8 in optical input interface A.
712    pub adat_0_pairs: [MixerSourcePair; 4],
713    /// A pair of S/PDIF input 1/2 in coaxial input interface.
714    pub spdif_pairs: [MixerSourcePair; 1],
715    /// Pairs of stream input 1-8, 17/18 in IEEE 1394 bus.
716    pub stream_pairs: [MixerSourcePair; 5],
717    /// Pairs of selectable inputs either ADAT input 9-18 in optical input interface B or
718    /// stream input 9-16 in IEEE 1394 bus.
719    pub selectable_pairs: [MixerSourcePair; 4],
720}
721
722/// Parameters for a pair (left and right) of outputs from mixer.
723#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
724pub struct MixerOutputPair {
725    /// Volume of the channels, between 0x00 and 0xff.
726    pub volume: u8,
727    /// Whether to mute the channels.
728    pub mute: bool,
729}
730
731fn serialize_mixer_output_pair(pair: &MixerOutputPair, raw: &mut [u8]) -> Result<(), String> {
732    assert!(raw.len() >= 12);
733
734    serialize_u8(&pair.volume, &mut raw[..4]);
735    serialize_bool(&pair.mute, &mut raw[8..12]);
736
737    Ok(())
738}
739
740fn deserialize_mixer_output_pair(pair: &mut MixerOutputPair, raw: &[u8]) -> Result<(), String> {
741    assert!(raw.len() >= 12);
742
743    deserialize_u8(&mut pair.volume, &raw[..4]);
744    deserialize_bool(&mut pair.mute, &raw[8..12]);
745
746    Ok(())
747}
748
749/// Parameters of stereo mixer.
750#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
751pub struct MixerParameters {
752    /// For sources of 9 stereo mixers.
753    pub sources: [MixerSources; 9],
754    /// For outputs of 9 stereo mixers.
755    pub outputs: [MixerOutputPair; 9],
756    /// For selectable input pairs. When expanded, ADAT input 9-18 in optical input interface B is
757    /// available instead of stream input 9-16 in IEEE 1384 bus.
758    pub expansion_mode: ExpansionMode,
759}
760
761impl FStudioParametersSerdes<MixerParameters> for FStudioProtocol {
762    const NAME: &'static str = "mixer-parameters";
763
764    const OFFSET_RANGES: &'static [Range<usize>] = &[
765        Range {
766            start: MIXER_PHYS_SRC_PARAMS_OFFSET,
767            end: MIXER_PHYS_SRC_PARAMS_OFFSET + MIXER_PHYS_SRC_PARAMS_SIZE,
768        },
769        Range {
770            start: MIXER_STREAM_SRC_PARAMS_OFFSET,
771            end: MIXER_STREAM_SRC_PARAMS_OFFSET + MIXER_STREAM_SRC_PARAMS_SIZE,
772        },
773        Range {
774            start: MIXER_SELECTABLE_SRC_PARAMS_OFFSET,
775            end: MIXER_SELECTABLE_SRC_PARAMS_OFFSET + MIXER_SELECTABLE_SRC_PARAMS_SIZE,
776        },
777        Range {
778            start: MIXER_OUTPUT_PARAMS_OFFSET,
779            end: MIXER_OUTPUT_PARAMS_OFFSET + MIXER_OUTPUT_PARAMS_SIZE,
780        },
781        Range {
782            start: MIXER_EXPANSION_MODE_OFFSET,
783            end: MIXER_EXPANSION_MODE_OFFSET + MIXER_EXPANSION_MODE_SIZE,
784        },
785        Range {
786            start: MIXER_SRC_LINK_OFFSET,
787            end: MIXER_SRC_LINK_OFFSET + MIXER_SRC_LINK_SIZE,
788        },
789    ];
790
791    fn serialize_params(params: &MixerParameters, raw: &mut [u8]) -> Result<(), String> {
792        params
793            .sources
794            .iter()
795            .enumerate()
796            .try_for_each(|(i, srcs)| {
797                srcs.analog_pairs
798                    .iter()
799                    .chain(srcs.adat_0_pairs.iter())
800                    .chain(srcs.spdif_pairs.iter())
801                    .enumerate()
802                    .try_for_each(|(j, pair)| {
803                        let pos = 4 * (3 * (i * 18 + j * 2));
804                        serialize_mixer_source_pair(pair, &mut raw[pos..(pos + 24)])
805                    })?;
806
807                srcs.stream_pairs
808                    .iter()
809                    .enumerate()
810                    .try_for_each(|(j, pair)| {
811                        let pos = 4 * (3 * (9 * 18 + i * 10 + j * 2));
812                        serialize_mixer_source_pair(pair, &mut raw[pos..(pos + 24)])
813                    })?;
814
815                srcs.selectable_pairs
816                    .iter()
817                    .enumerate()
818                    .try_for_each(|(j, pair)| {
819                        let pos = 4 * (3 * (9 * 28 + i * 8 + j * 2));
820                        serialize_mixer_source_pair(pair, &mut raw[pos..(pos + 24)])
821                    })
822            })?;
823
824        params
825            .outputs
826            .iter()
827            .enumerate()
828            .try_for_each(|(i, pair)| {
829                let pos = 4 * 3 * (9 * 36 + i);
830                serialize_mixer_output_pair(pair, &mut raw[pos..(pos + 12)])
831            })?;
832
833        let pos = 4 * (3 * 9 * 36 + 3 * 9);
834        serialize_expansion_mode(&params.expansion_mode, &mut raw[pos..(pos + 4)])?;
835
836        params.sources.iter().enumerate().for_each(|(i, srcs)| {
837            let mut val = 0u32;
838
839            srcs.analog_pairs
840                .iter()
841                .chain(srcs.adat_0_pairs.iter())
842                .chain(srcs.spdif_pairs.iter())
843                .enumerate()
844                .filter(|(_, pair)| pair.link)
845                .for_each(|(j, _)| val |= 1 << j);
846
847            srcs.stream_pairs
848                .iter()
849                .chain(srcs.selectable_pairs.iter())
850                .enumerate()
851                .filter(|(_, pair)| pair.link)
852                .for_each(|(j, _)| val |= 1 << (16 + j));
853
854            let pos = 4 * (3 * 9 * 36 + 3 * 9 + 1 + i);
855            serialize_u32(&val, &mut raw[pos..(pos + 4)]);
856        });
857
858        Ok(())
859    }
860
861    fn deserialize_params(params: &mut MixerParameters, raw: &[u8]) -> Result<(), String> {
862        params
863            .sources
864            .iter_mut()
865            .enumerate()
866            .try_for_each(|(i, srcs)| {
867                srcs.analog_pairs
868                    .iter_mut()
869                    .chain(srcs.adat_0_pairs.iter_mut())
870                    .chain(srcs.spdif_pairs.iter_mut())
871                    .enumerate()
872                    .try_for_each(|(j, pair)| {
873                        let pos = 4 * (3 * (i * 18 + j * 2));
874                        deserialize_mixer_source_pair(pair, &raw[pos..(pos + 24)])
875                    })?;
876
877                srcs.stream_pairs
878                    .iter_mut()
879                    .enumerate()
880                    .try_for_each(|(j, pair)| {
881                        let pos = 4 * (3 * (9 * 18 + i * 10 + j * 2));
882                        deserialize_mixer_source_pair(pair, &raw[pos..(pos + 24)])
883                    })?;
884
885                srcs.selectable_pairs
886                    .iter_mut()
887                    .enumerate()
888                    .try_for_each(|(j, pair)| {
889                        let pos = 4 * (3 * (9 * 28 + i * 8 + j * 2));
890                        deserialize_mixer_source_pair(pair, &raw[pos..(pos + 24)])
891                    })
892            })?;
893
894        params
895            .outputs
896            .iter_mut()
897            .enumerate()
898            .try_for_each(|(i, pair)| {
899                let pos = 4 * 3 * (9 * 36 + i);
900                deserialize_mixer_output_pair(pair, &raw[pos..(pos + 12)])
901            })?;
902
903        let pos = 4 * (3 * 9 * 36 + 3 * 9);
904        deserialize_expansion_mode(&mut params.expansion_mode, &raw[pos..(pos + 4)])?;
905
906        params.sources.iter_mut().enumerate().for_each(|(i, srcs)| {
907            let pos = 4 * (3 * 9 * 36 + 3 * 9 + 1 + i);
908            let mut val = 0u32;
909            deserialize_u32(&mut val, &raw[pos..(pos + 4)]);
910
911            srcs.analog_pairs
912                .iter_mut()
913                .chain(srcs.adat_0_pairs.iter_mut())
914                .chain(srcs.spdif_pairs.iter_mut())
915                .enumerate()
916                .for_each(|(j, pair)| pair.link = val & (1 << j) > 0);
917
918            srcs.stream_pairs
919                .iter_mut()
920                .chain(srcs.selectable_pairs.iter_mut())
921                .enumerate()
922                .for_each(|(j, pair)| pair.link = val & (1 << (16 + j)) > 0);
923        });
924
925        Ok(())
926    }
927}
928
929impl<O: FStudioOperation + FStudioParametersSerdes<MixerParameters>>
930    FStudioMutableParametersOperation<MixerParameters> for O
931{
932}
933
934/// The number of mixers.
935pub const MIXER_COUNT: usize = 9;
936
937#[cfg(test)]
938mod test {
939    use super::*;
940
941    #[test]
942    fn meter_params_serdes() {
943        let target = FStudioMeter {
944            analog_inputs: [0, 1, 2, 3, 4, 5, 6, 7],
945            stream_inputs: [17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0],
946            mixer_outputs: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17],
947        };
948
949        let size = compute_params_size(
950            <FStudioProtocol as FStudioParametersSerdes<FStudioMeter>>::OFFSET_RANGES,
951        );
952        let mut raw = vec![0; size];
953        assert!(FStudioProtocol::serialize_params(&target, &mut raw).is_ok());
954
955        let mut params = FStudioMeter::default();
956        assert!(FStudioProtocol::deserialize_params(&mut params, &raw).is_ok());
957
958        assert_eq!(target, params);
959    }
960
961    #[test]
962    fn output_params_serdes() {
963        let target = OutputParameters {
964            pairs: [Default::default(); 9],
965            main_assign: AssignTarget::AdatA67,
966            headphone_assigns: [
967                AssignTarget::Analog78,
968                AssignTarget::Spdif01,
969                AssignTarget::AdatA45,
970            ],
971            bnc_terminate: true,
972        };
973
974        let size = compute_params_size(
975            <FStudioProtocol as FStudioParametersSerdes<OutputParameters>>::OFFSET_RANGES,
976        );
977        let mut raw = vec![0; size];
978        assert!(FStudioProtocol::serialize_params(&target, &mut raw).is_ok());
979
980        let mut params = OutputParameters::default();
981        assert!(FStudioProtocol::deserialize_params(&mut params, &raw).is_ok());
982
983        assert_eq!(target, params, "{:02x?}", raw);
984    }
985
986    #[test]
987    fn mixer_params_serdes() {
988        let mut target = MixerParameters::default();
989        target.sources.iter_mut().enumerate().for_each(|(i, srcs)| {
990            srcs.analog_pairs
991                .iter_mut()
992                .chain(srcs.adat_0_pairs.iter_mut())
993                .chain(srcs.spdif_pairs.iter_mut())
994                .chain(srcs.stream_pairs.iter_mut())
995                .chain(srcs.selectable_pairs.iter_mut())
996                .enumerate()
997                .for_each(|(j, pair)| {
998                    pair.gains[0] = (i * 9 + j * 3) as u8;
999                    pair.gains[1] = (i * 11 + j * 1) as u8;
1000                    pair.balances[0] = (i * 7 + j * 5) as u8;
1001                    pair.balances[1] = (i * 5 + j * 7) as u8;
1002                    pair.mutes[0] = (i + j * 2) % 2 > 0;
1003                    pair.mutes[1] = (i * 2 + j) % 2 > 0;
1004                    pair.link = (i + j) % 2 > 0;
1005                });
1006        });
1007        target.outputs.iter_mut().enumerate().for_each(|(i, pair)| {
1008            pair.volume = 3 * i as u8;
1009            pair.mute = i % 2 > 0;
1010        });
1011        target.expansion_mode = ExpansionMode::AdatB0_7;
1012
1013        let size = compute_params_size(
1014            <FStudioProtocol as FStudioParametersSerdes<MixerParameters>>::OFFSET_RANGES,
1015        );
1016        let mut raw = vec![0; size];
1017        assert!(FStudioProtocol::serialize_params(&target, &mut raw).is_ok());
1018
1019        let mut params = MixerParameters::default();
1020        assert!(FStudioProtocol::deserialize_params(&mut params, &raw).is_ok());
1021
1022        assert_eq!(target, params);
1023    }
1024}