blob: ab73d0ba9495bb926ba8354444a35f942b963938 [file] [log] [blame]
Josh Coalson26560dd2001-02-08 00:38:41 +00001/* libFLAC - Free Lossless Audio Codec library
Josh Coalson0395dac2006-04-25 06:59:33 +00002 * Copyright (C) 2000,2001,2002,2003,2004,2005,2006 Josh Coalson
Josh Coalsonbb7f6b92000-12-10 04:09:52 +00003 *
Josh Coalsonafd81072003-01-31 23:34:56 +00004 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
Josh Coalsonbb7f6b92000-12-10 04:09:52 +00007 *
Josh Coalsonafd81072003-01-31 23:34:56 +00008 * - Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000010 *
Josh Coalsonafd81072003-01-31 23:34:56 +000011 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * - Neither the name of the Xiph.org Foundation nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000030 */
31
Josh Coalsonb1ec7962006-05-24 04:41:36 +000032#if HAVE_CONFIG_H
33# include <config.h>
34#endif
35
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000036#include <math.h>
Josh Coalson1b689822001-05-31 20:11:02 +000037#include "FLAC/assert.h"
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000038#include "FLAC/format.h"
Josh Coalsoneac10242002-10-04 05:25:54 +000039#include "private/bitmath.h"
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000040#include "private/lpc.h"
Josh Coalson03ed88b2002-05-17 06:19:28 +000041#if defined DEBUG || defined FLAC__OVERFLOW_DETECT || defined FLAC__OVERFLOW_DETECT_VERBOSE
42#include <stdio.h>
43#endif
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000044
Josh Coalson5f2b46d2004-11-09 01:34:01 +000045#ifndef FLAC__INTEGER_ONLY_LIBRARY
46
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000047#ifndef M_LN2
48/* math.h in VC++ doesn't seem to have this (how Microsoft is that?) */
49#define M_LN2 0.69314718055994530942
50#endif
51
Josh Coalsonbf0f52c2006-04-25 06:38:43 +000052void FLAC__lpc_window_data(const FLAC__real in[], const FLAC__real window[], FLAC__real out[], unsigned data_len)
53{
54 unsigned i;
55 for(i = 0; i < data_len; i++)
56 out[i] = in[i] * window[i];
57}
58
Josh Coalson77e3f312001-06-23 03:03:24 +000059void FLAC__lpc_compute_autocorrelation(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[])
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000060{
Josh Coalsonc0785cd2001-05-10 19:29:41 +000061 /* a readable, but slower, version */
62#if 0
Josh Coalson77e3f312001-06-23 03:03:24 +000063 FLAC__real d;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000064 unsigned i;
65
Josh Coalson1b689822001-05-31 20:11:02 +000066 FLAC__ASSERT(lag > 0);
67 FLAC__ASSERT(lag <= data_len);
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000068
Josh Coalson6e2b5652006-04-28 00:11:31 +000069 /*
70 * Technically we should subtract the mean first like so:
71 * for(i = 0; i < data_len; i++)
72 * data[i] -= mean;
73 * but it appears not to make enough of a difference to matter, and
74 * most signals are already closely centered around zero
75 */
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000076 while(lag--) {
77 for(i = lag, d = 0.0; i < data_len; i++)
78 d += data[i] * data[i - lag];
79 autoc[lag] = d;
80 }
Josh Coalsonc0785cd2001-05-10 19:29:41 +000081#endif
82
83 /*
84 * this version tends to run faster because of better data locality
85 * ('data_len' is usually much larger than 'lag')
86 */
Josh Coalson77e3f312001-06-23 03:03:24 +000087 FLAC__real d;
Josh Coalsonc0785cd2001-05-10 19:29:41 +000088 unsigned sample, coeff;
89 const unsigned limit = data_len - lag;
90
Josh Coalson1b689822001-05-31 20:11:02 +000091 FLAC__ASSERT(lag > 0);
92 FLAC__ASSERT(lag <= data_len);
Josh Coalsonc0785cd2001-05-10 19:29:41 +000093
94 for(coeff = 0; coeff < lag; coeff++)
95 autoc[coeff] = 0.0;
Josh Coalson376807d2001-05-16 19:23:35 +000096 for(sample = 0; sample <= limit; sample++) {
Josh Coalsonc0785cd2001-05-10 19:29:41 +000097 d = data[sample];
98 for(coeff = 0; coeff < lag; coeff++)
99 autoc[coeff] += d * data[sample+coeff];
100 }
Josh Coalson376807d2001-05-16 19:23:35 +0000101 for(; sample < data_len; sample++) {
Josh Coalsonc0785cd2001-05-10 19:29:41 +0000102 d = data[sample];
103 for(coeff = 0; coeff < data_len - sample; coeff++)
104 autoc[coeff] += d * data[sample+coeff];
105 }
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000106}
107
Josh Coalson09758432004-10-20 00:21:50 +0000108void FLAC__lpc_compute_lp_coefficients(const FLAC__real autoc[], unsigned max_order, FLAC__real lp_coeff[][FLAC__MAX_LPC_ORDER], FLAC__double error[])
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000109{
110 unsigned i, j;
Josh Coalson09758432004-10-20 00:21:50 +0000111 FLAC__double r, err, ref[FLAC__MAX_LPC_ORDER], lpc[FLAC__MAX_LPC_ORDER];
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000112
Josh Coalson1b689822001-05-31 20:11:02 +0000113 FLAC__ASSERT(0 < max_order);
114 FLAC__ASSERT(max_order <= FLAC__MAX_LPC_ORDER);
115 FLAC__ASSERT(autoc[0] != 0.0);
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000116
117 err = autoc[0];
118
119 for(i = 0; i < max_order; i++) {
120 /* Sum up this iteration's reflection coefficient. */
Josh Coalsona1b53c42001-05-24 19:27:08 +0000121 r = -autoc[i+1];
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000122 for(j = 0; j < i; j++)
123 r -= lpc[j] * autoc[i-j];
124 ref[i] = (r/=err);
125
126 /* Update LPC coefficients and total error. */
127 lpc[i]=r;
128 for(j = 0; j < (i>>1); j++) {
Josh Coalson09758432004-10-20 00:21:50 +0000129 FLAC__double tmp = lpc[j];
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000130 lpc[j] += r * lpc[i-1-j];
131 lpc[i-1-j] += r * tmp;
132 }
133 if(i & 1)
134 lpc[j] += lpc[j] * r;
135
136 err *= (1.0 - r * r);
137
138 /* save this order */
139 for(j = 0; j <= i; j++)
Josh Coalsonb35bebd2001-07-03 04:37:18 +0000140 lp_coeff[i][j] = (FLAC__real)(-lpc[j]); /* negate FIR filter coeff to get predictor coeff */
Josh Coalson09758432004-10-20 00:21:50 +0000141 error[i] = err;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000142 }
143}
144
Josh Coalsoneac10242002-10-04 05:25:54 +0000145int FLAC__lpc_quantize_coefficients(const FLAC__real lp_coeff[], unsigned order, unsigned precision, FLAC__int32 qlp_coeff[], int *shift)
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000146{
147 unsigned i;
Josh Coalson09758432004-10-20 00:21:50 +0000148 FLAC__double d, cmax = -1e32;
Josh Coalson5975e8a2001-07-03 04:10:21 +0000149 FLAC__int32 qmax, qmin;
150 const int max_shiftlimit = (1 << (FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN-1)) - 1;
151 const int min_shiftlimit = -max_shiftlimit - 1;
Josh Coalsonc625f902001-02-28 23:56:03 +0000152
Josh Coalson1b689822001-05-31 20:11:02 +0000153 FLAC__ASSERT(precision > 0);
154 FLAC__ASSERT(precision >= FLAC__MIN_QLP_COEFF_PRECISION);
Josh Coalsonc625f902001-02-28 23:56:03 +0000155
156 /* drop one bit for the sign; from here on out we consider only |lp_coeff[i]| */
157 precision--;
Josh Coalson5975e8a2001-07-03 04:10:21 +0000158 qmax = 1 << precision;
159 qmin = -qmax;
160 qmax--;
Josh Coalsonc625f902001-02-28 23:56:03 +0000161
162 for(i = 0; i < order; i++) {
163 if(lp_coeff[i] == 0.0)
164 continue;
Josh Coalsonf52360a2001-08-13 23:10:06 +0000165 d = fabs(lp_coeff[i]);
Josh Coalsonc625f902001-02-28 23:56:03 +0000166 if(d > cmax)
167 cmax = d;
Josh Coalsonc625f902001-02-28 23:56:03 +0000168 }
Josh Coalson5975e8a2001-07-03 04:10:21 +0000169redo_it:
Josh Coalsond3ed49f2001-07-18 23:47:19 +0000170 if(cmax <= 0.0) {
Josh Coalson456db822001-03-01 19:14:05 +0000171 /* => coefficients are all 0, which means our constant-detect didn't work */
Josh Coalsonc625f902001-02-28 23:56:03 +0000172 return 2;
173 }
174 else {
Josh Coalson8c6f90f2001-07-19 17:07:13 +0000175 int log2cmax;
Josh Coalsonc625f902001-02-28 23:56:03 +0000176
Josh Coalson765ff502002-08-27 05:46:11 +0000177 (void)frexp(cmax, &log2cmax);
Josh Coalson8c6f90f2001-07-19 17:07:13 +0000178 log2cmax--;
179 *shift = (int)precision - log2cmax - 1;
Josh Coalsonc625f902001-02-28 23:56:03 +0000180
181 if(*shift < min_shiftlimit || *shift > max_shiftlimit) {
Josh Coalsoneac10242002-10-04 05:25:54 +0000182#if 0
183 /*@@@ this does not seem to help at all, but was not extensively tested either: */
184 if(*shift > max_shiftlimit)
185 *shift = max_shiftlimit;
186 else
187#endif
188 return 1;
Josh Coalsonc625f902001-02-28 23:56:03 +0000189 }
190 }
191
Josh Coalson4e6b3ac2001-07-06 00:37:57 +0000192 if(*shift >= 0) {
193 for(i = 0; i < order; i++) {
Josh Coalson09758432004-10-20 00:21:50 +0000194 qlp_coeff[i] = (FLAC__int32)floor((FLAC__double)lp_coeff[i] * (FLAC__double)(1 << *shift));
Josh Coalson5975e8a2001-07-03 04:10:21 +0000195
Josh Coalson8c6f90f2001-07-19 17:07:13 +0000196 /* double-check the result */
Josh Coalson4e6b3ac2001-07-06 00:37:57 +0000197 if(qlp_coeff[i] > qmax || qlp_coeff[i] < qmin) {
Josh Coalson5975e8a2001-07-03 04:10:21 +0000198#ifdef FLAC__OVERFLOW_DETECT
Josh Coalson09758432004-10-20 00:21:50 +0000199 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, (FLAC__double)lp_coeff[i] * (FLAC__double)(1 << *shift), floor((FLAC__double)lp_coeff[i] * (FLAC__double)(1 << *shift)));
Josh Coalson5975e8a2001-07-03 04:10:21 +0000200#endif
Josh Coalson4e6b3ac2001-07-06 00:37:57 +0000201 cmax *= 2.0;
202 goto redo_it;
Josh Coalson5975e8a2001-07-03 04:10:21 +0000203 }
204 }
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000205 }
Josh Coalson4e6b3ac2001-07-06 00:37:57 +0000206 else { /* (*shift < 0) */
207 const int nshift = -(*shift);
Josh Coalson3dbbf942001-07-12 21:27:40 +0000208#ifdef DEBUG
Josh Coalson4e6b3ac2001-07-06 00:37:57 +0000209 fprintf(stderr,"FLAC__lpc_quantize_coefficients: negative shift = %d\n", *shift);
Josh Coalson3dbbf942001-07-12 21:27:40 +0000210#endif
Josh Coalson4e6b3ac2001-07-06 00:37:57 +0000211 for(i = 0; i < order; i++) {
Josh Coalson09758432004-10-20 00:21:50 +0000212 qlp_coeff[i] = (FLAC__int32)floor((FLAC__double)lp_coeff[i] / (FLAC__double)(1 << nshift));
Josh Coalson4e6b3ac2001-07-06 00:37:57 +0000213
Josh Coalson8c6f90f2001-07-19 17:07:13 +0000214 /* double-check the result */
Josh Coalson4e6b3ac2001-07-06 00:37:57 +0000215 if(qlp_coeff[i] > qmax || qlp_coeff[i] < qmin) {
216#ifdef FLAC__OVERFLOW_DETECT
Josh Coalson09758432004-10-20 00:21:50 +0000217 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, (FLAC__double)lp_coeff[i] / (FLAC__double)(1 << nshift), floor((FLAC__double)lp_coeff[i] / (FLAC__double)(1 << nshift)));
Josh Coalson4e6b3ac2001-07-06 00:37:57 +0000218#endif
219 cmax *= 2.0;
220 goto redo_it;
221 }
222 }
223 }
224
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000225 return 0;
226}
227
Josh Coalson7446e182005-01-26 04:04:38 +0000228void 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 +0000229{
Josh Coalsonbb6712e2001-04-24 22:54:07 +0000230#ifdef FLAC__OVERFLOW_DETECT
Josh Coalson77e3f312001-06-23 03:03:24 +0000231 FLAC__int64 sumo;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000232#endif
233 unsigned i, j;
Josh Coalson77e3f312001-06-23 03:03:24 +0000234 FLAC__int32 sum;
235 const FLAC__int32 *history;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000236
Josh Coalsonbb6712e2001-04-24 22:54:07 +0000237#ifdef FLAC__OVERFLOW_DETECT_VERBOSE
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000238 fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization);
239 for(i=0;i<order;i++)
240 fprintf(stderr,", q[%u]=%d",i,qlp_coeff[i]);
241 fprintf(stderr,"\n");
242#endif
Josh Coalson1b689822001-05-31 20:11:02 +0000243 FLAC__ASSERT(order > 0);
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000244
245 for(i = 0; i < data_len; i++) {
Josh Coalsonbb6712e2001-04-24 22:54:07 +0000246#ifdef FLAC__OVERFLOW_DETECT
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000247 sumo = 0;
248#endif
249 sum = 0;
250 history = data;
251 for(j = 0; j < order; j++) {
252 sum += qlp_coeff[j] * (*(--history));
Josh Coalsonbb6712e2001-04-24 22:54:07 +0000253#ifdef FLAC__OVERFLOW_DETECT
Josh Coalson77e3f312001-06-23 03:03:24 +0000254 sumo += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*history);
Josh Coalsonb3538c82003-01-12 08:42:23 +0000255#if defined _MSC_VER
Josh Coalson0c671c82003-01-08 08:04:42 +0000256 if(sumo > 2147483647I64 || sumo < -2147483648I64)
Josh Coalsonfec4a772004-03-22 05:47:25 +0000257 fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%I64d\n",i,j,qlp_coeff[j],*history,sumo);
Josh Coalsond37acf42001-07-09 18:22:46 +0000258#else
259 if(sumo > 2147483647ll || sumo < -2147483648ll)
Josh Coalsonb35bebd2001-07-03 04:37:18 +0000260 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 Coalsonfec4a772004-03-22 05:47:25 +0000261#endif
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000262#endif
263 }
264 *(residual++) = *(data++) - (sum >> lp_quantization);
265 }
266
Josh Coalson9f77a192001-02-08 00:26:45 +0000267 /* Here's a slower but clearer version:
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000268 for(i = 0; i < data_len; i++) {
269 sum = 0;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000270 for(j = 0; j < order; j++)
Josh Coalson9f77a192001-02-08 00:26:45 +0000271 sum += qlp_coeff[j] * data[i-j-1];
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000272 residual[i] = data[i] - (sum >> lp_quantization);
273 }
274 */
275}
276
Josh Coalson7446e182005-01-26 04:04:38 +0000277void FLAC__lpc_compute_residual_from_qlp_coefficients_wide(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[])
Josh Coalsoneac10242002-10-04 05:25:54 +0000278{
279 unsigned i, j;
280 FLAC__int64 sum;
281 const FLAC__int32 *history;
282
283#ifdef FLAC__OVERFLOW_DETECT_VERBOSE
284 fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization);
285 for(i=0;i<order;i++)
286 fprintf(stderr,", q[%u]=%d",i,qlp_coeff[i]);
287 fprintf(stderr,"\n");
288#endif
289 FLAC__ASSERT(order > 0);
290
291 for(i = 0; i < data_len; i++) {
292 sum = 0;
293 history = data;
294 for(j = 0; j < order; j++)
295 sum += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*(--history));
296#ifdef FLAC__OVERFLOW_DETECT
297 if(FLAC__bitmath_silog2_wide(sum >> lp_quantization) > 32) {
298 fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: OVERFLOW, i=%u, sum=%lld\n", i, sum >> lp_quantization);
299 break;
300 }
301 if(FLAC__bitmath_silog2_wide((FLAC__int64)(*data) - (sum >> lp_quantization)) > 32) {
302 fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: OVERFLOW, i=%u, data=%d, sum=%lld, residual=%lld\n", i, *data, sum >> lp_quantization, (FLAC__int64)(*data) - (sum >> lp_quantization));
303 break;
304 }
305#endif
306 *(residual++) = *(data++) - (FLAC__int32)(sum >> lp_quantization);
307 }
308}
309
Josh Coalson5f2b46d2004-11-09 01:34:01 +0000310#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
311
Josh Coalson77e3f312001-06-23 03:03:24 +0000312void 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 +0000313{
Josh Coalsonbb6712e2001-04-24 22:54:07 +0000314#ifdef FLAC__OVERFLOW_DETECT
Josh Coalson77e3f312001-06-23 03:03:24 +0000315 FLAC__int64 sumo;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000316#endif
317 unsigned i, j;
Josh Coalson77e3f312001-06-23 03:03:24 +0000318 FLAC__int32 sum;
319 const FLAC__int32 *history;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000320
Josh Coalsonbb6712e2001-04-24 22:54:07 +0000321#ifdef FLAC__OVERFLOW_DETECT_VERBOSE
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000322 fprintf(stderr,"FLAC__lpc_restore_signal: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization);
323 for(i=0;i<order;i++)
324 fprintf(stderr,", q[%u]=%d",i,qlp_coeff[i]);
325 fprintf(stderr,"\n");
326#endif
Josh Coalson1b689822001-05-31 20:11:02 +0000327 FLAC__ASSERT(order > 0);
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000328
329 for(i = 0; i < data_len; i++) {
Josh Coalsonbb6712e2001-04-24 22:54:07 +0000330#ifdef FLAC__OVERFLOW_DETECT
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000331 sumo = 0;
332#endif
333 sum = 0;
Josh Coalson9f77a192001-02-08 00:26:45 +0000334 history = data;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000335 for(j = 0; j < order; j++) {
336 sum += qlp_coeff[j] * (*(--history));
Josh Coalsonbb6712e2001-04-24 22:54:07 +0000337#ifdef FLAC__OVERFLOW_DETECT
Josh Coalson77e3f312001-06-23 03:03:24 +0000338 sumo += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*history);
Josh Coalsonb3538c82003-01-12 08:42:23 +0000339#if defined _MSC_VER
Josh Coalson0c671c82003-01-08 08:04:42 +0000340 if(sumo > 2147483647I64 || sumo < -2147483648I64)
Josh Coalsonfec4a772004-03-22 05:47:25 +0000341 fprintf(stderr,"FLAC__lpc_restore_signal: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%I64d\n",i,j,qlp_coeff[j],*history,sumo);
Josh Coalsond37acf42001-07-09 18:22:46 +0000342#else
343 if(sumo > 2147483647ll || sumo < -2147483648ll)
Josh Coalsonb35bebd2001-07-03 04:37:18 +0000344 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 Coalsonfec4a772004-03-22 05:47:25 +0000345#endif
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000346#endif
347 }
Josh Coalson9f77a192001-02-08 00:26:45 +0000348 *(data++) = *(residual++) + (sum >> lp_quantization);
349 }
350
351 /* Here's a slower but clearer version:
352 for(i = 0; i < data_len; i++) {
353 sum = 0;
354 for(j = 0; j < order; j++)
355 sum += qlp_coeff[j] * data[i-j-1];
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000356 data[i] = residual[i] + (sum >> lp_quantization);
357 }
Josh Coalson9f77a192001-02-08 00:26:45 +0000358 */
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000359}
360
Josh Coalsoneac10242002-10-04 05:25:54 +0000361void FLAC__lpc_restore_signal_wide(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[])
362{
363 unsigned i, j;
364 FLAC__int64 sum;
365 const FLAC__int32 *history;
366
367#ifdef FLAC__OVERFLOW_DETECT_VERBOSE
368 fprintf(stderr,"FLAC__lpc_restore_signal_wide: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization);
369 for(i=0;i<order;i++)
370 fprintf(stderr,", q[%u]=%d",i,qlp_coeff[i]);
371 fprintf(stderr,"\n");
372#endif
373 FLAC__ASSERT(order > 0);
374
375 for(i = 0; i < data_len; i++) {
376 sum = 0;
377 history = data;
378 for(j = 0; j < order; j++)
379 sum += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*(--history));
380#ifdef FLAC__OVERFLOW_DETECT
381 if(FLAC__bitmath_silog2_wide(sum >> lp_quantization) > 32) {
382 fprintf(stderr,"FLAC__lpc_restore_signal_wide: OVERFLOW, i=%u, sum=%lld\n", i, sum >> lp_quantization);
383 break;
384 }
385 if(FLAC__bitmath_silog2_wide((FLAC__int64)(*residual) + (sum >> lp_quantization)) > 32) {
386 fprintf(stderr,"FLAC__lpc_restore_signal_wide: OVERFLOW, i=%u, residual=%d, sum=%lld, data=%lld\n", i, *residual, sum >> lp_quantization, (FLAC__int64)(*residual) + (sum >> lp_quantization));
387 break;
388 }
389#endif
390 *(data++) = *(residual++) + (FLAC__int32)(sum >> lp_quantization);
391 }
392}
393
Josh Coalson5f2b46d2004-11-09 01:34:01 +0000394#ifndef FLAC__INTEGER_ONLY_LIBRARY
395
Josh Coalson09758432004-10-20 00:21:50 +0000396FLAC__double FLAC__lpc_compute_expected_bits_per_residual_sample(FLAC__double lpc_error, unsigned total_samples)
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000397{
Josh Coalson09758432004-10-20 00:21:50 +0000398 FLAC__double error_scale;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000399
Josh Coalson1b689822001-05-31 20:11:02 +0000400 FLAC__ASSERT(total_samples > 0);
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000401
Josh Coalson09758432004-10-20 00:21:50 +0000402 error_scale = 0.5 * M_LN2 * M_LN2 / (FLAC__double)total_samples;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000403
Josh Coalsonddc5bc72002-06-05 05:53:17 +0000404 return FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(lpc_error, error_scale);
Josh Coalsona1b53c42001-05-24 19:27:08 +0000405}
406
Josh Coalson09758432004-10-20 00:21:50 +0000407FLAC__double FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(FLAC__double lpc_error, FLAC__double error_scale)
Josh Coalsona1b53c42001-05-24 19:27:08 +0000408{
409 if(lpc_error > 0.0) {
Josh Coalson09758432004-10-20 00:21:50 +0000410 FLAC__double bps = (FLAC__double)0.5 * log(error_scale * lpc_error) / M_LN2;
Josh Coalsona1b53c42001-05-24 19:27:08 +0000411 if(bps >= 0.0)
412 return bps;
413 else
414 return 0.0;
415 }
Josh Coalson09758432004-10-20 00:21:50 +0000416 else if(lpc_error < 0.0) { /* error should not be negative but can happen due to inadequate floating-point resolution */
417 return 1e32;
Josh Coalsona1b53c42001-05-24 19:27:08 +0000418 }
Josh Coalson9f77a192001-02-08 00:26:45 +0000419 else {
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000420 return 0.0;
Josh Coalson9f77a192001-02-08 00:26:45 +0000421 }
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000422}
423
Josh Coalson6e2b5652006-04-28 00:11:31 +0000424unsigned FLAC__lpc_compute_best_order(const FLAC__double lpc_error[], unsigned max_order, unsigned total_samples, unsigned overhead_bits_per_order)
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000425{
Josh Coalson6e2b5652006-04-28 00:11:31 +0000426 unsigned order, index, best_index; /* 'index' the index into lpc_error; index==order-1 since lpc_error[0] is for order==1, lpc_error[1] is for order==2, etc */
427 FLAC__double bits, best_bits, error_scale;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000428
Josh Coalson1b689822001-05-31 20:11:02 +0000429 FLAC__ASSERT(max_order > 0);
430 FLAC__ASSERT(total_samples > 0);
Josh Coalsona1b53c42001-05-24 19:27:08 +0000431
Josh Coalson09758432004-10-20 00:21:50 +0000432 error_scale = 0.5 * M_LN2 * M_LN2 / (FLAC__double)total_samples;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000433
Josh Coalson6e2b5652006-04-28 00:11:31 +0000434 best_index = 0;
435 best_bits = (unsigned)(-1);
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000436
Josh Coalson6e2b5652006-04-28 00:11:31 +0000437 for(index = 0, order = 1; index < max_order; index++, order++) {
438 bits = FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(lpc_error[index], error_scale) * (FLAC__double)(total_samples - order) + (FLAC__double)(order * overhead_bits_per_order);
439 if(bits < best_bits) {
440 best_index = index;
441 best_bits = bits;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000442 }
443 }
444
Josh Coalson6e2b5652006-04-28 00:11:31 +0000445 return best_index+1; /* +1 since index of lpc_error[] is order-1 */
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000446}
Josh Coalson5f2b46d2004-11-09 01:34:01 +0000447
448#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */