Line | Branch | Exec | Source |
---|---|---|---|
1 | /* | ||
2 | * LPC utility code | ||
3 | * Copyright (c) 2006 Justin Ruggles <justin.ruggles@gmail.com> | ||
4 | * | ||
5 | * This file is part of FFmpeg. | ||
6 | * | ||
7 | * FFmpeg is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU Lesser General Public | ||
9 | * License as published by the Free Software Foundation; either | ||
10 | * version 2.1 of the License, or (at your option) any later version. | ||
11 | * | ||
12 | * FFmpeg is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * Lesser General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU Lesser General Public | ||
18 | * License along with FFmpeg; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
20 | */ | ||
21 | |||
22 | #include "libavutil/common.h" | ||
23 | #include "libavutil/lls.h" | ||
24 | #include "libavutil/mem_internal.h" | ||
25 | |||
26 | #define LPC_USE_DOUBLE | ||
27 | #include "lpc.h" | ||
28 | #include "libavutil/avassert.h" | ||
29 | |||
30 | |||
31 | /** | ||
32 | * Apply Welch window function to audio block | ||
33 | */ | ||
34 | 3999 | static void lpc_apply_welch_window_c(const int32_t *data, ptrdiff_t len, | |
35 | double *w_data) | ||
36 | { | ||
37 | int i, n2; | ||
38 | double w; | ||
39 | double c; | ||
40 | |||
41 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3999 times.
|
3999 | if (len == 1) { |
42 | ✗ | w_data[0] = 0.0; | |
43 | ✗ | return; | |
44 | } | ||
45 | |||
46 | 3999 | n2 = (len >> 1); | |
47 | 3999 | c = 2.0 / (len - 1.0); | |
48 | |||
49 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 3992 times.
|
3999 | if (len & 1) { |
50 |
2/2✓ Branch 0 taken 9538 times.
✓ Branch 1 taken 7 times.
|
9545 | for(i=0; i<n2; i++) { |
51 | 9538 | w = c - i - 1.0; | |
52 | 9538 | w = 1.0 - (w * w); | |
53 | 9538 | w_data[i] = data[i] * w; | |
54 | 9538 | w_data[len-1-i] = data[len-1-i] * w; | |
55 | } | ||
56 | 7 | w_data[n2] = 0.0; | |
57 | 7 | return; | |
58 | } | ||
59 | |||
60 | 3992 | w_data+=n2; | |
61 | 3992 | data+=n2; | |
62 |
2/2✓ Branch 0 taken 9305616 times.
✓ Branch 1 taken 3992 times.
|
9309608 | for(i=0; i<n2; i++) { |
63 | 9305616 | w = c - n2 + i; | |
64 | 9305616 | w = 1.0 - (w * w); | |
65 | 9305616 | w_data[-i-1] = data[-i-1] * w; | |
66 | 9305616 | w_data[+i ] = data[+i ] * w; | |
67 | } | ||
68 | } | ||
69 | |||
70 | /** | ||
71 | * Calculate autocorrelation data from audio samples | ||
72 | * A Welch window function is applied before calculation. | ||
73 | */ | ||
74 | 6140 | static void lpc_compute_autocorr_c(const double *data, ptrdiff_t len, int lag, | |
75 | double *autoc) | ||
76 | { | ||
77 | int i, j; | ||
78 | |||
79 |
2/2✓ Branch 0 taken 40475 times.
✓ Branch 1 taken 6140 times.
|
46615 | for(j=0; j<lag; j+=2){ |
80 | 40475 | double sum0 = 1.0, sum1 = 1.0; | |
81 |
2/2✓ Branch 0 taken 135720658 times.
✓ Branch 1 taken 40475 times.
|
135761133 | for(i=j; i<len; i++){ |
82 | 135720658 | sum0 += data[i] * data[i-j]; | |
83 | 135720658 | sum1 += data[i] * data[i-j-1]; | |
84 | } | ||
85 | 40475 | autoc[j ] = sum0; | |
86 | 40475 | autoc[j+1] = sum1; | |
87 | } | ||
88 | |||
89 |
2/2✓ Branch 0 taken 5844 times.
✓ Branch 1 taken 296 times.
|
6140 | if(j==lag){ |
90 | 5844 | double sum = 1.0; | |
91 |
2/2✓ Branch 0 taken 9852819 times.
✓ Branch 1 taken 5844 times.
|
9858663 | for(i=j-1; i<len; i+=2){ |
92 | 9852819 | sum += data[i ] * data[i-j ] | |
93 | 9852819 | + data[i+1] * data[i-j+1]; | |
94 | } | ||
95 | 5844 | autoc[j] = sum; | |
96 | } | ||
97 | 6140 | } | |
98 | |||
99 | /** | ||
100 | * Quantize LPC coefficients | ||
101 | */ | ||
102 | 11789 | static void quantize_lpc_coefs(double *lpc_in, int order, int precision, | |
103 | int32_t *lpc_out, int *shift, int min_shift, | ||
104 | int max_shift, int zero_shift) | ||
105 | { | ||
106 | int i; | ||
107 | double cmax, error; | ||
108 | int32_t qmax; | ||
109 | int sh; | ||
110 | |||
111 | /* define maximum levels */ | ||
112 | 11789 | qmax = (1 << (precision - 1)) - 1; | |
113 | |||
114 | /* find maximum coefficient value */ | ||
115 | 11789 | cmax = 0.0; | |
116 |
2/2✓ Branch 0 taken 58045 times.
✓ Branch 1 taken 11789 times.
|
69834 | for(i=0; i<order; i++) { |
117 |
2/2✓ Branch 0 taken 40383 times.
✓ Branch 1 taken 17662 times.
|
58045 | cmax= FFMAX(cmax, fabs(lpc_in[i])); |
118 | } | ||
119 | |||
120 | /* if maximum value quantizes to zero, return all zeros */ | ||
121 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11789 times.
|
11789 | if(cmax * (1 << max_shift) < 1.0) { |
122 | ✗ | *shift = zero_shift; | |
123 | ✗ | memset(lpc_out, 0, sizeof(int32_t) * order); | |
124 | ✗ | return; | |
125 | } | ||
126 | |||
127 | /* calculate level shift which scales max coeff to available bits */ | ||
128 | 11789 | sh = max_shift; | |
129 |
3/4✓ Branch 0 taken 20531 times.
✓ Branch 1 taken 11789 times.
✓ Branch 2 taken 20531 times.
✗ Branch 3 not taken.
|
32320 | while((cmax * (1 << sh) > qmax) && (sh > min_shift)) { |
130 | 20531 | sh--; | |
131 | } | ||
132 | |||
133 | /* since negative shift values are unsupported in decoder, scale down | ||
134 | coefficients instead */ | ||
135 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 11789 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
11789 | if(sh == 0 && cmax > qmax) { |
136 | ✗ | double scale = ((double)qmax) / cmax; | |
137 | ✗ | for(i=0; i<order; i++) { | |
138 | ✗ | lpc_in[i] *= scale; | |
139 | } | ||
140 | } | ||
141 | |||
142 | /* output quantized coefficients and level shift */ | ||
143 | 11789 | error=0; | |
144 |
2/2✓ Branch 0 taken 58045 times.
✓ Branch 1 taken 11789 times.
|
69834 | for(i=0; i<order; i++) { |
145 | 58045 | error -= lpc_in[i] * (1 << sh); | |
146 | 58045 | lpc_out[i] = av_clip(lrintf(error), -qmax, qmax); | |
147 | 58045 | error -= lpc_out[i]; | |
148 | } | ||
149 | 11789 | *shift = sh; | |
150 | } | ||
151 | |||
152 | 8957 | static int estimate_best_order(double *ref, int min_order, int max_order) | |
153 | { | ||
154 | int i, est; | ||
155 | |||
156 | 8957 | est = min_order; | |
157 |
2/2✓ Branch 0 taken 64458 times.
✓ Branch 1 taken 174 times.
|
64632 | for(i=max_order-1; i>=min_order-1; i--) { |
158 |
2/2✓ Branch 0 taken 8783 times.
✓ Branch 1 taken 55675 times.
|
64458 | if(ref[i] > 0.10) { |
159 | 8783 | est = i+1; | |
160 | 8783 | break; | |
161 | } | ||
162 | } | ||
163 | 8957 | return est; | |
164 | } | ||
165 | |||
166 | ✗ | int ff_lpc_calc_ref_coefs(LPCContext *s, | |
167 | const int32_t *samples, int order, double *ref) | ||
168 | { | ||
169 | double autoc[MAX_LPC_ORDER + 1]; | ||
170 | |||
171 | ✗ | s->lpc_apply_welch_window(samples, s->blocksize, s->windowed_samples); | |
172 | ✗ | s->lpc_compute_autocorr(s->windowed_samples, s->blocksize, order, autoc); | |
173 | ✗ | compute_ref_coefs(autoc, order, ref, NULL); | |
174 | |||
175 | ✗ | return order; | |
176 | } | ||
177 | |||
178 | 2147 | double ff_lpc_calc_ref_coefs_f(LPCContext *s, const float *samples, int len, | |
179 | int order, double *ref) | ||
180 | { | ||
181 | int i; | ||
182 | 2147 | double signal = 0.0f, avg_err = 0.0f; | |
183 | 2147 | double autoc[MAX_LPC_ORDER+1] = {0}, error[MAX_LPC_ORDER+1] = {0}; | |
184 | 2147 | const double a = 0.5f, b = 1.0f - a; | |
185 | |||
186 | /* Apply windowing */ | ||
187 |
2/2✓ Branch 0 taken 600615 times.
✓ Branch 1 taken 2147 times.
|
602762 | for (i = 0; i <= len / 2; i++) { |
188 | 600615 | double weight = a - b*cos((2*M_PI*i)/(len - 1)); | |
189 | 600615 | s->windowed_samples[i] = weight*samples[i]; | |
190 | 600615 | s->windowed_samples[len-1-i] = weight*samples[len-1-i]; | |
191 | } | ||
192 | |||
193 | 2147 | s->lpc_compute_autocorr(s->windowed_samples, len, order, autoc); | |
194 | 2147 | signal = autoc[0]; | |
195 | 2147 | compute_ref_coefs(autoc, order, ref, error); | |
196 |
2/2✓ Branch 0 taken 24284 times.
✓ Branch 1 taken 2147 times.
|
26431 | for (i = 0; i < order; i++) |
197 | 24284 | avg_err = (avg_err + error[i])/2.0f; | |
198 |
2/2✓ Branch 0 taken 2114 times.
✓ Branch 1 taken 33 times.
|
2147 | return avg_err ? signal/avg_err : NAN; |
199 | } | ||
200 | |||
201 | /** | ||
202 | * Calculate LPC coefficients for multiple orders | ||
203 | * | ||
204 | * @param lpc_type LPC method for determining coefficients, | ||
205 | * see #FFLPCType for details | ||
206 | */ | ||
207 | 9193 | int ff_lpc_calc_coefs(LPCContext *s, | |
208 | const int32_t *samples, int blocksize, int min_order, | ||
209 | int max_order, int precision, | ||
210 | int32_t coefs[][MAX_LPC_ORDER], int *shift, | ||
211 | enum FFLPCType lpc_type, int lpc_passes, | ||
212 | int omethod, int min_shift, int max_shift, int zero_shift) | ||
213 | { | ||
214 | double autoc[MAX_LPC_ORDER+1]; | ||
215 | 9193 | double ref[MAX_LPC_ORDER] = { 0 }; | |
216 | double lpc[MAX_LPC_ORDER][MAX_LPC_ORDER]; | ||
217 | 9193 | int i, j, pass = 0; | |
218 | int opt_order; | ||
219 | |||
220 | av_assert2(max_order >= MIN_LPC_ORDER && max_order <= MAX_LPC_ORDER && | ||
221 | lpc_type > FF_LPC_TYPE_FIXED); | ||
222 |
3/4✓ Branch 0 taken 9011 times.
✓ Branch 1 taken 182 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9011 times.
|
9193 | av_assert0(lpc_type == FF_LPC_TYPE_CHOLESKY || lpc_type == FF_LPC_TYPE_LEVINSON); |
223 | |||
224 | /* reinit LPC context if parameters have changed */ | ||
225 |
3/4✓ Branch 0 taken 9178 times.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 9178 times.
✗ Branch 3 not taken.
|
9193 | if (blocksize != s->blocksize || max_order != s->max_order || |
226 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9177 times.
|
9178 | lpc_type != s->lpc_type) { |
227 | 16 | ff_lpc_end(s); | |
228 | 16 | ff_lpc_init(s, blocksize, max_order, lpc_type); | |
229 | } | ||
230 | |||
231 |
2/2✓ Branch 0 taken 2589 times.
✓ Branch 1 taken 6604 times.
|
9193 | if(lpc_passes <= 0) |
232 | 2589 | lpc_passes = 2; | |
233 | |||
234 |
4/6✓ Branch 0 taken 182 times.
✓ Branch 1 taken 9011 times.
✓ Branch 2 taken 182 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 182 times.
✗ Branch 5 not taken.
|
9193 | if (lpc_type == FF_LPC_TYPE_LEVINSON || (lpc_type == FF_LPC_TYPE_CHOLESKY && lpc_passes > 1)) { |
235 | 9193 | s->lpc_apply_welch_window(samples, blocksize, s->windowed_samples); | |
236 | |||
237 | 9193 | s->lpc_compute_autocorr(s->windowed_samples, blocksize, max_order, autoc); | |
238 | |||
239 | 9193 | compute_lpc_coefs(autoc, max_order, &lpc[0][0], MAX_LPC_ORDER, 0, 1); | |
240 | |||
241 |
2/2✓ Branch 0 taken 97970 times.
✓ Branch 1 taken 9193 times.
|
107163 | for(i=0; i<max_order; i++) |
242 | 97970 | ref[i] = fabs(lpc[i][i]); | |
243 | |||
244 | 9193 | pass++; | |
245 | } | ||
246 | |||
247 |
2/2✓ Branch 0 taken 182 times.
✓ Branch 1 taken 9011 times.
|
9193 | if (lpc_type == FF_LPC_TYPE_CHOLESKY) { |
248 | 182 | LLSModel *m = s->lls_models; | |
249 | 182 | LOCAL_ALIGNED(32, double, var, [FFALIGN(MAX_LPC_ORDER+1,4)]); | |
250 | 182 | double av_uninit(weight); | |
251 | 182 | memset(var, 0, FFALIGN(MAX_LPC_ORDER+1,4)*sizeof(*var)); | |
252 | |||
253 |
2/2✓ Branch 0 taken 1456 times.
✓ Branch 1 taken 182 times.
|
1638 | for(j=0; j<max_order; j++) |
254 | 1456 | m[0].coeff[max_order-1][j] = -lpc[max_order-1][j]; | |
255 | |||
256 |
2/2✓ Branch 0 taken 182 times.
✓ Branch 1 taken 182 times.
|
364 | for(; pass<lpc_passes; pass++){ |
257 | 182 | avpriv_init_lls(&m[pass&1], max_order); | |
258 | |||
259 | 182 | weight=0; | |
260 |
2/2✓ Branch 0 taken 836444 times.
✓ Branch 1 taken 182 times.
|
836626 | for(i=max_order; i<blocksize; i++){ |
261 |
2/2✓ Branch 0 taken 7527996 times.
✓ Branch 1 taken 836444 times.
|
8364440 | for(j=0; j<=max_order; j++) |
262 | 7527996 | var[j]= samples[i-j]; | |
263 | |||
264 |
1/2✓ Branch 0 taken 836444 times.
✗ Branch 1 not taken.
|
836444 | if(pass){ |
265 | double eval, inv, rinv; | ||
266 | 836444 | eval= m[pass&1].evaluate_lls(&m[(pass-1)&1], var+1, max_order-1); | |
267 | 836444 | eval= (512>>pass) + fabs(eval - var[0]); | |
268 | 836444 | inv = 1/eval; | |
269 | 836444 | rinv = sqrt(inv); | |
270 |
2/2✓ Branch 0 taken 7527996 times.
✓ Branch 1 taken 836444 times.
|
8364440 | for(j=0; j<=max_order; j++) |
271 | 7527996 | var[j] *= rinv; | |
272 | 836444 | weight += inv; | |
273 | }else | ||
274 | ✗ | weight++; | |
275 | |||
276 | 836444 | m[pass&1].update_lls(&m[pass&1], var); | |
277 | } | ||
278 | 182 | avpriv_solve_lls(&m[pass&1], 0.001, 0); | |
279 | } | ||
280 | |||
281 |
2/2✓ Branch 0 taken 1456 times.
✓ Branch 1 taken 182 times.
|
1638 | for(i=0; i<max_order; i++){ |
282 |
2/2✓ Branch 0 taken 11648 times.
✓ Branch 1 taken 1456 times.
|
13104 | for(j=0; j<max_order; j++) |
283 | 11648 | lpc[i][j]=-m[(pass-1)&1].coeff[i][j]; | |
284 | 1456 | ref[i]= sqrt(m[(pass-1)&1].variance[i] / weight) * (blocksize - max_order) / 4000; | |
285 | } | ||
286 |
2/2✓ Branch 0 taken 1274 times.
✓ Branch 1 taken 182 times.
|
1456 | for(i=max_order-1; i>0; i--) |
287 | 1274 | ref[i] = ref[i-1] - ref[i]; | |
288 | } | ||
289 | |||
290 | 9193 | opt_order = max_order; | |
291 | |||
292 |
2/2✓ Branch 0 taken 8957 times.
✓ Branch 1 taken 236 times.
|
9193 | if(omethod == ORDER_METHOD_EST) { |
293 | 8957 | opt_order = estimate_best_order(ref, min_order, max_order); | |
294 | 8957 | i = opt_order-1; | |
295 | 8957 | quantize_lpc_coefs(lpc[i], i+1, precision, coefs[i], &shift[i], | |
296 | min_shift, max_shift, zero_shift); | ||
297 | } else { | ||
298 |
2/2✓ Branch 0 taken 2832 times.
✓ Branch 1 taken 236 times.
|
3068 | for(i=min_order-1; i<max_order; i++) { |
299 | 2832 | quantize_lpc_coefs(lpc[i], i+1, precision, coefs[i], &shift[i], | |
300 | min_shift, max_shift, zero_shift); | ||
301 | } | ||
302 | } | ||
303 | |||
304 | 9193 | return opt_order; | |
305 | } | ||
306 | |||
307 | 83 | av_cold int ff_lpc_init(LPCContext *s, int blocksize, int max_order, | |
308 | enum FFLPCType lpc_type) | ||
309 | { | ||
310 | 83 | s->blocksize = blocksize; | |
311 | 83 | s->max_order = max_order; | |
312 | 83 | s->lpc_type = lpc_type; | |
313 | |||
314 | 83 | s->windowed_buffer = av_mallocz((blocksize + 2 + FFALIGN(max_order, 4)) * | |
315 | sizeof(*s->windowed_samples)); | ||
316 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 83 times.
|
83 | if (!s->windowed_buffer) |
317 | ✗ | return AVERROR(ENOMEM); | |
318 | 83 | s->windowed_samples = s->windowed_buffer + FFALIGN(max_order, 4); | |
319 | |||
320 | 83 | s->lpc_apply_welch_window = lpc_apply_welch_window_c; | |
321 | 83 | s->lpc_compute_autocorr = lpc_compute_autocorr_c; | |
322 | |||
323 | #if ARCH_X86 | ||
324 | 83 | ff_lpc_init_x86(s); | |
325 | #endif | ||
326 | |||
327 | 83 | return 0; | |
328 | } | ||
329 | |||
330 | 83 | av_cold void ff_lpc_end(LPCContext *s) | |
331 | { | ||
332 | 83 | av_freep(&s->windowed_buffer); | |
333 | 83 | } | |
334 |