mcelp 1.0.1

Mitsubishi CELP speech codec: a 3.6 kbit/s speech encoder and decoder
Documentation
//! 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);
    }
}