libflo_audio/lossless/
lpc.rs1pub fn autocorrelation(samples: &[f32], max_lag: usize) -> Vec<f32> {
3 let n = samples.len();
4 let mut autocorr = vec![0.0; max_lag + 1];
5
6 for lag in 0..=max_lag {
7 let mut sum = 0.0;
8 for i in 0..(n.saturating_sub(lag)) {
9 sum += samples[i] * samples[i + lag];
10 }
11 autocorr[lag] = sum;
12 }
13
14 autocorr
15}
16
17pub fn levinson_durbin(autocorr: &[f32], order: usize) -> Vec<f32> {
19 if order == 0 || autocorr.is_empty() {
20 return vec![];
21 }
22
23 let mut coeffs = vec![0.0; order];
24 let mut prev = vec![0.0; order];
25 let mut error = autocorr[0];
26
27 if error.abs() < 1e-10 {
28 error = 1e-10;
29 }
30
31 for i in 0..order {
32 let mut lambda = autocorr.get(i + 1).copied().unwrap_or(0.0);
33 for j in 0..i {
34 lambda -= coeffs[j] * autocorr.get(i - j).copied().unwrap_or(0.0);
35 }
36 lambda /= error;
37 lambda = lambda.clamp(-0.999, 0.999);
38
39 prev.copy_from_slice(&coeffs);
40
41 coeffs[i] = lambda;
42 for j in 0..i {
43 coeffs[j] = prev[j] - lambda * prev[i - 1 - j];
44 }
45
46 error *= 1.0 - lambda * lambda;
47 if error.abs() < 1e-10 {
48 error = 1e-10;
49 }
50 }
51
52 coeffs
53}
54
55pub fn calculate_residuals(samples: &[f32], coeffs: &[f32]) -> Vec<f32> {
57 let order = coeffs.len();
58 let mut residuals = Vec::with_capacity(samples.len());
59
60 for i in 0..order.min(samples.len()) {
62 residuals.push(samples[i]);
63 }
64
65 for i in order..samples.len() {
67 let mut prediction = 0.0;
68 for (j, &coeff) in coeffs.iter().enumerate() {
69 prediction += coeff * samples[i - j - 1];
70 }
71 residuals.push(samples[i] - prediction);
72 }
73
74 residuals
75}
76
77pub fn reconstruct_samples(coeffs: &[f32], residuals: &[f32], target_len: usize) -> Vec<f32> {
79 let order = coeffs.len();
80 let mut samples = Vec::with_capacity(target_len);
81
82 for i in 0..order.min(residuals.len()) {
84 samples.push(residuals[i]);
85 }
86
87 for i in order..target_len.min(residuals.len()) {
89 let mut prediction = 0.0;
90 for (j, &coeff) in coeffs.iter().enumerate() {
91 if i > j {
92 prediction += coeff * samples[i - j - 1];
93 }
94 }
95 samples.push(prediction + residuals[i]);
96 }
97
98 while samples.len() < target_len {
100 samples.push(0.0);
101 }
102
103 samples
104}
105
106pub fn quantize_coefficients(coeffs: &[f32]) -> (Vec<i32>, u8) {
108 if coeffs.is_empty() {
109 return (vec![], 0);
110 }
111
112 let max_val = coeffs.iter().map(|&c| c.abs()).fold(0.0f32, f32::max);
113
114 let shift_bits = if max_val > 0.0 && max_val.is_finite() {
115 let ratio = 2147483647.0f32 / max_val;
116 if ratio > 1.0 {
117 (ratio.log2().floor() as i32).clamp(0, 28) as u8
118 } else {
119 0
120 }
121 } else {
122 15
123 };
124
125 let scale = if shift_bits < 31 {
126 (1u32 << shift_bits) as f32
127 } else {
128 2147483648.0
129 };
130 let quantized: Vec<i32> = coeffs.iter().map(|&c| (c * scale).round() as i32).collect();
131
132 (quantized, shift_bits)
133}
134
135pub fn dequantize_coefficients(coeffs: &[i32], shift_bits: u8) -> Vec<f32> {
137 let scale = if shift_bits < 31 {
138 1.0 / (1u32 << shift_bits) as f32
139 } else {
140 1.0 / 2147483648.0
141 };
142 coeffs.iter().map(|&c| c as f32 * scale).collect()
143}
144
145pub fn is_stable(coeffs: &[f32]) -> bool {
149 if coeffs.is_empty() {
150 return true;
151 }
152
153 let max_coef = coeffs.iter().map(|c| c.abs()).fold(0.0f32, f32::max);
155 if max_coef > 1.5 {
156 return false;
157 }
158
159 let sum_abs: f32 = coeffs.iter().map(|c| c.abs()).sum();
162 if sum_abs > coeffs.len() as f32 {
163 return false;
164 }
165
166 let test_len = 50.max(coeffs.len() * 5);
169 let mut output = vec![0.0f32; test_len];
170 output[0] = 1.0; for i in 1..test_len {
173 let mut val = 0.0;
174 for (j, &coeff) in coeffs.iter().enumerate() {
175 if i > j {
176 val += coeff * output[i - j - 1];
177 }
178 }
179 output[i] = val;
180
181 if val.abs() > 2.0 || !val.is_finite() {
183 return false;
184 }
185 }
186
187 true
188}
189
190pub fn is_stable_after_quantization(coeffs: &[f32]) -> bool {
192 if coeffs.is_empty() {
193 return true;
194 }
195
196 if !is_stable(coeffs) {
198 return false;
199 }
200
201 let (quantized, shift) = quantize_coefficients(coeffs);
203 let recovered = dequantize_coefficients(&quantized, shift);
204
205 is_stable(&recovered)
206}
207
208pub fn autocorr_int(samples: &[i32], order: usize) -> Vec<i64> {
214 let mut autocorr = vec![0i64; order + 1];
215 for lag in 0..=order {
216 for i in lag..samples.len() {
217 autocorr[lag] += (samples[i] as i64) * (samples[i - lag] as i64);
218 }
219 }
220 autocorr
221}
222
223pub fn levinson_durbin_int(autocorr: &[i64], order: usize) -> Option<(Vec<i32>, u8)> {
226 if autocorr.is_empty() || autocorr[0] == 0 {
227 return None;
228 }
229
230 let mut coeffs = vec![0.0f64; order];
232 let mut error = autocorr[0] as f64;
233
234 for i in 0..order {
235 let mut lambda = autocorr.get(i + 1).copied().unwrap_or(0) as f64;
236 for j in 0..i {
237 lambda -= coeffs[j] * autocorr.get(i - j).copied().unwrap_or(0) as f64;
238 }
239
240 if error.abs() < 1e-10 {
241 return None;
242 }
243
244 let gamma = lambda / error;
245
246 if gamma.abs() >= 1.0 {
248 return None;
249 }
250
251 let mut new_coeffs = vec![0.0f64; i + 1];
252 new_coeffs[i] = gamma;
253 for j in 0..i {
254 new_coeffs[j] = coeffs[j] - gamma * coeffs[i - 1 - j];
255 }
256 coeffs[..=i].copy_from_slice(&new_coeffs);
257
258 error *= 1.0 - gamma * gamma;
259 }
260
261 let max_coeff = coeffs.iter().map(|&c| c.abs()).fold(0.0f64, f64::max);
264 if max_coeff == 0.0 || !max_coeff.is_finite() {
265 return None;
266 }
267
268 let shift = ((1 << 30) as f64 / max_coeff).log2().floor() as u8;
270 let shift = shift.min(15); let scale = (1i64 << shift) as f64;
272
273 let coeffs_fp: Vec<i32> = coeffs.iter().map(|&c| (c * scale).round() as i32).collect();
274
275 Some((coeffs_fp, shift))
276}
277
278pub fn calc_residuals_int(samples: &[i32], coeffs: &[i32], shift: u8, order: usize) -> Vec<i32> {
280 let mut residuals = Vec::with_capacity(samples.len());
281
282 for i in 0..order.min(samples.len()) {
284 residuals.push(samples[i]);
285 }
286
287 for i in order..samples.len() {
289 let mut prediction: i64 = 0;
290 for (j, &coeff) in coeffs.iter().enumerate() {
291 prediction += (coeff as i64) * (samples[i - j - 1] as i64);
292 }
293 prediction >>= shift;
294 residuals.push(samples[i] - prediction as i32);
295 }
296
297 residuals
298}
299
300pub fn fixed_predictor_residuals(samples: &[i32], order: usize) -> Vec<i32> {
302 match order {
303 0 => samples.to_vec(),
304 1 => {
305 let mut r = vec![samples[0]];
307 for i in 1..samples.len() {
308 r.push(samples[i] - samples[i - 1]);
309 }
310 r
311 }
312 2 => {
313 let mut r = vec![samples[0]];
315 if samples.len() > 1 {
316 r.push(samples[1] - samples[0]);
317 }
318 for i in 2..samples.len() {
319 r.push(samples[i] - 2 * samples[i - 1] + samples[i - 2]);
320 }
321 r
322 }
323 3 => {
324 let mut r = vec![samples[0]];
326 if samples.len() > 1 {
327 r.push(samples[1] - samples[0]);
328 }
329 if samples.len() > 2 {
330 r.push(samples[2] - 2 * samples[1] + samples[0]);
331 }
332 for i in 3..samples.len() {
333 r.push(samples[i] - 3 * samples[i - 1] + 3 * samples[i - 2] - samples[i - 3]);
334 }
335 r
336 }
337 4 => {
338 let mut r = vec![samples[0]];
340 if samples.len() > 1 {
341 r.push(samples[1] - samples[0]);
342 }
343 if samples.len() > 2 {
344 r.push(samples[2] - 2 * samples[1] + samples[0]);
345 }
346 if samples.len() > 3 {
347 r.push(samples[3] - 3 * samples[2] + 3 * samples[1] - samples[0]);
348 }
349 for i in 4..samples.len() {
350 r.push(
351 samples[i] - 4 * samples[i - 1] + 6 * samples[i - 2] - 4 * samples[i - 3]
352 + samples[i - 4],
353 );
354 }
355 r
356 }
357 _ => samples.to_vec(),
358 }
359}