blob: af8b8746dc28aecca579b6f0a79bc72906c42647 [file] [log] [blame]
Josh Coalson26560dd2001-02-08 00:38:41 +00001/* libFLAC - Free Lossless Audio Codec library
Josh Coalson70118f62001-01-16 20:17:53 +00002 * Copyright (C) 2000,2001 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>
21#include <stdio.h>
Josh Coalson1b689822001-05-31 20:11:02 +000022#include "FLAC/assert.h"
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000023#include "FLAC/format.h"
24#include "private/lpc.h"
25
26#ifndef M_LN2
27/* math.h in VC++ doesn't seem to have this (how Microsoft is that?) */
28#define M_LN2 0.69314718055994530942
29#endif
30
Josh Coalson77e3f312001-06-23 03:03:24 +000031void FLAC__lpc_compute_autocorrelation(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[])
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000032{
Josh Coalsonc0785cd2001-05-10 19:29:41 +000033 /* a readable, but slower, version */
34#if 0
Josh Coalson77e3f312001-06-23 03:03:24 +000035 FLAC__real d;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000036 unsigned i;
37
Josh Coalson1b689822001-05-31 20:11:02 +000038 FLAC__ASSERT(lag > 0);
39 FLAC__ASSERT(lag <= data_len);
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000040
41 while(lag--) {
42 for(i = lag, d = 0.0; i < data_len; i++)
43 d += data[i] * data[i - lag];
44 autoc[lag] = d;
45 }
Josh Coalsonc0785cd2001-05-10 19:29:41 +000046#endif
47
48 /*
49 * this version tends to run faster because of better data locality
50 * ('data_len' is usually much larger than 'lag')
51 */
Josh Coalson77e3f312001-06-23 03:03:24 +000052 FLAC__real d;
Josh Coalsonc0785cd2001-05-10 19:29:41 +000053 unsigned sample, coeff;
54 const unsigned limit = data_len - lag;
55
Josh Coalson1b689822001-05-31 20:11:02 +000056 FLAC__ASSERT(lag > 0);
57 FLAC__ASSERT(lag <= data_len);
Josh Coalsonc0785cd2001-05-10 19:29:41 +000058
59 for(coeff = 0; coeff < lag; coeff++)
60 autoc[coeff] = 0.0;
Josh Coalson376807d2001-05-16 19:23:35 +000061 for(sample = 0; sample <= limit; sample++) {
Josh Coalsonc0785cd2001-05-10 19:29:41 +000062 d = data[sample];
63 for(coeff = 0; coeff < lag; coeff++)
64 autoc[coeff] += d * data[sample+coeff];
65 }
Josh Coalson376807d2001-05-16 19:23:35 +000066 for(; sample < data_len; sample++) {
Josh Coalsonc0785cd2001-05-10 19:29:41 +000067 d = data[sample];
68 for(coeff = 0; coeff < data_len - sample; coeff++)
69 autoc[coeff] += d * data[sample+coeff];
70 }
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000071}
72
Josh Coalson77e3f312001-06-23 03:03:24 +000073void 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 +000074{
75 unsigned i, j;
Josh Coalsonb35bebd2001-07-03 04:37:18 +000076 double r, err, ref[FLAC__MAX_LPC_ORDER], lpc[FLAC__MAX_LPC_ORDER];
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000077
Josh Coalson1b689822001-05-31 20:11:02 +000078 FLAC__ASSERT(0 < max_order);
79 FLAC__ASSERT(max_order <= FLAC__MAX_LPC_ORDER);
80 FLAC__ASSERT(autoc[0] != 0.0);
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000081
82 err = autoc[0];
83
84 for(i = 0; i < max_order; i++) {
85 /* Sum up this iteration's reflection coefficient. */
Josh Coalsona1b53c42001-05-24 19:27:08 +000086 r = -autoc[i+1];
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000087 for(j = 0; j < i; j++)
88 r -= lpc[j] * autoc[i-j];
89 ref[i] = (r/=err);
90
91 /* Update LPC coefficients and total error. */
92 lpc[i]=r;
93 for(j = 0; j < (i>>1); j++) {
Josh Coalsonb35bebd2001-07-03 04:37:18 +000094 double tmp = lpc[j];
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000095 lpc[j] += r * lpc[i-1-j];
96 lpc[i-1-j] += r * tmp;
97 }
98 if(i & 1)
99 lpc[j] += lpc[j] * r;
100
101 err *= (1.0 - r * r);
102
103 /* save this order */
104 for(j = 0; j <= i; j++)
Josh Coalsonb35bebd2001-07-03 04:37:18 +0000105 lp_coeff[i][j] = (FLAC__real)(-lpc[j]); /* negate FIR filter coeff to get predictor coeff */
106 error[i] = (FLAC__real)err;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000107 }
108}
109
Josh Coalson77e3f312001-06-23 03:03:24 +0000110int 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 +0000111{
112 unsigned i;
Josh Coalsonb35bebd2001-07-03 04:37:18 +0000113 double d, cmax = -1e32;
Josh Coalson5975e8a2001-07-03 04:10:21 +0000114 FLAC__int32 qmax, qmin;
115 const int max_shiftlimit = (1 << (FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN-1)) - 1;
116 const int min_shiftlimit = -max_shiftlimit - 1;
Josh Coalsonc625f902001-02-28 23:56:03 +0000117
Josh Coalson1b689822001-05-31 20:11:02 +0000118 FLAC__ASSERT(bits_per_sample > 0);
Josh Coalson77e3f312001-06-23 03:03:24 +0000119 FLAC__ASSERT(bits_per_sample <= sizeof(FLAC__int32)*8);
Josh Coalson1b689822001-05-31 20:11:02 +0000120 FLAC__ASSERT(precision > 0);
121 FLAC__ASSERT(precision >= FLAC__MIN_QLP_COEFF_PRECISION);
Josh Coalson77e3f312001-06-23 03:03:24 +0000122 FLAC__ASSERT(precision + bits_per_sample < sizeof(FLAC__int32)*8);
Josh Coalsonc625f902001-02-28 23:56:03 +0000123#ifdef NDEBUG
124 (void)bits_per_sample; /* silence compiler warning about unused parameter */
125#endif
126
127 /* drop one bit for the sign; from here on out we consider only |lp_coeff[i]| */
128 precision--;
Josh Coalson5975e8a2001-07-03 04:10:21 +0000129 qmax = 1 << precision;
130 qmin = -qmax;
131 qmax--;
Josh Coalsonc625f902001-02-28 23:56:03 +0000132
133 for(i = 0; i < order; i++) {
134 if(lp_coeff[i] == 0.0)
135 continue;
Josh Coalsonf52360a2001-08-13 23:10:06 +0000136 d = fabs(lp_coeff[i]);
Josh Coalsonc625f902001-02-28 23:56:03 +0000137 if(d > cmax)
138 cmax = d;
Josh Coalsonc625f902001-02-28 23:56:03 +0000139 }
Josh Coalson5975e8a2001-07-03 04:10:21 +0000140redo_it:
Josh Coalsond3ed49f2001-07-18 23:47:19 +0000141 if(cmax <= 0.0) {
Josh Coalson456db822001-03-01 19:14:05 +0000142 /* => coefficients are all 0, which means our constant-detect didn't work */
Josh Coalsonc625f902001-02-28 23:56:03 +0000143 return 2;
144 }
145 else {
Josh Coalson8c6f90f2001-07-19 17:07:13 +0000146 int log2cmax;
Josh Coalsonc625f902001-02-28 23:56:03 +0000147
Josh Coalson8c6f90f2001-07-19 17:07:13 +0000148 (void)frexp(cmax, &log2cmax);
149 log2cmax--;
150 *shift = (int)precision - log2cmax - 1;
Josh Coalsonc625f902001-02-28 23:56:03 +0000151
152 if(*shift < min_shiftlimit || *shift > max_shiftlimit) {
Josh Coalsonc625f902001-02-28 23:56:03 +0000153 return 1;
154 }
155 }
156
Josh Coalson4e6b3ac2001-07-06 00:37:57 +0000157 if(*shift >= 0) {
158 for(i = 0; i < order; i++) {
159 qlp_coeff[i] = (FLAC__int32)floor((double)lp_coeff[i] * (double)(1 << *shift));
Josh Coalson5975e8a2001-07-03 04:10:21 +0000160
Josh Coalson8c6f90f2001-07-19 17:07:13 +0000161 /* double-check the result */
Josh Coalson4e6b3ac2001-07-06 00:37:57 +0000162 if(qlp_coeff[i] > qmax || qlp_coeff[i] < qmin) {
Josh Coalson5975e8a2001-07-03 04:10:21 +0000163#ifdef FLAC__OVERFLOW_DETECT
Josh Coalson4e6b3ac2001-07-06 00:37:57 +0000164 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 +0000165#endif
Josh Coalson4e6b3ac2001-07-06 00:37:57 +0000166 cmax *= 2.0;
167 goto redo_it;
Josh Coalson5975e8a2001-07-03 04:10:21 +0000168 }
169 }
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000170 }
Josh Coalson4e6b3ac2001-07-06 00:37:57 +0000171 else { /* (*shift < 0) */
172 const int nshift = -(*shift);
Josh Coalson3dbbf942001-07-12 21:27:40 +0000173#ifdef DEBUG
Josh Coalson4e6b3ac2001-07-06 00:37:57 +0000174 fprintf(stderr,"FLAC__lpc_quantize_coefficients: negative shift = %d\n", *shift);
Josh Coalson3dbbf942001-07-12 21:27:40 +0000175#endif
Josh Coalson4e6b3ac2001-07-06 00:37:57 +0000176 for(i = 0; i < order; i++) {
177 qlp_coeff[i] = (FLAC__int32)floor((double)lp_coeff[i] / (double)(1 << nshift));
178
Josh Coalson8c6f90f2001-07-19 17:07:13 +0000179 /* double-check the result */
Josh Coalson4e6b3ac2001-07-06 00:37:57 +0000180 if(qlp_coeff[i] > qmax || qlp_coeff[i] < qmin) {
181#ifdef FLAC__OVERFLOW_DETECT
182 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)));
183#endif
184 cmax *= 2.0;
185 goto redo_it;
186 }
187 }
188 }
189
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000190 return 0;
191}
192
Josh Coalson77e3f312001-06-23 03:03:24 +0000193void 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 +0000194{
Josh Coalsonbb6712e2001-04-24 22:54:07 +0000195#ifdef FLAC__OVERFLOW_DETECT
Josh Coalson77e3f312001-06-23 03:03:24 +0000196 FLAC__int64 sumo;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000197#endif
198 unsigned i, j;
Josh Coalson77e3f312001-06-23 03:03:24 +0000199 FLAC__int32 sum;
200 const FLAC__int32 *history;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000201
Josh Coalsonbb6712e2001-04-24 22:54:07 +0000202#ifdef FLAC__OVERFLOW_DETECT_VERBOSE
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000203 fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization);
204 for(i=0;i<order;i++)
205 fprintf(stderr,", q[%u]=%d",i,qlp_coeff[i]);
206 fprintf(stderr,"\n");
207#endif
Josh Coalson1b689822001-05-31 20:11:02 +0000208 FLAC__ASSERT(order > 0);
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000209
210 for(i = 0; i < data_len; i++) {
Josh Coalsonbb6712e2001-04-24 22:54:07 +0000211#ifdef FLAC__OVERFLOW_DETECT
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000212 sumo = 0;
213#endif
214 sum = 0;
215 history = data;
216 for(j = 0; j < order; j++) {
217 sum += qlp_coeff[j] * (*(--history));
Josh Coalsonbb6712e2001-04-24 22:54:07 +0000218#ifdef FLAC__OVERFLOW_DETECT
Josh Coalson77e3f312001-06-23 03:03:24 +0000219 sumo += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*history);
Josh Coalson40333b12001-11-13 21:37:04 +0000220#if defined _MSC_VER || defined __MINGW32__ /* don't know how to do 64-bit literals in VC++ */
Josh Coalsond37acf42001-07-09 18:22:46 +0000221 if(sumo < 0) sumo = -sumo;
222 if(sumo > 2147483647)
223#else
224 if(sumo > 2147483647ll || sumo < -2147483648ll)
225#endif
226 {
Josh Coalsonb35bebd2001-07-03 04:37:18 +0000227 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 +0000228 }
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000229#endif
230 }
231 *(residual++) = *(data++) - (sum >> lp_quantization);
232 }
233
Josh Coalson9f77a192001-02-08 00:26:45 +0000234 /* Here's a slower but clearer version:
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000235 for(i = 0; i < data_len; i++) {
236 sum = 0;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000237 for(j = 0; j < order; j++)
Josh Coalson9f77a192001-02-08 00:26:45 +0000238 sum += qlp_coeff[j] * data[i-j-1];
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000239 residual[i] = data[i] - (sum >> lp_quantization);
240 }
241 */
242}
243
Josh Coalson77e3f312001-06-23 03:03:24 +0000244void 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 +0000245{
Josh Coalsonbb6712e2001-04-24 22:54:07 +0000246#ifdef FLAC__OVERFLOW_DETECT
Josh Coalson77e3f312001-06-23 03:03:24 +0000247 FLAC__int64 sumo;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000248#endif
249 unsigned i, j;
Josh Coalson77e3f312001-06-23 03:03:24 +0000250 FLAC__int32 sum;
251 const FLAC__int32 *history;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000252
Josh Coalsonbb6712e2001-04-24 22:54:07 +0000253#ifdef FLAC__OVERFLOW_DETECT_VERBOSE
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000254 fprintf(stderr,"FLAC__lpc_restore_signal: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization);
255 for(i=0;i<order;i++)
256 fprintf(stderr,", q[%u]=%d",i,qlp_coeff[i]);
257 fprintf(stderr,"\n");
258#endif
Josh Coalson1b689822001-05-31 20:11:02 +0000259 FLAC__ASSERT(order > 0);
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000260
261 for(i = 0; i < data_len; i++) {
Josh Coalsonbb6712e2001-04-24 22:54:07 +0000262#ifdef FLAC__OVERFLOW_DETECT
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000263 sumo = 0;
264#endif
265 sum = 0;
Josh Coalson9f77a192001-02-08 00:26:45 +0000266 history = data;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000267 for(j = 0; j < order; j++) {
268 sum += qlp_coeff[j] * (*(--history));
Josh Coalsonbb6712e2001-04-24 22:54:07 +0000269#ifdef FLAC__OVERFLOW_DETECT
Josh Coalson77e3f312001-06-23 03:03:24 +0000270 sumo += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*history);
Josh Coalson40333b12001-11-13 21:37:04 +0000271#if defined _MSC_VER || defined __MINGW32__ /* don't know how to do 64-bit literals in VC++ */
Josh Coalsond37acf42001-07-09 18:22:46 +0000272 if(sumo < 0) sumo = -sumo;
273 if(sumo > 2147483647)
274#else
275 if(sumo > 2147483647ll || sumo < -2147483648ll)
276#endif
277 {
Josh Coalsonb35bebd2001-07-03 04:37:18 +0000278 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 +0000279 }
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000280#endif
281 }
Josh Coalson9f77a192001-02-08 00:26:45 +0000282 *(data++) = *(residual++) + (sum >> lp_quantization);
283 }
284
285 /* Here's a slower but clearer version:
286 for(i = 0; i < data_len; i++) {
287 sum = 0;
288 for(j = 0; j < order; j++)
289 sum += qlp_coeff[j] * data[i-j-1];
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000290 data[i] = residual[i] + (sum >> lp_quantization);
291 }
Josh Coalson9f77a192001-02-08 00:26:45 +0000292 */
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000293}
294
Josh Coalson77e3f312001-06-23 03:03:24 +0000295FLAC__real FLAC__lpc_compute_expected_bits_per_residual_sample(FLAC__real lpc_error, unsigned total_samples)
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000296{
Josh Coalsonb35bebd2001-07-03 04:37:18 +0000297 double error_scale;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000298
Josh Coalson1b689822001-05-31 20:11:02 +0000299 FLAC__ASSERT(total_samples > 0);
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000300
Josh Coalson77e3f312001-06-23 03:03:24 +0000301 error_scale = 0.5 * M_LN2 * M_LN2 / (FLAC__real)total_samples;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000302
Josh Coalson9f77a192001-02-08 00:26:45 +0000303 if(lpc_error > 0.0) {
Josh Coalsonb35bebd2001-07-03 04:37:18 +0000304 FLAC__real bps = (FLAC__real)((double)0.5 * log(error_scale * lpc_error) / M_LN2);
Josh Coalson9f77a192001-02-08 00:26:45 +0000305 if(bps >= 0.0)
306 return bps;
307 else
308 return 0.0;
309 }
Josh Coalsona1b53c42001-05-24 19:27:08 +0000310 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 +0000311 return (FLAC__real)1e32;
Josh Coalsona1b53c42001-05-24 19:27:08 +0000312 }
313 else {
314 return 0.0;
315 }
316}
317
Josh Coalsonb35bebd2001-07-03 04:37:18 +0000318FLAC__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 +0000319{
320 if(lpc_error > 0.0) {
Josh Coalsonb35bebd2001-07-03 04:37:18 +0000321 FLAC__real bps = (FLAC__real)((double)0.5 * log(error_scale * lpc_error) / M_LN2);
Josh Coalsona1b53c42001-05-24 19:27:08 +0000322 if(bps >= 0.0)
323 return bps;
324 else
325 return 0.0;
326 }
327 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 +0000328 return (FLAC__real)1e32;
Josh Coalsona1b53c42001-05-24 19:27:08 +0000329 }
Josh Coalson9f77a192001-02-08 00:26:45 +0000330 else {
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000331 return 0.0;
Josh Coalson9f77a192001-02-08 00:26:45 +0000332 }
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000333}
334
Josh Coalson77e3f312001-06-23 03:03:24 +0000335unsigned 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 +0000336{
337 unsigned order, best_order;
Josh Coalsonb35bebd2001-07-03 04:37:18 +0000338 FLAC__real best_bits, tmp_bits;
339 double error_scale;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000340
Josh Coalson1b689822001-05-31 20:11:02 +0000341 FLAC__ASSERT(max_order > 0);
342 FLAC__ASSERT(total_samples > 0);
Josh Coalsona1b53c42001-05-24 19:27:08 +0000343
Josh Coalson77e3f312001-06-23 03:03:24 +0000344 error_scale = 0.5 * M_LN2 * M_LN2 / (FLAC__real)total_samples;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000345
346 best_order = 0;
Josh Coalson77e3f312001-06-23 03:03:24 +0000347 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 +0000348
349 for(order = 1; order < max_order; order++) {
Josh Coalson77e3f312001-06-23 03:03:24 +0000350 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 +0000351 if(tmp_bits < best_bits) {
352 best_order = order;
353 best_bits = tmp_bits;
354 }
355 }
356
357 return best_order+1; /* +1 since index of lpc_error[] is order-1 */
358}