Skip to main content

symphonia_core/audio/
conv.rs

1// Symphonia
2// Copyright (c) 2019-2026 The Project Symphonia Developers.
3//
4// This Source Code Form is subject to the terms of the Mozilla Public
5// License, v. 2.0. If a copy of the MPL was not distributed with this
6// file, You can obtain one at https://mozilla.org/MPL/2.0/.
7
8//! The `conv` module provides methods to convert samples between different sample types (formats).
9use crate::audio::sample::{Sample, i24, u24};
10
11pub mod dither {
12    //! The `dither` module provides methods to apply a dither to a sample.
13    //!
14    //! Dithering is the process of adding noise to the least significant digits of a sample before
15    //! down-converting (quantizing) it to a smaller sample type. The purpose of dithering is to
16    //! decorrelate the quantization error of the down-conversion from the source signal.
17    //!
18    //! Dithering is only applied on lossy conversions. Therefore the `dither` module will only
19    //! apply a dither to the following down-conversions:
20    //!
21    //! * { `i32`, `u32` } to { `i24`, `u24`, `i16`, `u16`, `i8`, `u8` }
22    //! * { `i24`, `u24` } to { `i16`, `u16`, `i8`, `u8` }
23    //! * { `i16`, `u16` } to { `i8`, `u8` }
24    //!
25    //! Multiple dithering algorithms are provided, each drawing noise from a different probability
26    //! distribution. In addition to different distributions, a dithering algorithm may also shape
27    //! the noise such that the bulk of the noise is placed in an inaudible frequency range.
28    use super::FromSample;
29    use crate::audio::sample::Sample;
30    use crate::audio::sample::{i24, u24};
31    use std::marker::PhantomData;
32
33    mod prng {
34        #[inline]
35        fn split_mix_64(x: &mut u64) -> u64 {
36            *x = x.wrapping_add(0x9e37_79b9_7f4a_7c15);
37            let mut z = *x;
38            z = (z ^ (z >> 30)).wrapping_mul(0xbf58_476d_1ce4_e5b9);
39            z = (z ^ (z >> 27)).wrapping_mul(0x94d0_49bb_1331_11eb);
40            z ^ (z >> 31)
41        }
42
43        /// `Xoshiro128pp` implements the xoshiro128++ pseudo-random number generator.
44        ///
45        /// This PRNG is the basis for all built-in dithering algorithms. It is one of, if not the
46        /// most, performant PRNGs that generate statistically valid random numbers. Note that it is
47        /// not cryptographically secure, but for dithering audio it is more than sufficient.
48        ///
49        /// `Xoshiro128pp` should be initialized with a reasonably random 64-bit seed, however the
50        /// seed will be further randomized via the SplitMix64 algorithm.
51        pub struct Xoshiro128pp {
52            s: [u32; 4],
53        }
54
55        impl Xoshiro128pp {
56            pub fn new(mut seed: u64) -> Self {
57                let a = split_mix_64(&mut seed);
58                let b = split_mix_64(&mut seed);
59
60                Xoshiro128pp {
61                    s: [
62                        (a & 0xffff_ffff) as u32,
63                        (a >> 32) as u32,
64                        (b & 0xffff_ffff) as u32,
65                        (b >> 32) as u32,
66                    ],
67                }
68            }
69
70            #[inline]
71            pub fn next(&mut self) -> u32 {
72                let x = self.s[0].wrapping_add(self.s[3]);
73
74                let result = x.rotate_left(7).wrapping_add(self.s[0]);
75
76                let t = self.s[1] << 9;
77
78                self.s[2] ^= self.s[0];
79                self.s[3] ^= self.s[1];
80                self.s[1] ^= self.s[2];
81                self.s[0] ^= self.s[3];
82
83                self.s[2] ^= t;
84
85                self.s[3] = self.s[3].rotate_left(11);
86
87                result
88            }
89        }
90    }
91
92    /// `RandomNoise` represents a sample of noise of a specified length in bits.
93    ///
94    /// TODO: `RandomNoise` should be parameterized by the number of bits once const generics land.
95    #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Default)]
96    pub struct RandomNoise(pub i32);
97
98    impl RandomNoise {
99        /// Instantiate a noise sample from a random 32-bit source.
100        pub fn from(random: i32, n_bits: u32) -> Self {
101            RandomNoise(random >> (32 - n_bits))
102        }
103    }
104
105    /// `AddNoise` is a trait for converting random noise into a `Sample`.
106    pub trait AddNoise<S: Sample> {
107        fn add_noise(self, sample: S) -> S;
108    }
109
110    macro_rules! add_noise_impl {
111        ($sample_type:ty, $self:ident, $sample:ident, $conv:expr) => (
112            impl AddNoise<$sample_type> for RandomNoise {
113                #[inline]
114                fn add_noise($self, $sample: $sample_type) -> $sample_type { $conv }
115            }
116        )
117    }
118
119    add_noise_impl!(i8, self, s, {
120        i8::from_sample(f32::from_sample(s) + f32::from_sample(self.0))
121    });
122    add_noise_impl!(u8, self, s, {
123        u8::from_sample(f32::from_sample(s) + f32::from_sample(self.0))
124    });
125    add_noise_impl!(i16, self, s, {
126        i16::from_sample(f32::from_sample(s) + f32::from_sample(self.0))
127    });
128    add_noise_impl!(u16, self, s, {
129        u16::from_sample(f32::from_sample(s) + f32::from_sample(self.0))
130    });
131    add_noise_impl!(i24, self, s, {
132        i24::from_sample(f32::from_sample(s) + f32::from_sample(self.0))
133    });
134    add_noise_impl!(u24, self, s, {
135        u24::from_sample(f32::from_sample(s) + f32::from_sample(self.0))
136    });
137    add_noise_impl!(i32, self, s, {
138        i32::from_sample(f64::from_sample(s) + f64::from_sample(self.0))
139    });
140    add_noise_impl!(u32, self, s, {
141        u32::from_sample(f64::from_sample(s) + f64::from_sample(self.0))
142    });
143    add_noise_impl!(f32, self, s, s + f32::from_sample(self.0));
144    add_noise_impl!(f64, self, s, s + f64::from_sample(self.0));
145
146    /// `Dither` is a trait for implementing dithering algorithms.
147    pub trait Dither<F: Sample, T: Sample> {
148        /// Dithers a `Sample` of source sample format `F` for an eventual conversion to the
149        /// destination sample format `T`.
150        fn dither(&mut self, sample: F) -> F;
151    }
152
153    /// The `Identity` dithering algorithm performs no dithering and returns the original sample.
154    pub struct Identity<F: Sample, T: Sample> {
155        from_type: PhantomData<F>,
156        to_type: PhantomData<T>,
157    }
158
159    impl<F: Sample, T: Sample> Identity<F, T> {
160        pub fn new() -> Self {
161            Identity { from_type: PhantomData, to_type: PhantomData }
162        }
163    }
164
165    impl<F: Sample, T: Sample> Dither<F, T> for Identity<F, T> {
166        fn dither(&mut self, sample: F) -> F {
167            sample
168        }
169    }
170
171    impl<F: Sample, T: Sample> Default for Identity<F, T> {
172        fn default() -> Self {
173            Self::new()
174        }
175    }
176
177    /// `Rectangular` implements a dither using uniformly distributed (white) noise without shaping.
178    pub struct Rectangular<F: Sample, T: Sample> {
179        prng: prng::Xoshiro128pp,
180        from_type: PhantomData<F>,
181        to_type: PhantomData<T>,
182    }
183
184    impl<F: Sample, T: Sample> Rectangular<F, T> {
185        pub fn new() -> Self {
186            Rectangular {
187                prng: prng::Xoshiro128pp::new(0xb2c1_01f4_425b_987e),
188                from_type: PhantomData,
189                to_type: PhantomData,
190            }
191        }
192    }
193
194    impl<F: Sample, T: Sample> Dither<F, T> for Rectangular<F, T>
195    where
196        RandomNoise: AddNoise<F>,
197    {
198        fn dither(&mut self, sample: F) -> F {
199            // A dither should be applied if and only if the effective number of bits of the source
200            // sample format is greater than that of the destination sample format.
201            debug_assert!(F::EFF_BITS > T::EFF_BITS);
202
203            // The number of low-order bits being truncated by the conversion will be dithered.
204            let dither_bits = 32 - T::EFF_BITS;
205
206            // Add the noise to the sample.
207            let noise = RandomNoise::from(self.prng.next() as i32, dither_bits);
208            noise.add_noise(sample)
209        }
210    }
211
212    impl<F: Sample, T: Sample> Default for Rectangular<F, T> {
213        fn default() -> Self {
214            Self::new()
215        }
216    }
217
218    /// `Triangular` implements a dither using a triangular distribution of noise without shaping.
219    pub struct Triangular<F: Sample, T: Sample> {
220        prng: prng::Xoshiro128pp,
221        from_type: PhantomData<F>,
222        to_type: PhantomData<T>,
223    }
224
225    impl<F: Sample, T: Sample> Triangular<F, T> {
226        pub fn new() -> Self {
227            Triangular {
228                prng: prng::Xoshiro128pp::new(0xb2c1_01f4_425b_987e),
229                from_type: PhantomData,
230                to_type: PhantomData,
231            }
232        }
233    }
234
235    impl<F: Sample, T: Sample> Dither<F, T> for Triangular<F, T>
236    where
237        RandomNoise: AddNoise<F>,
238    {
239        fn dither(&mut self, sample: F) -> F {
240            debug_assert!(F::EFF_BITS > T::EFF_BITS);
241
242            let dither_bits = 32 - T::EFF_BITS;
243
244            // Generate a triangular distribution from the uniform distribution.
245            let tpdf = (self.prng.next() as i32 >> 1) + (self.prng.next() as i32 >> 1);
246
247            // Add the noise to the sample.
248            let noise = RandomNoise::from(tpdf, dither_bits);
249            noise.add_noise(sample)
250        }
251    }
252
253    impl<F: Sample, T: Sample> Default for Triangular<F, T> {
254        fn default() -> Self {
255            Self::new()
256        }
257    }
258
259    /// Enumeration of dither algorithms.
260    #[non_exhaustive]
261    pub enum DitherType {
262        /// No dithering.
263        Identity,
264        /// Apply rectangular dithering. See `Rectangular` for more details.
265        Rectangular,
266        /// Apply triangular dithering. See `Triangular` for more details.
267        Triangular,
268    }
269
270    /// `MaybeDither` conditionally applies a dither to a sample depending on the source and
271    /// destination sample types.
272    pub trait MaybeDither<T: Sample>: Sample {
273        const DITHERABLE: bool;
274
275        fn maybe_dither<D: Dither<Self, T>>(self, dither: &mut D) -> Self;
276    }
277
278    /// Never apply a dither for this conversion.
279    macro_rules! dither_never {
280        ($to:ty, $from:ty) => {
281            impl MaybeDither<$to> for $from {
282                const DITHERABLE: bool = false;
283                #[inline(always)]
284                fn maybe_dither<D: Dither<$from, $to>>(self, _: &mut D) -> Self {
285                    self
286                }
287            }
288        };
289    }
290
291    /// Maybe apply a dither for this conversion.
292    macro_rules! dither_maybe {
293        ($to:ty, $from:ty) => {
294            impl MaybeDither<$to> for $from {
295                const DITHERABLE: bool = true;
296                #[inline(always)]
297                fn maybe_dither<D: Dither<$from, $to>>(self, dither: &mut D) -> Self {
298                    dither.dither(self)
299                }
300            }
301        };
302    }
303
304    // Dither table for conversions to u8
305    dither_never!(u8, u8);
306    dither_maybe!(u8, u16);
307    dither_maybe!(u8, u24);
308    dither_maybe!(u8, u32);
309    dither_never!(u8, i8);
310    dither_maybe!(u8, i16);
311    dither_maybe!(u8, i24);
312    dither_maybe!(u8, i32);
313    dither_never!(u8, f32);
314    dither_never!(u8, f64);
315
316    // Dither table for conversions to u16
317    dither_never!(u16, u8);
318    dither_never!(u16, u16);
319    dither_maybe!(u16, u24);
320    dither_maybe!(u16, u32);
321    dither_never!(u16, i8);
322    dither_never!(u16, i16);
323    dither_maybe!(u16, i24);
324    dither_maybe!(u16, i32);
325    dither_never!(u16, f32);
326    dither_never!(u16, f64);
327
328    // Dither table for conversions to u24
329    dither_never!(u24, u8);
330    dither_never!(u24, u16);
331    dither_never!(u24, u24);
332    dither_maybe!(u24, u32);
333    dither_never!(u24, i8);
334    dither_never!(u24, i16);
335    dither_never!(u24, i24);
336    dither_maybe!(u24, i32);
337    dither_never!(u24, f32);
338    dither_never!(u24, f64);
339
340    // Dither table for conversions to u32
341    dither_never!(u32, u8);
342    dither_never!(u32, u16);
343    dither_never!(u32, u24);
344    dither_never!(u32, u32);
345    dither_never!(u32, i8);
346    dither_never!(u32, i16);
347    dither_never!(u32, i24);
348    dither_never!(u32, i32);
349    dither_never!(u32, f32);
350    dither_never!(u32, f64);
351
352    // Dither table for conversions to i8
353    dither_never!(i8, u8);
354    dither_maybe!(i8, u16);
355    dither_maybe!(i8, u24);
356    dither_maybe!(i8, u32);
357    dither_never!(i8, i8);
358    dither_maybe!(i8, i16);
359    dither_maybe!(i8, i24);
360    dither_maybe!(i8, i32);
361    dither_never!(i8, f32);
362    dither_never!(i8, f64);
363
364    // Dither table for conversions to i16
365    dither_never!(i16, u8);
366    dither_never!(i16, u16);
367    dither_maybe!(i16, u24);
368    dither_maybe!(i16, u32);
369    dither_never!(i16, i8);
370    dither_never!(i16, i16);
371    dither_maybe!(i16, i24);
372    dither_maybe!(i16, i32);
373    dither_never!(i16, f32);
374    dither_never!(i16, f64);
375
376    // Dither table for conversions to i24
377    dither_never!(i24, u8);
378    dither_never!(i24, u16);
379    dither_never!(i24, u24);
380    dither_maybe!(i24, u32);
381    dither_never!(i24, i8);
382    dither_never!(i24, i16);
383    dither_never!(i24, i24);
384    dither_maybe!(i24, i32);
385    dither_never!(i24, f32);
386    dither_never!(i24, f64);
387
388    // Dither table for conversions to i32
389    dither_never!(i32, u8);
390    dither_never!(i32, u16);
391    dither_never!(i32, u24);
392    dither_never!(i32, u32);
393    dither_never!(i32, i8);
394    dither_never!(i32, i16);
395    dither_never!(i32, i24);
396    dither_never!(i32, i32);
397    dither_never!(i32, f32);
398    dither_never!(i32, f64);
399
400    // Dither table for conversions to f32
401    dither_never!(f32, u8);
402    dither_never!(f32, u16);
403    dither_never!(f32, u24);
404    dither_never!(f32, u32);
405    dither_never!(f32, i8);
406    dither_never!(f32, i16);
407    dither_never!(f32, i24);
408    dither_never!(f32, i32);
409    dither_never!(f32, f32);
410    dither_never!(f32, f64);
411
412    // Dither table for conversions to f64
413    dither_never!(f64, u8);
414    dither_never!(f64, u16);
415    dither_never!(f64, u24);
416    dither_never!(f64, u32);
417    dither_never!(f64, i8);
418    dither_never!(f64, i16);
419    dither_never!(f64, i24);
420    dither_never!(f64, i32);
421    dither_never!(f64, f32);
422    dither_never!(f64, f64);
423}
424
425/// `FromSample` implements a conversion from `Sample` type `F` to `Self`.
426///
427/// This may be a lossy conversion if converting from a sample type of higher precision to one of
428/// lower precision. No dithering is applied.
429pub trait FromSample<F> {
430    fn from_sample(val: F) -> Self;
431}
432
433// Notes on sample format converters
434//
435// In total there are 10 different sample formats, so there are 100 different sample format
436// converters. Of the 100 sample format converters, there are 64 int <-> int, 32 int <-> float, and
437// 4 float <-> float converters.
438//
439// A minimum version of Rust 1.45 is required. As of Rust 1.45 a `<float> as <integer>` cast
440// saturates (clamps) to the bounds of the integer. Therefore, no clamping is required. Symphonia
441// takes advantage of this behaviour.
442
443macro_rules! impl_convert {
444    ($from:ty, $to:ty, $sample:ident, $func:expr) => {
445        impl FromSample<$from> for $to {
446            #[inline(always)]
447            fn from_sample($sample: $from) -> Self {
448                $func
449            }
450        }
451    };
452}
453
454// i8 to ...
455
456#[inline(always)]
457fn i8_to_u8(s: i8) -> u8 {
458    (s as u8).wrapping_add(0x80)
459}
460
461impl_convert!(i8, u8, s, i8_to_u8(s)); // u8
462impl_convert!(i8, u16, s, (i8_to_u8(s) as u16) << 8); // u16
463impl_convert!(i8, u24, s, u24::from((i8_to_u8(s) as u32) << 16)); // u24
464impl_convert!(i8, u32, s, (i8_to_u8(s) as u32) << 24); // u3
465
466impl_convert!(i8, i8, s, s); // i8
467impl_convert!(i8, i16, s, (s as i16) << 8); // i16
468impl_convert!(i8, i24, s, i24::from((s as i32) << 16)); // i24
469impl_convert!(i8, i32, s, (s as i32) << 24); // i32
470
471impl_convert!(i8, f32, s, s as f32 / 128.0); // f32
472impl_convert!(i8, f64, s, s as f64 / 128.0); // f64
473
474// i16 to ...
475
476#[inline(always)]
477fn i16_to_u16(s: i16) -> u16 {
478    (s as u16).wrapping_add(0x8000)
479}
480
481impl_convert!(i16, u8, s, (i16_to_u16(s) >> 8) as u8); // u8
482impl_convert!(i16, u16, s, i16_to_u16(s)); // u16
483impl_convert!(i16, u24, s, u24::from((i16_to_u16(s) as u32) << 8)); // u24
484impl_convert!(i16, u32, s, (i16_to_u16(s) as u32) << 16); // u32
485
486impl_convert!(i16, i8, s, (s >> 8) as i8); // i8
487impl_convert!(i16, i16, s, s); // i16
488impl_convert!(i16, i24, s, i24::from((s as i32) << 8)); // i24
489impl_convert!(i16, i32, s, (s as i32) << 16); // i32
490
491impl_convert!(i16, f32, s, s as f32 / 32_768.0); // f32
492impl_convert!(i16, f64, s, s as f64 / 32_768.0); // f64
493
494// i24 to ...
495
496#[inline(always)]
497fn i24_to_u32(s: i24) -> u32 {
498    ((s.clamped().inner() << 8) as u32).wrapping_add(0x8000_0000)
499}
500
501impl_convert!(i24, u8, s, (i24_to_u32(s) >> 24) as u8); // u8
502impl_convert!(i24, u16, s, (i24_to_u32(s) >> 16) as u16); // u16
503impl_convert!(i24, u24, s, u24::from(i24_to_u32(s) >> 8)); // u24
504impl_convert!(i24, u32, s, i24_to_u32(s)); // u32
505
506impl_convert!(i24, i8, s, (s.clamped().inner() >> 16) as i8); // i8
507impl_convert!(i24, i16, s, (s.clamped().inner() >> 8) as i16); // i16
508impl_convert!(i24, i24, s, s); // i24
509impl_convert!(i24, i32, s, (s.clamped().inner()) << 8); // i32
510
511impl_convert!(i24, f32, s, s.clamped().inner() as f32 / 8_388_608.0); // f32
512impl_convert!(i24, f64, s, s.clamped().inner() as f64 / 8_388_608.0); // f64
513
514// i32 to ...
515
516#[inline(always)]
517fn i32_to_u32(s: i32) -> u32 {
518    (s as u32).wrapping_add(0x8000_0000)
519}
520
521impl_convert!(i32, u8, s, (i32_to_u32(s) >> 24) as u8); // u8
522impl_convert!(i32, u16, s, (i32_to_u32(s) >> 16) as u16); // u16
523impl_convert!(i32, u24, s, u24::from(i32_to_u32(s) >> 8)); // u24
524impl_convert!(i32, u32, s, i32_to_u32(s)); // u32
525
526impl_convert!(i32, i8, s, (s >> 24) as i8); // i8
527impl_convert!(i32, i16, s, (s >> 16) as i16); // i16
528impl_convert!(i32, i24, s, i24::from(s >> 8)); // i24
529impl_convert!(i32, i32, s, s); // i32
530
531impl_convert!(i32, f32, s, (s as f64 / 2_147_483_648.0) as f32); // f32
532impl_convert!(i32, f64, s, s as f64 / 2_147_483_648.0); // f64
533
534// u8 to ...
535
536impl_convert!(u8, u8, s, s); // u8
537impl_convert!(u8, u16, s, (s as u16) << 8); // u16
538impl_convert!(u8, u24, s, u24::from((s as u32) << 16)); // u24
539impl_convert!(u8, u32, s, (s as u32) << 24); // u32
540
541impl_convert!(u8, i8, s, s.wrapping_sub(0x80) as i8); // i8
542impl_convert!(u8, i16, s, ((s.wrapping_sub(0x80) as i8) as i16) << 8); // i16
543impl_convert!(u8, i24, s, i24::from(((s.wrapping_sub(0x80) as i8) as i32) << 16)); // i24
544impl_convert!(u8, i32, s, ((s.wrapping_sub(0x80) as i8) as i32) << 24); // i32
545
546impl_convert!(u8, f32, s, ((s as f32) / 128.0) - 1.0); // f32
547impl_convert!(u8, f64, s, ((s as f64) / 128.0) - 1.0); // f64
548
549// u16 to ...
550
551impl_convert!(u16, u8, s, (s >> 8) as u8); // u8
552impl_convert!(u16, u16, s, s); // u16
553impl_convert!(u16, u24, s, u24::from((s as u32) << 8)); // u24
554impl_convert!(u16, u32, s, (s as u32) << 16); // u32
555
556impl_convert!(u16, i8, s, (s.wrapping_sub(0x8000) >> 8) as i8); // i8
557impl_convert!(u16, i16, s, s.wrapping_sub(0x8000) as i16); // i16
558impl_convert!(u16, i24, s, i24::from(((s.wrapping_sub(0x8000) as i16) as i32) << 8)); // i24
559impl_convert!(u16, i32, s, ((s.wrapping_sub(0x8000) as i16) as i32) << 16); // i32
560
561impl_convert!(u16, f32, s, ((s as f32) / 32_768.0) - 1.0); // f32
562impl_convert!(u16, f64, s, ((s as f64) / 32_768.0) - 1.0); // f64
563
564// u24 to ...
565
566impl_convert!(u24, u8, s, (s.clamped().inner() >> 16) as u8); // u8
567impl_convert!(u24, u16, s, (s.clamped().inner() >> 8) as u16); // u16
568impl_convert!(u24, u24, s, s); // u24
569impl_convert!(u24, u32, s, s.clamped().inner() << 8); // u32
570
571impl_convert!(u24, i8, s, (s.clamped().inner().wrapping_sub(0x80_0000) >> 16) as i8); // i8
572impl_convert!(u24, i16, s, (s.clamped().inner().wrapping_sub(0x80_0000) >> 8) as i16); // i16
573impl_convert!(u24, i24, s, i24::from(s.clamped().inner().wrapping_sub(0x80_0000) as i32)); // i24
574impl_convert!(u24, i32, s, (s.clamped().inner().wrapping_sub(0x80_0000) << 8) as i32); // i32
575
576impl_convert!(u24, f32, s, ((s.clamped().inner() as f32) / 8_388_608.0) - 1.0); // f32
577impl_convert!(u24, f64, s, ((s.clamped().inner() as f64) / 8_388_608.0) - 1.0); // f64
578
579// u32 to ...
580
581impl_convert!(u32, u8, s, (s >> 24) as u8); // u8
582impl_convert!(u32, u16, s, (s >> 16) as u16); // u16
583impl_convert!(u32, u24, s, u24::from(s >> 8)); // u24
584impl_convert!(u32, u32, s, s); // u32
585
586impl_convert!(u32, i8, s, (s.wrapping_sub(0x8000_0000) >> 24) as i8); // i8
587impl_convert!(u32, i16, s, (s.wrapping_sub(0x8000_0000) >> 16) as i16); // i16
588impl_convert!(u32, i24, s, i24::from((s.wrapping_sub(0x8000_0000) as i32) >> 8)); // i24
589impl_convert!(u32, i32, s, s.wrapping_sub(0x8000_0000) as i32); // i32
590
591impl_convert!(u32, f32, s, (((s as f64) / 2_147_483_648.0) - 1.0) as f32); // f32
592impl_convert!(u32, f64, s, ((s as f64) / 2_147_483_648.0) - 1.0); // f64
593
594// f32 to ...
595
596impl_convert!(f32, u8, s, ((s.clamped() + 1.0) * 128.0) as u8); // u8
597impl_convert!(f32, u16, s, ((s.clamped() + 1.0) * 32_768.0) as u16); // u16
598impl_convert!(f32, u24, s, u24::from(((s.clamped() + 1.0) * 8_388_608.0) as u32)); // u24
599impl_convert!(f32, u32, s, ((s.clamped() + 1.0) as f64 * 2_147_483_648.0) as u32); // u32
600
601impl_convert!(f32, i8, s, (s.clamped() * 128.0) as i8); // i8
602impl_convert!(f32, i16, s, (s.clamped() * 32_768.0) as i16); // i16
603impl_convert!(f32, i24, s, i24::from((s.clamped() * 8_388_608.0) as i32)); // i24
604impl_convert!(f32, i32, s, (s.clamped() as f64 * 2_147_483_648.0) as i32); // i32
605
606impl_convert!(f32, f32, s, s); // f32
607impl_convert!(f32, f64, s, s as f64); // f64
608
609// f64 to ...
610
611impl_convert!(f64, u8, s, ((s.clamped() + 1.0) * 128.0) as u8); // u8
612impl_convert!(f64, u16, s, ((s.clamped() + 1.0) * 32_768.0) as u16); // u16
613impl_convert!(f64, u24, s, u24::from(((s.clamped() + 1.0) * 8_388_608.0) as u32)); // u24
614impl_convert!(f64, u32, s, ((s.clamped() + 1.0) * 2_147_483_648.0) as u32); // u32
615
616impl_convert!(f64, i8, s, (s.clamped() * 128.0) as i8); // i8
617impl_convert!(f64, i16, s, (s.clamped() * 32_768.0) as i16); // i16
618impl_convert!(f64, i24, s, i24::from((s.clamped() * 8_388_608.0) as i32)); // i24
619impl_convert!(f64, i32, s, (s.clamped() * 2_147_483_648.0) as i32); // i32
620
621impl_convert!(f64, f32, s, s as f32); // f32
622impl_convert!(f64, f64, s, s); // f64
623
624/// `IntoSample` implements a conversion from `Self` to `Sample` type `T`.
625///
626/// This may be a lossy conversion if converting from a sample type of higher precision to one of
627/// lower precision. No dithering is applied.
628pub trait IntoSample<T> {
629    fn into_sample(self) -> T;
630}
631
632impl<F, T: FromSample<F>> IntoSample<T> for F {
633    #[inline]
634    fn into_sample(self) -> T {
635        T::from_sample(self)
636    }
637}
638
639/// `ReversibleSample` is a trait that when implemented for `Self`, that `Sample` type implements
640/// reversible conversions between `Self` and the parameterized `Sample` type `S`.
641pub trait ReversibleSample<S>: Sample + FromSample<S> + IntoSample<S> {}
642impl<S, T> ReversibleSample<S> for T where T: Sample + FromSample<S> + IntoSample<S> {}
643
644pub trait ConvertibleSample:
645    Sample
646    + FromSample<i8>
647    + FromSample<u8>
648    + FromSample<i16>
649    + FromSample<u16>
650    + FromSample<i24>
651    + FromSample<u24>
652    + FromSample<i32>
653    + FromSample<u32>
654    + FromSample<f32>
655    + FromSample<f64>
656{
657}
658
659impl<S> ConvertibleSample for S where
660    S: Sample
661        + FromSample<i8>
662        + FromSample<u8>
663        + FromSample<i16>
664        + FromSample<u16>
665        + FromSample<i24>
666        + FromSample<u24>
667        + FromSample<i32>
668        + FromSample<u32>
669        + FromSample<f32>
670        + FromSample<f64>
671{
672}
673
674#[cfg(test)]
675mod tests {
676    use super::FromSample;
677    use crate::audio::sample::{Sample, i24, u24};
678
679    #[test]
680    fn verify_u8_from_sample() {
681        assert_eq!(u8::from_sample(u8::MAX), u8::MAX);
682        assert_eq!(u8::from_sample(u8::MID), u8::MID);
683        assert_eq!(u8::from_sample(u8::MIN), u8::MIN);
684
685        assert_eq!(u8::from_sample(u16::MAX), u8::MAX);
686        assert_eq!(u8::from_sample(u16::MID), u8::MID);
687        assert_eq!(u8::from_sample(u16::MIN), u8::MIN);
688
689        assert_eq!(u8::from_sample(u24::MAX), u8::MAX);
690        assert_eq!(u8::from_sample(u24::MID), u8::MID);
691        assert_eq!(u8::from_sample(u24::MIN), u8::MIN);
692
693        assert_eq!(u8::from_sample(u32::MAX), u8::MAX);
694        assert_eq!(u8::from_sample(u32::MID), u8::MID);
695        assert_eq!(u8::from_sample(u32::MIN), u8::MIN);
696
697        assert_eq!(u8::from_sample(i8::MAX), u8::MAX);
698        assert_eq!(u8::from_sample(i8::MID), u8::MID);
699        assert_eq!(u8::from_sample(i8::MIN), u8::MIN);
700
701        assert_eq!(u8::from_sample(i16::MAX), u8::MAX);
702        assert_eq!(u8::from_sample(i16::MID), u8::MID);
703        assert_eq!(u8::from_sample(i16::MIN), u8::MIN);
704
705        assert_eq!(u8::from_sample(i24::MAX), u8::MAX);
706        assert_eq!(u8::from_sample(i24::MID), u8::MID);
707        assert_eq!(u8::from_sample(i24::MIN), u8::MIN);
708
709        assert_eq!(u8::from_sample(i32::MAX), u8::MAX);
710        assert_eq!(u8::from_sample(i32::MID), u8::MID);
711        assert_eq!(u8::from_sample(i32::MIN), u8::MIN);
712
713        assert_eq!(u8::from_sample(1.0f32), u8::MAX);
714        assert_eq!(u8::from_sample(0f32), u8::MID);
715        assert_eq!(u8::from_sample(-1.0f32), u8::MIN);
716
717        assert_eq!(u8::from_sample(1.0f64), u8::MAX);
718        assert_eq!(u8::from_sample(0f64), u8::MID);
719        assert_eq!(u8::from_sample(-1.0f64), u8::MIN);
720    }
721
722    #[test]
723    fn verify_u16_from_sample() {
724        assert_eq!(u16::from_sample(u8::MAX), u16::MAX - 255);
725        assert_eq!(u16::from_sample(u8::MID), u16::MID);
726        assert_eq!(u16::from_sample(u8::MIN), u16::MIN);
727
728        assert_eq!(u16::from_sample(u16::MAX), u16::MAX);
729        assert_eq!(u16::from_sample(u16::MID), u16::MID);
730        assert_eq!(u16::from_sample(u16::MIN), u16::MIN);
731
732        assert_eq!(u16::from_sample(u24::MAX), u16::MAX);
733        assert_eq!(u16::from_sample(u24::MID), u16::MID);
734        assert_eq!(u16::from_sample(u24::MIN), u16::MIN);
735
736        assert_eq!(u16::from_sample(u32::MAX), u16::MAX);
737        assert_eq!(u16::from_sample(u32::MID), u16::MID);
738        assert_eq!(u16::from_sample(u32::MIN), u16::MIN);
739
740        assert_eq!(u16::from_sample(i8::MAX), u16::MAX - 255);
741        assert_eq!(u16::from_sample(i8::MID), u16::MID);
742        assert_eq!(u16::from_sample(i8::MIN), u16::MIN);
743
744        assert_eq!(u16::from_sample(i16::MAX), u16::MAX);
745        assert_eq!(u16::from_sample(i16::MID), u16::MID);
746        assert_eq!(u16::from_sample(i16::MIN), u16::MIN);
747
748        assert_eq!(u16::from_sample(i24::MAX), u16::MAX);
749        assert_eq!(u16::from_sample(i24::MID), u16::MID);
750        assert_eq!(u16::from_sample(i24::MIN), u16::MIN);
751
752        assert_eq!(u16::from_sample(i32::MAX), u16::MAX);
753        assert_eq!(u16::from_sample(i32::MID), u16::MID);
754        assert_eq!(u16::from_sample(i32::MIN), u16::MIN);
755
756        assert_eq!(u16::from_sample(1.0f32), u16::MAX);
757        assert_eq!(u16::from_sample(0f32), u16::MID);
758        assert_eq!(u16::from_sample(-1.0f32), u16::MIN);
759
760        assert_eq!(u16::from_sample(1.0f64), u16::MAX);
761        assert_eq!(u16::from_sample(0f64), u16::MID);
762        assert_eq!(u16::from_sample(-1.0f64), u16::MIN);
763    }
764
765    #[test]
766    fn verify_u24_from_sample() {
767        assert_eq!(u24::from_sample(u8::MAX), u24::MAX - u24::from(65_535u32));
768        assert_eq!(u24::from_sample(u8::MID), u24::MID);
769        assert_eq!(u24::from_sample(u8::MIN), u24::MIN);
770
771        assert_eq!(u24::from_sample(u16::MAX), u24::MAX - u24::from(255u32));
772        assert_eq!(u24::from_sample(u16::MID), u24::MID);
773        assert_eq!(u24::from_sample(u16::MIN), u24::MIN);
774
775        assert_eq!(u24::from_sample(u24::MAX), u24::MAX);
776        assert_eq!(u24::from_sample(u24::MID), u24::MID);
777        assert_eq!(u24::from_sample(u24::MIN), u24::MIN);
778
779        assert_eq!(u24::from_sample(u32::MAX), u24::MAX);
780        assert_eq!(u24::from_sample(u32::MID), u24::MID);
781        assert_eq!(u24::from_sample(u32::MIN), u24::MIN);
782
783        assert_eq!(u24::from_sample(i8::MAX), u24::MAX - u24::from(65_535u32));
784        assert_eq!(u24::from_sample(i8::MID), u24::MID);
785        assert_eq!(u24::from_sample(i8::MIN), u24::MIN);
786
787        assert_eq!(u24::from_sample(i16::MAX), u24::MAX - u24::from(255u32));
788        assert_eq!(u24::from_sample(i16::MID), u24::MID);
789        assert_eq!(u24::from_sample(i16::MIN), u24::MIN);
790
791        assert_eq!(u24::from_sample(i24::MAX), u24::MAX);
792        assert_eq!(u24::from_sample(i24::MID), u24::MID);
793        assert_eq!(u24::from_sample(i24::MIN), u24::MIN);
794
795        assert_eq!(u24::from_sample(i32::MAX), u24::MAX);
796        assert_eq!(u24::from_sample(i32::MID), u24::MID);
797        assert_eq!(u24::from_sample(i32::MIN), u24::MIN);
798
799        assert_eq!(u24::from_sample(1.0f32), u24::MAX);
800        assert_eq!(u24::from_sample(0f32), u24::MID);
801        assert_eq!(u24::from_sample(-1.0f32), u24::MIN);
802
803        assert_eq!(u24::from_sample(1.0f64), u24::MAX);
804        assert_eq!(u24::from_sample(0f64), u24::MID);
805        assert_eq!(u24::from_sample(-1.0f64), u24::MIN);
806    }
807
808    #[test]
809    fn verify_u32_from_sample() {
810        assert_eq!(u32::from_sample(u8::MAX), u32::MAX - 16_777_215);
811        assert_eq!(u32::from_sample(u8::MID), u32::MID);
812        assert_eq!(u32::from_sample(u8::MIN), u32::MIN);
813
814        assert_eq!(u32::from_sample(u16::MAX), u32::MAX - 65_535);
815        assert_eq!(u32::from_sample(u16::MID), u32::MID);
816        assert_eq!(u32::from_sample(u16::MIN), u32::MIN);
817
818        assert_eq!(u32::from_sample(u24::MAX), u32::MAX - 255);
819        assert_eq!(u32::from_sample(u24::MID), u32::MID);
820        assert_eq!(u32::from_sample(u24::MIN), u32::MIN);
821
822        assert_eq!(u32::from_sample(u32::MAX), u32::MAX);
823        assert_eq!(u32::from_sample(u32::MID), u32::MID);
824        assert_eq!(u32::from_sample(u32::MIN), u32::MIN);
825
826        assert_eq!(u32::from_sample(i8::MAX), u32::MAX - 16_777_215);
827        assert_eq!(u32::from_sample(i8::MID), u32::MID);
828        assert_eq!(u32::from_sample(i8::MIN), u32::MIN);
829
830        assert_eq!(u32::from_sample(i16::MAX), u32::MAX - 65_535);
831        assert_eq!(u32::from_sample(i16::MID), u32::MID);
832        assert_eq!(u32::from_sample(i16::MIN), u32::MIN);
833
834        assert_eq!(u32::from_sample(i24::MAX), u32::MAX - 255);
835        assert_eq!(u32::from_sample(i24::MID), u32::MID);
836        assert_eq!(u32::from_sample(i24::MIN), u32::MIN);
837
838        assert_eq!(u32::from_sample(i32::MAX), u32::MAX);
839        assert_eq!(u32::from_sample(i32::MID), u32::MID);
840        assert_eq!(u32::from_sample(i32::MIN), u32::MIN);
841
842        assert_eq!(u32::from_sample(1.0f32), u32::MAX);
843        assert_eq!(u32::from_sample(0f32), u32::MID);
844        assert_eq!(u32::from_sample(-1.0f32), u32::MIN);
845
846        assert_eq!(u32::from_sample(1.0f64), u32::MAX);
847        assert_eq!(u32::from_sample(0f64), u32::MID);
848        assert_eq!(u32::from_sample(-1.0f64), u32::MIN);
849    }
850
851    #[test]
852    fn verify_i8_from_sample() {
853        assert_eq!(i8::from_sample(u8::MAX), i8::MAX);
854        assert_eq!(i8::from_sample(u8::MID), i8::MID);
855        assert_eq!(i8::from_sample(u8::MIN), i8::MIN);
856
857        assert_eq!(i8::from_sample(u16::MAX), i8::MAX);
858        assert_eq!(i8::from_sample(u16::MID), i8::MID);
859        assert_eq!(i8::from_sample(u16::MIN), i8::MIN);
860
861        assert_eq!(i8::from_sample(u24::MAX), i8::MAX);
862        assert_eq!(i8::from_sample(u24::MID), i8::MID);
863        assert_eq!(i8::from_sample(u24::MIN), i8::MIN);
864
865        assert_eq!(i8::from_sample(u32::MAX), i8::MAX);
866        assert_eq!(i8::from_sample(u32::MID), i8::MID);
867        assert_eq!(i8::from_sample(u32::MIN), i8::MIN);
868
869        assert_eq!(i8::from_sample(i8::MAX), i8::MAX);
870        assert_eq!(i8::from_sample(i8::MID), i8::MID);
871        assert_eq!(i8::from_sample(i8::MIN), i8::MIN);
872
873        assert_eq!(i8::from_sample(i16::MAX), i8::MAX);
874        assert_eq!(i8::from_sample(i16::MID), i8::MID);
875        assert_eq!(i8::from_sample(i16::MIN), i8::MIN);
876
877        assert_eq!(i8::from_sample(i24::MAX), i8::MAX);
878        assert_eq!(i8::from_sample(i24::MID), i8::MID);
879        assert_eq!(i8::from_sample(i24::MIN), i8::MIN);
880
881        assert_eq!(i8::from_sample(i32::MAX), i8::MAX);
882        assert_eq!(i8::from_sample(i32::MID), i8::MID);
883        assert_eq!(i8::from_sample(i32::MIN), i8::MIN);
884
885        assert_eq!(i8::from_sample(1.0f32), i8::MAX);
886        assert_eq!(i8::from_sample(0f32), i8::MID);
887        assert_eq!(i8::from_sample(-1.0f32), i8::MIN);
888
889        assert_eq!(i8::from_sample(1.0f64), i8::MAX);
890        assert_eq!(i8::from_sample(0f64), i8::MID);
891        assert_eq!(i8::from_sample(-1.0f64), i8::MIN);
892    }
893
894    #[test]
895    fn verify_i16_from_sample() {
896        assert_eq!(i16::from_sample(u8::MAX), i16::MAX - 255);
897        assert_eq!(i16::from_sample(u8::MID), i16::MID);
898        assert_eq!(i16::from_sample(u8::MIN), i16::MIN);
899
900        assert_eq!(i16::from_sample(u16::MAX), i16::MAX);
901        assert_eq!(i16::from_sample(u16::MID), i16::MID);
902        assert_eq!(i16::from_sample(u16::MIN), i16::MIN);
903
904        assert_eq!(i16::from_sample(u24::MAX), i16::MAX);
905        assert_eq!(i16::from_sample(u24::MID), i16::MID);
906        assert_eq!(i16::from_sample(u24::MIN), i16::MIN);
907
908        assert_eq!(i16::from_sample(u32::MAX), i16::MAX);
909        assert_eq!(i16::from_sample(u32::MID), i16::MID);
910        assert_eq!(i16::from_sample(u32::MIN), i16::MIN);
911
912        assert_eq!(i16::from_sample(i8::MAX), i16::MAX - 255);
913        assert_eq!(i16::from_sample(i8::MID), i16::MID);
914        assert_eq!(i16::from_sample(i8::MIN), i16::MIN);
915
916        assert_eq!(i16::from_sample(i16::MAX), i16::MAX);
917        assert_eq!(i16::from_sample(i16::MID), i16::MID);
918        assert_eq!(i16::from_sample(i16::MIN), i16::MIN);
919
920        assert_eq!(i16::from_sample(i24::MAX), i16::MAX);
921        assert_eq!(i16::from_sample(i24::MID), i16::MID);
922        assert_eq!(i16::from_sample(i24::MIN), i16::MIN);
923
924        assert_eq!(i16::from_sample(i32::MAX), i16::MAX);
925        assert_eq!(i16::from_sample(i32::MID), i16::MID);
926        assert_eq!(i16::from_sample(i32::MIN), i16::MIN);
927
928        assert_eq!(i16::from_sample(1.0f32), i16::MAX);
929        assert_eq!(i16::from_sample(0f32), i16::MID);
930        assert_eq!(i16::from_sample(-1.0f32), i16::MIN);
931
932        assert_eq!(i16::from_sample(1.0f64), i16::MAX);
933        assert_eq!(i16::from_sample(0f64), i16::MID);
934        assert_eq!(i16::from_sample(-1.0f64), i16::MIN);
935    }
936
937    #[test]
938    fn verify_i24_from_sample() {
939        assert_eq!(i24::from_sample(u8::MAX), i24::MAX - i24::from(65_535));
940        assert_eq!(i24::from_sample(u8::MID), i24::MID);
941        assert_eq!(i24::from_sample(u8::MIN), i24::MIN);
942
943        assert_eq!(i24::from_sample(u16::MAX), i24::MAX - i24::from(255));
944        assert_eq!(i24::from_sample(u16::MID), i24::MID);
945        assert_eq!(i24::from_sample(u16::MIN), i24::MIN);
946
947        assert_eq!(i24::from_sample(u24::MAX), i24::MAX);
948        assert_eq!(i24::from_sample(u24::MID), i24::MID);
949        assert_eq!(i24::from_sample(u24::MIN), i24::MIN);
950
951        assert_eq!(i24::from_sample(u32::MAX), i24::MAX);
952        assert_eq!(i24::from_sample(u32::MID), i24::MID);
953        assert_eq!(i24::from_sample(u32::MIN), i24::MIN);
954
955        assert_eq!(i24::from_sample(i8::MAX), i24::MAX - i24::from(65_535));
956        assert_eq!(i24::from_sample(i8::MID), i24::MID);
957        assert_eq!(i24::from_sample(i8::MIN), i24::MIN);
958
959        assert_eq!(i24::from_sample(i16::MAX), i24::MAX - i24::from(255));
960        assert_eq!(i24::from_sample(i16::MID), i24::MID);
961        assert_eq!(i24::from_sample(i16::MIN), i24::MIN);
962
963        assert_eq!(i24::from_sample(i24::MAX), i24::MAX);
964        assert_eq!(i24::from_sample(i24::MID), i24::MID);
965        assert_eq!(i24::from_sample(i24::MIN), i24::MIN);
966
967        assert_eq!(i24::from_sample(i32::MAX), i24::MAX);
968        assert_eq!(i24::from_sample(i32::MID), i24::MID);
969        assert_eq!(i24::from_sample(i32::MIN), i24::MIN);
970
971        assert_eq!(i24::from_sample(1.0f32), i24::MAX);
972        assert_eq!(i24::from_sample(0f32), i24::MID);
973        assert_eq!(i24::from_sample(-1.0f32), i24::MIN);
974
975        assert_eq!(i24::from_sample(1.0f64), i24::MAX);
976        assert_eq!(i24::from_sample(0f64), i24::MID);
977        assert_eq!(i24::from_sample(-1.0f64), i24::MIN);
978    }
979
980    #[test]
981    fn verify_i32_from_sample() {
982        assert_eq!(i32::from_sample(u8::MAX), i32::MAX - 16_777_215);
983        assert_eq!(i32::from_sample(u8::MID), i32::MID);
984        assert_eq!(i32::from_sample(u8::MIN), i32::MIN);
985
986        assert_eq!(i32::from_sample(u16::MAX), i32::MAX - 65_535);
987        assert_eq!(i32::from_sample(u16::MID), i32::MID);
988        assert_eq!(i32::from_sample(u16::MIN), i32::MIN);
989
990        assert_eq!(i32::from_sample(u24::MAX), i32::MAX - 255);
991        assert_eq!(i32::from_sample(u24::MID), i32::MID);
992        assert_eq!(i32::from_sample(u24::MIN), i32::MIN);
993
994        assert_eq!(i32::from_sample(u32::MAX), i32::MAX);
995        assert_eq!(i32::from_sample(u32::MID), i32::MID);
996        assert_eq!(i32::from_sample(u32::MIN), i32::MIN);
997
998        assert_eq!(i32::from_sample(i8::MAX), i32::MAX - 16_777_215);
999        assert_eq!(i32::from_sample(i8::MID), i32::MID);
1000        assert_eq!(i32::from_sample(i8::MIN), i32::MIN);
1001
1002        assert_eq!(i32::from_sample(i16::MAX), i32::MAX - 65_535);
1003        assert_eq!(i32::from_sample(i16::MID), i32::MID);
1004        assert_eq!(i32::from_sample(i16::MIN), i32::MIN);
1005
1006        assert_eq!(i32::from_sample(i24::MAX), i32::MAX - 255);
1007        assert_eq!(i32::from_sample(i24::MID), i32::MID);
1008        assert_eq!(i32::from_sample(i24::MIN), i32::MIN);
1009
1010        assert_eq!(i32::from_sample(i32::MAX), i32::MAX);
1011        assert_eq!(i32::from_sample(i32::MID), i32::MID);
1012        assert_eq!(i32::from_sample(i32::MIN), i32::MIN);
1013
1014        assert_eq!(i32::from_sample(1.0f32), i32::MAX);
1015        assert_eq!(i32::from_sample(0f32), i32::MID);
1016        assert_eq!(i32::from_sample(-1.0f32), i32::MIN);
1017
1018        assert_eq!(i32::from_sample(1.0f64), i32::MAX);
1019        assert_eq!(i32::from_sample(0f64), i32::MID);
1020        assert_eq!(i32::from_sample(-1.0f64), i32::MIN);
1021    }
1022
1023    #[test]
1024    fn verify_f64_from_sample() {
1025        assert_eq!(f64::from_sample(u8::MAX), 127.0 / 128.0);
1026        assert_eq!(f64::from_sample(u8::MID), 0.0);
1027        assert_eq!(f64::from_sample(u8::MIN), -1.0);
1028
1029        assert_eq!(f64::from_sample(u16::MAX), 32_767.0 / 32_768.0);
1030        assert_eq!(f64::from_sample(u16::MID), 0.0);
1031        assert_eq!(f64::from_sample(u16::MIN), -1.0);
1032
1033        assert_eq!(f64::from_sample(u24::MAX), 8_388_607.0 / 8_388_608.0);
1034        assert_eq!(f64::from_sample(u24::MID), 0.0);
1035        assert_eq!(f64::from_sample(u24::MIN), -1.0);
1036
1037        assert_eq!(f64::from_sample(u32::MAX), 2_147_483_647.0 / 2_147_483_648.0);
1038        assert_eq!(f64::from_sample(u32::MID), 0.0);
1039        assert_eq!(f64::from_sample(u32::MIN), -1.0);
1040
1041        assert_eq!(f64::from_sample(i8::MAX), 127.0 / 128.0);
1042        assert_eq!(f64::from_sample(i8::MID), 0.0);
1043        assert_eq!(f64::from_sample(i8::MIN), -1.0);
1044
1045        assert_eq!(f64::from_sample(i16::MAX), 32_767.0 / 32_768.0);
1046        assert_eq!(f64::from_sample(i16::MID), 0.0);
1047        assert_eq!(f64::from_sample(i16::MIN), -1.0);
1048
1049        assert_eq!(f64::from_sample(i24::MAX), 8_388_607.0 / 8_388_608.0);
1050        assert_eq!(f64::from_sample(i24::MID), 0.0);
1051        assert_eq!(f64::from_sample(i24::MIN), -1.0);
1052
1053        assert_eq!(f64::from_sample(i32::MAX), 2_147_483_647.0 / 2_147_483_648.0);
1054        assert_eq!(f64::from_sample(i32::MID), 0.0);
1055        assert_eq!(f64::from_sample(i32::MIN), -1.0);
1056
1057        assert_eq!(f64::from_sample(1.0f32), 1.0);
1058        assert_eq!(f64::from_sample(0f32), 0.0);
1059        assert_eq!(f64::from_sample(-1.0f32), -1.0);
1060
1061        assert_eq!(f64::from_sample(1.0f64), 1.0);
1062        assert_eq!(f64::from_sample(0f64), 0.0);
1063        assert_eq!(f64::from_sample(-1.0f64), -1.0);
1064    }
1065
1066    #[test]
1067    fn verify_f32_from_sample() {
1068        assert_eq!(f32::from_sample(u8::MAX), 127.0 / 128.0);
1069        assert_eq!(f32::from_sample(u8::MID), 0.0);
1070        assert_eq!(f32::from_sample(u8::MIN), -1.0);
1071
1072        assert_eq!(f32::from_sample(u16::MAX), 32_767.0 / 32_768.0);
1073        assert_eq!(f32::from_sample(u16::MID), 0.0);
1074        assert_eq!(f32::from_sample(u16::MIN), -1.0);
1075
1076        assert_eq!(f32::from_sample(u24::MAX), 8_388_607.0 / 8_388_608.0);
1077        assert_eq!(f32::from_sample(u24::MID), 0.0);
1078        assert_eq!(f32::from_sample(u24::MIN), -1.0);
1079
1080        assert_eq!(f32::from_sample(u32::MAX), 2_147_483_647.0 / 2_147_483_648.0);
1081        assert_eq!(f32::from_sample(u32::MID), 0.0);
1082        assert_eq!(f32::from_sample(u32::MIN), -1.0);
1083
1084        assert_eq!(f32::from_sample(i8::MAX), 127.0 / 128.0);
1085        assert_eq!(f32::from_sample(i8::MID), 0.0);
1086        assert_eq!(f32::from_sample(i8::MIN), -1.0);
1087
1088        assert_eq!(f32::from_sample(i16::MAX), 32_767.0 / 32_768.0);
1089        assert_eq!(f32::from_sample(i16::MID), 0.0);
1090        assert_eq!(f32::from_sample(i16::MIN), -1.0);
1091
1092        assert_eq!(f32::from_sample(i24::MAX), 8_388_607.0 / 8_388_608.0);
1093        assert_eq!(f32::from_sample(i24::MID), 0.0);
1094        assert_eq!(f32::from_sample(i24::MIN), -1.0);
1095
1096        assert_eq!(f32::from_sample(i32::MAX), 2_147_483_647.0 / 2_147_483_648.0);
1097        assert_eq!(f32::from_sample(i32::MID), 0.0);
1098        assert_eq!(f32::from_sample(i32::MIN), -1.0);
1099
1100        assert_eq!(f32::from_sample(1.0f32), 1.0);
1101        assert_eq!(f32::from_sample(0f32), 0.0);
1102        assert_eq!(f32::from_sample(-1.0f32), -1.0);
1103
1104        assert_eq!(f32::from_sample(1.0f64), 1.0);
1105        assert_eq!(f32::from_sample(0f64), 0.0);
1106        assert_eq!(f32::from_sample(-1.0f64), -1.0);
1107    }
1108}