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