blob: c0165c3dee492b6a234c4f72f2277d94ba1a8698 [file] [log] [blame]
Josh Coalson26560dd2001-02-08 00:38:41 +00001/* libFLAC - Free Lossless Audio Codec library
Josh Coalson305ae2e2002-01-26 17:36:39 +00002 * Copyright (C) 2000,2001,2002 Josh Coalson
Josh Coalsonbb7f6b92000-12-10 04:09:52 +00003 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 */
19
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000020#include <math.h>
Josh Coalson1b689822001-05-31 20:11:02 +000021#include "FLAC/assert.h"
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000022#include "FLAC/format.h"
23#include "private/lpc.h"
Josh Coalson03ed88b2002-05-17 06:19:28 +000024#if defined DEBUG || defined FLAC__OVERFLOW_DETECT || defined FLAC__OVERFLOW_DETECT_VERBOSE
25#include <stdio.h>
26#endif
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000027
28#ifndef M_LN2
29/* math.h in VC++ doesn't seem to have this (how Microsoft is that?) */
30#define M_LN2 0.69314718055994530942
31#endif
32
Josh Coalson77e3f312001-06-23 03:03:24 +000033void FLAC__lpc_compute_autocorrelation(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[])
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000034{
Josh Coalsonc0785cd2001-05-10 19:29:41 +000035 /* a readable, but slower, version */
36#if 0
Josh Coalson77e3f312001-06-23 03:03:24 +000037 FLAC__real d;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000038 unsigned i;
39
Josh Coalson1b689822001-05-31 20:11:02 +000040 FLAC__ASSERT(lag > 0);
41 FLAC__ASSERT(lag <= data_len);
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000042
43 while(lag--) {
44 for(i = lag, d = 0.0; i < data_len; i++)
45 d += data[i] * data[i - lag];
46 autoc[lag] = d;
47 }
Josh Coalsonc0785cd2001-05-10 19:29:41 +000048#endif
49
50 /*
51 * this version tends to run faster because of better data locality
52 * ('data_len' is usually much larger than 'lag')
53 */
Josh Coalson77e3f312001-06-23 03:03:24 +000054 FLAC__real d;
Josh Coalsonc0785cd2001-05-10 19:29:41 +000055 unsigned sample, coeff;
56 const unsigned limit = data_len - lag;
57
Josh Coalson1b689822001-05-31 20:11:02 +000058 FLAC__ASSERT(lag > 0);
59 FLAC__ASSERT(lag <= data_len);
Josh Coalsonc0785cd2001-05-10 19:29:41 +000060
61 for(coeff = 0; coeff < lag; coeff++)
62 autoc[coeff] = 0.0;
Josh Coalson376807d2001-05-16 19:23:35 +000063 for(sample = 0; sample <= limit; sample++) {
Josh Coalsonc0785cd2001-05-10 19:29:41 +000064 d = data[sample];
65 for(coeff = 0; coeff < lag; coeff++)
66 autoc[coeff] += d * data[sample+coeff];
67 }
Josh Coalson376807d2001-05-16 19:23:35 +000068 for(; sample < data_len; sample++) {
Josh Coalsonc0785cd2001-05-10 19:29:41 +000069 d = data[sample];
70 for(coeff = 0; coeff < data_len - sample; coeff++)
71 autoc[coeff] += d * data[sample+coeff];
72 }
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000073}
74
Josh Coalson77e3f312001-06-23 03:03:24 +000075void FLAC__lpc_compute_lp_coefficients(const FLAC__real autoc[], unsigned max_order, FLAC__real lp_coeff[][FLAC__MAX_LPC_ORDER], FLAC__real error[])
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000076{
77 unsigned i, j;
Josh Coalsonb35bebd2001-07-03 04:37:18 +000078 double r, err, ref[FLAC__MAX_LPC_ORDER], lpc[FLAC__MAX_LPC_ORDER];
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000079
Josh Coalson1b689822001-05-31 20:11:02 +000080 FLAC__ASSERT(0 < max_order);
81 FLAC__ASSERT(max_order <= FLAC__MAX_LPC_ORDER);
82 FLAC__ASSERT(autoc[0] != 0.0);
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000083
84 err = autoc[0];
85
86 for(i = 0; i < max_order; i++) {
87 /* Sum up this iteration's reflection coefficient. */
Josh Coalsona1b53c42001-05-24 19:27:08 +000088 r = -autoc[i+1];
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000089 for(j = 0; j < i; j++)
90 r -= lpc[j] * autoc[i-j];
91 ref[i] = (r/=err);
92
93 /* Update LPC coefficients and total error. */
94 lpc[i]=r;
95 for(j = 0; j < (i>>1); j++) {
Josh Coalsonb35bebd2001-07-03 04:37:18 +000096 double tmp = lpc[j];
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000097 lpc[j] += r * lpc[i-1-j];
98 lpc[i-1-j] += r * tmp;
99 }
100 if(i & 1)
101 lpc[j] += lpc[j] * r;
102
103 err *= (1.0 - r * r);
104
105 /* save this order */
106 for(j = 0; j <= i; j++)
Josh Coalsonb35bebd2001-07-03 04:37:18 +0000107 lp_coeff[i][j] = (FLAC__real)(-lpc[j]); /* negate FIR filter coeff to get predictor coeff */
108 error[i] = (FLAC__real)err;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000109 }
110}
111
Josh Coalson77e3f312001-06-23 03:03:24 +0000112int FLAC__lpc_quantize_coefficients(const FLAC__real lp_coeff[], unsigned order, unsigned precision, unsigned bits_per_sample, FLAC__int32 qlp_coeff[], int *shift)
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000113{
114 unsigned i;
Josh Coalsonb35bebd2001-07-03 04:37:18 +0000115 double d, cmax = -1e32;
Josh Coalson5975e8a2001-07-03 04:10:21 +0000116 FLAC__int32 qmax, qmin;
117 const int max_shiftlimit = (1 << (FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN-1)) - 1;
118 const int min_shiftlimit = -max_shiftlimit - 1;
Josh Coalsonc625f902001-02-28 23:56:03 +0000119
Josh Coalson1b689822001-05-31 20:11:02 +0000120 FLAC__ASSERT(bits_per_sample > 0);
Josh Coalson77e3f312001-06-23 03:03:24 +0000121 FLAC__ASSERT(bits_per_sample <= sizeof(FLAC__int32)*8);
Josh Coalson1b689822001-05-31 20:11:02 +0000122 FLAC__ASSERT(precision > 0);
123 FLAC__ASSERT(precision >= FLAC__MIN_QLP_COEFF_PRECISION);
Josh Coalson77e3f312001-06-23 03:03:24 +0000124 FLAC__ASSERT(precision + bits_per_sample < sizeof(FLAC__int32)*8);
Josh Coalsonc625f902001-02-28 23:56:03 +0000125#ifdef NDEBUG
126 (void)bits_per_sample; /* silence compiler warning about unused parameter */
127#endif
128
129 /* drop one bit for the sign; from here on out we consider only |lp_coeff[i]| */
130 precision--;
Josh Coalson5975e8a2001-07-03 04:10:21 +0000131 qmax = 1 << precision;
132 qmin = -qmax;
133 qmax--;
Josh Coalsonc625f902001-02-28 23:56:03 +0000134
135 for(i = 0; i < order; i++) {
136 if(lp_coeff[i] == 0.0)
137 continue;
Josh Coalsonf52360a2001-08-13 23:10:06 +0000138 d = fabs(lp_coeff[i]);
Josh Coalsonc625f902001-02-28 23:56:03 +0000139 if(d > cmax)
140 cmax = d;
Josh Coalsonc625f902001-02-28 23:56:03 +0000141 }
Josh Coalson5975e8a2001-07-03 04:10:21 +0000142redo_it:
Josh Coalsond3ed49f2001-07-18 23:47:19 +0000143 if(cmax <= 0.0) {
Josh Coalson456db822001-03-01 19:14:05 +0000144 /* => coefficients are all 0, which means our constant-detect didn't work */
Josh Coalsonc625f902001-02-28 23:56:03 +0000145 return 2;
146 }
147 else {
Josh Coalson8c6f90f2001-07-19 17:07:13 +0000148 int log2cmax;
Josh Coalsonc625f902001-02-28 23:56:03 +0000149
Josh Coalson8c6f90f2001-07-19 17:07:13 +0000150 (void)frexp(cmax, &log2cmax);
151 log2cmax--;
152 *shift = (int)precision - log2cmax - 1;
Josh Coalsonc625f902001-02-28 23:56:03 +0000153
154 if(*shift < min_shiftlimit || *shift > max_shiftlimit) {
Josh Coalsonc625f902001-02-28 23:56:03 +0000155 return 1;
156 }
157 }
158
Josh Coalson4e6b3ac2001-07-06 00:37:57 +0000159 if(*shift >= 0) {
160 for(i = 0; i < order; i++) {
161 qlp_coeff[i] = (FLAC__int32)floor((double)lp_coeff[i] * (double)(1 << *shift));
Josh Coalson5975e8a2001-07-03 04:10:21 +0000162
Josh Coalson8c6f90f2001-07-19 17:07:13 +0000163 /* double-check the result */
Josh Coalson4e6b3ac2001-07-06 00:37:57 +0000164 if(qlp_coeff[i] > qmax || qlp_coeff[i] < qmin) {
Josh Coalson5975e8a2001-07-03 04:10:21 +0000165#ifdef FLAC__OVERFLOW_DETECT
Josh Coalson4e6b3ac2001-07-06 00:37:57 +0000166 fprintf(stderr,"FLAC__lpc_quantize_coefficients: compensating for overflow, qlp_coeff[%u]=%d, lp_coeff[%u]=%f, cmax=%f, precision=%u, shift=%d, q=%f, f(q)=%f\n", i, qlp_coeff[i], i, lp_coeff[i], cmax, precision, *shift, (double)lp_coeff[i] * (double)(1 << *shift), floor((double)lp_coeff[i] * (double)(1 << *shift)));
Josh Coalson5975e8a2001-07-03 04:10:21 +0000167#endif
Josh Coalson4e6b3ac2001-07-06 00:37:57 +0000168 cmax *= 2.0;
169 goto redo_it;
Josh Coalson5975e8a2001-07-03 04:10:21 +0000170 }
171 }
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000172 }
Josh Coalson4e6b3ac2001-07-06 00:37:57 +0000173 else { /* (*shift < 0) */
174 const int nshift = -(*shift);
Josh Coalson3dbbf942001-07-12 21:27:40 +0000175#ifdef DEBUG
Josh Coalson4e6b3ac2001-07-06 00:37:57 +0000176 fprintf(stderr,"FLAC__lpc_quantize_coefficients: negative shift = %d\n", *shift);
Josh Coalson3dbbf942001-07-12 21:27:40 +0000177#endif
Josh Coalson4e6b3ac2001-07-06 00:37:57 +0000178 for(i = 0; i < order; i++) {
179 qlp_coeff[i] = (FLAC__int32)floor((double)lp_coeff[i] / (double)(1 << nshift));
180
Josh Coalson8c6f90f2001-07-19 17:07:13 +0000181 /* double-check the result */
Josh Coalson4e6b3ac2001-07-06 00:37:57 +0000182 if(qlp_coeff[i] > qmax || qlp_coeff[i] < qmin) {
183#ifdef FLAC__OVERFLOW_DETECT
184 fprintf(stderr,"FLAC__lpc_quantize_coefficients: compensating for overflow, qlp_coeff[%u]=%d, lp_coeff[%u]=%f, cmax=%f, precision=%u, shift=%d, q=%f, f(q)=%f\n", i, qlp_coeff[i], i, lp_coeff[i], cmax, precision, *shift, (double)lp_coeff[i] / (double)(1 << nshift), floor((double)lp_coeff[i] / (double)(1 << nshift)));
185#endif
186 cmax *= 2.0;
187 goto redo_it;
188 }
189 }
190 }
191
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000192 return 0;
193}
194
Josh Coalson77e3f312001-06-23 03:03:24 +0000195void FLAC__lpc_compute_residual_from_qlp_coefficients(const FLAC__int32 data[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[])
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000196{
Josh Coalsonbb6712e2001-04-24 22:54:07 +0000197#ifdef FLAC__OVERFLOW_DETECT
Josh Coalson77e3f312001-06-23 03:03:24 +0000198 FLAC__int64 sumo;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000199#endif
200 unsigned i, j;
Josh Coalson77e3f312001-06-23 03:03:24 +0000201 FLAC__int32 sum;
202 const FLAC__int32 *history;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000203
Josh Coalsonbb6712e2001-04-24 22:54:07 +0000204#ifdef FLAC__OVERFLOW_DETECT_VERBOSE
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000205 fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization);
206 for(i=0;i<order;i++)
207 fprintf(stderr,", q[%u]=%d",i,qlp_coeff[i]);
208 fprintf(stderr,"\n");
209#endif
Josh Coalson1b689822001-05-31 20:11:02 +0000210 FLAC__ASSERT(order > 0);
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000211
212 for(i = 0; i < data_len; i++) {
Josh Coalsonbb6712e2001-04-24 22:54:07 +0000213#ifdef FLAC__OVERFLOW_DETECT
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000214 sumo = 0;
215#endif
216 sum = 0;
217 history = data;
218 for(j = 0; j < order; j++) {
219 sum += qlp_coeff[j] * (*(--history));
Josh Coalsonbb6712e2001-04-24 22:54:07 +0000220#ifdef FLAC__OVERFLOW_DETECT
Josh Coalson77e3f312001-06-23 03:03:24 +0000221 sumo += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*history);
Josh Coalson40333b12001-11-13 21:37:04 +0000222#if defined _MSC_VER || defined __MINGW32__ /* don't know how to do 64-bit literals in VC++ */
Josh Coalsond37acf42001-07-09 18:22:46 +0000223 if(sumo < 0) sumo = -sumo;
224 if(sumo > 2147483647)
225#else
226 if(sumo > 2147483647ll || sumo < -2147483648ll)
227#endif
228 {
Josh Coalsonb35bebd2001-07-03 04:37:18 +0000229 fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%lld\n",i,j,qlp_coeff[j],*history,sumo);
Josh Coalson9f77a192001-02-08 00:26:45 +0000230 }
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000231#endif
232 }
233 *(residual++) = *(data++) - (sum >> lp_quantization);
234 }
235
Josh Coalson9f77a192001-02-08 00:26:45 +0000236 /* Here's a slower but clearer version:
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000237 for(i = 0; i < data_len; i++) {
238 sum = 0;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000239 for(j = 0; j < order; j++)
Josh Coalson9f77a192001-02-08 00:26:45 +0000240 sum += qlp_coeff[j] * data[i-j-1];
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000241 residual[i] = data[i] - (sum >> lp_quantization);
242 }
243 */
244}
245
Josh Coalson77e3f312001-06-23 03:03:24 +0000246void FLAC__lpc_restore_signal(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[])
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000247{
Josh Coalsonbb6712e2001-04-24 22:54:07 +0000248#ifdef FLAC__OVERFLOW_DETECT
Josh Coalson77e3f312001-06-23 03:03:24 +0000249 FLAC__int64 sumo;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000250#endif
251 unsigned i, j;
Josh Coalson77e3f312001-06-23 03:03:24 +0000252 FLAC__int32 sum;
253 const FLAC__int32 *history;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000254
Josh Coalsonbb6712e2001-04-24 22:54:07 +0000255#ifdef FLAC__OVERFLOW_DETECT_VERBOSE
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000256 fprintf(stderr,"FLAC__lpc_restore_signal: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization);
257 for(i=0;i<order;i++)
258 fprintf(stderr,", q[%u]=%d",i,qlp_coeff[i]);
259 fprintf(stderr,"\n");
260#endif
Josh Coalson1b689822001-05-31 20:11:02 +0000261 FLAC__ASSERT(order > 0);
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000262
263 for(i = 0; i < data_len; i++) {
Josh Coalsonbb6712e2001-04-24 22:54:07 +0000264#ifdef FLAC__OVERFLOW_DETECT
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000265 sumo = 0;
266#endif
267 sum = 0;
Josh Coalson9f77a192001-02-08 00:26:45 +0000268 history = data;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000269 for(j = 0; j < order; j++) {
270 sum += qlp_coeff[j] * (*(--history));
Josh Coalsonbb6712e2001-04-24 22:54:07 +0000271#ifdef FLAC__OVERFLOW_DETECT
Josh Coalson77e3f312001-06-23 03:03:24 +0000272 sumo += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*history);
Josh Coalson40333b12001-11-13 21:37:04 +0000273#if defined _MSC_VER || defined __MINGW32__ /* don't know how to do 64-bit literals in VC++ */
Josh Coalsond37acf42001-07-09 18:22:46 +0000274 if(sumo < 0) sumo = -sumo;
275 if(sumo > 2147483647)
276#else
277 if(sumo > 2147483647ll || sumo < -2147483648ll)
278#endif
279 {
Josh Coalsonb35bebd2001-07-03 04:37:18 +0000280 fprintf(stderr,"FLAC__lpc_restore_signal: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%lld\n",i,j,qlp_coeff[j],*history,sumo);
Josh Coalson9f77a192001-02-08 00:26:45 +0000281 }
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000282#endif
283 }
Josh Coalson9f77a192001-02-08 00:26:45 +0000284 *(data++) = *(residual++) + (sum >> lp_quantization);
285 }
286
287 /* Here's a slower but clearer version:
288 for(i = 0; i < data_len; i++) {
289 sum = 0;
290 for(j = 0; j < order; j++)
291 sum += qlp_coeff[j] * data[i-j-1];
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000292 data[i] = residual[i] + (sum >> lp_quantization);
293 }
Josh Coalson9f77a192001-02-08 00:26:45 +0000294 */
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000295}
296
Josh Coalson77e3f312001-06-23 03:03:24 +0000297FLAC__real FLAC__lpc_compute_expected_bits_per_residual_sample(FLAC__real lpc_error, unsigned total_samples)
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000298{
Josh Coalsonb35bebd2001-07-03 04:37:18 +0000299 double error_scale;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000300
Josh Coalson1b689822001-05-31 20:11:02 +0000301 FLAC__ASSERT(total_samples > 0);
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000302
Josh Coalson77e3f312001-06-23 03:03:24 +0000303 error_scale = 0.5 * M_LN2 * M_LN2 / (FLAC__real)total_samples;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000304
Josh Coalson9f77a192001-02-08 00:26:45 +0000305 if(lpc_error > 0.0) {
Josh Coalsonb35bebd2001-07-03 04:37:18 +0000306 FLAC__real bps = (FLAC__real)((double)0.5 * log(error_scale * lpc_error) / M_LN2);
Josh Coalson9f77a192001-02-08 00:26:45 +0000307 if(bps >= 0.0)
308 return bps;
309 else
310 return 0.0;
311 }
Josh Coalsona1b53c42001-05-24 19:27:08 +0000312 else if(lpc_error < 0.0) { /* error should not be negative but can happen due to inadequate float resolution */
Josh Coalsonb35bebd2001-07-03 04:37:18 +0000313 return (FLAC__real)1e32;
Josh Coalsona1b53c42001-05-24 19:27:08 +0000314 }
315 else {
316 return 0.0;
317 }
318}
319
Josh Coalsonb35bebd2001-07-03 04:37:18 +0000320FLAC__real FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(FLAC__real lpc_error, double error_scale)
Josh Coalsona1b53c42001-05-24 19:27:08 +0000321{
322 if(lpc_error > 0.0) {
Josh Coalsonb35bebd2001-07-03 04:37:18 +0000323 FLAC__real bps = (FLAC__real)((double)0.5 * log(error_scale * lpc_error) / M_LN2);
Josh Coalsona1b53c42001-05-24 19:27:08 +0000324 if(bps >= 0.0)
325 return bps;
326 else
327 return 0.0;
328 }
329 else if(lpc_error < 0.0) { /* error should not be negative but can happen due to inadequate float resolution */
Josh Coalsonb35bebd2001-07-03 04:37:18 +0000330 return (FLAC__real)1e32;
Josh Coalsona1b53c42001-05-24 19:27:08 +0000331 }
Josh Coalson9f77a192001-02-08 00:26:45 +0000332 else {
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000333 return 0.0;
Josh Coalson9f77a192001-02-08 00:26:45 +0000334 }
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000335}
336
Josh Coalson77e3f312001-06-23 03:03:24 +0000337unsigned FLAC__lpc_compute_best_order(const FLAC__real lpc_error[], unsigned max_order, unsigned total_samples, unsigned bits_per_signal_sample)
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000338{
339 unsigned order, best_order;
Josh Coalsonb35bebd2001-07-03 04:37:18 +0000340 FLAC__real best_bits, tmp_bits;
341 double error_scale;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000342
Josh Coalson1b689822001-05-31 20:11:02 +0000343 FLAC__ASSERT(max_order > 0);
344 FLAC__ASSERT(total_samples > 0);
Josh Coalsona1b53c42001-05-24 19:27:08 +0000345
Josh Coalson77e3f312001-06-23 03:03:24 +0000346 error_scale = 0.5 * M_LN2 * M_LN2 / (FLAC__real)total_samples;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000347
348 best_order = 0;
Josh Coalson77e3f312001-06-23 03:03:24 +0000349 best_bits = FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(lpc_error[0], error_scale) * (FLAC__real)total_samples;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000350
351 for(order = 1; order < max_order; order++) {
Josh Coalson77e3f312001-06-23 03:03:24 +0000352 tmp_bits = FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(lpc_error[order], error_scale) * (FLAC__real)(total_samples - order) + (FLAC__real)(order * bits_per_signal_sample);
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000353 if(tmp_bits < best_bits) {
354 best_order = order;
355 best_bits = tmp_bits;
356 }
357 }
358
359 return best_order+1; /* +1 since index of lpc_error[] is order-1 */
360}