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