Skip to main content

audioadapter_sample/
sample.rs

1#![allow(non_camel_case_types)]
2
3use num_traits::{PrimInt, ToPrimitive, float::FloatCore};
4
5// ------ 16-bit integer formats ------
6
7/// 16 bit signed integer, little endian. Stored as 2 bytes.
8#[derive(Debug, Clone, Copy)]
9pub struct I16_LE([u8; 2]);
10
11/// 16 bit signed integer, big endian. Stored as 2 bytes.
12#[derive(Debug, Clone, Copy)]
13pub struct I16_BE([u8; 2]);
14
15/// 16 bit unsigned integer, little endian. Stored as 2 bytes.
16#[derive(Debug, Clone, Copy)]
17pub struct U16_LE([u8; 2]);
18
19/// 16 bit unsigned integer, big endian. Stored as 2 bytes.
20#[derive(Debug, Clone, Copy)]
21pub struct U16_BE([u8; 2]);
22
23// ----- 24-bit formats -----
24
25/// 24 bit signed integer, little endian. Stored as 3 bytes.
26#[derive(Debug, Clone, Copy)]
27pub struct I24_LE([u8; 3]);
28
29/// 24 bit signed integer, little endian. Stored as 4 bytes left justified.
30/// The 24 data bits are stored in the three most significant bytes,
31/// while the least significant byte is unused padding.
32#[derive(Debug, Clone, Copy)]
33pub struct I24_4LJ_LE([u8; 4]);
34
35/// 24 bit signed integer, little endian. Stored as 4 bytes right justified.
36/// The 24 data bits are stored in the three least significant bytes,
37/// while the most significant byte is unused padding.
38#[derive(Debug, Clone, Copy)]
39pub struct I24_4RJ_LE([u8; 4]);
40
41/// 24 bit signed integer, big endian. Stored as 3 bytes.
42#[derive(Debug, Clone, Copy)]
43pub struct I24_BE([u8; 3]);
44
45/// 24 bit signed integer, big endian. Stored as 4 bytes left justified.
46/// The 24 data bits are stored in the three most significant bytes,
47/// while the least significant byte is unused padding.
48#[derive(Debug, Clone, Copy)]
49pub struct I24_4LJ_BE([u8; 4]);
50
51/// 24 bit signed integer, big endian. Stored as 4 bytes right justified.
52/// The 24 data bits are stored in the three least significant bytes,
53/// while the most significant byte is unused padding.
54#[derive(Debug, Clone, Copy)]
55pub struct I24_4RJ_BE([u8; 4]);
56
57/// 24 bit unsigned integer, little endian. Stored as 3 bytes.
58#[derive(Debug, Clone, Copy)]
59pub struct U24_LE([u8; 3]);
60
61/// 24 bit unsigned integer, little endian. Stored as 4 bytes left justified.
62/// The 24 data bits are stored in the three most significant bytes,
63/// while the least significant byte is unused padding.
64#[derive(Debug, Clone, Copy)]
65pub struct U24_4LJ_LE([u8; 4]);
66
67/// 24 bit unsigned integer, little endian. Stored as 4 bytes right justified.
68/// The 24 data bits are stored in the three least significant bytes,
69/// while the most significant byte is unused padding.
70#[derive(Debug, Clone, Copy)]
71pub struct U24_4RJ_LE([u8; 4]);
72
73/// 24 bit unsigned integer, big endian. Stored as 3 bytes.
74#[derive(Debug, Clone, Copy)]
75pub struct U24_BE([u8; 3]);
76
77/// 24 bit unsigned integer, big endian. Stored as 4 bytes left justified.
78/// The 24 data bits are stored in the three most significant bytes,
79/// while the least significant byte is unused padding.
80#[derive(Debug, Clone, Copy)]
81pub struct U24_4LJ_BE([u8; 4]);
82
83/// 24 bit unsigned integer, big endian. Stored as 4 bytes right justified.
84/// The 24 data bits are stored in the three least significant bytes,
85/// while the most significant byte is unused padding.
86#[derive(Debug, Clone, Copy)]
87pub struct U24_4RJ_BE([u8; 4]);
88
89// ------ 32-bit integer formats ------
90
91/// 32 bit signed integer, little endian. Stored as 4 bytes.
92#[derive(Debug, Clone, Copy)]
93pub struct I32_LE([u8; 4]);
94
95/// 32 bit signed integer, big endian. Stored as 4 bytes.
96#[derive(Debug, Clone, Copy)]
97pub struct I32_BE([u8; 4]);
98
99/// 32 bit unsigned integer, little endian. Stored as 4 bytes.
100#[derive(Debug, Clone, Copy)]
101pub struct U32_LE([u8; 4]);
102
103/// 32 bit unsigned integer, big endian. Stored as 4 bytes.
104#[derive(Debug, Clone, Copy)]
105pub struct U32_BE([u8; 4]);
106
107// ----- 64-bit integer formats ------
108
109/// 64 bit signed integer, little endian. Stored as 8 bytes.
110#[derive(Debug, Clone, Copy)]
111pub struct I64_LE([u8; 8]);
112
113/// 64 bit signed integer, big endian. Stored as 8 bytes.
114#[derive(Debug, Clone, Copy)]
115pub struct I64_BE([u8; 8]);
116
117/// 64 bit unsigned integer, little endian. Stored as 8 bytes.
118#[derive(Debug, Clone, Copy)]
119pub struct U64_LE([u8; 8]);
120
121/// 64 bit unsigned integer, big endian. Stored as 8 bytes.
122#[derive(Debug, Clone, Copy)]
123pub struct U64_BE([u8; 8]);
124
125// ----- floating point formats -----
126
127/// 32 bit floating point, little endian. Stored as 4 bytes.
128#[derive(Debug, Clone, Copy)]
129pub struct F32_LE([u8; 4]);
130
131/// 32 bit floating point, big endian. Stored as 4 bytes.
132#[derive(Debug, Clone, Copy)]
133pub struct F32_BE([u8; 4]);
134
135/// 64 bit floating point, little endian. Stored as 8 bytes.
136#[derive(Debug, Clone, Copy)]
137pub struct F64_LE([u8; 8]);
138
139/// 64 bit floating point, big endian. Stored as 8 bytes.
140#[derive(Debug, Clone, Copy)]
141pub struct F64_BE([u8; 8]);
142
143/// Convert a float to an integer, clamp at the min and max limits of the integer.
144fn to_clamped_int<T: FloatCore + ToPrimitive, U: PrimInt>(
145    value: T,
146    converted: Option<U>,
147) -> ConversionResult<U> {
148    if let Some(val) = converted {
149        return ConversionResult {
150            clipped: false,
151            value: val,
152        };
153    }
154    if value.is_nan() {
155        return ConversionResult {
156            clipped: true,
157            value: U::zero(),
158        };
159    }
160    if value > T::zero() {
161        return ConversionResult {
162            clipped: true,
163            value: U::max_value(),
164        };
165    }
166    ConversionResult {
167        clipped: true,
168        value: U::min_value(),
169    }
170}
171
172/// A conversion result, containing the resulting value as `value`
173/// and a boolean `clipped` indicating if the value was clipped during conversion.
174pub struct ConversionResult<T> {
175    pub clipped: bool,
176    pub value: T,
177}
178
179/// A trait for converting a given sample type to and from floating point values.
180/// The floating point values use the range -1.0 to +1.0.
181/// When converting to/from signed integers, the range does not include +1.0.
182/// For example, an 8-bit signed integer supports the range -128 to +127.
183/// When these values are converted to float, 0 becomes 0.0,
184/// -128 becomes -1.0, and 127 becomes 127/128 ≈ 0.992.
185/// Unsigned integers are also converted to the same -1.0 to +1.0 range.
186/// For an 8-but unsigned integer, 128 is the center point and becomes 0.0.
187/// The value 0 becomes -1.0, and 255 becomes 127/128 ≈ 0.992.
188pub trait RawSample
189where
190    Self: Sized,
191{
192    /// Convert the sample value to a float in the range -1.0 .. +1.0.
193    fn to_scaled_float<T: FloatCore + ToPrimitive>(&self) -> T;
194
195    /// Convert a float in the range -1.0 .. +1.0 to a sample value.
196    ///
197    /// For integer formats, values outside the allowed range are clipped to the
198    /// nearest limit and the returned `clipped` flag is set.
199    /// Floating point formats are not range-limited: values outside -1.0 .. +1.0
200    /// are valid headroom, are passed through unchanged, and never set `clipped`.
201    fn from_scaled_float<T: FloatCore + ToPrimitive>(value: T) -> ConversionResult<Self>;
202}
203
204/// A trait for converting samples stored as raw bytes into a numerical type.
205/// Each implementation defines the associated type `NumericType`,
206/// which is the nearest matching numeric type for the original format.
207/// If a direct match exists, this is used.
208/// For example signed 16 bit integer samples use [i16].
209/// For formats that don't have a direct match,
210/// the next larger numeric type is used.
211/// For example for 24 bit signed integers,
212/// this means [i32].
213/// The values are scaled to use the full range of the `NumericType`
214/// associated type.
215pub trait BytesSample {
216    /// The closest matching numeric type.
217    type NumericType: Copy;
218
219    /// The number of bytes making up each sample value.
220    const BYTES_PER_SAMPLE: usize;
221
222    /// Create a sample with all bytes set to zero.
223    ///
224    /// This gives a correctly sized, valid value whose bytes can then be
225    /// overwritten, for example via [`as_mut_slice`](Self::as_mut_slice) when
226    /// reading from a stream.
227    fn zero() -> Self;
228
229    /// Create a new ByteSample from a slice of raw bytes.
230    /// The slice length must be at least the number of bytes
231    /// for a sample value.
232    fn from_slice(bytes: &[u8]) -> Self;
233
234    /// Return the raw bytes as a slice.
235    fn as_slice(&self) -> &[u8];
236
237    /// Return the raw bytes as a mutable slice.
238    fn as_mut_slice(&mut self) -> &mut [u8];
239
240    /// Convert the raw bytes to a numerical value.
241    fn to_number(&self) -> Self::NumericType;
242
243    /// Convert a numerical value to raw bytes.
244    fn from_number(value: Self::NumericType) -> Self;
245}
246
247macro_rules! rawsample_for_int {
248    ($type:ident, $to:ident) => {
249        impl RawSample for $type {
250            fn to_scaled_float<T: FloatCore + ToPrimitive>(&self) -> T {
251                T::from(*self).unwrap() / (T::from($type::MAX).unwrap() + T::one())
252            }
253
254            fn from_scaled_float<T: FloatCore + ToPrimitive>(value: T) -> ConversionResult<Self> {
255                let scaled = value * (T::from($type::MAX).unwrap() + T::one());
256                let converted = scaled.$to();
257                to_clamped_int(scaled, converted)
258            }
259        }
260    };
261}
262
263rawsample_for_int!(i8, to_i8);
264rawsample_for_int!(i16, to_i16);
265rawsample_for_int!(i32, to_i32);
266rawsample_for_int!(i64, to_i64);
267
268macro_rules! rawsample_for_uint {
269    ($type:ident, $to:ident) => {
270        impl RawSample for $type {
271            fn to_scaled_float<T: FloatCore + ToPrimitive>(&self) -> T {
272                let max_ampl = (T::from($type::MAX).unwrap() + T::one()) / T::from(2).unwrap();
273                (T::from(*self).unwrap() - max_ampl) / max_ampl
274            }
275
276            fn from_scaled_float<T: FloatCore + ToPrimitive>(value: T) -> ConversionResult<Self> {
277                let max_ampl = (T::from($type::MAX).unwrap() + T::one()) / T::from(2).unwrap();
278                let scaled = value * max_ampl + max_ampl;
279                let converted = scaled.$to();
280                to_clamped_int(scaled, converted)
281            }
282        }
283    };
284}
285
286rawsample_for_uint!(u8, to_u8);
287rawsample_for_uint!(u16, to_u16);
288rawsample_for_uint!(u32, to_u32);
289rawsample_for_uint!(u64, to_u64);
290
291macro_rules! rawsample_for_float {
292    ($type:ident, $to:ident) => {
293        impl RawSample for $type {
294            fn to_scaled_float<T: FloatCore + ToPrimitive>(&self) -> T {
295                T::from(*self).unwrap_or(T::zero())
296            }
297
298            fn from_scaled_float<T: FloatCore + ToPrimitive>(value: T) -> ConversionResult<Self> {
299                // Floating point formats are not range-limited. Values outside
300                // -1.0..1.0 are valid headroom and pass through unchanged, so no
301                // clipping is applied and `clipped` is always false.
302                ConversionResult {
303                    clipped: false,
304                    value: value.$to().unwrap_or(0.0),
305                }
306            }
307        }
308    };
309}
310
311rawsample_for_float!(f32, to_f32);
312rawsample_for_float!(f64, to_f64);
313
314// 24 bit formats, needs more work than others
315// because they don't map directly to a normal numerical type,
316
317/// 24 bit signed integer, little endian, stored as 4 bytes right justified.
318/// The data is in the lower 3 bytes and the most significant byte is padding.
319impl BytesSample for I24_4RJ_LE {
320    type NumericType = i32;
321    const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
322
323    fn zero() -> Self {
324        Self(Default::default())
325    }
326
327    fn from_slice(bytes: &[u8]) -> Self {
328        Self(bytes[0..4].try_into().unwrap())
329    }
330
331    fn as_slice(&self) -> &[u8] {
332        &self.0
333    }
334
335    fn as_mut_slice(&mut self) -> &mut [u8] {
336        &mut self.0
337    }
338
339    fn to_number(&self) -> Self::NumericType {
340        let padded = [0, self.0[0], self.0[1], self.0[2]];
341        i32::from_le_bytes(padded)
342    }
343
344    fn from_number(value: Self::NumericType) -> Self {
345        let bytes = value.to_le_bytes();
346        Self([bytes[1], bytes[2], bytes[3], 0])
347    }
348}
349
350/// 24 bit signed integer, little endian, stored as 4 bytes left justified.
351/// The data is in the upper 3 bytes and the least significant byte is padding.
352impl BytesSample for I24_4LJ_LE {
353    type NumericType = i32;
354    const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
355
356    fn zero() -> Self {
357        Self(Default::default())
358    }
359
360    fn from_slice(bytes: &[u8]) -> Self {
361        Self(bytes[0..4].try_into().unwrap())
362    }
363
364    fn as_slice(&self) -> &[u8] {
365        &self.0
366    }
367
368    fn as_mut_slice(&mut self) -> &mut [u8] {
369        &mut self.0
370    }
371
372    fn to_number(&self) -> Self::NumericType {
373        let padded = [0, self.0[1], self.0[2], self.0[3]];
374        i32::from_le_bytes(padded)
375    }
376
377    fn from_number(value: Self::NumericType) -> Self {
378        let bytes = value.to_le_bytes();
379        Self([0, bytes[1], bytes[2], bytes[3]])
380    }
381}
382
383/// 24 bit signed integer, little endian, stored as 3 bytes without padding.
384impl BytesSample for I24_LE {
385    type NumericType = i32;
386    const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
387
388    fn zero() -> Self {
389        Self(Default::default())
390    }
391
392    fn from_slice(bytes: &[u8]) -> Self {
393        Self(bytes[0..3].try_into().unwrap())
394    }
395
396    fn as_slice(&self) -> &[u8] {
397        &self.0
398    }
399
400    fn as_mut_slice(&mut self) -> &mut [u8] {
401        &mut self.0
402    }
403
404    fn to_number(&self) -> Self::NumericType {
405        let padded = [0, self.0[0], self.0[1], self.0[2]];
406        i32::from_le_bytes(padded)
407    }
408
409    fn from_number(value: Self::NumericType) -> Self {
410        let bytes = value.to_le_bytes();
411        Self([bytes[1], bytes[2], bytes[3]])
412    }
413}
414
415/// 24 bit signed integer, big endian, stored as 4 bytes right justified.
416/// The data is in the lower 3 bytes and the most significant byte is padding.
417impl BytesSample for I24_4RJ_BE {
418    type NumericType = i32;
419    const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
420
421    fn zero() -> Self {
422        Self(Default::default())
423    }
424
425    fn from_slice(bytes: &[u8]) -> Self {
426        Self(bytes[0..4].try_into().unwrap())
427    }
428
429    fn as_slice(&self) -> &[u8] {
430        &self.0
431    }
432
433    fn as_mut_slice(&mut self) -> &mut [u8] {
434        &mut self.0
435    }
436
437    fn to_number(&self) -> Self::NumericType {
438        let padded = [self.0[1], self.0[2], self.0[3], 0];
439        i32::from_be_bytes(padded)
440    }
441
442    fn from_number(value: Self::NumericType) -> Self {
443        let bytes = value.to_be_bytes();
444        Self([0, bytes[0], bytes[1], bytes[2]])
445    }
446}
447
448/// 24 bit signed integer, big endian, stored as 4 bytes left justified.
449/// The data is in the upper 3 bytes and the least significant byte is padding.
450impl BytesSample for I24_4LJ_BE {
451    type NumericType = i32;
452    const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
453
454    fn zero() -> Self {
455        Self(Default::default())
456    }
457
458    fn from_slice(bytes: &[u8]) -> Self {
459        Self(bytes[0..4].try_into().unwrap())
460    }
461
462    fn as_slice(&self) -> &[u8] {
463        &self.0
464    }
465
466    fn as_mut_slice(&mut self) -> &mut [u8] {
467        &mut self.0
468    }
469
470    fn to_number(&self) -> Self::NumericType {
471        let padded = [self.0[0], self.0[1], self.0[2], 0];
472        i32::from_be_bytes(padded)
473    }
474
475    fn from_number(value: Self::NumericType) -> Self {
476        let bytes = value.to_be_bytes();
477        Self([bytes[0], bytes[1], bytes[2], 0])
478    }
479}
480
481/// 24 bit signed integer, big endian, stored as 3 bytes without padding.
482impl BytesSample for I24_BE {
483    type NumericType = i32;
484    const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
485
486    fn zero() -> Self {
487        Self(Default::default())
488    }
489
490    fn from_slice(bytes: &[u8]) -> Self {
491        Self(bytes[0..3].try_into().unwrap())
492    }
493
494    fn as_slice(&self) -> &[u8] {
495        &self.0
496    }
497
498    fn as_mut_slice(&mut self) -> &mut [u8] {
499        &mut self.0
500    }
501
502    fn to_number(&self) -> Self::NumericType {
503        let padded = [self.0[0], self.0[1], self.0[2], 0];
504        i32::from_be_bytes(padded)
505    }
506
507    fn from_number(value: Self::NumericType) -> Self {
508        let bytes = value.to_be_bytes();
509        Self([bytes[0], bytes[1], bytes[2]])
510    }
511}
512
513/// 24 bit unsigned integer, little endian, stored as 4 bytes right justified.
514/// The data is in the lower 3 bytes and the most significant byte is padding.
515impl BytesSample for U24_4RJ_LE {
516    type NumericType = u32;
517    const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
518
519    fn zero() -> Self {
520        Self(Default::default())
521    }
522
523    fn from_slice(bytes: &[u8]) -> Self {
524        Self(bytes[0..4].try_into().unwrap())
525    }
526
527    fn as_slice(&self) -> &[u8] {
528        &self.0
529    }
530
531    fn as_mut_slice(&mut self) -> &mut [u8] {
532        &mut self.0
533    }
534
535    fn to_number(&self) -> Self::NumericType {
536        let padded = [0, self.0[0], self.0[1], self.0[2]];
537        u32::from_le_bytes(padded)
538    }
539
540    fn from_number(value: Self::NumericType) -> Self {
541        let bytes = value.to_le_bytes();
542        Self([bytes[1], bytes[2], bytes[3], 0])
543    }
544}
545
546/// 24 bit unsigned integer, little endian, stored as 4 bytes left justified.
547/// The data is in the upper 3 bytes and the least significant byte is padding.
548impl BytesSample for U24_4LJ_LE {
549    type NumericType = u32;
550    const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
551
552    fn zero() -> Self {
553        Self(Default::default())
554    }
555
556    fn from_slice(bytes: &[u8]) -> Self {
557        Self(bytes[0..4].try_into().unwrap())
558    }
559
560    fn as_slice(&self) -> &[u8] {
561        &self.0
562    }
563
564    fn as_mut_slice(&mut self) -> &mut [u8] {
565        &mut self.0
566    }
567
568    fn to_number(&self) -> Self::NumericType {
569        let padded = [0, self.0[1], self.0[2], self.0[3]];
570        u32::from_le_bytes(padded)
571    }
572
573    fn from_number(value: Self::NumericType) -> Self {
574        let bytes = value.to_le_bytes();
575        Self([0, bytes[1], bytes[2], bytes[3]])
576    }
577}
578
579/// 24 bit unsigned integer, little endian, stored as 3 bytes without padding.
580impl BytesSample for U24_LE {
581    type NumericType = u32;
582    const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
583
584    fn zero() -> Self {
585        Self(Default::default())
586    }
587
588    fn from_slice(bytes: &[u8]) -> Self {
589        Self(bytes[0..3].try_into().unwrap())
590    }
591
592    fn as_slice(&self) -> &[u8] {
593        &self.0
594    }
595
596    fn as_mut_slice(&mut self) -> &mut [u8] {
597        &mut self.0
598    }
599
600    fn to_number(&self) -> Self::NumericType {
601        let padded = [0, self.0[0], self.0[1], self.0[2]];
602        u32::from_le_bytes(padded)
603    }
604
605    fn from_number(value: Self::NumericType) -> Self {
606        let bytes = value.to_le_bytes();
607        Self([bytes[1], bytes[2], bytes[3]])
608    }
609}
610
611/// 24 bit unsigned integer, big endian, stored as 4 bytes right justified.
612/// The data is in the lower 3 bytes and the most significant byte is padding.
613impl BytesSample for U24_4RJ_BE {
614    type NumericType = u32;
615    const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
616
617    fn zero() -> Self {
618        Self(Default::default())
619    }
620
621    fn from_slice(bytes: &[u8]) -> Self {
622        Self(bytes[0..4].try_into().unwrap())
623    }
624
625    fn as_slice(&self) -> &[u8] {
626        &self.0
627    }
628
629    fn as_mut_slice(&mut self) -> &mut [u8] {
630        &mut self.0
631    }
632
633    fn to_number(&self) -> Self::NumericType {
634        let padded = [self.0[1], self.0[2], self.0[3], 0];
635        u32::from_be_bytes(padded)
636    }
637
638    fn from_number(value: Self::NumericType) -> Self {
639        let bytes = value.to_be_bytes();
640        Self([0, bytes[0], bytes[1], bytes[2]])
641    }
642}
643
644/// 24 bit unsigned integer, big endian, stored as 4 bytes left justified.
645/// The data is in the upper 3 bytes and the least significant byte is padding.
646impl BytesSample for U24_4LJ_BE {
647    type NumericType = u32;
648    const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
649
650    fn zero() -> Self {
651        Self(Default::default())
652    }
653
654    fn from_slice(bytes: &[u8]) -> Self {
655        Self(bytes[0..4].try_into().unwrap())
656    }
657
658    fn as_slice(&self) -> &[u8] {
659        &self.0
660    }
661
662    fn as_mut_slice(&mut self) -> &mut [u8] {
663        &mut self.0
664    }
665
666    fn to_number(&self) -> Self::NumericType {
667        let padded = [self.0[0], self.0[1], self.0[2], 0];
668        u32::from_be_bytes(padded)
669    }
670
671    fn from_number(value: Self::NumericType) -> Self {
672        let bytes = value.to_be_bytes();
673        Self([bytes[0], bytes[1], bytes[2], 0])
674    }
675}
676
677/// 24 bit unsigned integer, big endian, stored as 3 bytes without padding.
678impl BytesSample for U24_BE {
679    type NumericType = u32;
680    const BYTES_PER_SAMPLE: usize = core::mem::size_of::<Self>();
681
682    fn zero() -> Self {
683        Self(Default::default())
684    }
685
686    fn from_slice(bytes: &[u8]) -> Self {
687        Self(bytes[0..3].try_into().unwrap())
688    }
689
690    fn as_slice(&self) -> &[u8] {
691        &self.0
692    }
693
694    fn as_mut_slice(&mut self) -> &mut [u8] {
695        &mut self.0
696    }
697
698    fn to_number(&self) -> Self::NumericType {
699        let padded = [self.0[0], self.0[1], self.0[2], 0];
700        u32::from_be_bytes(padded)
701    }
702
703    fn from_number(value: Self::NumericType) -> Self {
704        let bytes = value.to_be_bytes();
705        Self([bytes[0], bytes[1], bytes[2]])
706    }
707}
708
709macro_rules! bytessample_for_newtype {
710    ($type:ident, $newtype:ident, $from:ident, $to:ident) => {
711        impl BytesSample for $newtype {
712            type NumericType = $type;
713            const BYTES_PER_SAMPLE: usize = core::mem::size_of::<$type>();
714
715            fn zero() -> Self {
716                Self(Default::default())
717            }
718
719            fn from_slice(bytes: &[u8]) -> Self {
720                Self(bytes.try_into().unwrap())
721            }
722
723            fn as_slice(&self) -> &[u8] {
724                &self.0
725            }
726
727            fn as_mut_slice(&mut self) -> &mut [u8] {
728                &mut self.0
729            }
730
731            fn to_number(&self) -> Self::NumericType {
732                $type::$from(self.0)
733            }
734
735            fn from_number(value: Self::NumericType) -> Self {
736                Self(value.$to())
737            }
738        }
739    };
740}
741
742bytessample_for_newtype!(i64, I64_LE, from_le_bytes, to_le_bytes);
743bytessample_for_newtype!(u64, U64_LE, from_le_bytes, to_le_bytes);
744bytessample_for_newtype!(i64, I64_BE, from_be_bytes, to_be_bytes);
745bytessample_for_newtype!(u64, U64_BE, from_be_bytes, to_be_bytes);
746
747bytessample_for_newtype!(i16, I16_LE, from_le_bytes, to_le_bytes);
748bytessample_for_newtype!(u16, U16_LE, from_le_bytes, to_le_bytes);
749bytessample_for_newtype!(i16, I16_BE, from_be_bytes, to_be_bytes);
750bytessample_for_newtype!(u16, U16_BE, from_be_bytes, to_be_bytes);
751
752bytessample_for_newtype!(i32, I32_LE, from_le_bytes, to_le_bytes);
753bytessample_for_newtype!(u32, U32_LE, from_le_bytes, to_le_bytes);
754bytessample_for_newtype!(i32, I32_BE, from_be_bytes, to_be_bytes);
755bytessample_for_newtype!(u32, U32_BE, from_be_bytes, to_be_bytes);
756
757bytessample_for_newtype!(f32, F32_LE, from_le_bytes, to_le_bytes);
758bytessample_for_newtype!(f32, F32_BE, from_be_bytes, to_be_bytes);
759bytessample_for_newtype!(f64, F64_LE, from_le_bytes, to_le_bytes);
760bytessample_for_newtype!(f64, F64_BE, from_be_bytes, to_be_bytes);
761
762impl<V> RawSample for V
763where
764    V: BytesSample,
765    <V as BytesSample>::NumericType: RawSample,
766{
767    fn to_scaled_float<T: FloatCore + ToPrimitive>(&self) -> T {
768        let value = self.to_number();
769        value.to_scaled_float()
770    }
771
772    fn from_scaled_float<T: FloatCore + ToPrimitive>(value: T) -> ConversionResult<Self> {
773        let value = <V as BytesSample>::NumericType::from_scaled_float(value);
774        ConversionResult {
775            clipped: value.clipped,
776            value: V::from_number(value.value),
777        }
778    }
779}
780
781#[cfg(test)]
782mod tests {
783    use super::*;
784
785    macro_rules! assert_conversion_eq {
786        ($result:expr, $value:expr, $clipped:expr, $desc:expr) => {
787            assert_eq!($result.value, $value, $desc);
788            assert_eq!($result.clipped, $clipped, $desc);
789        };
790    }
791
792    macro_rules! test_to_signed_int {
793        ($fname:ident, $float:ty, $int:ident, $bits:expr) => {
794            #[test]
795            fn $fname() {
796                let val: $float = 0.25;
797                assert_conversion_eq!(
798                    $int::from_scaled_float(val),
799                    1 << ($bits - 3),
800                    false,
801                    "check +0.25"
802                );
803                let val: $float = -0.25;
804                assert_conversion_eq!(
805                    $int::from_scaled_float(val),
806                    -1 << ($bits - 3),
807                    false,
808                    "check -0.25"
809                );
810                let val: $float = 1.1;
811                assert_conversion_eq!(
812                    $int::from_scaled_float(val),
813                    $int::MAX,
814                    true,
815                    "clipped positive"
816                );
817                let val: $float = -1.1;
818                assert_conversion_eq!(
819                    $int::from_scaled_float(val),
820                    $int::MIN,
821                    true,
822                    "clipped negative"
823                );
824            }
825        };
826    }
827
828    macro_rules! test_to_unsigned_int {
829        ($fname:ident, $float:ty, $int:ident, $bits:expr) => {
830            #[test]
831            fn $fname() {
832                let val: $float = -0.5;
833                assert_conversion_eq!(
834                    $int::from_scaled_float(val),
835                    1 << ($bits - 2),
836                    false,
837                    "check -0.5"
838                );
839                let val: $float = 0.5;
840                assert_conversion_eq!(
841                    $int::from_scaled_float(val),
842                    $int::MAX - (1 << ($bits - 2)) + 1,
843                    false,
844                    "check 0.5"
845                );
846                let val: $float = 1.1;
847                assert_conversion_eq!(
848                    $int::from_scaled_float(val),
849                    $int::MAX,
850                    true,
851                    "clipped positive"
852                );
853                let val: $float = -1.1;
854                assert_conversion_eq!(
855                    $int::from_scaled_float(val),
856                    $int::MIN,
857                    true,
858                    "clipped negative"
859                );
860            }
861        };
862    }
863
864    test_to_signed_int!(convert_f32_to_i8, f32, i8, 8);
865    test_to_signed_int!(convert_642_to_i8, f64, i8, 8);
866    test_to_signed_int!(convert_f32_to_i16, f32, i16, 16);
867    test_to_signed_int!(convert_f64_to_i16, f64, i16, 16);
868    test_to_signed_int!(convert_f32_to_i32, f32, i32, 32);
869    test_to_signed_int!(convert_f64_to_i32, f64, i32, 32);
870    test_to_signed_int!(convert_f32_to_i64, f32, i64, 64);
871    test_to_signed_int!(convert_f64_to_i64, f64, i64, 64);
872
873    test_to_unsigned_int!(convert_f32_to_u8, f32, u8, 8);
874    test_to_unsigned_int!(convert_f64_to_u8, f64, u8, 8);
875    test_to_unsigned_int!(convert_f32_to_u16, f32, u16, 16);
876    test_to_unsigned_int!(convert_f64_to_u16, f64, u16, 16);
877    test_to_unsigned_int!(convert_f32_to_u32, f32, u32, 32);
878    test_to_unsigned_int!(convert_f64_to_u32, f64, u32, 32);
879    test_to_unsigned_int!(convert_f32_to_u64, f32, u64, 64);
880    test_to_unsigned_int!(convert_f64_to_u64, f64, u64, 64);
881
882    macro_rules! test_from_signed_int {
883        ($fname:ident, $float:ty, $int:ident, $bits:expr) => {
884            #[test]
885            fn $fname() {
886                let val: $int = -1 << ($bits - 2);
887                assert_eq!(val.to_scaled_float::<$float>(), -0.5, "check -0.5");
888                let val: $int = 1 << ($bits - 2);
889                assert_eq!(val.to_scaled_float::<$float>(), 0.5, "check 0.5");
890                let val: $int = $int::MIN;
891                assert_eq!(val.to_scaled_float::<$float>(), -1.0, "negative limit");
892            }
893        };
894    }
895
896    macro_rules! test_from_unsigned_int {
897        ($fname:ident, $float:ty, $int:ident, $bits:expr) => {
898            #[test]
899            fn $fname() {
900                let val: $int = 1 << ($bits - 2);
901                assert_eq!(val.to_scaled_float::<$float>(), -0.5, "check -0.5");
902                let val: $int = $int::MAX - (1 << ($bits - 2)) + 1;
903                assert_eq!(val.to_scaled_float::<$float>(), 0.5, "check 0.5");
904                let val: $int = 0;
905                assert_eq!(val.to_scaled_float::<$float>(), -1.0, "negative limit");
906            }
907        };
908    }
909
910    test_from_signed_int!(convert_f32_from_i8, f32, i8, 8);
911    test_from_signed_int!(convert_f64_from_i8, f64, i8, 8);
912    test_from_signed_int!(convert_f32_from_i16, f32, i16, 16);
913    test_from_signed_int!(convert_f64_from_i16, f64, i16, 16);
914    test_from_signed_int!(convert_f32_from_i32, f32, i32, 32);
915    test_from_signed_int!(convert_f64_from_i32, f64, i32, 32);
916    test_from_signed_int!(convert_f32_from_i64, f32, i64, 64);
917    test_from_signed_int!(convert_f64_from_i64, f64, i64, 64);
918
919    test_from_unsigned_int!(convert_f32_from_u8, f32, u8, 8);
920    test_from_unsigned_int!(convert_f64_from_u8, f64, u8, 8);
921    test_from_unsigned_int!(convert_f32_from_u16, f32, u16, 16);
922    test_from_unsigned_int!(convert_f64_from_u16, f64, u16, 16);
923    test_from_unsigned_int!(convert_f32_from_u32, f32, u32, 32);
924    test_from_unsigned_int!(convert_f64_from_u32, f64, u32, 32);
925    test_from_unsigned_int!(convert_f32_from_u64, f32, u64, 64);
926    test_from_unsigned_int!(convert_f64_from_u64, f64, u64, 64);
927
928    #[test]
929    fn test_to_clamped_int() {
930        let converted = to_clamped_int::<f32, i32>(12345.0, Some(12345));
931        assert_conversion_eq!(converted, 12345, false, "in range f32 i32");
932
933        let converted = to_clamped_int::<f32, i32>(1.0e10, None);
934        assert_conversion_eq!(converted, i32::MAX, true, "above range f32 i32");
935
936        let converted = to_clamped_int::<f32, i32>(-1.0e10, None);
937        assert_conversion_eq!(converted, i32::MIN, true, "below range f32 i32");
938
939        let converted = to_clamped_int::<f64, i32>(12345.0, Some(12345));
940        assert_conversion_eq!(converted, 12345, false, "in range f64 i32");
941
942        let converted = to_clamped_int::<f64, i32>(1.0e10, None);
943        assert_conversion_eq!(converted, i32::MAX, true, "above range f64 i32");
944
945        let converted = to_clamped_int::<f64, i32>(-1.0e10, None);
946        assert_conversion_eq!(converted, i32::MIN, true, "below range f64 i32");
947    }
948
949    #[test]
950    fn test_to_clamped_uint() {
951        let converted = to_clamped_int::<f32, u32>(12345.0, Some(12345));
952        assert_conversion_eq!(converted, 12345, false, "in range f32 u32");
953
954        let converted = to_clamped_int::<f32, u32>(1.0e10, None);
955        assert_conversion_eq!(converted, u32::MAX, true, "above range f32 u32");
956
957        let converted = to_clamped_int::<f32, u32>(-1.0, None);
958        assert_conversion_eq!(converted, u32::MIN, true, "below range f32 u32");
959
960        let converted = to_clamped_int::<f64, u32>(12345.0, Some(12345));
961        assert_conversion_eq!(converted, 12345, false, "in range f64 u32");
962
963        let converted = to_clamped_int::<f64, u32>(1.0e10, None);
964        assert_conversion_eq!(converted, u32::MAX, true, "above range f64 u32");
965
966        let converted = to_clamped_int::<f64, u32>(-1.0, None);
967        assert_conversion_eq!(converted, u32::MIN, true, "below range f64 u32");
968    }
969
970    macro_rules! test_simple_int_bytes {
971        ($fname:ident, $number:ty, $wrapper:ident, $to_bytes_fn:ident) => {
972            #[test]
973            #[allow(non_snake_case)]
974            fn $fname() {
975                let number: $number = <$number>::MAX / 5 * 4;
976                let wrapped = $wrapper(number.$to_bytes_fn());
977                assert_eq!(number, wrapped.to_number());
978            }
979        };
980    }
981
982    macro_rules! test_float_bytes {
983        ($fname:ident, $number:ty, $wrapper:ident, $to_bytes_fn:ident) => {
984            #[test]
985            #[allow(non_snake_case)]
986            fn $fname() {
987                let number: $number = 12345.0;
988                let wrapped = $wrapper(number.$to_bytes_fn());
989                assert_eq!(number, wrapped.to_number());
990            }
991        };
992    }
993
994    test_simple_int_bytes!(convert_i16_from_I16_LE, i16, I16_LE, to_le_bytes);
995    test_simple_int_bytes!(convert_i16_from_I16_BE, i16, I16_BE, to_be_bytes);
996    test_simple_int_bytes!(convert_i32_from_I32_LE, i32, I32_LE, to_le_bytes);
997    test_simple_int_bytes!(convert_i32_from_I32_BE, i32, I32_BE, to_be_bytes);
998    test_simple_int_bytes!(convert_i64_from_I64_LE, i64, I64_LE, to_le_bytes);
999    test_simple_int_bytes!(convert_i64_from_I64_BE, i64, I64_BE, to_be_bytes);
1000
1001    test_simple_int_bytes!(convert_u16_from_U16_LE, u16, U16_LE, to_le_bytes);
1002    test_simple_int_bytes!(convert_u16_from_U16_BE, u16, U16_BE, to_be_bytes);
1003    test_simple_int_bytes!(convert_u32_from_U32_LE, u32, U32_LE, to_le_bytes);
1004    test_simple_int_bytes!(convert_u32_from_U32_BE, u32, U32_BE, to_be_bytes);
1005    test_simple_int_bytes!(convert_u64_from_U64_LE, u64, U64_LE, to_le_bytes);
1006    test_simple_int_bytes!(convert_u64_from_U64_BE, u64, U64_BE, to_be_bytes);
1007
1008    test_float_bytes!(convert_f32_fom_F32_LE, f32, F32_LE, to_le_bytes);
1009    test_float_bytes!(convert_f32_fom_F32_BE, f32, F32_BE, to_be_bytes);
1010    test_float_bytes!(convert_f64_fom_F64_LE, f64, F64_LE, to_le_bytes);
1011    test_float_bytes!(convert_f64_fom_F64_BE, f64, F64_BE, to_be_bytes);
1012
1013    #[test]
1014    #[allow(non_snake_case)]
1015    fn test_I24_LE() {
1016        let number = i32::MAX / 5 * 4;
1017
1018        // make sure LSB is zero
1019        let number = number >> 8;
1020        let number = number << 8;
1021
1022        let allbytes = number.to_le_bytes();
1023        // Little-endian stores the LSB at the smallest address.
1024        // Drop the LSB!
1025        let bytes = [allbytes[1], allbytes[2], allbytes[3]];
1026
1027        let wrapped = I24_LE(bytes);
1028        assert_eq!(number, wrapped.to_number());
1029    }
1030
1031    #[test]
1032    #[allow(non_snake_case)]
1033    fn test_I24_BE() {
1034        let number = i32::MAX / 5 * 4;
1035
1036        // make sure LSB is zero
1037        let number = number >> 8;
1038        let number = number << 8;
1039
1040        let allbytes = number.to_be_bytes();
1041        // Big-endian stores the LSB at the largest address.
1042        // Drop the LSB!
1043        let bytes = [allbytes[0], allbytes[1], allbytes[2]];
1044
1045        let wrapped = I24_BE(bytes);
1046        assert_eq!(number, wrapped.to_number());
1047    }
1048
1049    #[test]
1050    #[allow(non_snake_case)]
1051    fn test_I24_4RJ_LE() {
1052        let number = i32::MAX / 5 * 4;
1053
1054        // make sure LSB is zero
1055        let number = number >> 8;
1056        let number = number << 8;
1057
1058        let allbytes = number.to_le_bytes();
1059        // Little-endian stores the LSB at the smallest address.
1060        // Drop the LSB and insert padding at MSB!
1061        let bytes = [allbytes[1], allbytes[2], allbytes[3], 0];
1062
1063        let wrapped = I24_4RJ_LE(bytes);
1064        assert_eq!(number, wrapped.to_number());
1065    }
1066
1067    #[test]
1068    #[allow(non_snake_case)]
1069    fn test_I24_4RJ_BE() {
1070        let number = i32::MAX / 5 * 4;
1071
1072        // make sure LSB is zero
1073        let number = number >> 8;
1074        let number = number << 8;
1075
1076        let allbytes = number.to_be_bytes();
1077        // Big-endian stores the LSB at the largest address.
1078        // Drop the LSB and insert padding at MSB!
1079        let bytes = [0, allbytes[0], allbytes[1], allbytes[2]];
1080
1081        let wrapped = I24_4RJ_BE(bytes);
1082        assert_eq!(number, wrapped.to_number());
1083    }
1084
1085    #[test]
1086    #[allow(non_snake_case)]
1087    fn test_I24_4LJ_LE() {
1088        let number = i32::MAX / 5 * 4;
1089
1090        // make sure LSB is zero
1091        let number = number >> 8;
1092        let number = number << 8;
1093
1094        let allbytes = number.to_le_bytes();
1095        // Little-endian stores the LSB at the smallest address.
1096        // Put a zero at LSB and keep the rest unchanged.
1097        let bytes = [0, allbytes[1], allbytes[2], allbytes[3]];
1098
1099        let wrapped = I24_4LJ_LE(bytes);
1100        assert_eq!(number, wrapped.to_number());
1101    }
1102
1103    #[test]
1104    #[allow(non_snake_case)]
1105    fn test_I24_4LJ_BE() {
1106        let number = i32::MAX / 5 * 4;
1107
1108        // make sure LSB is zero
1109        let number = number >> 8;
1110        let number = number << 8;
1111
1112        let allbytes = number.to_be_bytes();
1113        // Big-endian stores the LSB at the largest address.
1114        // Put a zero at LSB and keep the rest unchanged.
1115        let bytes = [allbytes[0], allbytes[1], allbytes[2], 0];
1116
1117        let wrapped = I24_4LJ_BE(bytes);
1118        assert_eq!(number, wrapped.to_number());
1119    }
1120
1121    #[test]
1122    #[allow(non_snake_case)]
1123    fn test_U24_LE() {
1124        let number = u32::MAX / 5 * 4;
1125
1126        // make sure LSB is zero
1127        let number = number >> 8;
1128        let number = number << 8;
1129
1130        let allbytes = number.to_le_bytes();
1131        // Little-endian stores the LSB at the smallest address.
1132        // Drop the LSB!
1133        let bytes = [allbytes[1], allbytes[2], allbytes[3]];
1134
1135        let wrapped = U24_LE(bytes);
1136        assert_eq!(number, wrapped.to_number());
1137    }
1138
1139    #[test]
1140    #[allow(non_snake_case)]
1141    fn test_U24_BE() {
1142        let number = u32::MAX / 5 * 4;
1143
1144        // make sure LSB is zero
1145        let number = number >> 8;
1146        let number = number << 8;
1147
1148        let allbytes = number.to_be_bytes();
1149        // Big-endian stores the LSB at the largest address.
1150        // Drop the LSB!
1151        let bytes = [allbytes[0], allbytes[1], allbytes[2]];
1152
1153        let wrapped = U24_BE(bytes);
1154        assert_eq!(number, wrapped.to_number());
1155    }
1156
1157    #[test]
1158    #[allow(non_snake_case)]
1159    fn test_U24_4RJ_LE() {
1160        let number = u32::MAX / 5 * 4;
1161
1162        // make sure LSB is zero
1163        let number = number >> 8;
1164        let number = number << 8;
1165
1166        let allbytes = number.to_le_bytes();
1167        // Little-endian stores the LSB at the smallest address.
1168        // Drop the LSB and insert padding at MSB!
1169        let bytes = [allbytes[1], allbytes[2], allbytes[3], 0];
1170
1171        let wrapped = U24_4RJ_LE(bytes);
1172        assert_eq!(number, wrapped.to_number());
1173    }
1174
1175    #[test]
1176    #[allow(non_snake_case)]
1177    fn test_U24_4RJ_BE() {
1178        let number = u32::MAX / 5 * 4;
1179
1180        // make sure LSB is zero
1181        let number = number >> 8;
1182        let number = number << 8;
1183
1184        let allbytes = number.to_be_bytes();
1185        // Big-endian stores the LSB at the largest address.
1186        // Drop the LSB and insert padding at MSB!
1187        let bytes = [0, allbytes[0], allbytes[1], allbytes[2]];
1188
1189        let wrapped = U24_4RJ_BE(bytes);
1190        assert_eq!(number, wrapped.to_number());
1191    }
1192
1193    #[test]
1194    #[allow(non_snake_case)]
1195    fn test_U24_4LJ_LE() {
1196        let number = u32::MAX / 5 * 4;
1197
1198        // make sure LSB is zero
1199        let number = number >> 8;
1200        let number = number << 8;
1201
1202        let allbytes = number.to_le_bytes();
1203        // Little-endian stores the LSB at the smallest address.
1204        // Put a zero at LSB and keep the rest unchanged.
1205        let bytes = [0, allbytes[1], allbytes[2], allbytes[3]];
1206
1207        let wrapped = U24_4LJ_LE(bytes);
1208        assert_eq!(number, wrapped.to_number());
1209    }
1210
1211    #[test]
1212    #[allow(non_snake_case)]
1213    fn test_U24_4LJ_BE() {
1214        let number = u32::MAX / 5 * 4;
1215
1216        // make sure LSB is zero
1217        let number = number >> 8;
1218        let number = number << 8;
1219
1220        let allbytes = number.to_be_bytes();
1221        // Big-endian stores the LSB at the largest address.
1222        // Put a zero at LSB and keep the rest unchanged.
1223        let bytes = [allbytes[0], allbytes[1], allbytes[2], 0];
1224
1225        let wrapped = U24_4LJ_BE(bytes);
1226        assert_eq!(number, wrapped.to_number());
1227    }
1228}