1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
//! Linear to mu-law conversion.
//!
//! Plain G.711 mu-law with a bias of 33 and the usual complemented output, but
//! computed the way the reference does it: the biased magnitude is normalised by
//! shifting until the segment number falls out, and the segment and mantissa
//! fields are complemented individually rather than the finished byte.
/// Bias added before segmenting, in the 13-bit domain.
const BIAS: i16 = 33;
/// Largest representable biased magnitude.
const CLIP: i16 = 8191;
/// Convert a signed sample to its sign and biased 13-bit magnitude.
fn biased_magnitude(sample: i16) -> (bool, i16) {
let negative = sample < 0;
let magnitude = if negative { !sample } else { sample };
(negative, ((magnitude >> 2) + BIAS).min(CLIP))
}
/// Encode the complemented segment and mantissa fields of a magnitude.
fn magnitude_byte(mut magnitude: i16) -> u8 {
let mut high = magnitude >> 6;
magnitude >>= 1;
let mut segment = 1;
while high != 0 {
high >>= 1;
segment += 1;
magnitude >>= 1;
}
let field = ((8 - segment) as i16) << 4;
let mantissa = 15 - (magnitude & 15);
(field | mantissa) as u8
}
/// Convert one linear sample to a mu-law byte.
pub fn from_linear(sample: i16) -> u8 {
let (negative, magnitude) = biased_magnitude(sample);
let byte = magnitude_byte(magnitude);
if negative { byte } else { byte | 0x80 }
}
/// Convert a whole frame in place.
pub fn frame_from_linear(samples: &[i16], out: &mut [u8]) {
for (o, &s) in out.iter_mut().zip(samples) {
*o = from_linear(s);
}
}