codec_core/codecs/g711/
reference.rs1pub fn alaw_compress(sample: i16) -> u8 {
41 let mut ix = if sample < 0 {
42 (((!sample) as u16) >> 4) as i16
43 } else {
44 sample >> 4
45 };
46
47 if ix > 15 {
48 let mut iexp = 1;
49 while ix > 16 + 15 {
50 ix >>= 1;
51 iexp += 1;
52 }
53 ix -= 16;
54 ix += iexp << 4;
55 }
56
57 if sample >= 0 {
58 ix |= 0x0080;
59 }
60
61 (ix ^ 0x0055) as u8
62}
63
64pub fn alaw_expand(compressed: u8) -> i16 {
80 let mut ix = (compressed ^ 0x0055) as i16;
81
82 ix &= 0x007F;
83 let iexp = ix >> 4;
84 let mut mant = ix & 0x000F;
85
86 if iexp > 0 {
87 mant = mant + 16;
88 }
89
90 mant = (mant << 4) + 0x0008;
91
92 if iexp > 1 {
93 mant = mant << (iexp - 1);
94 }
95
96 if compressed > 127 {
97 mant
98 } else {
99 -mant
100 }
101}
102
103pub fn ulaw_compress(sample: i16) -> u8 {
119 let absno = if sample < 0 {
120 (((!sample) as u16) >> 2) as i16 + 33
121 } else {
122 (sample >> 2) + 33
123 };
124
125 let absno = if absno > 0x1FFF { 0x1FFF } else { absno };
126
127 let mut i = absno >> 6;
128 let mut segno = 1;
129 while i != 0 {
130 segno += 1;
131 i >>= 1;
132 }
133
134 let high_nibble = 0x0008 - segno;
135 let low_nibble = 0x000F - ((absno >> segno) & 0x000F);
136 let mut result = (high_nibble << 4) | low_nibble;
137
138 if sample >= 0 {
139 result |= 0x0080;
140 }
141
142 result as u8
143}
144
145pub fn ulaw_expand(compressed: u8) -> i16 {
161 let sign = if compressed < 0x0080 { -1 } else { 1 };
162 let mantissa = (!compressed) as i16;
163 let exponent = (mantissa >> 4) & 0x0007;
164 let segment = exponent + 1;
165 let mantissa = mantissa & 0x000F;
166
167 let step = 4 << segment;
168
169 sign * (
170 ((0x0080) << exponent) +
171 step * mantissa +
172 step / 2 -
173 4 * 33
174 )
175}
176
177
178
179
180
181
182
183
184
185#[cfg(test)]
186mod tests {
187 use super::*;
188
189 #[test]
190 fn test_alaw_basic_round_trip() {
191 let test_samples = vec![0i16, 100, -100, 1000, -1000, 10000, -10000];
192
193 for sample in test_samples {
194 let encoded = alaw_compress(sample);
195 let decoded = alaw_expand(encoded);
196 let error = (decoded - sample).abs();
197
198 assert!(error < 2000, "A-law error too large for {}: {} (error: {})", sample, decoded, error);
200 }
201 }
202
203 #[test]
204 fn test_ulaw_basic_round_trip() {
205 let test_samples = vec![0i16, 100, -100, 1000, -1000, 10000, -10000];
206
207 for sample in test_samples {
208 let encoded = ulaw_compress(sample);
209 let decoded = ulaw_expand(encoded);
210 let error = (decoded - sample).abs();
211
212 assert!(error < 2000, "μ-law error too large for {}: {} (error: {})", sample, decoded, error);
214 }
215 }
216
217
218
219
220
221 #[test]
222 fn test_boundary_values() {
223 let boundary_samples = vec![-32768i16, -32767, -1, 0, 1, 32766, 32767];
224
225 for sample in boundary_samples {
226 let alaw_encoded = alaw_compress(sample);
228 let alaw_decoded = alaw_expand(alaw_encoded);
229
230 let ulaw_encoded = ulaw_compress(sample);
232 let ulaw_decoded = ulaw_expand(ulaw_encoded);
233
234 assert!(alaw_decoded >= -32768 && alaw_decoded <= 32767);
236 assert!(ulaw_decoded >= -32768 && ulaw_decoded <= 32767);
237 }
238 }
239
240 #[test]
241 fn test_known_values() {
242 assert_eq!(alaw_compress(0), 0xd5);
244 assert_eq!(alaw_compress(128), 0xdd);
245 assert_eq!(alaw_compress(1024), 0xe5);
246 assert_eq!(alaw_compress(-128), 0x52);
247 assert_eq!(alaw_compress(-1024), 0x7a);
248
249 assert_eq!(ulaw_compress(0), 0xff);
250 assert_eq!(ulaw_compress(128), 0xef);
251 assert_eq!(ulaw_compress(1024), 0xcd);
252 assert_eq!(ulaw_compress(-128), 0x6f);
253 assert_eq!(ulaw_compress(-1024), 0x4d);
254
255 assert_eq!(alaw_expand(0xd5), 8);
256 assert_eq!(alaw_expand(0xdd), 136);
257 assert_eq!(alaw_expand(0xe5), 1056);
258 assert_eq!(alaw_expand(0x52), -120);
259 assert_eq!(alaw_expand(0x7a), -1008);
260
261 assert_eq!(ulaw_expand(0xff), 0);
262 assert_eq!(ulaw_expand(0xef), 132);
263 assert_eq!(ulaw_expand(0xcd), 1052);
264 assert_eq!(ulaw_expand(0x6f), -132);
265 assert_eq!(ulaw_expand(0x4d), -1052);
266 }
267}