firewire_dice_protocols/tcelectronic/
ch_strip.rs

1// SPDX-License-Identifier: LGPL-3.0-or-later
2// Copyright (c) 2020 Takashi Sakamoto
3
4//! Data of channel strip effect in protocol defined by TC Electronic for Konnekt series.
5//!
6//! The module includes structure, trait and its implementation for data of channel strip effect in
7//! protocol defined by TC Electronic for Konnekt series. It's called as `Fabrik C`.
8
9use super::*;
10
11/// Type of source.
12#[derive(Debug, Copy, Clone, PartialEq, Eq)]
13pub enum ChStripSrcType {
14    FemaleVocal,
15    MaleVocal,
16    Guitar,
17    Piano,
18    Speak,
19    Choir,
20    Horns,
21    Bass,
22    Kick,
23    Snare,
24    MixRock,
25    MixSoft,
26    Percussion,
27    Kit,
28    MixAcoustic,
29    MixPurist,
30    House,
31    Trance,
32    Chill,
33    HipHop,
34    DrumAndBass,
35    ElectroTechno,
36}
37
38impl Default for ChStripSrcType {
39    fn default() -> Self {
40        ChStripSrcType::FemaleVocal
41    }
42}
43
44const CH_STRIP_SRC_TYPES: &[ChStripSrcType] = &[
45    ChStripSrcType::FemaleVocal,
46    ChStripSrcType::MaleVocal,
47    ChStripSrcType::Guitar,
48    ChStripSrcType::Piano,
49    ChStripSrcType::Speak,
50    ChStripSrcType::Choir,
51    ChStripSrcType::Horns,
52    ChStripSrcType::Bass,
53    ChStripSrcType::Kick,
54    ChStripSrcType::Snare,
55    ChStripSrcType::MixRock,
56    ChStripSrcType::MixSoft,
57    ChStripSrcType::Percussion,
58    ChStripSrcType::Kit,
59    ChStripSrcType::MixAcoustic,
60    ChStripSrcType::MixPurist,
61    ChStripSrcType::House,
62    ChStripSrcType::Trance,
63    ChStripSrcType::Chill,
64    ChStripSrcType::HipHop,
65    ChStripSrcType::DrumAndBass,
66    ChStripSrcType::ElectroTechno,
67];
68
69const CH_STRIP_SRC_TYPE_LABEL: &str = "channel strip source type";
70
71fn serialize_src_type(src_type: &ChStripSrcType, raw: &mut [u8]) -> Result<(), String> {
72    serialize_position(CH_STRIP_SRC_TYPES, src_type, raw, CH_STRIP_SRC_TYPE_LABEL)
73}
74
75fn deserialize_src_type(src_type: &mut ChStripSrcType, raw: &[u8]) -> Result<(), String> {
76    deserialize_position(CH_STRIP_SRC_TYPES, src_type, raw, CH_STRIP_SRC_TYPE_LABEL)
77}
78
79/// State of compressor part.
80#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
81pub struct CompState {
82    /// The gain of input. 0..360 (-18.0..18.0 dB).
83    pub input_gain: u32,
84    /// The gain of output. 0..360 (-18.0..18.0 dB).
85    pub make_up_gain: u32,
86    /// Whether three bands are available or not.
87    pub full_band_enabled: bool,
88    /// The amount to control for low/mid/high frequencies. 0..200 (-100.0..+100.0 %)
89    pub ctl: [u32; 3],
90    /// The level of low/mid/high frequencies. 0..48 (-18.0..+6.0 dB)
91    pub level: [u32; 3],
92}
93
94/// State of deesser part.
95#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
96pub struct DeesserState {
97    /// The ratio to deesser. 0..10 (0..100 %)
98    pub ratio: u32,
99    /// Whether to bypass deesser effect.
100    pub bypass: bool,
101}
102
103/// State of equalizer part.
104#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
105pub struct EqState {
106    /// Whether to enable equalizer.
107    pub enabled: bool,
108    /// The bandwidth. 0..39
109    pub bandwidth: u32,
110    /// The gain. 0..240 (-12.0..+12.0 dB)
111    pub gain: u32,
112    // blank
113    /// The frequency. 0..240 (20.0..40.0 Hz)
114    pub freq: u32,
115}
116
117/// State of limitter part.
118#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
119pub struct LimitterState {
120    /// The threshold to limit. 0..72 (-18.0..+18.0)
121    pub threshold: u32,
122}
123
124/// State entry of channel strip effect.
125#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
126pub struct ChStripState {
127    pub src_type: ChStripSrcType,
128    /// Compressor for low/mid/high frequencies.
129    pub comp: CompState,
130    /// Deesser.
131    pub deesser: DeesserState,
132    /// Equalizers for low/mid-low/mid-high/high frequencies.
133    pub eq: [EqState; 4],
134    /// Whether to bypass equalizer or not.
135    pub eq_bypass: bool,
136    /// Limitter.
137    pub limitter: LimitterState,
138    /// Whether to bypass limitter or not.
139    pub limitter_bypass: bool,
140    /// Whether to bypass whole parts or not.
141    pub bypass: bool,
142}
143
144impl ChStripState {
145    pub(crate) const SIZE: usize = 144;
146}
147
148pub(crate) fn calculate_ch_strip_state_segment_size(count: usize) -> usize {
149    (((count + 1) / 2) * 4) + count + ChStripState::SIZE
150}
151
152fn calculate_ch_strip_state_segment_pos(idx: usize) -> usize {
153    (((idx + 1) / 2) * 4) + idx * ChStripState::SIZE
154}
155
156pub(crate) fn serialize_ch_strip_states(
157    states: &[ChStripState],
158    raw: &mut [u8],
159) -> Result<(), String> {
160    assert!(raw.len() >= calculate_ch_strip_state_segment_size(states.len()));
161
162    states.iter().enumerate().try_for_each(|(i, s)| {
163        let pos = calculate_ch_strip_state_segment_pos(i);
164        let r = &mut raw[pos..(pos + ChStripState::SIZE)];
165
166        serialize_u32(&s.comp.input_gain, &mut r[..4]);
167        serialize_src_type(&s.src_type, &mut r[4..8])?;
168        serialize_bool(&s.comp.full_band_enabled, &mut r[8..12]);
169        serialize_u32(&s.deesser.ratio, &mut r[12..16]);
170        serialize_bool(&s.deesser.bypass, &mut r[16..20]);
171        serialize_bool(&s.eq[0].enabled, &mut r[20..24]);
172        serialize_u32(&s.eq[0].bandwidth, &mut r[24..28]);
173        serialize_u32(&s.eq[0].gain, &mut r[28..32]);
174        // blank
175        serialize_u32(&s.eq[0].freq, &mut r[36..40]);
176        serialize_bool(&s.eq[1].enabled, &mut r[40..44]);
177        serialize_u32(&s.eq[1].bandwidth, &mut r[44..48]);
178        serialize_u32(&s.eq[1].gain, &mut r[48..52]);
179        // blank
180        serialize_u32(&s.eq[1].freq, &mut r[56..60]);
181        serialize_bool(&s.eq[2].enabled, &mut r[60..64]);
182        serialize_u32(&s.eq[2].bandwidth, &mut r[64..68]);
183        serialize_u32(&s.eq[2].gain, &mut r[68..72]);
184        // blank
185        serialize_u32(&s.eq[2].freq, &mut r[76..80]);
186        serialize_bool(&s.eq[3].enabled, &mut r[80..84]);
187        serialize_u32(&s.eq[3].bandwidth, &mut r[84..88]);
188        serialize_u32(&s.eq[3].gain, &mut r[88..92]);
189        // blank
190        serialize_u32(&s.eq[3].freq, &mut r[96..100]);
191        serialize_bool(&s.eq_bypass, &mut r[100..104]);
192        serialize_u32(&s.comp.ctl[0], &mut r[104..108]);
193        serialize_u32(&s.comp.level[0], &mut r[108..112]);
194        serialize_u32(&s.comp.ctl[1], &mut r[112..116]);
195        serialize_u32(&s.comp.level[1], &mut r[116..120]);
196        serialize_u32(&s.comp.ctl[2], &mut r[120..124]);
197        serialize_u32(&s.comp.level[2], &mut r[124..128]);
198        serialize_bool(&s.limitter_bypass, &mut r[128..132]);
199        serialize_u32(&s.comp.make_up_gain, &mut r[132..136]);
200        serialize_u32(&s.limitter.threshold, &mut r[136..140]);
201        serialize_bool(&s.bypass, &mut r[140..]);
202
203        Ok(())
204    })
205}
206
207pub(crate) fn deserialize_ch_strip_states(
208    states: &mut [ChStripState],
209    raw: &[u8],
210) -> Result<(), String> {
211    assert!(raw.len() >= calculate_ch_strip_state_segment_size(states.len()));
212
213    states.iter_mut().enumerate().try_for_each(|(i, s)| {
214        let pos = calculate_ch_strip_state_segment_pos(i);
215        let r = &raw[pos..(pos + ChStripState::SIZE)];
216
217        deserialize_u32(&mut s.comp.input_gain, &r[..4]);
218        deserialize_src_type(&mut s.src_type, &r[4..8])?;
219        deserialize_bool(&mut s.comp.full_band_enabled, &r[8..12]);
220        deserialize_u32(&mut s.deesser.ratio, &r[12..16]);
221        deserialize_bool(&mut s.deesser.bypass, &r[16..20]);
222        deserialize_bool(&mut s.eq[0].enabled, &r[20..24]);
223        deserialize_u32(&mut s.eq[0].bandwidth, &r[24..28]);
224        deserialize_u32(&mut s.eq[0].gain, &r[28..32]);
225        // blank
226        deserialize_u32(&mut s.eq[0].freq, &r[36..40]);
227        deserialize_bool(&mut s.eq[1].enabled, &r[40..44]);
228        deserialize_u32(&mut s.eq[1].bandwidth, &r[44..48]);
229        deserialize_u32(&mut s.eq[1].gain, &r[48..52]);
230        // blank
231        deserialize_u32(&mut s.eq[1].freq, &r[56..60]);
232        deserialize_bool(&mut s.eq[2].enabled, &r[60..64]);
233        deserialize_u32(&mut s.eq[2].bandwidth, &r[64..68]);
234        deserialize_u32(&mut s.eq[2].gain, &r[68..72]);
235        // blank
236        deserialize_u32(&mut s.eq[2].freq, &r[76..80]);
237        deserialize_bool(&mut s.eq[3].enabled, &r[80..84]);
238        deserialize_u32(&mut s.eq[3].bandwidth, &r[84..88]);
239        deserialize_u32(&mut s.eq[3].gain, &r[88..92]);
240        // blank
241        deserialize_u32(&mut s.eq[3].freq, &r[96..100]);
242        deserialize_bool(&mut s.eq_bypass, &r[100..104]);
243        deserialize_u32(&mut s.comp.ctl[0], &r[104..108]);
244        deserialize_u32(&mut s.comp.level[0], &r[108..112]);
245        deserialize_u32(&mut s.comp.ctl[1], &r[112..116]);
246        deserialize_u32(&mut s.comp.level[1], &r[116..120]);
247        deserialize_u32(&mut s.comp.ctl[2], &r[120..124]);
248        deserialize_u32(&mut s.comp.level[2], &r[124..128]);
249        deserialize_bool(&mut s.limitter_bypass, &r[128..132]);
250        deserialize_u32(&mut s.comp.make_up_gain, &r[132..136]);
251        deserialize_u32(&mut s.limitter.threshold, &r[136..140]);
252        deserialize_bool(&mut s.bypass, &r[140..]);
253
254        Ok(())
255    })
256}
257
258/// Meter entry of channel strip effect.
259#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
260pub struct ChStripMeter {
261    /// Input meter. -72..0 (-72.0..0.0 dB)
262    pub input: i32,
263    /// Limit meter. -12..0 (-12.0..0.0 dB)
264    pub limit: i32,
265    /// Output meter. -72..0 (-72.0..0.0 dB)
266    pub output: i32,
267    /// Gain meter at low/middle/high frequency. -24..18 (-24.0..18.0 dB)
268    pub gains: [i32; 3],
269}
270
271impl ChStripMeter {
272    pub(crate) const SIZE: usize = 28;
273}
274
275pub(crate) fn calculate_ch_strip_meter_segment_size(count: usize) -> usize {
276    (((count + 1) / 2) * 4) + count * ChStripMeter::SIZE
277}
278
279fn calculate_ch_strip_meter_segment_pos(idx: usize) -> usize {
280    (((idx + 1) / 2) * 4) + idx * ChStripMeter::SIZE
281}
282
283pub(crate) fn serialize_ch_strip_meters(
284    meters: &[ChStripMeter],
285    raw: &mut [u8],
286) -> Result<(), String> {
287    assert!(raw.len() >= calculate_ch_strip_meter_segment_size(meters.len()));
288
289    meters.iter().enumerate().try_for_each(|(i, m)| {
290        let pos = calculate_ch_strip_meter_segment_pos(i);
291        let r = &mut raw[pos..(pos + ChStripMeter::SIZE)];
292
293        serialize_i32(&m.input, &mut r[..4]);
294        serialize_i32(&m.limit, &mut r[4..8]);
295        serialize_i32(&m.output, &mut r[8..12]);
296        serialize_i32(&m.gains[0], &mut r[20..24]);
297        serialize_i32(&m.gains[1], &mut r[16..20]);
298        serialize_i32(&m.gains[2], &mut r[12..16]);
299
300        Ok(())
301    })
302}
303
304pub(crate) fn deserialize_ch_strip_meters(
305    meters: &mut [ChStripMeter],
306    raw: &[u8],
307) -> Result<(), String> {
308    assert!(raw.len() >= calculate_ch_strip_meter_segment_size(meters.len()));
309
310    meters.iter_mut().enumerate().try_for_each(|(i, m)| {
311        let pos = calculate_ch_strip_meter_segment_pos(i);
312        let r = &raw[pos..(pos + ChStripMeter::SIZE)];
313
314        deserialize_i32(&mut m.input, &r[..4]);
315        deserialize_i32(&mut m.limit, &r[4..8]);
316        deserialize_i32(&mut m.output, &r[8..12]);
317        deserialize_i32(&mut m.gains[0], &r[20..24]);
318        deserialize_i32(&mut m.gains[1], &r[16..20]);
319        deserialize_i32(&mut m.gains[2], &r[12..16]);
320
321        Ok(())
322    })
323}