rtc_media/audio/
sample.rs1use std::io::{Cursor, Read};
2
3use byteorder::{ByteOrder, ReadBytesExt};
4#[cfg(test)]
5use nearly_eq::NearlyEq;
6
7#[derive(Eq, PartialEq, Copy, Clone, Default, Debug)]
8#[repr(transparent)]
9pub struct Sample<Raw>(Raw);
13
14impl From<i16> for Sample<i16> {
15 #[inline]
16 fn from(raw: i16) -> Self {
17 Self(raw)
18 }
19}
20
21impl From<f32> for Sample<f32> {
22 #[inline]
23 fn from(raw: f32) -> Self {
24 Self(raw.clamp(-1.0, 1.0))
25 }
26}
27
28macro_rules! impl_from_sample_for_raw {
29 ($raw:ty) => {
30 impl From<Sample<$raw>> for $raw {
31 #[inline]
32 fn from(sample: Sample<$raw>) -> $raw {
33 sample.0
34 }
35 }
36 };
37}
38
39impl_from_sample_for_raw!(i16);
40impl_from_sample_for_raw!(f32);
41
42impl From<Sample<i16>> for Sample<f32> {
63 #[inline]
64 fn from(sample: Sample<i16>) -> Self {
65 let divisor = if sample.0 < 0 {
66 i16::MIN as f32
67 } else {
68 i16::MAX as f32
69 }
70 .abs();
71 Self::from((sample.0 as f32) / divisor)
72 }
73}
74
75impl From<Sample<f32>> for Sample<i16> {
76 #[inline]
77 fn from(sample: Sample<f32>) -> Self {
78 let multiplier = if sample.0 < 0.0 {
79 i16::MIN as f32
80 } else {
81 i16::MAX as f32
82 }
83 .abs();
84 Self::from((sample.0 * multiplier) as i16)
85 }
86}
87
88trait FromBytes: Sized {
89 fn from_reader<B: ByteOrder, R: Read>(reader: &mut R) -> Result<Self, std::io::Error>;
90
91 fn from_bytes<B: ByteOrder>(bytes: &[u8]) -> Result<Self, std::io::Error> {
92 let mut cursor = Cursor::new(bytes);
93 Self::from_reader::<B, _>(&mut cursor)
94 }
95}
96
97impl FromBytes for Sample<i16> {
98 fn from_reader<B: ByteOrder, R: Read>(reader: &mut R) -> Result<Self, std::io::Error> {
99 reader.read_i16::<B>().map(Self::from)
100 }
101}
102
103impl FromBytes for Sample<f32> {
104 fn from_reader<B: ByteOrder, R: Read>(reader: &mut R) -> Result<Self, std::io::Error> {
105 reader.read_f32::<B>().map(Self::from)
106 }
107}
108
109#[cfg(test)]
110impl<Raw> NearlyEq<Self, Raw> for Sample<Raw>
111where
112 Raw: NearlyEq<Raw, Raw>,
113{
114 fn eps() -> Raw {
115 Raw::eps()
116 }
117
118 fn eq(&self, other: &Self, eps: &Raw) -> bool {
119 NearlyEq::eq(&self.0, &other.0, eps)
120 }
121}
122
123#[cfg(test)]
124mod tests {
125 use nearly_eq::assert_nearly_eq;
126
127 use super::*;
128
129 #[test]
130 fn sample_i16_from_i16() {
131 assert_eq!(Sample::<i16>::from(i16::MIN).0, i16::MIN);
133 assert_eq!(Sample::<i16>::from(i16::MIN / 2).0, i16::MIN / 2);
134 assert_eq!(Sample::<i16>::from(0).0, 0);
135 assert_eq!(Sample::<i16>::from(i16::MAX / 2).0, i16::MAX / 2);
136 assert_eq!(Sample::<i16>::from(i16::MAX).0, i16::MAX);
137 }
138
139 #[test]
140 fn sample_f32_from_f32() {
141 assert_eq!(Sample::<f32>::from(-1.0).0, -1.0);
142 assert_eq!(Sample::<f32>::from(-0.5).0, -0.5);
143 assert_eq!(Sample::<f32>::from(0.0).0, 0.0);
144 assert_eq!(Sample::<f32>::from(0.5).0, 0.5);
145 assert_eq!(Sample::<f32>::from(1.0).0, 1.0);
146
147 assert_eq!(Sample::<f32>::from(f32::MIN).0, -1.0);
149 assert_eq!(Sample::<f32>::from(f32::MAX).0, 1.0);
150 }
151
152 #[test]
153 fn sample_i16_from_sample_f32() {
154 assert_nearly_eq!(
155 Sample::<i16>::from(Sample::<f32>::from(-1.0)),
156 Sample::from(i16::MIN)
157 );
158 assert_nearly_eq!(
159 Sample::<i16>::from(Sample::<f32>::from(-0.5)),
160 Sample::from(i16::MIN / 2)
161 );
162 assert_nearly_eq!(
163 Sample::<i16>::from(Sample::<f32>::from(0.0)),
164 Sample::from(0)
165 );
166 assert_nearly_eq!(
167 Sample::<i16>::from(Sample::<f32>::from(0.5)),
168 Sample::from(i16::MAX / 2)
169 );
170 assert_nearly_eq!(
171 Sample::<i16>::from(Sample::<f32>::from(1.0)),
172 Sample::from(i16::MAX)
173 );
174 }
175
176 #[test]
177 fn sample_f32_from_sample_i16() {
178 assert_nearly_eq!(
179 Sample::<f32>::from(Sample::<i16>::from(i16::MIN)),
180 Sample::from(-1.0)
181 );
182 assert_nearly_eq!(
183 Sample::<f32>::from(Sample::<i16>::from(i16::MIN / 2)),
184 Sample::from(-0.5)
185 );
186 assert_nearly_eq!(
187 Sample::<f32>::from(Sample::<i16>::from(0)),
188 Sample::from(0.0)
189 );
190 assert_nearly_eq!(
191 Sample::<f32>::from(Sample::<i16>::from(i16::MAX / 2)),
192 Sample::from(0.5),
193 0.0001 );
195 assert_nearly_eq!(
196 Sample::<f32>::from(Sample::<i16>::from(i16::MAX)),
197 Sample::from(1.0)
198 );
199 }
200}