firewire_bebob_protocols/presonus/
firebox.rs

1// SPDX-License-Identifier: LGPL-3.0-or-later
2// Copyright (c) 2021 Takashi Sakamoto
3
4//! Protocol implementation for Firebox.
5//!
6//! The module includes structure, enumeration, and trait and its implementation for protocol
7//! defined by PreSonus for Firebox.
8//!
9//! ## Diagram of internal signal flow
10//!
11//! ```text
12//! analog-input-1/2 ------------------------+----------------> stream-output-1/2
13//! analog-input-3/4 ------------------------|-+--------------> stream-output-3/4
14//! analog-input-5/6 ------------------------|-|-+------------> stream-output-5/6
15//!                                          | | |
16//!                                          v v v
17//!                                       ++=======++
18//!                                       || 8 x 2 ||
19//!                  stream-source-1/2 -> || mixer ||
20//!                  (one source only)    ++=======++
21//!                       ^ ^ ^ ^              |
22//!                       | | | |        mixer-output-1/2
23//!                       | | | |           | | | | |
24//! stream-input-1/2 -----+-|-|-|---+------or-|-|-|-|---------> analog-output-1/2
25//! stream-input-3/4 -------+-|-|---|-+------or-|-|-|---------> analog-output-3/4
26//! stream-input-5/6 ---------+-|---|-|-+------or-|-|---------> analog-output-5/6
27//! stream-input-7/8 -----------+---|-|-|-+------or-|---------> digital-output-1/2
28//!                                 | | | |         |
29//!                                 v v v v         v
30//!                                 (one source only)
31//!                                         |
32//!                                         +-----------------> headphone-1/2
33//! ```
34
35use super::*;
36
37/// The protocol implementation of clock operation.
38#[derive(Default, Debug)]
39pub struct FireboxClkProtocol;
40
41impl MediaClockFrequencyOperation for FireboxClkProtocol {
42    const FREQ_LIST: &'static [u32] = &[44100, 48000, 88200, 96000];
43}
44
45impl SamplingClockSourceOperation for FireboxClkProtocol {
46    const DST: SignalAddr = SignalAddr::Subunit(SignalSubunitAddr {
47        subunit: MUSIC_SUBUNIT_0,
48        plug_id: 0x05,
49    });
50
51    const SRC_LIST: &'static [SignalAddr] = &[
52        // Internal.
53        SignalAddr::Subunit(SignalSubunitAddr {
54            subunit: MUSIC_SUBUNIT_0,
55            plug_id: 0x06,
56        }),
57        // S/PDIF in coaxial interface.
58        SignalAddr::Unit(SignalUnitAddr::Ext(0x03)),
59    ];
60}
61
62/// The protocol implementation of physical output.
63#[derive(Default, Debug)]
64pub struct FireboxPhysOutputProtocol;
65
66impl AvcAudioFeatureSpecification for FireboxPhysOutputProtocol {
67    const ENTRIES: &'static [(u8, AudioCh)] = &[
68        (0x01, AudioCh::Each(0)),
69        (0x01, AudioCh::Each(1)),
70        (0x02, AudioCh::Each(0)),
71        (0x02, AudioCh::Each(1)),
72        (0x03, AudioCh::Each(0)),
73        (0x03, AudioCh::Each(1)),
74    ];
75}
76
77impl AvcLevelOperation for FireboxPhysOutputProtocol {}
78
79impl AvcMuteOperation for FireboxPhysOutputProtocol {}
80
81impl AvcSelectorOperation for FireboxPhysOutputProtocol {
82    // NOTE: "analog-output-1/2", "analog-output-3/4", "analog-output-5/6", "digital-output-1/2"
83    const FUNC_BLOCK_ID_LIST: &'static [u8] = &[0x01, 0x02, 0x03, 0x05];
84    // NOTE: "stream-input", "mixer-output-1/2"
85    const INPUT_PLUG_ID_LIST: &'static [u8] = &[0x00, 0x01];
86}
87
88/// The protocol implementation of headphone.
89#[derive(Default, Debug)]
90pub struct FireboxHeadphoneProtocol;
91
92impl AvcAudioFeatureSpecification for FireboxHeadphoneProtocol {
93    const ENTRIES: &'static [(u8, AudioCh)] = &[(0x04, AudioCh::Each(0)), (0x04, AudioCh::Each(1))];
94}
95
96impl AvcLevelOperation for FireboxHeadphoneProtocol {}
97
98impl AvcMuteOperation for FireboxHeadphoneProtocol {}
99
100impl AvcSelectorOperation for FireboxHeadphoneProtocol {
101    // NOTE: "headphone-1/2"
102    const FUNC_BLOCK_ID_LIST: &'static [u8] = &[0x04];
103    // NOTE: "stream-input-1/2", "stream-input-3/4", "stream-input-5/6", "stream-input-7/8",
104    //       "mixer-output-1/2"
105    const INPUT_PLUG_ID_LIST: &'static [u8] = &[0x00, 0x01, 0x02, 0x03, 0x04];
106}
107
108/// The protocol implementation of physical source for mixer.
109#[derive(Default, Debug)]
110pub struct FireboxMixerPhysSourceProtocol;
111
112impl AvcAudioFeatureSpecification for FireboxMixerPhysSourceProtocol {
113    const ENTRIES: &'static [(u8, AudioCh)] = &[
114        (0x05, AudioCh::Each(0)),
115        (0x05, AudioCh::Each(1)),
116        (0x06, AudioCh::Each(0)),
117        (0x06, AudioCh::Each(1)),
118        (0x07, AudioCh::Each(0)),
119        (0x07, AudioCh::Each(1)),
120    ];
121}
122
123impl AvcLevelOperation for FireboxMixerPhysSourceProtocol {}
124
125impl AvcLrBalanceOperation for FireboxMixerPhysSourceProtocol {}
126
127impl AvcMuteOperation for FireboxMixerPhysSourceProtocol {}
128
129/// The protocol implementation of stream source for mixer.
130#[derive(Default, Debug)]
131pub struct FireboxMixerStreamSourceProtocol;
132
133impl AvcAudioFeatureSpecification for FireboxMixerStreamSourceProtocol {
134    const ENTRIES: &'static [(u8, AudioCh)] = &[(0x08, AudioCh::Each(0))];
135}
136
137impl AvcLevelOperation for FireboxMixerStreamSourceProtocol {}
138
139impl AvcMuteOperation for FireboxMixerStreamSourceProtocol {}
140
141impl AvcSelectorOperation for FireboxMixerStreamSourceProtocol {
142    // NOTE: "stream-source-1/2"
143    const FUNC_BLOCK_ID_LIST: &'static [u8] = &[0x06];
144    // NOTE: "stream-input-1/2", "stream-input-3/4", "stream-input-5/6", "stream-input-7/8",
145    const INPUT_PLUG_ID_LIST: &'static [u8] = &[0x00, 0x01, 0x02, 0x03];
146}
147/// The protocol implementation of mixer output.
148#[derive(Default, Debug)]
149pub struct FireboxMixerOutputProtocol;
150
151impl AvcAudioFeatureSpecification for FireboxMixerOutputProtocol {
152    const ENTRIES: &'static [(u8, AudioCh)] = &[(0x09, AudioCh::Each(0)), (0x09, AudioCh::Each(1))];
153}
154
155impl AvcLevelOperation for FireboxMixerOutputProtocol {}
156
157impl AvcLrBalanceOperation for FireboxMixerOutputProtocol {}
158
159impl AvcMuteOperation for FireboxMixerOutputProtocol {}
160
161/// The parameters of analog inputs.
162#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
163pub struct FireboxAnalogInputParameters {
164    /// Boost signal for analog input 1-4.
165    pub boosts: [bool; FireboxAnalogInputProtocol::CH_COUNT],
166}
167
168/// The protocol implementation of analog inputs.
169#[derive(Default, Debug)]
170pub struct FireboxAnalogInputProtocol;
171
172impl FireboxAnalogInputProtocol {
173    const BOOST_OFF: i16 = VolumeData::VALUE_MIN;
174    const BOOST_ON: i16 = VolumeData::VALUE_ZERO;
175
176    const FUNC_BLOCK_ID_LIST: &'static [u8] = &[0x0a, 0x0b];
177    const INPUT_PLUG_ID_LIST: &'static [u8] = &[0x00, 0x01];
178
179    const CH_COUNT: usize = 4;
180
181    /// Cache state of hardware to the parameters.
182    pub fn cache(
183        avc: &BebobAvc,
184        params: &mut FireboxAnalogInputParameters,
185        timeout_ms: u32,
186    ) -> Result<(), Error> {
187        params
188            .boosts
189            .iter_mut()
190            .enumerate()
191            .try_for_each(|(i, boost)| {
192                let func_block_id = Self::FUNC_BLOCK_ID_LIST[i / 2];
193                let input_plug_id = Self::INPUT_PLUG_ID_LIST[i % 2];
194
195                let mut op = AudioFeature::new(
196                    func_block_id,
197                    CtlAttr::Current,
198                    AudioCh::Each(input_plug_id),
199                    FeatureCtl::Volume(VolumeData::new(1)),
200                );
201                avc.status(&AUDIO_SUBUNIT_0_ADDR, &mut op, timeout_ms)
202                    .map(|_| {
203                        if let FeatureCtl::Volume(data) = op.ctl {
204                            *boost = data.0[0] == Self::BOOST_ON;
205                        }
206                    })
207            })
208    }
209
210    /// Update hardware when detecting changes in the parameters.
211    pub fn update(
212        avc: &BebobAvc,
213        params: &FireboxAnalogInputParameters,
214        prev: &mut FireboxAnalogInputParameters,
215        timeout_ms: u32,
216    ) -> Result<(), Error> {
217        prev.boosts
218            .iter_mut()
219            .zip(params.boosts.iter())
220            .enumerate()
221            .filter(|(_, (o, n))| !o.eq(n))
222            .try_for_each(|(i, (old, &new))| {
223                let func_block_id = Self::FUNC_BLOCK_ID_LIST[i / 2];
224                let input_plug_id = Self::INPUT_PLUG_ID_LIST[i % 2];
225
226                let mut op = AudioFeature::new(
227                    func_block_id,
228                    CtlAttr::Current,
229                    AudioCh::Each(input_plug_id),
230                    FeatureCtl::Volume(VolumeData(vec![if new {
231                        Self::BOOST_ON
232                    } else {
233                        Self::BOOST_OFF
234                    }])),
235                );
236                avc.control(&AUDIO_SUBUNIT_0_ADDR, &mut op, timeout_ms)
237                    .map(|_| *old = new)
238            })
239    }
240}