Directory: | ../../../ffmpeg/ |
---|---|
File: | src/libavcodec/lpc.c |
Date: | 2022-07-04 00:18:54 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 137 | 150 | 91.3% |
Branches: | 75 | 88 | 85.2% |
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 | 3975 | static void lpc_apply_welch_window_c(const int32_t *data, int len, | |
35 | double *w_data) | ||
36 | { | ||
37 | int i, n2; | ||
38 | double w; | ||
39 | double c; | ||
40 | |||
41 | 3975 | n2 = (len >> 1); | |
42 | 3975 | c = 2.0 / (len - 1.0); | |
43 | |||
44 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3973 times.
|
3975 | if (len & 1) { |
45 |
2/2✓ Branch 0 taken 1048 times.
✓ Branch 1 taken 2 times.
|
1050 | for(i=0; i<n2; i++) { |
46 | 1048 | w = c - i - 1.0; | |
47 | 1048 | w = 1.0 - (w * w); | |
48 | 1048 | w_data[i] = data[i] * w; | |
49 | 1048 | w_data[len-1-i] = data[len-1-i] * w; | |
50 | } | ||
51 | 2 | return; | |
52 | } | ||
53 | |||
54 | 3973 | w_data+=n2; | |
55 | 3973 | data+=n2; | |
56 |
2/2✓ Branch 0 taken 9262922 times.
✓ Branch 1 taken 3973 times.
|
9266895 | for(i=0; i<n2; i++) { |
57 | 9262922 | w = c - n2 + i; | |
58 | 9262922 | w = 1.0 - (w * w); | |
59 | 9262922 | w_data[-i-1] = data[-i-1] * w; | |
60 | 9262922 | w_data[+i ] = data[+i ] * w; | |
61 | } | ||
62 | } | ||
63 | |||
64 | /** | ||
65 | * Calculate autocorrelation data from audio samples | ||
66 | * A Welch window function is applied before calculation. | ||
67 | */ | ||
68 | 6122 | static void lpc_compute_autocorr_c(const double *data, int len, int lag, | |
69 | double *autoc) | ||
70 | { | ||
71 | int i, j; | ||
72 | |||
73 |
2/2✓ Branch 0 taken 40403 times.
✓ Branch 1 taken 6122 times.
|
46525 | for(j=0; j<lag; j+=2){ |
74 | 40403 | double sum0 = 1.0, sum1 = 1.0; | |
75 |
2/2✓ Branch 0 taken 135404674 times.
✓ Branch 1 taken 40403 times.
|
135445077 | for(i=j; i<len; i++){ |
76 | 135404674 | sum0 += data[i] * data[i-j]; | |
77 | 135404674 | sum1 += data[i] * data[i-j-1]; | |
78 | } | ||
79 | 40403 | autoc[j ] = sum0; | |
80 | 40403 | autoc[j+1] = sum1; | |
81 | } | ||
82 | |||
83 |
2/2✓ Branch 0 taken 5826 times.
✓ Branch 1 taken 296 times.
|
6122 | if(j==lag){ |
84 | 5826 | double sum = 1.0; | |
85 |
2/2✓ Branch 0 taken 9813349 times.
✓ Branch 1 taken 5826 times.
|
9819175 | for(i=j-1; i<len; i+=2){ |
86 | 9813349 | sum += data[i ] * data[i-j ] | |
87 | 9813349 | + data[i+1] * data[i-j+1]; | |
88 | } | ||
89 | 5826 | autoc[j] = sum; | |
90 | } | ||
91 | 6122 | } | |
92 | |||
93 | /** | ||
94 | * Quantize LPC coefficients | ||
95 | */ | ||
96 | 11771 | static void quantize_lpc_coefs(double *lpc_in, int order, int precision, | |
97 | int32_t *lpc_out, int *shift, int min_shift, | ||
98 | int max_shift, int zero_shift) | ||
99 | { | ||
100 | int i; | ||
101 | double cmax, error; | ||
102 | int32_t qmax; | ||
103 | int sh; | ||
104 | |||
105 | /* define maximum levels */ | ||
106 | 11771 | qmax = (1 << (precision - 1)) - 1; | |
107 | |||
108 | /* find maximum coefficient value */ | ||
109 | 11771 | cmax = 0.0; | |
110 |
2/2✓ Branch 0 taken 57912 times.
✓ Branch 1 taken 11771 times.
|
69683 | for(i=0; i<order; i++) { |
111 |
2/2✓ Branch 0 taken 40285 times.
✓ Branch 1 taken 17627 times.
|
57912 | cmax= FFMAX(cmax, fabs(lpc_in[i])); |
112 | } | ||
113 | |||
114 | /* if maximum value quantizes to zero, return all zeros */ | ||
115 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11771 times.
|
11771 | if(cmax * (1 << max_shift) < 1.0) { |
116 | ✗ | *shift = zero_shift; | |
117 | ✗ | memset(lpc_out, 0, sizeof(int32_t) * order); | |
118 | ✗ | return; | |
119 | } | ||
120 | |||
121 | /* calculate level shift which scales max coeff to available bits */ | ||
122 | 11771 | sh = max_shift; | |
123 |
3/4✓ Branch 0 taken 20493 times.
✓ Branch 1 taken 11771 times.
✓ Branch 2 taken 20493 times.
✗ Branch 3 not taken.
|
32264 | while((cmax * (1 << sh) > qmax) && (sh > min_shift)) { |
124 | 20493 | sh--; | |
125 | } | ||
126 | |||
127 | /* since negative shift values are unsupported in decoder, scale down | ||
128 | coefficients instead */ | ||
129 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 11771 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
11771 | if(sh == 0 && cmax > qmax) { |
130 | ✗ | double scale = ((double)qmax) / cmax; | |
131 | ✗ | for(i=0; i<order; i++) { | |
132 | ✗ | lpc_in[i] *= scale; | |
133 | } | ||
134 | } | ||
135 | |||
136 | /* output quantized coefficients and level shift */ | ||
137 | 11771 | error=0; | |
138 |
2/2✓ Branch 0 taken 57912 times.
✓ Branch 1 taken 11771 times.
|
69683 | for(i=0; i<order; i++) { |
139 | 57912 | error -= lpc_in[i] * (1 << sh); | |
140 | 57912 | lpc_out[i] = av_clip(lrintf(error), -qmax, qmax); | |
141 | 57912 | error -= lpc_out[i]; | |
142 | } | ||
143 | 11771 | *shift = sh; | |
144 | } | ||
145 | |||
146 | 8939 | static int estimate_best_order(double *ref, int min_order, int max_order) | |
147 | { | ||
148 | int i, est; | ||
149 | |||
150 | 8939 | est = min_order; | |
151 |
2/2✓ Branch 0 taken 64429 times.
✓ Branch 1 taken 174 times.
|
64603 | for(i=max_order-1; i>=min_order-1; i--) { |
152 |
2/2✓ Branch 0 taken 8765 times.
✓ Branch 1 taken 55664 times.
|
64429 | if(ref[i] > 0.10) { |
153 | 8765 | est = i+1; | |
154 | 8765 | break; | |
155 | } | ||
156 | } | ||
157 | 8939 | return est; | |
158 | } | ||
159 | |||
160 | ✗ | int ff_lpc_calc_ref_coefs(LPCContext *s, | |
161 | const int32_t *samples, int order, double *ref) | ||
162 | { | ||
163 | double autoc[MAX_LPC_ORDER + 1]; | ||
164 | |||
165 | ✗ | s->lpc_apply_welch_window(samples, s->blocksize, s->windowed_samples); | |
166 | ✗ | s->lpc_compute_autocorr(s->windowed_samples, s->blocksize, order, autoc); | |
167 | ✗ | compute_ref_coefs(autoc, order, ref, NULL); | |
168 | |||
169 | ✗ | return order; | |
170 | } | ||
171 | |||
172 | 2147 | double ff_lpc_calc_ref_coefs_f(LPCContext *s, const float *samples, int len, | |
173 | int order, double *ref) | ||
174 | { | ||
175 | int i; | ||
176 | 2147 | double signal = 0.0f, avg_err = 0.0f; | |
177 | 2147 | double autoc[MAX_LPC_ORDER+1] = {0}, error[MAX_LPC_ORDER+1] = {0}; | |
178 | 2147 | const double a = 0.5f, b = 1.0f - a; | |
179 | |||
180 | /* Apply windowing */ | ||
181 |
2/2✓ Branch 0 taken 600615 times.
✓ Branch 1 taken 2147 times.
|
602762 | for (i = 0; i <= len / 2; i++) { |
182 | 600615 | double weight = a - b*cos((2*M_PI*i)/(len - 1)); | |
183 | 600615 | s->windowed_samples[i] = weight*samples[i]; | |
184 | 600615 | s->windowed_samples[len-1-i] = weight*samples[len-1-i]; | |
185 | } | ||
186 | |||
187 | 2147 | s->lpc_compute_autocorr(s->windowed_samples, len, order, autoc); | |
188 | 2147 | signal = autoc[0]; | |
189 | 2147 | compute_ref_coefs(autoc, order, ref, error); | |
190 |
2/2✓ Branch 0 taken 24284 times.
✓ Branch 1 taken 2147 times.
|
26431 | for (i = 0; i < order; i++) |
191 | 24284 | avg_err = (avg_err + error[i])/2.0f; | |
192 |
2/2✓ Branch 0 taken 2114 times.
✓ Branch 1 taken 33 times.
|
2147 | return avg_err ? signal/avg_err : NAN; |
193 | } | ||
194 | |||
195 | /** | ||
196 | * Calculate LPC coefficients for multiple orders | ||
197 | * | ||
198 | * @param lpc_type LPC method for determining coefficients, | ||
199 | * see #FFLPCType for details | ||
200 | */ | ||
201 | 9175 | int ff_lpc_calc_coefs(LPCContext *s, | |
202 | const int32_t *samples, int blocksize, int min_order, | ||
203 | int max_order, int precision, | ||
204 | int32_t coefs[][MAX_LPC_ORDER], int *shift, | ||
205 | enum FFLPCType lpc_type, int lpc_passes, | ||
206 | int omethod, int min_shift, int max_shift, int zero_shift) | ||
207 | { | ||
208 | double autoc[MAX_LPC_ORDER+1]; | ||
209 | 9175 | double ref[MAX_LPC_ORDER] = { 0 }; | |
210 | double lpc[MAX_LPC_ORDER][MAX_LPC_ORDER]; | ||
211 | 9175 | int i, j, pass = 0; | |
212 | int opt_order; | ||
213 | |||
214 | av_assert2(max_order >= MIN_LPC_ORDER && max_order <= MAX_LPC_ORDER && | ||
215 | lpc_type > FF_LPC_TYPE_FIXED); | ||
216 |
3/4✓ Branch 0 taken 8993 times.
✓ Branch 1 taken 182 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8993 times.
|
9175 | av_assert0(lpc_type == FF_LPC_TYPE_CHOLESKY || lpc_type == FF_LPC_TYPE_LEVINSON); |
217 | |||
218 | /* reinit LPC context if parameters have changed */ | ||
219 |
3/4✓ Branch 0 taken 9161 times.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 9161 times.
✗ Branch 3 not taken.
|
9175 | if (blocksize != s->blocksize || max_order != s->max_order || |
220 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9160 times.
|
9161 | lpc_type != s->lpc_type) { |
221 | 15 | ff_lpc_end(s); | |
222 | 15 | ff_lpc_init(s, blocksize, max_order, lpc_type); | |
223 | } | ||
224 | |||
225 |
2/2✓ Branch 0 taken 2589 times.
✓ Branch 1 taken 6586 times.
|
9175 | if(lpc_passes <= 0) |
226 | 2589 | lpc_passes = 2; | |
227 | |||
228 |
4/6✓ Branch 0 taken 182 times.
✓ Branch 1 taken 8993 times.
✓ Branch 2 taken 182 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 182 times.
✗ Branch 5 not taken.
|
9175 | if (lpc_type == FF_LPC_TYPE_LEVINSON || (lpc_type == FF_LPC_TYPE_CHOLESKY && lpc_passes > 1)) { |
229 | 9175 | s->lpc_apply_welch_window(samples, blocksize, s->windowed_samples); | |
230 | |||
231 | 9175 | s->lpc_compute_autocorr(s->windowed_samples, blocksize, max_order, autoc); | |
232 | |||
233 | 9175 | compute_lpc_coefs(autoc, max_order, &lpc[0][0], MAX_LPC_ORDER, 0, 1); | |
234 | |||
235 |
2/2✓ Branch 0 taken 97826 times.
✓ Branch 1 taken 9175 times.
|
107001 | for(i=0; i<max_order; i++) |
236 | 97826 | ref[i] = fabs(lpc[i][i]); | |
237 | |||
238 | 9175 | pass++; | |
239 | } | ||
240 | |||
241 |
2/2✓ Branch 0 taken 182 times.
✓ Branch 1 taken 8993 times.
|
9175 | if (lpc_type == FF_LPC_TYPE_CHOLESKY) { |
242 | 182 | LLSModel *m = s->lls_models; | |
243 | 182 | LOCAL_ALIGNED(32, double, var, [FFALIGN(MAX_LPC_ORDER+1,4)]); | |
244 | 182 | double av_uninit(weight); | |
245 | 182 | memset(var, 0, FFALIGN(MAX_LPC_ORDER+1,4)*sizeof(*var)); | |
246 | |||
247 |
2/2✓ Branch 0 taken 1456 times.
✓ Branch 1 taken 182 times.
|
1638 | for(j=0; j<max_order; j++) |
248 | 1456 | m[0].coeff[max_order-1][j] = -lpc[max_order-1][j]; | |
249 | |||
250 |
2/2✓ Branch 0 taken 182 times.
✓ Branch 1 taken 182 times.
|
364 | for(; pass<lpc_passes; pass++){ |
251 | 182 | avpriv_init_lls(&m[pass&1], max_order); | |
252 | |||
253 | 182 | weight=0; | |
254 |
2/2✓ Branch 0 taken 836444 times.
✓ Branch 1 taken 182 times.
|
836626 | for(i=max_order; i<blocksize; i++){ |
255 |
2/2✓ Branch 0 taken 7527996 times.
✓ Branch 1 taken 836444 times.
|
8364440 | for(j=0; j<=max_order; j++) |
256 | 7527996 | var[j]= samples[i-j]; | |
257 | |||
258 |
1/2✓ Branch 0 taken 836444 times.
✗ Branch 1 not taken.
|
836444 | if(pass){ |
259 | double eval, inv, rinv; | ||
260 | 836444 | eval= m[pass&1].evaluate_lls(&m[(pass-1)&1], var+1, max_order-1); | |
261 | 836444 | eval= (512>>pass) + fabs(eval - var[0]); | |
262 | 836444 | inv = 1/eval; | |
263 | 836444 | rinv = sqrt(inv); | |
264 |
2/2✓ Branch 0 taken 7527996 times.
✓ Branch 1 taken 836444 times.
|
8364440 | for(j=0; j<=max_order; j++) |
265 | 7527996 | var[j] *= rinv; | |
266 | 836444 | weight += inv; | |
267 | }else | ||
268 | ✗ | weight++; | |
269 | |||
270 | 836444 | m[pass&1].update_lls(&m[pass&1], var); | |
271 | } | ||
272 | 182 | avpriv_solve_lls(&m[pass&1], 0.001, 0); | |
273 | } | ||
274 | |||
275 |
2/2✓ Branch 0 taken 1456 times.
✓ Branch 1 taken 182 times.
|
1638 | for(i=0; i<max_order; i++){ |
276 |
2/2✓ Branch 0 taken 11648 times.
✓ Branch 1 taken 1456 times.
|
13104 | for(j=0; j<max_order; j++) |
277 | 11648 | lpc[i][j]=-m[(pass-1)&1].coeff[i][j]; | |
278 | 1456 | ref[i]= sqrt(m[(pass-1)&1].variance[i] / weight) * (blocksize - max_order) / 4000; | |
279 | } | ||
280 |
2/2✓ Branch 0 taken 1274 times.
✓ Branch 1 taken 182 times.
|
1456 | for(i=max_order-1; i>0; i--) |
281 | 1274 | ref[i] = ref[i-1] - ref[i]; | |
282 | } | ||
283 | |||
284 | 9175 | opt_order = max_order; | |
285 | |||
286 |
2/2✓ Branch 0 taken 8939 times.
✓ Branch 1 taken 236 times.
|
9175 | if(omethod == ORDER_METHOD_EST) { |
287 | 8939 | opt_order = estimate_best_order(ref, min_order, max_order); | |
288 | 8939 | i = opt_order-1; | |
289 | 8939 | quantize_lpc_coefs(lpc[i], i+1, precision, coefs[i], &shift[i], | |
290 | min_shift, max_shift, zero_shift); | ||
291 | } else { | ||
292 |
2/2✓ Branch 0 taken 2832 times.
✓ Branch 1 taken 236 times.
|
3068 | for(i=min_order-1; i<max_order; i++) { |
293 | 2832 | quantize_lpc_coefs(lpc[i], i+1, precision, coefs[i], &shift[i], | |
294 | min_shift, max_shift, zero_shift); | ||
295 | } | ||
296 | } | ||
297 | |||
298 | 9175 | return opt_order; | |
299 | } | ||
300 | |||
301 | 68 | av_cold int ff_lpc_init(LPCContext *s, int blocksize, int max_order, | |
302 | enum FFLPCType lpc_type) | ||
303 | { | ||
304 | 68 | s->blocksize = blocksize; | |
305 | 68 | s->max_order = max_order; | |
306 | 68 | s->lpc_type = lpc_type; | |
307 | |||
308 | 68 | s->windowed_buffer = av_mallocz((blocksize + 2 + FFALIGN(max_order, 4)) * | |
309 | sizeof(*s->windowed_samples)); | ||
310 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 68 times.
|
68 | if (!s->windowed_buffer) |
311 | ✗ | return AVERROR(ENOMEM); | |
312 | 68 | s->windowed_samples = s->windowed_buffer + FFALIGN(max_order, 4); | |
313 | |||
314 | 68 | s->lpc_apply_welch_window = lpc_apply_welch_window_c; | |
315 | 68 | s->lpc_compute_autocorr = lpc_compute_autocorr_c; | |
316 | |||
317 | #if ARCH_X86 | ||
318 | 68 | ff_lpc_init_x86(s); | |
319 | #endif | ||
320 | |||
321 | 68 | return 0; | |
322 | } | ||
323 | |||
324 | 68 | av_cold void ff_lpc_end(LPCContext *s) | |
325 | { | ||
326 | 68 | av_freep(&s->windowed_buffer); | |
327 | 68 | } | |
328 |