rodio/conversions/
sample.rs

1use cpal::{FromSample, Sample as CpalSample};
2use std::marker::PhantomData;
3
4/// Converts the samples data type to `O`.
5#[derive(Clone, Debug)]
6pub struct DataConverter<I, O> {
7    input: I,
8    marker: PhantomData<O>,
9}
10
11impl<I, O> DataConverter<I, O> {
12    /// Builds a new converter.
13    #[inline]
14    pub fn new(input: I) -> DataConverter<I, O> {
15        DataConverter {
16            input,
17            marker: PhantomData,
18        }
19    }
20
21    /// Destroys this iterator and returns the underlying iterator.
22    #[inline]
23    pub fn into_inner(self) -> I {
24        self.input
25    }
26
27    /// get mutable access to the iterator
28    #[inline]
29    pub fn inner_mut(&mut self) -> &mut I {
30        &mut self.input
31    }
32}
33
34impl<I, O> Iterator for DataConverter<I, O>
35where
36    I: Iterator,
37    I::Item: Sample,
38    O: FromSample<I::Item> + Sample,
39{
40    type Item = O;
41
42    #[inline]
43    fn next(&mut self) -> Option<O> {
44        self.input.next().map(|s| CpalSample::from_sample(s))
45    }
46
47    #[inline]
48    fn size_hint(&self) -> (usize, Option<usize>) {
49        self.input.size_hint()
50    }
51}
52
53impl<I, O> ExactSizeIterator for DataConverter<I, O>
54where
55    I: ExactSizeIterator,
56    I::Item: Sample,
57    O: FromSample<I::Item> + Sample,
58{
59}
60
61/// Represents a value of a single sample.
62///
63/// This trait is implemented by default on three types: `i16`, `u16` and `f32`.
64///
65/// - For `i16`, silence corresponds to the value `0`. The minimum and maximum amplitudes are
66///   represented by `i16::min_value()` and `i16::max_value()` respectively.
67/// - For `u16`, silence corresponds to the value `u16::max_value() / 2`. The minimum and maximum
68///   amplitudes are represented by `0` and `u16::max_value()` respectively.
69/// - For `f32`, silence corresponds to the value `0.0`. The minimum and maximum amplitudes are
70///   represented by `-1.0` and `1.0` respectively.
71///
72/// You can implement this trait on your own type as well if you wish so.
73///
74pub trait Sample: CpalSample {
75    /// Linear interpolation between two samples.
76    ///
77    /// The result should be equal to
78    /// `first * numerator / denominator + second * (1 - numerator / denominator)`.
79    fn lerp(first: Self, second: Self, numerator: u32, denominator: u32) -> Self;
80    /// Multiplies the value of this sample by the given amount.
81    fn amplify(self, value: f32) -> Self;
82
83    /// Converts the sample to an f32 value.
84    fn to_f32(self) -> f32;
85
86    /// Calls `saturating_add` on the sample.
87    fn saturating_add(self, other: Self) -> Self;
88
89    /// Returns the value corresponding to the absence of sound.
90    fn zero_value() -> Self;
91}
92
93impl Sample for u16 {
94    #[inline]
95    fn lerp(first: u16, second: u16, numerator: u32, denominator: u32) -> u16 {
96        let a = first as i32;
97        let b = second as i32;
98        let n = numerator as i32;
99        let d = denominator as i32;
100        (a + (b - a) * n / d) as u16
101    }
102
103    #[inline]
104    fn amplify(self, value: f32) -> u16 {
105        ((self as f32) * value) as u16
106    }
107
108    #[inline]
109    fn to_f32(self) -> f32 {
110        // Convert u16 to f32 in the range [-1.0, 1.0]
111        (self as f32 - 32768.0) / 32768.0
112    }
113
114    #[inline]
115    fn saturating_add(self, other: u16) -> u16 {
116        self.saturating_add(other)
117    }
118
119    #[inline]
120    fn zero_value() -> u16 {
121        32768
122    }
123}
124
125impl Sample for i16 {
126    #[inline]
127    fn lerp(first: i16, second: i16, numerator: u32, denominator: u32) -> i16 {
128        (first as i32 + (second as i32 - first as i32) * numerator as i32 / denominator as i32)
129            as i16
130    }
131
132    #[inline]
133    fn amplify(self, value: f32) -> i16 {
134        ((self as f32) * value) as i16
135    }
136
137    #[inline]
138    fn to_f32(self) -> f32 {
139        // Convert i16 to f32 in the range [-1.0, 1.0]
140        self as f32 / 32768.0
141    }
142
143    #[inline]
144    fn saturating_add(self, other: i16) -> i16 {
145        self.saturating_add(other)
146    }
147
148    #[inline]
149    fn zero_value() -> i16 {
150        0
151    }
152}
153
154impl Sample for f32 {
155    #[inline]
156    fn lerp(first: f32, second: f32, numerator: u32, denominator: u32) -> f32 {
157        first + (second - first) * numerator as f32 / denominator as f32
158    }
159
160    #[inline]
161    fn amplify(self, value: f32) -> f32 {
162        self * value
163    }
164
165    #[inline]
166    fn to_f32(self) -> f32 {
167        // f32 is already in the correct format
168        self
169    }
170
171    #[inline]
172    fn saturating_add(self, other: f32) -> f32 {
173        self + other
174    }
175
176    #[inline]
177    fn zero_value() -> f32 {
178        0.0
179    }
180}