alsa_ctl_tlv_codec/
items.rs

1// SPDX-License-Identifier: MIT
2// Copyright (c) 2020 Takashi Sakamoto
3
4//! A set of minimum items in TLV (Type-Length-Value) of ALSA control interface.
5
6use super::*;
7
8/// The data to express dB scale in TLV (Type-Length-Value) of ALSA control interface.
9///
10/// It has `SNDRV_CTL_TLVT_DB_SCALE` (=1) in its type field and has two elements in value field.
11#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
12pub struct DbScale {
13    /// The minimum value by dB expression, in 0.1 dB unit. This corresponds to the minimum
14    /// value in the state of control element.
15    pub min: i32,
16    /// The step by dB expression, in 0.1 dB unit. This corresponds to one increase of the value
17    /// in the state of control element.
18    pub step: u16,
19    /// If true, the value less than or equals to [`CTL_VALUE_MUTE`] (=-9999999) is available to
20    /// mute the control element explicitly.
21    pub mute_avail: bool,
22}
23
24/// When information about dB includes mute_avail, the value is available to mute the control
25/// element. It's relevant to `SNDRV_CTL_TLVD_DB_GAIN_MUTE` macro in UAPI of Linux kernel.
26pub const CTL_VALUE_MUTE: i32 = SNDRV_CTL_TLVD_DB_GAIN_MUTE;
27
28/// The value of dB should be expressed in 0.1 dB unit in data of TLV and crate structures.
29pub const DB_VALUE_MULTIPLIER: i32 = 100;
30
31impl DbScale {
32    const VALUE_COUNT: usize = 2;
33}
34
35impl<'a> TlvData<'a> for DbScale {
36    fn value_type(&self) -> u32 {
37        SNDRV_CTL_TLVT_DB_SCALE
38    }
39
40    fn value_length(&self) -> usize {
41        Self::VALUE_COUNT
42    }
43
44    fn value(&self) -> Vec<u32> {
45        let mut raw = Vec::new();
46        raw.push(self.min as u32);
47        raw.push(self.step as u32);
48        if self.mute_avail {
49            raw[1] |= SNDRV_CTL_TLVD_DB_SCALE_MUTE;
50        }
51        raw
52    }
53}
54
55const TYPES_FOR_DB_SCALE: &'static [u32] = &[SNDRV_CTL_TLVT_DB_SCALE];
56
57impl std::convert::TryFrom<&[u32]> for DbScale {
58    type Error = TlvDecodeError;
59
60    fn try_from(raw: &[u32]) -> Result<Self, Self::Error> {
61        // At least, type and length field should be included.
62        if raw.len() < 2 {
63            Err(Self::Error::new(TlvDecodeErrorCtx::Length(raw.len(), 2), 0))
64        // Check type field.
65        } else if raw[0] != SNDRV_CTL_TLVT_DB_SCALE {
66            Err(Self::Error::new(
67                TlvDecodeErrorCtx::ValueType(raw[0], TYPES_FOR_DB_SCALE),
68                0,
69            ))
70        } else {
71            // Check length field against length of value field.
72            let value_length = (raw[1] / 4) as usize;
73            let value = &raw[2..];
74            if value.len() < value_length {
75                Err(Self::Error::new(
76                    TlvDecodeErrorCtx::ValueLength(value_length, value.len()),
77                    1,
78                ))
79            } else {
80                // Decode value field.
81                Ok(Self {
82                    min: value[0] as i32,
83                    step: (value[1] & SNDRV_CTL_TLVD_DB_SCALE_MASK) as u16,
84                    mute_avail: value[1] & SNDRV_CTL_TLVD_DB_SCALE_MUTE > 0,
85                })
86            }
87        }
88    }
89}
90
91impl From<&DbScale> for Vec<u32> {
92    fn from(data: &DbScale) -> Self {
93        let mut raw = Vec::new();
94        raw.push(data.value_type());
95        raw.push(4 * data.value_length() as u32);
96        raw.append(&mut data.value());
97        raw
98    }
99}
100
101impl From<DbScale> for Vec<u32> {
102    fn from(data: DbScale) -> Self {
103        (&data).into()
104    }
105}
106
107/// The data to express dB interval in TLV (Type-Length-Value) of ALSA control interface.
108///
109/// It has three variants below;
110///  * SNDRV_CTL_TLVT_DB_LINEAR(=2)
111///  * SNDRV_CTL_TLVT_DB_MINMAX(=4)
112///  * SNDRV_CTL_TLVT_DB_MINMAX_MUTE(=5)
113///
114///  All of them have two elements in value field.
115#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
116pub struct DbInterval {
117    /// The minimum value by dB expression, in 0.1 dB unit. This corresponds to the minimum
118    /// value in the state of control element.
119    pub min: i32,
120    /// The maximum value by dB expression, 0.1 dB unit. This corresponds to the maximum value
121    /// in the state of control element.
122    pub max: i32,
123    /// If true, the value in the state of control element increases linearly, thus need calculation
124    /// to convert to the value by dB expression. The calculation shall be:
125    ///
126    /// 20 * log10( current_value / ( maximum_value - minimum_value ) ) (* 100 in 0.1dB unit)
127    ///
128    /// Else, the value in the state of control element corresponds to dB expression itself.
129    pub linear: bool,
130    /// If true, the value less than or equals to [`CTL_VALUE_MUTE`] (=-9999999) is available to
131    /// mute the control element explicitly.
132    pub mute_avail: bool,
133}
134
135impl DbInterval {
136    const VALUE_COUNT: usize = 2;
137}
138
139impl<'a> TlvData<'a> for DbInterval {
140    fn value_type(&self) -> u32 {
141        if self.linear {
142            SNDRV_CTL_TLVT_DB_LINEAR
143        } else if self.mute_avail {
144            SNDRV_CTL_TLVT_DB_MINMAX_MUTE
145        } else {
146            SNDRV_CTL_TLVT_DB_MINMAX
147        }
148    }
149
150    fn value_length(&self) -> usize {
151        Self::VALUE_COUNT
152    }
153
154    fn value(&self) -> Vec<u32> {
155        vec![self.min as u32, self.max as u32]
156    }
157}
158
159const TYPES_FOR_DB_INTERVAL: &'static [u32] = &[
160    SNDRV_CTL_TLVT_DB_LINEAR,
161    SNDRV_CTL_TLVT_DB_MINMAX,
162    SNDRV_CTL_TLVT_DB_MINMAX_MUTE,
163];
164
165impl std::convert::TryFrom<&[u32]> for DbInterval {
166    type Error = TlvDecodeError;
167
168    fn try_from(raw: &[u32]) -> Result<Self, Self::Error> {
169        // At least, type and length field should be included.
170        if raw.len() < 2 {
171            Err(Self::Error::new(TlvDecodeErrorCtx::Length(raw.len(), 2), 0))
172        } else {
173            // Check length field against length of value field.
174            let value_length = (raw[1] / 4) as usize;
175            let value = &raw[2..];
176            if value.len() < value_length || value.len() < Self::VALUE_COUNT {
177                Err(Self::Error::new(
178                    TlvDecodeErrorCtx::ValueLength(value_length, value.len()),
179                    1,
180                ))
181            } else {
182                // Check type field.
183                match raw[0] {
184                    SNDRV_CTL_TLVT_DB_LINEAR => Ok(Self {
185                        min: value[0] as i32,
186                        max: value[1] as i32,
187                        linear: true,
188                        mute_avail: true,
189                    }),
190                    SNDRV_CTL_TLVT_DB_MINMAX => Ok(Self {
191                        min: value[0] as i32,
192                        max: value[1] as i32,
193                        linear: false,
194                        mute_avail: false,
195                    }),
196                    SNDRV_CTL_TLVT_DB_MINMAX_MUTE => Ok(Self {
197                        min: value[0] as i32,
198                        max: value[1] as i32,
199                        linear: false,
200                        mute_avail: true,
201                    }),
202                    _ => Err(Self::Error::new(
203                        TlvDecodeErrorCtx::ValueType(raw[0], TYPES_FOR_DB_INTERVAL),
204                        0,
205                    )),
206                }
207            }
208        }
209    }
210}
211
212impl From<&DbInterval> for Vec<u32> {
213    fn from(data: &DbInterval) -> Self {
214        let mut raw = Vec::new();
215        raw.push(data.value_type());
216        raw.push(4 * data.value_length() as u32);
217        raw.append(&mut data.value());
218        raw
219    }
220}
221
222impl From<DbInterval> for Vec<u32> {
223    fn from(data: DbInterval) -> Self {
224        (&data).into()
225    }
226}
227
228/// The enumeration to express generic channel position corresponding to physical port on real
229/// device. They are defined as `SNDRV_CHMAP_XXX` enumeration in UAPI of Linux kernel.
230#[derive(Debug, Copy, Clone, PartialEq, Eq)]
231pub enum ChmapGenericPos {
232    Unknown,
233    NotAvailable,
234    Monaural,
235    FrontLeft,
236    FrontRight,
237    RearLeft,
238    RearRight,
239    FrontCenter,
240    LowFrequencyEffect,
241    SideLeft,
242    SideRight,
243    RearCenter,
244    FrontLeftCenter,
245    FrontRightCenter,
246    RearLeftCenter,
247    RearRightCenter,
248    FrontLeftWide,
249    FrontRightWide,
250    FrontLeftHigh,
251    FrontCenterHigh,
252    FrontRightHigh,
253    TopCenter,
254    TopFrontLeft,
255    TopFrontRight,
256    TopFrontCenter,
257    TopRearLeft,
258    TopRearRight,
259    TopRearCenter,
260    TopFrontLeftCenter,
261    TopFrontRightCenter,
262    TopSideLeft,
263    TopSideRight,
264    LeftLowFrequencyEffect,
265    RightLowFrequencyEffect,
266    BottomCenter,
267    BottomLeftCenter,
268    BottomRightCenter,
269    Reserved(u16),
270}
271
272impl Default for ChmapGenericPos {
273    fn default() -> Self {
274        Self::Unknown
275    }
276}
277
278impl std::convert::From<u16> for ChmapGenericPos {
279    fn from(val: u16) -> Self {
280        match val as u16 {
281            SNDRV_CHMAP_UNKNOWN => Self::Unknown,
282            SNDRV_CHMAP_NA => Self::NotAvailable,
283            SNDRV_CHMAP_MONO => Self::Monaural,
284            SNDRV_CHMAP_FL => Self::FrontLeft,
285            SNDRV_CHMAP_FR => Self::FrontRight,
286            SNDRV_CHMAP_RL => Self::RearLeft,
287            SNDRV_CHMAP_RR => Self::RearRight,
288            SNDRV_CHMAP_FC => Self::FrontCenter,
289            SNDRV_CHMAP_LFE => Self::LowFrequencyEffect,
290            SNDRV_CHMAP_SL => Self::SideLeft,
291            SNDRV_CHMAP_SR => Self::SideRight,
292            SNDRV_CHMAP_RC => Self::RearCenter,
293            SNDRV_CHMAP_FLC => Self::FrontLeftCenter,
294            SNDRV_CHMAP_FRC => Self::FrontRightCenter,
295            SNDRV_CHMAP_RLC => Self::RearLeftCenter,
296            SNDRV_CHMAP_RRC => Self::RearRightCenter,
297            SNDRV_CHMAP_FLW => Self::FrontLeftWide,
298            SNDRV_CHMAP_FRW => Self::FrontRightWide,
299            SNDRV_CHMAP_FLH => Self::FrontLeftHigh,
300            SNDRV_CHMAP_FCH => Self::FrontCenterHigh,
301            SNDRV_CHMAP_FRH => Self::FrontRightHigh,
302            SNDRV_CHMAP_TC => Self::TopCenter,
303            SNDRV_CHMAP_TFL => Self::TopFrontLeft,
304            SNDRV_CHMAP_TFR => Self::TopFrontRight,
305            SNDRV_CHMAP_TFC => Self::TopFrontCenter,
306            SNDRV_CHMAP_TRL => Self::TopRearLeft,
307            SNDRV_CHMAP_TRR => Self::TopRearRight,
308            SNDRV_CHMAP_TRC => Self::TopRearCenter,
309            SNDRV_CHMAP_TFLC => Self::TopFrontLeftCenter,
310            SNDRV_CHMAP_TFRC => Self::TopFrontRightCenter,
311            SNDRV_CHMAP_TSL => Self::TopSideLeft,
312            SNDRV_CHMAP_TSR => Self::TopSideRight,
313            SNDRV_CHMAP_LLFE => Self::LeftLowFrequencyEffect,
314            SNDRV_CHMAP_RLFE => Self::RightLowFrequencyEffect,
315            SNDRV_CHMAP_BC => Self::BottomCenter,
316            SNDRV_CHMAP_BLC => Self::BottomLeftCenter,
317            SNDRV_CHMAP_BRC => Self::BottomRightCenter,
318            _ => Self::Reserved(val),
319        }
320    }
321}
322
323impl From<ChmapGenericPos> for u16 {
324    fn from(code: ChmapGenericPos) -> Self {
325        match code {
326            ChmapGenericPos::Unknown => SNDRV_CHMAP_UNKNOWN,
327            ChmapGenericPos::NotAvailable => SNDRV_CHMAP_NA,
328            ChmapGenericPos::Monaural => SNDRV_CHMAP_MONO,
329            ChmapGenericPos::FrontLeft => SNDRV_CHMAP_FL,
330            ChmapGenericPos::FrontRight => SNDRV_CHMAP_FR,
331            ChmapGenericPos::RearLeft => SNDRV_CHMAP_RL,
332            ChmapGenericPos::RearRight => SNDRV_CHMAP_RR,
333            ChmapGenericPos::FrontCenter => SNDRV_CHMAP_FC,
334            ChmapGenericPos::LowFrequencyEffect => SNDRV_CHMAP_LFE,
335            ChmapGenericPos::SideLeft => SNDRV_CHMAP_SL,
336            ChmapGenericPos::SideRight => SNDRV_CHMAP_SR,
337            ChmapGenericPos::RearCenter => SNDRV_CHMAP_RC,
338            ChmapGenericPos::FrontLeftCenter => SNDRV_CHMAP_FLC,
339            ChmapGenericPos::FrontRightCenter => SNDRV_CHMAP_FRC,
340            ChmapGenericPos::RearLeftCenter => SNDRV_CHMAP_RLC,
341            ChmapGenericPos::RearRightCenter => SNDRV_CHMAP_RRC,
342            ChmapGenericPos::FrontLeftWide => SNDRV_CHMAP_FLW,
343            ChmapGenericPos::FrontRightWide => SNDRV_CHMAP_FRW,
344            ChmapGenericPos::FrontLeftHigh => SNDRV_CHMAP_FLH,
345            ChmapGenericPos::FrontCenterHigh => SNDRV_CHMAP_FCH,
346            ChmapGenericPos::FrontRightHigh => SNDRV_CHMAP_FRH,
347            ChmapGenericPos::TopCenter => SNDRV_CHMAP_TC,
348            ChmapGenericPos::TopFrontLeft => SNDRV_CHMAP_TFL,
349            ChmapGenericPos::TopFrontRight => SNDRV_CHMAP_TFR,
350            ChmapGenericPos::TopFrontCenter => SNDRV_CHMAP_TFC,
351            ChmapGenericPos::TopRearLeft => SNDRV_CHMAP_TRL,
352            ChmapGenericPos::TopRearRight => SNDRV_CHMAP_TRR,
353            ChmapGenericPos::TopRearCenter => SNDRV_CHMAP_TRC,
354            ChmapGenericPos::TopFrontLeftCenter => SNDRV_CHMAP_TFLC,
355            ChmapGenericPos::TopFrontRightCenter => SNDRV_CHMAP_TFRC,
356            ChmapGenericPos::TopSideLeft => SNDRV_CHMAP_TSL,
357            ChmapGenericPos::TopSideRight => SNDRV_CHMAP_TSR,
358            ChmapGenericPos::LeftLowFrequencyEffect => SNDRV_CHMAP_LLFE,
359            ChmapGenericPos::RightLowFrequencyEffect => SNDRV_CHMAP_RLFE,
360            ChmapGenericPos::BottomCenter => SNDRV_CHMAP_BC,
361            ChmapGenericPos::BottomLeftCenter => SNDRV_CHMAP_BLC,
362            ChmapGenericPos::BottomRightCenter => SNDRV_CHMAP_BRC,
363            ChmapGenericPos::Reserved(val) => val,
364        }
365    }
366}
367
368/// The enumeration to express channel position.
369#[derive(Debug, Copy, Clone, PartialEq, Eq)]
370pub enum ChmapPos {
371    /// The position of channel is generic. It's relevant to the series of `SNDRV_CHMAP_XXX` macro.
372    Generic(ChmapGenericPos),
373    /// The position of channel is specific, programmed by driver. It's relevant to
374    /// `SNDRV_CHMAP_DRIVER_SPEC` macro in UAPI of Linux kernel.
375    Specific(u16),
376}
377
378impl Default for ChmapPos {
379    fn default() -> Self {
380        Self::Generic(Default::default())
381    }
382}
383
384/// The entry to express information of each channel in channel map.
385#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
386pub struct ChmapEntry {
387    /// The position of channel.
388    pub pos: ChmapPos,
389    /// If true, phase is inverted (e.g. a microphone channel within multiple channels). It's
390    /// relevant to `SNDRV_CHMAP_PHASE_INVERSE` macro in UAPI of Linux kernel.
391    pub phase_inverse: bool,
392}
393
394impl std::convert::From<u32> for ChmapEntry {
395    fn from(val: u32) -> Self {
396        let pos_val = (val & 0x0000ffff) as u16;
397        let phase_inverse = val & SNDRV_CHMAP_PHASE_INVERSE > 0;
398        let driver_spec = val & SNDRV_CHMAP_DRIVER_SPEC > 0;
399        let pos = if driver_spec {
400            ChmapPos::Specific(pos_val)
401        } else {
402            ChmapPos::Generic(ChmapGenericPos::from(pos_val))
403        };
404        ChmapEntry { pos, phase_inverse }
405    }
406}
407
408impl From<ChmapEntry> for u32 {
409    fn from(entry: ChmapEntry) -> Self {
410        let mut val = match entry.pos {
411            ChmapPos::Generic(p) => u16::from(p) as u32,
412            ChmapPos::Specific(p) => (p as u32) | SNDRV_CHMAP_DRIVER_SPEC,
413        };
414        if entry.phase_inverse {
415            val |= SNDRV_CHMAP_PHASE_INVERSE;
416        }
417        val
418    }
419}
420
421/// The mode for channel map.
422#[derive(Debug, Copy, Clone, PartialEq, Eq)]
423pub enum ChmapMode {
424    /// The map is fixed and no way to change. It's relevant to `SNDRV_CTL_TLVT_CHMAP_FIXED`.
425    Fixed,
426    /// Each entry in the map is exchangeable arbitrarily. It's relevant to
427    /// `SNDRV_CTL_TLVT_CHMAP_VAR`.
428    ArbitraryExchangeable,
429    /// The stereo pair of entries in the map is exchangeable. It's relevant to
430    /// `SNDRV_CTL_TLVT_CHMAP_PAIRED`.
431    PairedExchangeable,
432}
433
434impl Default for ChmapMode {
435    fn default() -> Self {
436        Self::Fixed
437    }
438}
439
440/// The data to express channel map of PCM substream in TLV (Type-Length-Value) of ALSA control interface.
441///
442/// It has three variants below;
443///  * `SNDRV_CTL_TLVT_CHMAP_FIXED` (=0x101)
444///  * `SNDRV_CTL_TLVT_CHMAP_VAR` (=0x102)
445///  * `SNDRV_CTL_TLVT_CHMAP_PAIRED` (=0x103)
446///
447/// The length of value field is variable depending on the number of channels.
448#[derive(Default, Debug, Clone, PartialEq, Eq)]
449pub struct Chmap {
450    /// The mode of map.
451    pub mode: ChmapMode,
452    /// The entries of map corresponding to each channel.
453    pub entries: Vec<ChmapEntry>,
454}
455
456impl<'a> TlvData<'a> for Chmap {
457    fn value_type(&self) -> u32 {
458        match self.mode {
459            ChmapMode::Fixed => SNDRV_CTL_TLVT_CHMAP_FIXED,
460            ChmapMode::ArbitraryExchangeable => SNDRV_CTL_TLVT_CHMAP_VAR,
461            ChmapMode::PairedExchangeable => SNDRV_CTL_TLVT_CHMAP_PAIRED,
462        }
463    }
464
465    fn value_length(&self) -> usize {
466        self.entries.len()
467    }
468
469    fn value(&self) -> Vec<u32> {
470        let mut raw = Vec::new();
471        self.entries
472            .iter()
473            .for_each(|&entry| raw.push(u32::from(entry)));
474        raw
475    }
476}
477
478const TYPES_FOR_CHMAP: &'static [u32] = &[
479    SNDRV_CTL_TLVT_CHMAP_FIXED,
480    SNDRV_CTL_TLVT_CHMAP_VAR,
481    SNDRV_CTL_TLVT_CHMAP_PAIRED,
482];
483
484impl std::convert::TryFrom<&[u32]> for Chmap {
485    type Error = TlvDecodeError;
486
487    fn try_from(raw: &[u32]) -> Result<Self, Self::Error> {
488        // At least, type and length field should be included.
489        if raw.len() < 2 {
490            Err(Self::Error::new(TlvDecodeErrorCtx::Length(raw.len(), 2), 0))
491        } else {
492            // Check type field.
493            let mode = match raw[0] {
494                SNDRV_CTL_TLVT_CHMAP_FIXED => Ok(ChmapMode::Fixed),
495                SNDRV_CTL_TLVT_CHMAP_VAR => Ok(ChmapMode::ArbitraryExchangeable),
496                SNDRV_CTL_TLVT_CHMAP_PAIRED => Ok(ChmapMode::PairedExchangeable),
497                _ => Err(Self::Error::new(
498                    TlvDecodeErrorCtx::ValueType(raw[0], TYPES_FOR_CHMAP),
499                    0,
500                )),
501            }?;
502
503            // Check length field against length of value field.
504            let value_length = (raw[1] / 4) as usize;
505            let value = &raw[2..];
506            if value.len() < value_length {
507                Err(Self::Error::new(
508                    TlvDecodeErrorCtx::ValueLength(value_length, value.len()),
509                    1,
510                ))
511            } else if mode == ChmapMode::PairedExchangeable && value.len() % 2 > 0 {
512                Err(Self::Error::new(
513                    TlvDecodeErrorCtx::ValueLength(value_length, value.len()),
514                    1,
515                ))
516            } else {
517                // Decode value field.
518                let entries = value.iter().map(|&val| ChmapEntry::from(val)).collect();
519                Ok(Self { mode, entries })
520            }
521        }
522    }
523}
524
525impl From<&Chmap> for Vec<u32> {
526    fn from(data: &Chmap) -> Self {
527        let mut raw = Vec::new();
528        raw.push(data.value_type());
529        raw.push(4 * data.value_length() as u32);
530        raw.append(&mut data.value());
531        raw
532    }
533}
534
535impl From<Chmap> for Vec<u32> {
536    fn from(data: Chmap) -> Self {
537        (&data).into()
538    }
539}
540
541#[cfg(test)]
542mod test {
543    use super::{Chmap, ChmapEntry, ChmapGenericPos, ChmapMode, ChmapPos};
544    use super::{DbInterval, DbScale};
545    use std::convert::TryFrom;
546
547    #[test]
548    fn test_dbitem() {
549        let raw = [1u32, 8, -10i32 as u32, 0x00000010];
550        let item = DbScale::try_from(raw.as_ref()).unwrap();
551        assert_eq!(item.min, -10);
552        assert_eq!(item.step, 16);
553        assert_eq!(item.mute_avail, false);
554        assert_eq!(&Vec::<u32>::from(item)[..], &raw[..]);
555    }
556
557    #[test]
558    fn test_dbitem_mute_avail() {
559        let raw = [1u32, 8, 10, 0x00010010];
560        let item = DbScale::try_from(raw.as_ref()).unwrap();
561        assert_eq!(item.min, 10);
562        assert_eq!(item.step, 16);
563        assert_eq!(item.mute_avail, true);
564        assert_eq!(&Vec::<u32>::from(item)[..], &raw[..]);
565    }
566
567    #[test]
568    fn test_dbinterval() {
569        let raw = [4u32, 8, -100i32 as u32, 100];
570        let item = DbInterval::try_from(&raw[..]).unwrap();
571        assert_eq!(item.min, -100);
572        assert_eq!(item.max, 100);
573        assert_eq!(item.linear, false);
574        assert_eq!(item.mute_avail, false);
575        assert_eq!(&Vec::<u32>::from(item)[..], &raw[..]);
576    }
577
578    #[test]
579    fn test_dbinterval_mute() {
580        let raw = [5u32, 8, -100i32 as u32, 100];
581        let item = DbInterval::try_from(&raw[..]).unwrap();
582        assert_eq!(item.min, -100);
583        assert_eq!(item.max, 100);
584        assert_eq!(item.linear, false);
585        assert_eq!(item.mute_avail, true);
586        assert_eq!(&Vec::<u32>::from(item)[..], &raw[..]);
587    }
588
589    #[test]
590    fn test_dbinterval_linear() {
591        let raw = [2u32, 8, -100i32 as u32, 100];
592        let item = DbInterval::try_from(&raw[..]).unwrap();
593        assert_eq!(item.min, -100);
594        assert_eq!(item.max, 100);
595        assert_eq!(item.linear, true);
596        assert_eq!(item.mute_avail, true);
597        assert_eq!(&Vec::<u32>::from(item)[..], &raw[..]);
598    }
599
600    #[test]
601    fn test_chmapgenericpos() {
602        (0..u16::MAX).for_each(|val| {
603            let generic_pos = ChmapGenericPos::from(val);
604            assert_eq!(u16::from(generic_pos), val);
605        });
606    }
607
608    #[test]
609    fn test_chmapentry() {
610        (0..37).for_each(|val| {
611            let raw = val as u32;
612            let entry = ChmapEntry::try_from(raw).unwrap();
613            assert_eq!(entry.phase_inverse, false);
614            assert_eq!(u32::from(entry), raw);
615
616            let raw = 0x00010000u32 | (val as u32);
617            let entry = ChmapEntry::try_from(raw).unwrap();
618            assert_eq!(entry.phase_inverse, true);
619            assert_eq!(u32::from(entry), raw);
620
621            let raw = 0x00020000u32 | (val as u32);
622            let entry = ChmapEntry::try_from(raw).unwrap();
623            assert_eq!(entry.phase_inverse, false);
624            assert_eq!(u32::from(entry), raw);
625        });
626    }
627
628    #[test]
629    fn test_chmap_fixed() {
630        let raw = [0x101u32, 8, 3, 4];
631        let map = Chmap::try_from(&raw[..]).unwrap();
632        assert_eq!(map.mode, ChmapMode::Fixed);
633        assert_eq!(
634            &map.entries[..],
635            &[
636                ChmapEntry {
637                    pos: ChmapPos::Generic(ChmapGenericPos::FrontLeft),
638                    phase_inverse: false
639                },
640                ChmapEntry {
641                    pos: ChmapPos::Generic(ChmapGenericPos::FrontRight),
642                    phase_inverse: false
643                },
644            ]
645        );
646        assert_eq!(&Vec::<u32>::from(map)[..], &raw[..]);
647    }
648
649    #[test]
650    fn test_chmap_arbitrary_exchangeable() {
651        let raw = [0x102u32, 12, 3, 4, 8];
652        let map = Chmap::try_from(&raw[..]).unwrap();
653        assert_eq!(map.mode, ChmapMode::ArbitraryExchangeable);
654        assert_eq!(
655            &map.entries[..],
656            &[
657                ChmapEntry {
658                    pos: ChmapPos::Generic(ChmapGenericPos::FrontLeft),
659                    phase_inverse: false
660                },
661                ChmapEntry {
662                    pos: ChmapPos::Generic(ChmapGenericPos::FrontRight),
663                    phase_inverse: false
664                },
665                ChmapEntry {
666                    pos: ChmapPos::Generic(ChmapGenericPos::LowFrequencyEffect),
667                    phase_inverse: false
668                },
669            ][..]
670        );
671        assert_eq!(&Vec::<u32>::from(map)[..], &raw[..]);
672    }
673
674    #[test]
675    fn test_chmap_paired_exchangeable() {
676        let raw = [0x103u32, 16, 3, 4, 5, 6];
677        let map = Chmap::try_from(&raw[..]).unwrap();
678        assert_eq!(map.mode, ChmapMode::PairedExchangeable);
679        assert_eq!(
680            &map.entries[..],
681            &[
682                ChmapEntry {
683                    pos: ChmapPos::Generic(ChmapGenericPos::FrontLeft),
684                    phase_inverse: false
685                },
686                ChmapEntry {
687                    pos: ChmapPos::Generic(ChmapGenericPos::FrontRight),
688                    phase_inverse: false
689                },
690                ChmapEntry {
691                    pos: ChmapPos::Generic(ChmapGenericPos::RearLeft),
692                    phase_inverse: false
693                },
694                ChmapEntry {
695                    pos: ChmapPos::Generic(ChmapGenericPos::RearRight),
696                    phase_inverse: false
697                },
698            ][..]
699        );
700        assert_eq!(&Vec::<u32>::from(map)[..], &raw[..]);
701    }
702}