Skip to main content

audioadapter_sample/
sample.rs

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