geng_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
28impl<I, O> Iterator for DataConverter<I, O>
29where
30    I: Iterator,
31    I::Item: Sample,
32    O: FromSample<I::Item> + Sample,
33{
34    type Item = O;
35
36    #[inline]
37    fn next(&mut self) -> Option<O> {
38        self.input.next().map(|s| CpalSample::from_sample(s))
39    }
40
41    #[inline]
42    fn size_hint(&self) -> (usize, Option<usize>) {
43        self.input.size_hint()
44    }
45}
46
47impl<I, O> ExactSizeIterator for DataConverter<I, O>
48where
49    I: ExactSizeIterator,
50    I::Item: Sample,
51    O: FromSample<I::Item> + Sample,
52{
53}
54
55/// Represents a value of a single sample.
56///
57/// This trait is implemented by default on three types: `i16`, `u16` and `f32`.
58///
59/// - For `i16`, silence corresponds to the value `0`. The minimum and maximum amplitudes are
60///   represented by `i16::min_value()` and `i16::max_value()` respectively.
61/// - For `u16`, silence corresponds to the value `u16::max_value() / 2`. The minimum and maximum
62///   amplitudes are represented by `0` and `u16::max_value()` respectively.
63/// - For `f32`, silence corresponds to the value `0.0`. The minimum and maximum amplitudes are
64///  represented by `-1.0` and `1.0` respectively.
65///
66/// You can implement this trait on your own type as well if you wish so.
67///
68pub trait Sample: CpalSample {
69    /// Linear interpolation between two samples.
70    ///
71    /// The result should be equal to
72    /// `first * numerator / denominator + second * (1 - numerator / denominator)`.
73    fn lerp(first: Self, second: Self, numerator: u32, denominator: u32) -> Self;
74    /// Multiplies the value of this sample by the given amount.
75    fn amplify(self, value: f32) -> Self;
76
77    /// Calls `saturating_add` on the sample.
78    fn saturating_add(self, other: Self) -> Self;
79
80    /// Returns the value corresponding to the absence of sound.
81    fn zero_value() -> Self;
82}
83
84impl Sample for u16 {
85    #[inline]
86    fn lerp(first: u16, second: u16, numerator: u32, denominator: u32) -> u16 {
87        let a = first as i32;
88        let b = second as i32;
89        let n = numerator as i32;
90        let d = denominator as i32;
91        (a + (b - a) * n / d) as u16
92    }
93
94    #[inline]
95    fn amplify(self, value: f32) -> u16 {
96        ((self as f32) * value) as u16
97    }
98
99    #[inline]
100    fn saturating_add(self, other: u16) -> u16 {
101        self.saturating_add(other)
102    }
103
104    #[inline]
105    fn zero_value() -> u16 {
106        32768
107    }
108}
109
110impl Sample for i16 {
111    #[inline]
112    fn lerp(first: i16, second: i16, numerator: u32, denominator: u32) -> i16 {
113        (first as i32 + (second as i32 - first as i32) * numerator as i32 / denominator as i32)
114            as i16
115    }
116
117    #[inline]
118    fn amplify(self, value: f32) -> i16 {
119        ((self as f32) * value) as i16
120    }
121
122    #[inline]
123    fn saturating_add(self, other: i16) -> i16 {
124        self.saturating_add(other)
125    }
126
127    #[inline]
128    fn zero_value() -> i16 {
129        0
130    }
131}
132
133impl Sample for f32 {
134    #[inline]
135    fn lerp(first: f32, second: f32, numerator: u32, denominator: u32) -> f32 {
136        first + (second - first) * numerator as f32 / denominator as f32
137    }
138
139    #[inline]
140    fn amplify(self, value: f32) -> f32 {
141        self * value
142    }
143
144    #[inline]
145    fn saturating_add(self, other: f32) -> f32 {
146        self + other
147    }
148
149    #[inline]
150    fn zero_value() -> f32 {
151        0.0
152    }
153}