Josh Coalson | 26560dd | 2001-02-08 00:38:41 +0000 | [diff] [blame] | 1 | /* libFLAC - Free Lossless Audio Codec library |
Josh Coalson | 0395dac | 2006-04-25 06:59:33 +0000 | [diff] [blame] | 2 | * Copyright (C) 2000,2001,2002,2003,2004,2005,2006 Josh Coalson |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 3 | * |
Josh Coalson | afd8107 | 2003-01-31 23:34:56 +0000 | [diff] [blame] | 4 | * Redistribution and use in source and binary forms, with or without |
| 5 | * modification, are permitted provided that the following conditions |
| 6 | * are met: |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 7 | * |
Josh Coalson | afd8107 | 2003-01-31 23:34:56 +0000 | [diff] [blame] | 8 | * - Redistributions of source code must retain the above copyright |
| 9 | * notice, this list of conditions and the following disclaimer. |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 10 | * |
Josh Coalson | afd8107 | 2003-01-31 23:34:56 +0000 | [diff] [blame] | 11 | * - 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 Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 30 | */ |
| 31 | |
Josh Coalson | b1ec796 | 2006-05-24 04:41:36 +0000 | [diff] [blame] | 32 | #if HAVE_CONFIG_H |
| 33 | # include <config.h> |
| 34 | #endif |
| 35 | |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 36 | #include <math.h> |
Josh Coalson | 1b68982 | 2001-05-31 20:11:02 +0000 | [diff] [blame] | 37 | #include "FLAC/assert.h" |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 38 | #include "FLAC/format.h" |
Josh Coalson | eac1024 | 2002-10-04 05:25:54 +0000 | [diff] [blame] | 39 | #include "private/bitmath.h" |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 40 | #include "private/lpc.h" |
Josh Coalson | 03ed88b | 2002-05-17 06:19:28 +0000 | [diff] [blame] | 41 | #if defined DEBUG || defined FLAC__OVERFLOW_DETECT || defined FLAC__OVERFLOW_DETECT_VERBOSE |
| 42 | #include <stdio.h> |
| 43 | #endif |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 44 | |
Josh Coalson | 5f2b46d | 2004-11-09 01:34:01 +0000 | [diff] [blame] | 45 | #ifndef FLAC__INTEGER_ONLY_LIBRARY |
| 46 | |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 47 | #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 Coalson | bf0f52c | 2006-04-25 06:38:43 +0000 | [diff] [blame] | 52 | void 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 Coalson | 77e3f31 | 2001-06-23 03:03:24 +0000 | [diff] [blame] | 59 | void FLAC__lpc_compute_autocorrelation(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]) |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 60 | { |
Josh Coalson | c0785cd | 2001-05-10 19:29:41 +0000 | [diff] [blame] | 61 | /* a readable, but slower, version */ |
| 62 | #if 0 |
Josh Coalson | 77e3f31 | 2001-06-23 03:03:24 +0000 | [diff] [blame] | 63 | FLAC__real d; |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 64 | unsigned i; |
| 65 | |
Josh Coalson | 1b68982 | 2001-05-31 20:11:02 +0000 | [diff] [blame] | 66 | FLAC__ASSERT(lag > 0); |
| 67 | FLAC__ASSERT(lag <= data_len); |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 68 | |
Josh Coalson | 6e2b565 | 2006-04-28 00:11:31 +0000 | [diff] [blame] | 69 | /* |
| 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 Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 76 | 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 Coalson | c0785cd | 2001-05-10 19:29:41 +0000 | [diff] [blame] | 81 | #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 Coalson | 77e3f31 | 2001-06-23 03:03:24 +0000 | [diff] [blame] | 87 | FLAC__real d; |
Josh Coalson | c0785cd | 2001-05-10 19:29:41 +0000 | [diff] [blame] | 88 | unsigned sample, coeff; |
| 89 | const unsigned limit = data_len - lag; |
| 90 | |
Josh Coalson | 1b68982 | 2001-05-31 20:11:02 +0000 | [diff] [blame] | 91 | FLAC__ASSERT(lag > 0); |
| 92 | FLAC__ASSERT(lag <= data_len); |
Josh Coalson | c0785cd | 2001-05-10 19:29:41 +0000 | [diff] [blame] | 93 | |
| 94 | for(coeff = 0; coeff < lag; coeff++) |
| 95 | autoc[coeff] = 0.0; |
Josh Coalson | 376807d | 2001-05-16 19:23:35 +0000 | [diff] [blame] | 96 | for(sample = 0; sample <= limit; sample++) { |
Josh Coalson | c0785cd | 2001-05-10 19:29:41 +0000 | [diff] [blame] | 97 | d = data[sample]; |
| 98 | for(coeff = 0; coeff < lag; coeff++) |
| 99 | autoc[coeff] += d * data[sample+coeff]; |
| 100 | } |
Josh Coalson | 376807d | 2001-05-16 19:23:35 +0000 | [diff] [blame] | 101 | for(; sample < data_len; sample++) { |
Josh Coalson | c0785cd | 2001-05-10 19:29:41 +0000 | [diff] [blame] | 102 | d = data[sample]; |
| 103 | for(coeff = 0; coeff < data_len - sample; coeff++) |
| 104 | autoc[coeff] += d * data[sample+coeff]; |
| 105 | } |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 106 | } |
| 107 | |
Josh Coalson | 32b9bae | 2006-11-27 16:27:41 +0000 | [diff] [blame] | 108 | void FLAC__lpc_compute_lp_coefficients(const FLAC__real autoc[], unsigned *max_order, FLAC__real lp_coeff[][FLAC__MAX_LPC_ORDER], FLAC__double error[]) |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 109 | { |
| 110 | unsigned i, j; |
Josh Coalson | 0975843 | 2004-10-20 00:21:50 +0000 | [diff] [blame] | 111 | FLAC__double r, err, ref[FLAC__MAX_LPC_ORDER], lpc[FLAC__MAX_LPC_ORDER]; |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 112 | |
Josh Coalson | 32b9bae | 2006-11-27 16:27:41 +0000 | [diff] [blame] | 113 | FLAC__ASSERT(0 != max_order); |
| 114 | FLAC__ASSERT(0 < *max_order); |
| 115 | FLAC__ASSERT(*max_order <= FLAC__MAX_LPC_ORDER); |
Josh Coalson | 1b68982 | 2001-05-31 20:11:02 +0000 | [diff] [blame] | 116 | FLAC__ASSERT(autoc[0] != 0.0); |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 117 | |
| 118 | err = autoc[0]; |
| 119 | |
Josh Coalson | 32b9bae | 2006-11-27 16:27:41 +0000 | [diff] [blame] | 120 | for(i = 0; i < *max_order; i++) { |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 121 | /* Sum up this iteration's reflection coefficient. */ |
Josh Coalson | a1b53c4 | 2001-05-24 19:27:08 +0000 | [diff] [blame] | 122 | r = -autoc[i+1]; |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 123 | 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 Coalson | 0975843 | 2004-10-20 00:21:50 +0000 | [diff] [blame] | 130 | FLAC__double tmp = lpc[j]; |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 131 | 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 Coalson | b35bebd | 2001-07-03 04:37:18 +0000 | [diff] [blame] | 141 | lp_coeff[i][j] = (FLAC__real)(-lpc[j]); /* negate FIR filter coeff to get predictor coeff */ |
Josh Coalson | 0975843 | 2004-10-20 00:21:50 +0000 | [diff] [blame] | 142 | error[i] = err; |
Josh Coalson | 32b9bae | 2006-11-27 16:27:41 +0000 | [diff] [blame] | 143 | |
Josh Coalson | 76ba93a | 2007-01-28 17:37:55 +0000 | [diff] [blame] | 144 | /* see SF bug #1601812 http://sourceforge.net/tracker/index.php?func=detail&aid=1601812&group_id=13478&atid=113478 */ |
Josh Coalson | 32b9bae | 2006-11-27 16:27:41 +0000 | [diff] [blame] | 145 | if(err == 0.0) { |
| 146 | *max_order = i+1; |
| 147 | return; |
| 148 | } |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 149 | } |
| 150 | } |
| 151 | |
Josh Coalson | eac1024 | 2002-10-04 05:25:54 +0000 | [diff] [blame] | 152 | int FLAC__lpc_quantize_coefficients(const FLAC__real lp_coeff[], unsigned order, unsigned precision, FLAC__int32 qlp_coeff[], int *shift) |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 153 | { |
| 154 | unsigned i; |
Josh Coalson | 0486d43 | 2007-02-02 06:14:41 +0000 | [diff] [blame^] | 155 | FLAC__double cmax; |
Josh Coalson | 5975e8a | 2001-07-03 04:10:21 +0000 | [diff] [blame] | 156 | FLAC__int32 qmax, qmin; |
Josh Coalson | c625f90 | 2001-02-28 23:56:03 +0000 | [diff] [blame] | 157 | |
Josh Coalson | 1b68982 | 2001-05-31 20:11:02 +0000 | [diff] [blame] | 158 | FLAC__ASSERT(precision > 0); |
| 159 | FLAC__ASSERT(precision >= FLAC__MIN_QLP_COEFF_PRECISION); |
Josh Coalson | c625f90 | 2001-02-28 23:56:03 +0000 | [diff] [blame] | 160 | |
| 161 | /* drop one bit for the sign; from here on out we consider only |lp_coeff[i]| */ |
| 162 | precision--; |
Josh Coalson | 5975e8a | 2001-07-03 04:10:21 +0000 | [diff] [blame] | 163 | qmax = 1 << precision; |
| 164 | qmin = -qmax; |
| 165 | qmax--; |
Josh Coalson | c625f90 | 2001-02-28 23:56:03 +0000 | [diff] [blame] | 166 | |
Josh Coalson | 0486d43 | 2007-02-02 06:14:41 +0000 | [diff] [blame^] | 167 | /* calc cmax = max( |lp_coeff[i]| ) */ |
| 168 | cmax = 0.0; |
Josh Coalson | c625f90 | 2001-02-28 23:56:03 +0000 | [diff] [blame] | 169 | for(i = 0; i < order; i++) { |
Josh Coalson | 0486d43 | 2007-02-02 06:14:41 +0000 | [diff] [blame^] | 170 | const FLAC__double d = fabs(lp_coeff[i]); |
Josh Coalson | c625f90 | 2001-02-28 23:56:03 +0000 | [diff] [blame] | 171 | if(d > cmax) |
| 172 | cmax = d; |
Josh Coalson | c625f90 | 2001-02-28 23:56:03 +0000 | [diff] [blame] | 173 | } |
Josh Coalson | 0486d43 | 2007-02-02 06:14:41 +0000 | [diff] [blame^] | 174 | |
Josh Coalson | d3ed49f | 2001-07-18 23:47:19 +0000 | [diff] [blame] | 175 | if(cmax <= 0.0) { |
Josh Coalson | 456db82 | 2001-03-01 19:14:05 +0000 | [diff] [blame] | 176 | /* => coefficients are all 0, which means our constant-detect didn't work */ |
Josh Coalson | c625f90 | 2001-02-28 23:56:03 +0000 | [diff] [blame] | 177 | return 2; |
| 178 | } |
| 179 | else { |
Josh Coalson | 0486d43 | 2007-02-02 06:14:41 +0000 | [diff] [blame^] | 180 | const int max_shiftlimit = (1 << (FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN-1)) - 1; |
| 181 | const int min_shiftlimit = -max_shiftlimit - 1; |
Josh Coalson | 8c6f90f | 2001-07-19 17:07:13 +0000 | [diff] [blame] | 182 | int log2cmax; |
Josh Coalson | c625f90 | 2001-02-28 23:56:03 +0000 | [diff] [blame] | 183 | |
Josh Coalson | 765ff50 | 2002-08-27 05:46:11 +0000 | [diff] [blame] | 184 | (void)frexp(cmax, &log2cmax); |
Josh Coalson | 8c6f90f | 2001-07-19 17:07:13 +0000 | [diff] [blame] | 185 | log2cmax--; |
| 186 | *shift = (int)precision - log2cmax - 1; |
Josh Coalson | c625f90 | 2001-02-28 23:56:03 +0000 | [diff] [blame] | 187 | |
| 188 | if(*shift < min_shiftlimit || *shift > max_shiftlimit) { |
Josh Coalson | 0486d43 | 2007-02-02 06:14:41 +0000 | [diff] [blame^] | 189 | #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 Coalson | eac1024 | 2002-10-04 05:25:54 +0000 | [diff] [blame] | 192 | #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 Coalson | c625f90 | 2001-02-28 23:56:03 +0000 | [diff] [blame] | 199 | } |
| 200 | } |
| 201 | |
Josh Coalson | 4e6b3ac | 2001-07-06 00:37:57 +0000 | [diff] [blame] | 202 | if(*shift >= 0) { |
Josh Coalson | 0486d43 | 2007-02-02 06:14:41 +0000 | [diff] [blame^] | 203 | FLAC__double error = 0.0; |
| 204 | FLAC__int32 q; |
Josh Coalson | 4e6b3ac | 2001-07-06 00:37:57 +0000 | [diff] [blame] | 205 | for(i = 0; i < order; i++) { |
Josh Coalson | 0486d43 | 2007-02-02 06:14:41 +0000 | [diff] [blame^] | 206 | error += lp_coeff[i] * (1 << *shift); |
| 207 | q = lround(error); /* round() is also suitable */ |
Josh Coalson | 5975e8a | 2001-07-03 04:10:21 +0000 | [diff] [blame] | 208 | #ifdef FLAC__OVERFLOW_DETECT |
Josh Coalson | 0486d43 | 2007-02-02 06:14:41 +0000 | [diff] [blame^] | 209 | 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 Coalson | 5975e8a | 2001-07-03 04:10:21 +0000 | [diff] [blame] | 213 | #endif |
Josh Coalson | 0486d43 | 2007-02-02 06:14:41 +0000 | [diff] [blame^] | 214 | if(q > qmax) |
| 215 | q = qmax; |
| 216 | else if(q < qmin) |
| 217 | q = qmin; |
| 218 | error -= q; |
| 219 | qlp_coeff[i] = q; |
Josh Coalson | 5975e8a | 2001-07-03 04:10:21 +0000 | [diff] [blame] | 220 | } |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 221 | } |
Josh Coalson | 0486d43 | 2007-02-02 06:14:41 +0000 | [diff] [blame^] | 222 | /* 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 Coalson | 4e6b3ac | 2001-07-06 00:37:57 +0000 | [diff] [blame] | 227 | const int nshift = -(*shift); |
Josh Coalson | 0486d43 | 2007-02-02 06:14:41 +0000 | [diff] [blame^] | 228 | FLAC__double error = 0.0; |
| 229 | FLAC__int32 q; |
Josh Coalson | 3dbbf94 | 2001-07-12 21:27:40 +0000 | [diff] [blame] | 230 | #ifdef DEBUG |
Josh Coalson | 4e6b3ac | 2001-07-06 00:37:57 +0000 | [diff] [blame] | 231 | fprintf(stderr,"FLAC__lpc_quantize_coefficients: negative shift = %d\n", *shift); |
Josh Coalson | 3dbbf94 | 2001-07-12 21:27:40 +0000 | [diff] [blame] | 232 | #endif |
Josh Coalson | 4e6b3ac | 2001-07-06 00:37:57 +0000 | [diff] [blame] | 233 | for(i = 0; i < order; i++) { |
Josh Coalson | 0486d43 | 2007-02-02 06:14:41 +0000 | [diff] [blame^] | 234 | error += lp_coeff[i] / (1 << nshift); |
| 235 | q = lround(error); /* round() is also suitable */ |
Josh Coalson | 4e6b3ac | 2001-07-06 00:37:57 +0000 | [diff] [blame] | 236 | #ifdef FLAC__OVERFLOW_DETECT |
Josh Coalson | 0486d43 | 2007-02-02 06:14:41 +0000 | [diff] [blame^] | 237 | 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 Coalson | 4e6b3ac | 2001-07-06 00:37:57 +0000 | [diff] [blame] | 241 | #endif |
Josh Coalson | 0486d43 | 2007-02-02 06:14:41 +0000 | [diff] [blame^] | 242 | if(q > qmax) |
| 243 | q = qmax; |
| 244 | else if(q < qmin) |
| 245 | q = qmin; |
| 246 | error -= q; |
| 247 | qlp_coeff[i] = q; |
Josh Coalson | 4e6b3ac | 2001-07-06 00:37:57 +0000 | [diff] [blame] | 248 | } |
Josh Coalson | 0486d43 | 2007-02-02 06:14:41 +0000 | [diff] [blame^] | 249 | *shift = 0; |
Josh Coalson | 4e6b3ac | 2001-07-06 00:37:57 +0000 | [diff] [blame] | 250 | } |
| 251 | |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 252 | return 0; |
| 253 | } |
| 254 | |
Josh Coalson | 7446e18 | 2005-01-26 04:04:38 +0000 | [diff] [blame] | 255 | void 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 Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 256 | { |
Josh Coalson | bb6712e | 2001-04-24 22:54:07 +0000 | [diff] [blame] | 257 | #ifdef FLAC__OVERFLOW_DETECT |
Josh Coalson | 77e3f31 | 2001-06-23 03:03:24 +0000 | [diff] [blame] | 258 | FLAC__int64 sumo; |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 259 | #endif |
| 260 | unsigned i, j; |
Josh Coalson | 77e3f31 | 2001-06-23 03:03:24 +0000 | [diff] [blame] | 261 | FLAC__int32 sum; |
| 262 | const FLAC__int32 *history; |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 263 | |
Josh Coalson | bb6712e | 2001-04-24 22:54:07 +0000 | [diff] [blame] | 264 | #ifdef FLAC__OVERFLOW_DETECT_VERBOSE |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 265 | 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 Coalson | 1b68982 | 2001-05-31 20:11:02 +0000 | [diff] [blame] | 270 | FLAC__ASSERT(order > 0); |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 271 | |
| 272 | for(i = 0; i < data_len; i++) { |
Josh Coalson | bb6712e | 2001-04-24 22:54:07 +0000 | [diff] [blame] | 273 | #ifdef FLAC__OVERFLOW_DETECT |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 274 | sumo = 0; |
| 275 | #endif |
| 276 | sum = 0; |
| 277 | history = data; |
| 278 | for(j = 0; j < order; j++) { |
| 279 | sum += qlp_coeff[j] * (*(--history)); |
Josh Coalson | bb6712e | 2001-04-24 22:54:07 +0000 | [diff] [blame] | 280 | #ifdef FLAC__OVERFLOW_DETECT |
Josh Coalson | 77e3f31 | 2001-06-23 03:03:24 +0000 | [diff] [blame] | 281 | sumo += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*history); |
Josh Coalson | b3538c8 | 2003-01-12 08:42:23 +0000 | [diff] [blame] | 282 | #if defined _MSC_VER |
Josh Coalson | 0c671c8 | 2003-01-08 08:04:42 +0000 | [diff] [blame] | 283 | if(sumo > 2147483647I64 || sumo < -2147483648I64) |
Josh Coalson | fec4a77 | 2004-03-22 05:47:25 +0000 | [diff] [blame] | 284 | 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 Coalson | d37acf4 | 2001-07-09 18:22:46 +0000 | [diff] [blame] | 285 | #else |
| 286 | if(sumo > 2147483647ll || sumo < -2147483648ll) |
Josh Coalson | ab56ef1 | 2006-11-17 06:52:19 +0000 | [diff] [blame] | 287 | 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 Coalson | fec4a77 | 2004-03-22 05:47:25 +0000 | [diff] [blame] | 288 | #endif |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 289 | #endif |
| 290 | } |
| 291 | *(residual++) = *(data++) - (sum >> lp_quantization); |
| 292 | } |
| 293 | |
Josh Coalson | 9f77a19 | 2001-02-08 00:26:45 +0000 | [diff] [blame] | 294 | /* Here's a slower but clearer version: |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 295 | for(i = 0; i < data_len; i++) { |
| 296 | sum = 0; |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 297 | for(j = 0; j < order; j++) |
Josh Coalson | 9f77a19 | 2001-02-08 00:26:45 +0000 | [diff] [blame] | 298 | sum += qlp_coeff[j] * data[i-j-1]; |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 299 | residual[i] = data[i] - (sum >> lp_quantization); |
| 300 | } |
| 301 | */ |
| 302 | } |
| 303 | |
Josh Coalson | 7446e18 | 2005-01-26 04:04:38 +0000 | [diff] [blame] | 304 | void 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 Coalson | eac1024 | 2002-10-04 05:25:54 +0000 | [diff] [blame] | 305 | { |
| 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 Coalson | ab56ef1 | 2006-11-17 06:52:19 +0000 | [diff] [blame] | 325 | fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: OVERFLOW, i=%u, sum=%lld\n", i, (long long)(sum >> lp_quantization)); |
Josh Coalson | eac1024 | 2002-10-04 05:25:54 +0000 | [diff] [blame] | 326 | break; |
| 327 | } |
| 328 | if(FLAC__bitmath_silog2_wide((FLAC__int64)(*data) - (sum >> lp_quantization)) > 32) { |
Josh Coalson | ab56ef1 | 2006-11-17 06:52:19 +0000 | [diff] [blame] | 329 | 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 Coalson | eac1024 | 2002-10-04 05:25:54 +0000 | [diff] [blame] | 330 | break; |
| 331 | } |
| 332 | #endif |
| 333 | *(residual++) = *(data++) - (FLAC__int32)(sum >> lp_quantization); |
| 334 | } |
| 335 | } |
| 336 | |
Josh Coalson | 5f2b46d | 2004-11-09 01:34:01 +0000 | [diff] [blame] | 337 | #endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */ |
| 338 | |
Josh Coalson | 77e3f31 | 2001-06-23 03:03:24 +0000 | [diff] [blame] | 339 | void 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 Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 340 | { |
Josh Coalson | bb6712e | 2001-04-24 22:54:07 +0000 | [diff] [blame] | 341 | #ifdef FLAC__OVERFLOW_DETECT |
Josh Coalson | 77e3f31 | 2001-06-23 03:03:24 +0000 | [diff] [blame] | 342 | FLAC__int64 sumo; |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 343 | #endif |
| 344 | unsigned i, j; |
Josh Coalson | 77e3f31 | 2001-06-23 03:03:24 +0000 | [diff] [blame] | 345 | FLAC__int32 sum; |
Josh Coalson | 7581d12 | 2006-11-20 07:19:15 +0000 | [diff] [blame] | 346 | const FLAC__int32 *r = residual, *history; |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 347 | |
Josh Coalson | bb6712e | 2001-04-24 22:54:07 +0000 | [diff] [blame] | 348 | #ifdef FLAC__OVERFLOW_DETECT_VERBOSE |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 349 | 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 Coalson | 1b68982 | 2001-05-31 20:11:02 +0000 | [diff] [blame] | 354 | FLAC__ASSERT(order > 0); |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 355 | |
| 356 | for(i = 0; i < data_len; i++) { |
Josh Coalson | bb6712e | 2001-04-24 22:54:07 +0000 | [diff] [blame] | 357 | #ifdef FLAC__OVERFLOW_DETECT |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 358 | sumo = 0; |
| 359 | #endif |
| 360 | sum = 0; |
Josh Coalson | 9f77a19 | 2001-02-08 00:26:45 +0000 | [diff] [blame] | 361 | history = data; |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 362 | for(j = 0; j < order; j++) { |
| 363 | sum += qlp_coeff[j] * (*(--history)); |
Josh Coalson | bb6712e | 2001-04-24 22:54:07 +0000 | [diff] [blame] | 364 | #ifdef FLAC__OVERFLOW_DETECT |
Josh Coalson | 77e3f31 | 2001-06-23 03:03:24 +0000 | [diff] [blame] | 365 | sumo += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*history); |
Josh Coalson | b3538c8 | 2003-01-12 08:42:23 +0000 | [diff] [blame] | 366 | #if defined _MSC_VER |
Josh Coalson | 0c671c8 | 2003-01-08 08:04:42 +0000 | [diff] [blame] | 367 | if(sumo > 2147483647I64 || sumo < -2147483648I64) |
Josh Coalson | fec4a77 | 2004-03-22 05:47:25 +0000 | [diff] [blame] | 368 | 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 Coalson | d37acf4 | 2001-07-09 18:22:46 +0000 | [diff] [blame] | 369 | #else |
| 370 | if(sumo > 2147483647ll || sumo < -2147483648ll) |
Josh Coalson | ab56ef1 | 2006-11-17 06:52:19 +0000 | [diff] [blame] | 371 | 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 Coalson | fec4a77 | 2004-03-22 05:47:25 +0000 | [diff] [blame] | 372 | #endif |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 373 | #endif |
| 374 | } |
Josh Coalson | 7581d12 | 2006-11-20 07:19:15 +0000 | [diff] [blame] | 375 | *(data++) = *(r++) + (sum >> lp_quantization); |
Josh Coalson | 9f77a19 | 2001-02-08 00:26:45 +0000 | [diff] [blame] | 376 | } |
| 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 Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 383 | data[i] = residual[i] + (sum >> lp_quantization); |
| 384 | } |
Josh Coalson | 9f77a19 | 2001-02-08 00:26:45 +0000 | [diff] [blame] | 385 | */ |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 386 | } |
| 387 | |
Josh Coalson | eac1024 | 2002-10-04 05:25:54 +0000 | [diff] [blame] | 388 | void 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 Coalson | 7581d12 | 2006-11-20 07:19:15 +0000 | [diff] [blame] | 392 | const FLAC__int32 *r = residual, *history; |
Josh Coalson | eac1024 | 2002-10-04 05:25:54 +0000 | [diff] [blame] | 393 | |
| 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 Coalson | ab56ef1 | 2006-11-17 06:52:19 +0000 | [diff] [blame] | 409 | fprintf(stderr,"FLAC__lpc_restore_signal_wide: OVERFLOW, i=%u, sum=%lld\n", i, (long long)(sum >> lp_quantization)); |
Josh Coalson | eac1024 | 2002-10-04 05:25:54 +0000 | [diff] [blame] | 410 | break; |
| 411 | } |
Josh Coalson | 7581d12 | 2006-11-20 07:19:15 +0000 | [diff] [blame] | 412 | 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 Coalson | eac1024 | 2002-10-04 05:25:54 +0000 | [diff] [blame] | 414 | break; |
| 415 | } |
| 416 | #endif |
Josh Coalson | 7581d12 | 2006-11-20 07:19:15 +0000 | [diff] [blame] | 417 | *(data++) = *(r++) + (FLAC__int32)(sum >> lp_quantization); |
Josh Coalson | eac1024 | 2002-10-04 05:25:54 +0000 | [diff] [blame] | 418 | } |
| 419 | } |
| 420 | |
Josh Coalson | 5f2b46d | 2004-11-09 01:34:01 +0000 | [diff] [blame] | 421 | #ifndef FLAC__INTEGER_ONLY_LIBRARY |
| 422 | |
Josh Coalson | 0975843 | 2004-10-20 00:21:50 +0000 | [diff] [blame] | 423 | FLAC__double FLAC__lpc_compute_expected_bits_per_residual_sample(FLAC__double lpc_error, unsigned total_samples) |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 424 | { |
Josh Coalson | 0975843 | 2004-10-20 00:21:50 +0000 | [diff] [blame] | 425 | FLAC__double error_scale; |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 426 | |
Josh Coalson | 1b68982 | 2001-05-31 20:11:02 +0000 | [diff] [blame] | 427 | FLAC__ASSERT(total_samples > 0); |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 428 | |
Josh Coalson | 0975843 | 2004-10-20 00:21:50 +0000 | [diff] [blame] | 429 | error_scale = 0.5 * M_LN2 * M_LN2 / (FLAC__double)total_samples; |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 430 | |
Josh Coalson | ddc5bc7 | 2002-06-05 05:53:17 +0000 | [diff] [blame] | 431 | return FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(lpc_error, error_scale); |
Josh Coalson | a1b53c4 | 2001-05-24 19:27:08 +0000 | [diff] [blame] | 432 | } |
| 433 | |
Josh Coalson | 0975843 | 2004-10-20 00:21:50 +0000 | [diff] [blame] | 434 | FLAC__double FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(FLAC__double lpc_error, FLAC__double error_scale) |
Josh Coalson | a1b53c4 | 2001-05-24 19:27:08 +0000 | [diff] [blame] | 435 | { |
| 436 | if(lpc_error > 0.0) { |
Josh Coalson | 0975843 | 2004-10-20 00:21:50 +0000 | [diff] [blame] | 437 | FLAC__double bps = (FLAC__double)0.5 * log(error_scale * lpc_error) / M_LN2; |
Josh Coalson | a1b53c4 | 2001-05-24 19:27:08 +0000 | [diff] [blame] | 438 | if(bps >= 0.0) |
| 439 | return bps; |
| 440 | else |
| 441 | return 0.0; |
| 442 | } |
Josh Coalson | 0975843 | 2004-10-20 00:21:50 +0000 | [diff] [blame] | 443 | else if(lpc_error < 0.0) { /* error should not be negative but can happen due to inadequate floating-point resolution */ |
| 444 | return 1e32; |
Josh Coalson | a1b53c4 | 2001-05-24 19:27:08 +0000 | [diff] [blame] | 445 | } |
Josh Coalson | 9f77a19 | 2001-02-08 00:26:45 +0000 | [diff] [blame] | 446 | else { |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 447 | return 0.0; |
Josh Coalson | 9f77a19 | 2001-02-08 00:26:45 +0000 | [diff] [blame] | 448 | } |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 449 | } |
| 450 | |
Josh Coalson | 6e2b565 | 2006-04-28 00:11:31 +0000 | [diff] [blame] | 451 | unsigned FLAC__lpc_compute_best_order(const FLAC__double lpc_error[], unsigned max_order, unsigned total_samples, unsigned overhead_bits_per_order) |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 452 | { |
Josh Coalson | 6e2b565 | 2006-04-28 00:11:31 +0000 | [diff] [blame] | 453 | 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 Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 455 | |
Josh Coalson | 1b68982 | 2001-05-31 20:11:02 +0000 | [diff] [blame] | 456 | FLAC__ASSERT(max_order > 0); |
| 457 | FLAC__ASSERT(total_samples > 0); |
Josh Coalson | a1b53c4 | 2001-05-24 19:27:08 +0000 | [diff] [blame] | 458 | |
Josh Coalson | 0975843 | 2004-10-20 00:21:50 +0000 | [diff] [blame] | 459 | error_scale = 0.5 * M_LN2 * M_LN2 / (FLAC__double)total_samples; |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 460 | |
Josh Coalson | 6e2b565 | 2006-04-28 00:11:31 +0000 | [diff] [blame] | 461 | best_index = 0; |
| 462 | best_bits = (unsigned)(-1); |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 463 | |
Josh Coalson | 6e2b565 | 2006-04-28 00:11:31 +0000 | [diff] [blame] | 464 | 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 Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 469 | } |
| 470 | } |
| 471 | |
Josh Coalson | 6e2b565 | 2006-04-28 00:11:31 +0000 | [diff] [blame] | 472 | return best_index+1; /* +1 since index of lpc_error[] is order-1 */ |
Josh Coalson | bb7f6b9 | 2000-12-10 04:09:52 +0000 | [diff] [blame] | 473 | } |
Josh Coalson | 5f2b46d | 2004-11-09 01:34:01 +0000 | [diff] [blame] | 474 | |
| 475 | #endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */ |