blob: c21b6dd3704eadaebf1d2cf8052f6cd32e86dd8d [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 Coalson32b9bae2006-11-27 16:27:41 +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 Coalson32b9bae2006-11-27 16:27:41 +0000113 FLAC__ASSERT(0 != max_order);
114 FLAC__ASSERT(0 < *max_order);
115 FLAC__ASSERT(*max_order <= FLAC__MAX_LPC_ORDER);
Josh Coalson1b689822001-05-31 20:11:02 +0000116 FLAC__ASSERT(autoc[0] != 0.0);
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000117
118 err = autoc[0];
119
Josh Coalson32b9bae2006-11-27 16:27:41 +0000120 for(i = 0; i < *max_order; i++) {
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000121 /* Sum up this iteration's reflection coefficient. */
Josh Coalsona1b53c42001-05-24 19:27:08 +0000122 r = -autoc[i+1];
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000123 for(j = 0; j < i; j++)
124 r -= lpc[j] * autoc[i-j];
125 ref[i] = (r/=err);
126
127 /* Update LPC coefficients and total error. */
128 lpc[i]=r;
129 for(j = 0; j < (i>>1); j++) {
Josh Coalson09758432004-10-20 00:21:50 +0000130 FLAC__double tmp = lpc[j];
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000131 lpc[j] += r * lpc[i-1-j];
132 lpc[i-1-j] += r * tmp;
133 }
134 if(i & 1)
135 lpc[j] += lpc[j] * r;
136
137 err *= (1.0 - r * r);
138
139 /* save this order */
140 for(j = 0; j <= i; j++)
Josh Coalsonb35bebd2001-07-03 04:37:18 +0000141 lp_coeff[i][j] = (FLAC__real)(-lpc[j]); /* negate FIR filter coeff to get predictor coeff */
Josh Coalson09758432004-10-20 00:21:50 +0000142 error[i] = err;
Josh Coalson32b9bae2006-11-27 16:27:41 +0000143
Josh Coalson76ba93a2007-01-28 17:37:55 +0000144 /* see SF bug #1601812 http://sourceforge.net/tracker/index.php?func=detail&aid=1601812&group_id=13478&atid=113478 */
Josh Coalson32b9bae2006-11-27 16:27:41 +0000145 if(err == 0.0) {
146 *max_order = i+1;
147 return;
148 }
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000149 }
150}
151
Josh Coalsoneac10242002-10-04 05:25:54 +0000152int 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 +0000153{
154 unsigned i;
Josh Coalson0486d432007-02-02 06:14:41 +0000155 FLAC__double cmax;
Josh Coalson5975e8a2001-07-03 04:10:21 +0000156 FLAC__int32 qmax, qmin;
Josh Coalsonc625f902001-02-28 23:56:03 +0000157
Josh Coalson1b689822001-05-31 20:11:02 +0000158 FLAC__ASSERT(precision > 0);
159 FLAC__ASSERT(precision >= FLAC__MIN_QLP_COEFF_PRECISION);
Josh Coalsonc625f902001-02-28 23:56:03 +0000160
161 /* drop one bit for the sign; from here on out we consider only |lp_coeff[i]| */
162 precision--;
Josh Coalson5975e8a2001-07-03 04:10:21 +0000163 qmax = 1 << precision;
164 qmin = -qmax;
165 qmax--;
Josh Coalsonc625f902001-02-28 23:56:03 +0000166
Josh Coalson0486d432007-02-02 06:14:41 +0000167 /* calc cmax = max( |lp_coeff[i]| ) */
168 cmax = 0.0;
Josh Coalsonc625f902001-02-28 23:56:03 +0000169 for(i = 0; i < order; i++) {
Josh Coalson0486d432007-02-02 06:14:41 +0000170 const FLAC__double d = fabs(lp_coeff[i]);
Josh Coalsonc625f902001-02-28 23:56:03 +0000171 if(d > cmax)
172 cmax = d;
Josh Coalsonc625f902001-02-28 23:56:03 +0000173 }
Josh Coalson0486d432007-02-02 06:14:41 +0000174
Josh Coalsond3ed49f2001-07-18 23:47:19 +0000175 if(cmax <= 0.0) {
Josh Coalson456db822001-03-01 19:14:05 +0000176 /* => coefficients are all 0, which means our constant-detect didn't work */
Josh Coalsonc625f902001-02-28 23:56:03 +0000177 return 2;
178 }
179 else {
Josh Coalson0486d432007-02-02 06:14:41 +0000180 const int max_shiftlimit = (1 << (FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN-1)) - 1;
181 const int min_shiftlimit = -max_shiftlimit - 1;
Josh Coalson8c6f90f2001-07-19 17:07:13 +0000182 int log2cmax;
Josh Coalsonc625f902001-02-28 23:56:03 +0000183
Josh Coalson765ff502002-08-27 05:46:11 +0000184 (void)frexp(cmax, &log2cmax);
Josh Coalson8c6f90f2001-07-19 17:07:13 +0000185 log2cmax--;
186 *shift = (int)precision - log2cmax - 1;
Josh Coalsonc625f902001-02-28 23:56:03 +0000187
188 if(*shift < min_shiftlimit || *shift > max_shiftlimit) {
Josh Coalson0486d432007-02-02 06:14:41 +0000189#ifdef FLAC__OVERFLOW_DETECT
190 fprintf(stderr,"FLAC__lpc_quantize_coefficients: shift out of limit: shift=%d cmax=%f precision=%u\n",q,qmax,*shift,cmax,precision+1);
191#endif
Josh Coalsoneac10242002-10-04 05:25:54 +0000192#if 0
193 /*@@@ this does not seem to help at all, but was not extensively tested either: */
194 if(*shift > max_shiftlimit)
195 *shift = max_shiftlimit;
196 else
197#endif
198 return 1;
Josh Coalsonc625f902001-02-28 23:56:03 +0000199 }
200 }
201
Josh Coalson4e6b3ac2001-07-06 00:37:57 +0000202 if(*shift >= 0) {
Josh Coalson0486d432007-02-02 06:14:41 +0000203 FLAC__double error = 0.0;
204 FLAC__int32 q;
Josh Coalson4e6b3ac2001-07-06 00:37:57 +0000205 for(i = 0; i < order; i++) {
Josh Coalson0486d432007-02-02 06:14:41 +0000206 error += lp_coeff[i] * (1 << *shift);
207 q = lround(error); /* round() is also suitable */
Josh Coalson5975e8a2001-07-03 04:10:21 +0000208#ifdef FLAC__OVERFLOW_DETECT
Josh Coalson0486d432007-02-02 06:14:41 +0000209 if(q > qmax)
210 fprintf(stderr,"FLAC__lpc_quantize_coefficients: quantizer overflow: q>qmax %d>%d shift=%d cmax=%f precision=%u lpc[%u]=%f\n",q,qmax,*shift,cmax,precision+1,i,lp_coeff[i]);
211 else if(q < qmin)
212 fprintf(stderr,"FLAC__lpc_quantize_coefficients: quantizer overflow: q<qmin %d<%d shift=%d cmax=%f precision=%u lpc[%u]=%f\n",q,qmin,*shift,cmax,precision+1,i,lp_coeff[i]);
Josh Coalson5975e8a2001-07-03 04:10:21 +0000213#endif
Josh Coalson0486d432007-02-02 06:14:41 +0000214 if(q > qmax)
215 q = qmax;
216 else if(q < qmin)
217 q = qmin;
218 error -= q;
219 qlp_coeff[i] = q;
Josh Coalson5975e8a2001-07-03 04:10:21 +0000220 }
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000221 }
Josh Coalson0486d432007-02-02 06:14:41 +0000222 /* negative shift is very rare but due to design flaw, negative shift is
223 * a NOP in the decoder, so it must be handled specially by scaling down
224 * coeffs
225 */
226 else {
Josh Coalson4e6b3ac2001-07-06 00:37:57 +0000227 const int nshift = -(*shift);
Josh Coalson0486d432007-02-02 06:14:41 +0000228 FLAC__double error = 0.0;
229 FLAC__int32 q;
Josh Coalson3dbbf942001-07-12 21:27:40 +0000230#ifdef DEBUG
Josh Coalson4e6b3ac2001-07-06 00:37:57 +0000231 fprintf(stderr,"FLAC__lpc_quantize_coefficients: negative shift = %d\n", *shift);
Josh Coalson3dbbf942001-07-12 21:27:40 +0000232#endif
Josh Coalson4e6b3ac2001-07-06 00:37:57 +0000233 for(i = 0; i < order; i++) {
Josh Coalson0486d432007-02-02 06:14:41 +0000234 error += lp_coeff[i] / (1 << nshift);
235 q = lround(error); /* round() is also suitable */
Josh Coalson4e6b3ac2001-07-06 00:37:57 +0000236#ifdef FLAC__OVERFLOW_DETECT
Josh Coalson0486d432007-02-02 06:14:41 +0000237 if(q > qmax)
238 fprintf(stderr,"FLAC__lpc_quantize_coefficients: quantizer overflow: q>qmax %d>%d shift=%d cmax=%f precision=%u lpc[%u]=%f\n",q,qmax,*shift,cmax,precision+1,i,lp_coeff[i]);
239 else if(q < qmin)
240 fprintf(stderr,"FLAC__lpc_quantize_coefficients: quantizer overflow: q<qmin %d<%d shift=%d cmax=%f precision=%u lpc[%u]=%f\n",q,qmin,*shift,cmax,precision+1,i,lp_coeff[i]);
Josh Coalson4e6b3ac2001-07-06 00:37:57 +0000241#endif
Josh Coalson0486d432007-02-02 06:14:41 +0000242 if(q > qmax)
243 q = qmax;
244 else if(q < qmin)
245 q = qmin;
246 error -= q;
247 qlp_coeff[i] = q;
Josh Coalson4e6b3ac2001-07-06 00:37:57 +0000248 }
Josh Coalson0486d432007-02-02 06:14:41 +0000249 *shift = 0;
Josh Coalson4e6b3ac2001-07-06 00:37:57 +0000250 }
251
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000252 return 0;
253}
254
Josh Coalson7446e182005-01-26 04:04:38 +0000255void 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 +0000256{
Josh Coalsonbb6712e2001-04-24 22:54:07 +0000257#ifdef FLAC__OVERFLOW_DETECT
Josh Coalson77e3f312001-06-23 03:03:24 +0000258 FLAC__int64 sumo;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000259#endif
260 unsigned i, j;
Josh Coalson77e3f312001-06-23 03:03:24 +0000261 FLAC__int32 sum;
262 const FLAC__int32 *history;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000263
Josh Coalsonbb6712e2001-04-24 22:54:07 +0000264#ifdef FLAC__OVERFLOW_DETECT_VERBOSE
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000265 fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization);
266 for(i=0;i<order;i++)
267 fprintf(stderr,", q[%u]=%d",i,qlp_coeff[i]);
268 fprintf(stderr,"\n");
269#endif
Josh Coalson1b689822001-05-31 20:11:02 +0000270 FLAC__ASSERT(order > 0);
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000271
272 for(i = 0; i < data_len; i++) {
Josh Coalsonbb6712e2001-04-24 22:54:07 +0000273#ifdef FLAC__OVERFLOW_DETECT
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000274 sumo = 0;
275#endif
276 sum = 0;
277 history = data;
278 for(j = 0; j < order; j++) {
279 sum += qlp_coeff[j] * (*(--history));
Josh Coalsonbb6712e2001-04-24 22:54:07 +0000280#ifdef FLAC__OVERFLOW_DETECT
Josh Coalson77e3f312001-06-23 03:03:24 +0000281 sumo += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*history);
Josh Coalsonb3538c82003-01-12 08:42:23 +0000282#if defined _MSC_VER
Josh Coalson0c671c82003-01-08 08:04:42 +0000283 if(sumo > 2147483647I64 || sumo < -2147483648I64)
Josh Coalsonfec4a772004-03-22 05:47:25 +0000284 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 +0000285#else
286 if(sumo > 2147483647ll || sumo < -2147483648ll)
Josh Coalsonab56ef12006-11-17 06:52:19 +0000287 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,(long long)sumo);
Josh Coalsonfec4a772004-03-22 05:47:25 +0000288#endif
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000289#endif
290 }
291 *(residual++) = *(data++) - (sum >> lp_quantization);
292 }
293
Josh Coalson9f77a192001-02-08 00:26:45 +0000294 /* Here's a slower but clearer version:
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000295 for(i = 0; i < data_len; i++) {
296 sum = 0;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000297 for(j = 0; j < order; j++)
Josh Coalson9f77a192001-02-08 00:26:45 +0000298 sum += qlp_coeff[j] * data[i-j-1];
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000299 residual[i] = data[i] - (sum >> lp_quantization);
300 }
301 */
302}
303
Josh Coalson7446e182005-01-26 04:04:38 +0000304void 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 +0000305{
306 unsigned i, j;
307 FLAC__int64 sum;
308 const FLAC__int32 *history;
309
310#ifdef FLAC__OVERFLOW_DETECT_VERBOSE
311 fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization);
312 for(i=0;i<order;i++)
313 fprintf(stderr,", q[%u]=%d",i,qlp_coeff[i]);
314 fprintf(stderr,"\n");
315#endif
316 FLAC__ASSERT(order > 0);
317
318 for(i = 0; i < data_len; i++) {
319 sum = 0;
320 history = data;
321 for(j = 0; j < order; j++)
322 sum += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*(--history));
323#ifdef FLAC__OVERFLOW_DETECT
324 if(FLAC__bitmath_silog2_wide(sum >> lp_quantization) > 32) {
Josh Coalsonab56ef12006-11-17 06:52:19 +0000325 fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: OVERFLOW, i=%u, sum=%lld\n", i, (long long)(sum >> lp_quantization));
Josh Coalsoneac10242002-10-04 05:25:54 +0000326 break;
327 }
328 if(FLAC__bitmath_silog2_wide((FLAC__int64)(*data) - (sum >> lp_quantization)) > 32) {
Josh Coalsonab56ef12006-11-17 06:52:19 +0000329 fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: OVERFLOW, i=%u, data=%d, sum=%lld, residual=%lld\n", i, *data, (long long)(sum >> lp_quantization), (long long)((FLAC__int64)(*data) - (sum >> lp_quantization)));
Josh Coalsoneac10242002-10-04 05:25:54 +0000330 break;
331 }
332#endif
333 *(residual++) = *(data++) - (FLAC__int32)(sum >> lp_quantization);
334 }
335}
336
Josh Coalson5f2b46d2004-11-09 01:34:01 +0000337#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
338
Josh Coalson77e3f312001-06-23 03:03:24 +0000339void 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 +0000340{
Josh Coalsonbb6712e2001-04-24 22:54:07 +0000341#ifdef FLAC__OVERFLOW_DETECT
Josh Coalson77e3f312001-06-23 03:03:24 +0000342 FLAC__int64 sumo;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000343#endif
344 unsigned i, j;
Josh Coalson77e3f312001-06-23 03:03:24 +0000345 FLAC__int32 sum;
Josh Coalson7581d122006-11-20 07:19:15 +0000346 const FLAC__int32 *r = residual, *history;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000347
Josh Coalsonbb6712e2001-04-24 22:54:07 +0000348#ifdef FLAC__OVERFLOW_DETECT_VERBOSE
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000349 fprintf(stderr,"FLAC__lpc_restore_signal: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization);
350 for(i=0;i<order;i++)
351 fprintf(stderr,", q[%u]=%d",i,qlp_coeff[i]);
352 fprintf(stderr,"\n");
353#endif
Josh Coalson1b689822001-05-31 20:11:02 +0000354 FLAC__ASSERT(order > 0);
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000355
356 for(i = 0; i < data_len; i++) {
Josh Coalsonbb6712e2001-04-24 22:54:07 +0000357#ifdef FLAC__OVERFLOW_DETECT
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000358 sumo = 0;
359#endif
360 sum = 0;
Josh Coalson9f77a192001-02-08 00:26:45 +0000361 history = data;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000362 for(j = 0; j < order; j++) {
363 sum += qlp_coeff[j] * (*(--history));
Josh Coalsonbb6712e2001-04-24 22:54:07 +0000364#ifdef FLAC__OVERFLOW_DETECT
Josh Coalson77e3f312001-06-23 03:03:24 +0000365 sumo += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*history);
Josh Coalsonb3538c82003-01-12 08:42:23 +0000366#if defined _MSC_VER
Josh Coalson0c671c82003-01-08 08:04:42 +0000367 if(sumo > 2147483647I64 || sumo < -2147483648I64)
Josh Coalsonfec4a772004-03-22 05:47:25 +0000368 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 +0000369#else
370 if(sumo > 2147483647ll || sumo < -2147483648ll)
Josh Coalsonab56ef12006-11-17 06:52:19 +0000371 fprintf(stderr,"FLAC__lpc_restore_signal: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%lld\n",i,j,qlp_coeff[j],*history,(long long)sumo);
Josh Coalsonfec4a772004-03-22 05:47:25 +0000372#endif
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000373#endif
374 }
Josh Coalson7581d122006-11-20 07:19:15 +0000375 *(data++) = *(r++) + (sum >> lp_quantization);
Josh Coalson9f77a192001-02-08 00:26:45 +0000376 }
377
378 /* Here's a slower but clearer version:
379 for(i = 0; i < data_len; i++) {
380 sum = 0;
381 for(j = 0; j < order; j++)
382 sum += qlp_coeff[j] * data[i-j-1];
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000383 data[i] = residual[i] + (sum >> lp_quantization);
384 }
Josh Coalson9f77a192001-02-08 00:26:45 +0000385 */
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000386}
387
Josh Coalsoneac10242002-10-04 05:25:54 +0000388void 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[])
389{
390 unsigned i, j;
391 FLAC__int64 sum;
Josh Coalson7581d122006-11-20 07:19:15 +0000392 const FLAC__int32 *r = residual, *history;
Josh Coalsoneac10242002-10-04 05:25:54 +0000393
394#ifdef FLAC__OVERFLOW_DETECT_VERBOSE
395 fprintf(stderr,"FLAC__lpc_restore_signal_wide: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization);
396 for(i=0;i<order;i++)
397 fprintf(stderr,", q[%u]=%d",i,qlp_coeff[i]);
398 fprintf(stderr,"\n");
399#endif
400 FLAC__ASSERT(order > 0);
401
402 for(i = 0; i < data_len; i++) {
403 sum = 0;
404 history = data;
405 for(j = 0; j < order; j++)
406 sum += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*(--history));
407#ifdef FLAC__OVERFLOW_DETECT
408 if(FLAC__bitmath_silog2_wide(sum >> lp_quantization) > 32) {
Josh Coalsonab56ef12006-11-17 06:52:19 +0000409 fprintf(stderr,"FLAC__lpc_restore_signal_wide: OVERFLOW, i=%u, sum=%lld\n", i, (long long)(sum >> lp_quantization));
Josh Coalsoneac10242002-10-04 05:25:54 +0000410 break;
411 }
Josh Coalson7581d122006-11-20 07:19:15 +0000412 if(FLAC__bitmath_silog2_wide((FLAC__int64)(*r) + (sum >> lp_quantization)) > 32) {
413 fprintf(stderr,"FLAC__lpc_restore_signal_wide: OVERFLOW, i=%u, residual=%d, sum=%lld, data=%lld\n", i, *r, (long long)(sum >> lp_quantization), (long long)((FLAC__int64)(*r) + (sum >> lp_quantization)));
Josh Coalsoneac10242002-10-04 05:25:54 +0000414 break;
415 }
416#endif
Josh Coalson7581d122006-11-20 07:19:15 +0000417 *(data++) = *(r++) + (FLAC__int32)(sum >> lp_quantization);
Josh Coalsoneac10242002-10-04 05:25:54 +0000418 }
419}
420
Josh Coalson5f2b46d2004-11-09 01:34:01 +0000421#ifndef FLAC__INTEGER_ONLY_LIBRARY
422
Josh Coalson09758432004-10-20 00:21:50 +0000423FLAC__double FLAC__lpc_compute_expected_bits_per_residual_sample(FLAC__double lpc_error, unsigned total_samples)
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000424{
Josh Coalson09758432004-10-20 00:21:50 +0000425 FLAC__double error_scale;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000426
Josh Coalson1b689822001-05-31 20:11:02 +0000427 FLAC__ASSERT(total_samples > 0);
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000428
Josh Coalson09758432004-10-20 00:21:50 +0000429 error_scale = 0.5 * M_LN2 * M_LN2 / (FLAC__double)total_samples;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000430
Josh Coalsonddc5bc72002-06-05 05:53:17 +0000431 return FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(lpc_error, error_scale);
Josh Coalsona1b53c42001-05-24 19:27:08 +0000432}
433
Josh Coalson09758432004-10-20 00:21:50 +0000434FLAC__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 +0000435{
436 if(lpc_error > 0.0) {
Josh Coalson09758432004-10-20 00:21:50 +0000437 FLAC__double bps = (FLAC__double)0.5 * log(error_scale * lpc_error) / M_LN2;
Josh Coalsona1b53c42001-05-24 19:27:08 +0000438 if(bps >= 0.0)
439 return bps;
440 else
441 return 0.0;
442 }
Josh Coalson09758432004-10-20 00:21:50 +0000443 else if(lpc_error < 0.0) { /* error should not be negative but can happen due to inadequate floating-point resolution */
444 return 1e32;
Josh Coalsona1b53c42001-05-24 19:27:08 +0000445 }
Josh Coalson9f77a192001-02-08 00:26:45 +0000446 else {
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000447 return 0.0;
Josh Coalson9f77a192001-02-08 00:26:45 +0000448 }
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000449}
450
Josh Coalson6e2b5652006-04-28 00:11:31 +0000451unsigned 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 +0000452{
Josh Coalson6e2b5652006-04-28 00:11:31 +0000453 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 */
454 FLAC__double bits, best_bits, error_scale;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000455
Josh Coalson1b689822001-05-31 20:11:02 +0000456 FLAC__ASSERT(max_order > 0);
457 FLAC__ASSERT(total_samples > 0);
Josh Coalsona1b53c42001-05-24 19:27:08 +0000458
Josh Coalson09758432004-10-20 00:21:50 +0000459 error_scale = 0.5 * M_LN2 * M_LN2 / (FLAC__double)total_samples;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000460
Josh Coalson6e2b5652006-04-28 00:11:31 +0000461 best_index = 0;
462 best_bits = (unsigned)(-1);
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000463
Josh Coalson6e2b5652006-04-28 00:11:31 +0000464 for(index = 0, order = 1; index < max_order; index++, order++) {
465 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);
466 if(bits < best_bits) {
467 best_index = index;
468 best_bits = bits;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000469 }
470 }
471
Josh Coalson6e2b5652006-04-28 00:11:31 +0000472 return best_index+1; /* +1 since index of lpc_error[] is order-1 */
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000473}
Josh Coalson5f2b46d2004-11-09 01:34:01 +0000474
475#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */