embedded_dsp/
companding.rs1#[allow(unused_imports)]
9use crate::math::FloatMath;
10
11const MU: f32 = 255.0;
12const A_LAW: f32 = 87.6;
13const LN_1P_MU: f32 = 5.545_177_5; const LN_A_LAW: f32 = 4.472_781; const A_LAW_DENOM: f32 = 1.0 + LN_A_LAW; #[inline(always)]
19fn sign(x: f32) -> f32 {
20 if x < 0.0 { -1.0 } else { 1.0 }
21}
22
23pub fn mu_law_compress_f32(x: f32) -> f32 {
26 let ax = x.abs();
27 sign(x) * (1.0 + MU * ax).ln() / LN_1P_MU
28}
29
30pub fn mu_law_expand_f32(y: f32) -> f32 {
33 let ay = y.abs();
34 sign(y) * ((1.0 + MU).powf(ay) - 1.0) / MU
35}
36
37pub fn a_law_compress_f32(x: f32) -> f32 {
40 let ax = x.abs();
41 if ax < 1.0 / A_LAW {
42 sign(x) * (A_LAW * ax) / A_LAW_DENOM
43 } else {
44 sign(x) * (1.0 + (A_LAW * ax).ln()) / A_LAW_DENOM
45 }
46}
47
48pub fn a_law_expand_f32(y: f32) -> f32 {
51 let ay = y.abs();
52 if ay < 1.0 / A_LAW_DENOM {
53 sign(y) * ay * A_LAW_DENOM / A_LAW
54 } else {
55 sign(y) * (ay * A_LAW_DENOM - 1.0).exp() / A_LAW
56 }
57}
58
59fn top_bit(x: i32) -> i32 {
62 if x <= 0 {
63 -1
64 } else {
65 31 - (x as u32).leading_zeros() as i32
66 }
67}
68
69pub fn linear_to_ulaw(sample: i16) -> u8 {
71 const BIAS: i32 = 0x84;
72 let mut pcm = sample as i32;
73 let mask = if pcm < 0 {
74 pcm = BIAS - pcm;
75 0x7F
76 } else {
77 pcm += BIAS;
78 0xFF
79 };
80 if pcm > 0x7FFF {
81 pcm = 0x7FFF;
82 }
83 let seg = top_bit(pcm | 0xFF) - 7;
84 if seg >= 8 {
85 (0x7F ^ mask) as u8
86 } else {
87 let uval = (seg << 4) | ((pcm >> (seg + 3)) & 0x0F);
88 (uval ^ mask) as u8
89 }
90}
91
92pub fn ulaw_to_linear(u: u8) -> i16 {
94 const BIAS: i32 = 0x84;
95 let u = (!u) as i32;
96 let mut t = ((u & 0x0F) << 3) + BIAS;
97 t <<= (u & 0x70) >> 4;
98 let out = if u & 0x80 != 0 { BIAS - t } else { t - BIAS };
99 out.clamp(i16::MIN as i32, i16::MAX as i32) as i16
100}
101
102pub fn linear_to_alaw(sample: i16) -> u8 {
104 let mut pcm = sample as i32;
105 let mask = if pcm >= 0 {
106 0xD5
107 } else {
108 pcm = -pcm - 8;
109 0x55
110 };
111 let seg = top_bit(pcm | 0xFF) - 7;
112 if seg >= 8 {
113 (0x7F ^ mask) as u8
114 } else {
115 let shift = if seg != 0 { seg + 3 } else { 4 };
116 let aval = (seg << 4) | ((pcm >> shift) & 0x0F);
117 (aval ^ mask) as u8
118 }
119}
120
121pub fn alaw_to_linear(a: u8) -> i16 {
123 let a = (a ^ 0x55) as i32;
124 let mut t = (a & 0x0F) << 4;
125 let seg = (a & 0x70) >> 4;
126 if seg != 0 {
127 t = (t + 0x108) << (seg - 1);
128 } else {
129 t += 8;
130 }
131 let out = if a & 0x80 != 0 { t } else { -t };
132 out.clamp(i16::MIN as i32, i16::MAX as i32) as i16
133}