1 /* Copyright (C) 2007 Jean-Marc Valin
4 Arbitrary resampling code
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are
10 1. Redistributions of source code must retain the above copyright notice,
11 this list of conditions and the following disclaimer.
13 2. Redistributions in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in the
15 documentation and/or other materials provided with the distribution.
17 3. The name of the author may not be used to endorse or promote products
18 derived from this software without specific prior written permission.
20 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
24 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 POSSIBILITY OF SUCH DAMAGE.
34 The design goals of this code are:
36 - SIMD-friendly algorithm
37 - Low memory requirement
38 - Good *perceptual* quality (and not best SNR)
40 Warning: This resampler is relatively new. Although I think I got rid of
41 all the major bugs and I don't expect the API to change anymore, there
42 may be something I've missed. So use with caution.
44 This algorithm is based on this original resampling algorithm:
45 Smith, Julius O. Digital Audio Resampling Home Page
46 Center for Computer Research in Music and Acoustics (CCRMA),
47 Stanford University, 2007.
48 Web published at http://www-ccrma.stanford.edu/~jos/resample/.
50 There is one main difference, though. This resampler uses cubic
51 interpolation instead of linear interpolation in the above paper. This
52 makes the table much smaller and makes it possible to compute that table
53 on a per-stream basis. In turn, being able to tweak the table for each
54 stream makes it possible to both reduce complexity on simple ratios
55 (e.g. 2/3), and get rid of the rounding operations in the inner loop.
56 The latter both reduces CPU time and makes the algorithm more SIMD-friendly.
60 #include "config-speex.h"
65 static void *speex_alloc (int size
) {return calloc(size
,1);}
66 static void *speex_realloc (void *ptr
, int size
) {return realloc(ptr
, size
);}
67 static void speex_free (void *ptr
) {free(ptr
);}
68 #include "speex_resampler.h"
70 #else /* OUTSIDE_SPEEX */
72 #include "speex/speex_resampler.h"
74 #include "os_support.h"
75 #endif /* OUTSIDE_SPEEX */
80 #define M_PI 3.14159263
84 #define WORD2INT(x) ((x) < -32767 ? -32768 : ((x) > 32766 ? 32767 : (x)))
86 #define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x))))
89 /*#define float double*/
90 #define FILTER_SIZE 64
93 #define IMAX(a,b) ((a) > (b) ? (a) : (b))
94 #define IMIN(a,b) ((a) < (b) ? (a) : (b))
100 typedef int (*resampler_basic_func
)(SpeexResamplerState
*, spx_uint32_t
, const spx_word16_t
*, spx_uint32_t
*, spx_word16_t
*, spx_uint32_t
*);
102 struct SpeexResamplerState_
{
103 spx_uint32_t in_rate
;
104 spx_uint32_t out_rate
;
105 spx_uint32_t num_rate
;
106 spx_uint32_t den_rate
;
109 spx_uint32_t nb_channels
;
110 spx_uint32_t filt_len
;
111 spx_uint32_t mem_alloc_size
;
115 spx_uint32_t oversample
;
119 /* These are per-channel */
120 spx_int32_t
*last_sample
;
121 spx_uint32_t
*samp_frac_num
;
122 spx_uint32_t
*magic_samples
;
125 spx_word16_t
*sinc_table
;
126 spx_uint32_t sinc_table_length
;
127 resampler_basic_func resampler_ptr
;
133 static double kaiser12_table
[68] = {
134 0.99859849, 1.00000000, 0.99859849, 0.99440475, 0.98745105, 0.97779076,
135 0.96549770, 0.95066529, 0.93340547, 0.91384741, 0.89213598, 0.86843014,
136 0.84290116, 0.81573067, 0.78710866, 0.75723148, 0.72629970, 0.69451601,
137 0.66208321, 0.62920216, 0.59606986, 0.56287762, 0.52980938, 0.49704014,
138 0.46473455, 0.43304576, 0.40211431, 0.37206735, 0.34301800, 0.31506490,
139 0.28829195, 0.26276832, 0.23854851, 0.21567274, 0.19416736, 0.17404546,
140 0.15530766, 0.13794294, 0.12192957, 0.10723616, 0.09382272, 0.08164178,
141 0.07063950, 0.06075685, 0.05193064, 0.04409466, 0.03718069, 0.03111947,
142 0.02584161, 0.02127838, 0.01736250, 0.01402878, 0.01121463, 0.00886058,
143 0.00691064, 0.00531256, 0.00401805, 0.00298291, 0.00216702, 0.00153438,
144 0.00105297, 0.00069463, 0.00043489, 0.00025272, 0.00013031, 0.0000527734,
145 0.00001000, 0.00000000};
147 static double kaiser12_table[36] = {
148 0.99440475, 1.00000000, 0.99440475, 0.97779076, 0.95066529, 0.91384741,
149 0.86843014, 0.81573067, 0.75723148, 0.69451601, 0.62920216, 0.56287762,
150 0.49704014, 0.43304576, 0.37206735, 0.31506490, 0.26276832, 0.21567274,
151 0.17404546, 0.13794294, 0.10723616, 0.08164178, 0.06075685, 0.04409466,
152 0.03111947, 0.02127838, 0.01402878, 0.00886058, 0.00531256, 0.00298291,
153 0.00153438, 0.00069463, 0.00025272, 0.0000527734, 0.00000500, 0.00000000};
155 static double kaiser10_table
[36] = {
156 0.99537781, 1.00000000, 0.99537781, 0.98162644, 0.95908712, 0.92831446,
157 0.89005583, 0.84522401, 0.79486424, 0.74011713, 0.68217934, 0.62226347,
158 0.56155915, 0.50119680, 0.44221549, 0.38553619, 0.33194107, 0.28205962,
159 0.23636152, 0.19515633, 0.15859932, 0.12670280, 0.09935205, 0.07632451,
160 0.05731132, 0.04193980, 0.02979584, 0.02044510, 0.01345224, 0.00839739,
161 0.00488951, 0.00257636, 0.00115101, 0.00035515, 0.00000000, 0.00000000};
163 static double kaiser8_table
[36] = {
164 0.99635258, 1.00000000, 0.99635258, 0.98548012, 0.96759014, 0.94302200,
165 0.91223751, 0.87580811, 0.83439927, 0.78875245, 0.73966538, 0.68797126,
166 0.63451750, 0.58014482, 0.52566725, 0.47185369, 0.41941150, 0.36897272,
167 0.32108304, 0.27619388, 0.23465776, 0.19672670, 0.16255380, 0.13219758,
168 0.10562887, 0.08273982, 0.06335451, 0.04724088, 0.03412321, 0.02369490,
169 0.01563093, 0.00959968, 0.00527363, 0.00233883, 0.00050000, 0.00000000};
171 static double kaiser6_table
[36] = {
172 0.99733006, 1.00000000, 0.99733006, 0.98935595, 0.97618418, 0.95799003,
173 0.93501423, 0.90755855, 0.87598009, 0.84068475, 0.80211977, 0.76076565,
174 0.71712752, 0.67172623, 0.62508937, 0.57774224, 0.53019925, 0.48295561,
175 0.43647969, 0.39120616, 0.34752997, 0.30580127, 0.26632152, 0.22934058,
176 0.19505503, 0.16360756, 0.13508755, 0.10953262, 0.08693120, 0.06722600,
177 0.05031820, 0.03607231, 0.02432151, 0.01487334, 0.00752000, 0.00000000};
184 static struct FuncDef _KAISER12
= {kaiser12_table
, 64};
185 #define KAISER12 (&_KAISER12)
186 /*static struct FuncDef _KAISER12 = {kaiser12_table, 32};
187 #define KAISER12 (&_KAISER12)*/
188 static struct FuncDef _KAISER10
= {kaiser10_table
, 32};
189 #define KAISER10 (&_KAISER10)
190 static struct FuncDef _KAISER8
= {kaiser8_table
, 32};
191 #define KAISER8 (&_KAISER8)
192 static struct FuncDef _KAISER6
= {kaiser6_table
, 32};
193 #define KAISER6 (&_KAISER6)
195 struct QualityMapping
{
198 float downsample_bandwidth
;
199 float upsample_bandwidth
;
200 struct FuncDef
*window_func
;
204 /* This table maps conversion quality to internal parameters. There are two
205 reasons that explain why the up-sampling bandwidth is larger than the
206 down-sampling bandwidth:
207 1) When up-sampling, we can assume that the spectrum is already attenuated
208 close to the Nyquist rate (from an A/D or a previous resampling filter)
209 2) Any aliasing that occurs very close to the Nyquist rate will be masked
210 by the sinusoids/noise just below the Nyquist rate (guaranteed only for
213 static const struct QualityMapping quality_map
[11] = {
214 { 8, 4, 0.830f
, 0.860f
, KAISER6
}, /* Q0 */
215 { 16, 4, 0.850f
, 0.880f
, KAISER6
}, /* Q1 */
216 { 32, 4, 0.882f
, 0.910f
, KAISER6
}, /* Q2 */ /* 82.3% cutoff ( ~60 dB stop) 6 */
217 { 48, 8, 0.895f
, 0.917f
, KAISER8
}, /* Q3 */ /* 84.9% cutoff ( ~80 dB stop) 8 */
218 { 64, 8, 0.921f
, 0.940f
, KAISER8
}, /* Q4 */ /* 88.7% cutoff ( ~80 dB stop) 8 */
219 { 80, 16, 0.922f
, 0.940f
, KAISER10
}, /* Q5 */ /* 89.1% cutoff (~100 dB stop) 10 */
220 { 96, 16, 0.940f
, 0.945f
, KAISER10
}, /* Q6 */ /* 91.5% cutoff (~100 dB stop) 10 */
221 {128, 16, 0.950f
, 0.950f
, KAISER10
}, /* Q7 */ /* 93.1% cutoff (~100 dB stop) 10 */
222 {160, 16, 0.960f
, 0.960f
, KAISER10
}, /* Q8 */ /* 94.5% cutoff (~100 dB stop) 10 */
223 {192, 32, 0.968f
, 0.968f
, KAISER12
}, /* Q9 */ /* 95.5% cutoff (~100 dB stop) 10 */
224 {256, 32, 0.975f
, 0.975f
, KAISER12
}, /* Q10 */ /* 96.6% cutoff (~100 dB stop) 10 */
226 /*8,24,40,56,80,104,128,160,200,256,320*/
227 static double compute_func(float x
, struct FuncDef
*func
)
232 y
= x
*func
->oversample
;
235 /* CSE with handle the repeated powers */
236 interp
[3] = -0.1666666667*frac
+ 0.1666666667*(frac
*frac
*frac
);
237 interp
[2] = frac
+ 0.5*(frac
*frac
) - 0.5*(frac
*frac
*frac
);
238 /*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/
239 interp
[0] = -0.3333333333*frac
+ 0.5*(frac
*frac
) - 0.1666666667*(frac
*frac
*frac
);
240 /* Just to make sure we don't have rounding problems */
241 interp
[1] = 1.f
-interp
[3]-interp
[2]-interp
[0];
243 /*sum = frac*accum[1] + (1-frac)*accum[2];*/
244 return interp
[0]*func
->table
[ind
] + interp
[1]*func
->table
[ind
+1] + interp
[2]*func
->table
[ind
+2] + interp
[3]*func
->table
[ind
+3];
249 int main(int argc
, char **argv
)
254 printf ("%f\n", compute_func(i
/256., KAISER12
));
261 /* The slow way of computing a sinc for the table. Should improve that some day */
262 static spx_word16_t
sinc(float cutoff
, float x
, int N
, struct FuncDef
*window_func
)
264 /*fprintf (stderr, "%f ", x);*/
265 float xx
= x
* cutoff
;
267 return WORD2INT(32768.*cutoff
);
268 else if (fabs(x
) > .5f
*N
)
270 /*FIXME: Can it really be any slower than this? */
271 return WORD2INT(32768.*cutoff
*sin(M_PI
*xx
)/(M_PI
*xx
) * compute_func(fabs(2.*x
/N
), window_func
));
274 /* The slow way of computing a sinc for the table. Should improve that some day */
275 static spx_word16_t
sinc(float cutoff
, float x
, int N
, struct FuncDef
*window_func
)
277 /*fprintf (stderr, "%f ", x);*/
278 float xx
= x
* cutoff
;
281 else if (fabs(x
) > .5*N
)
283 /*FIXME: Can it really be any slower than this? */
284 return cutoff
*sin(M_PI
*xx
)/(M_PI
*xx
) * compute_func(fabs(2.*x
/N
), window_func
);
289 static void cubic_coef(spx_word16_t x
, spx_word16_t interp
[4])
291 /* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation
292 but I know it's MMSE-optimal on a sinc */
294 x2
= MULT16_16_P15(x
, x
);
295 x3
= MULT16_16_P15(x
, x2
);
296 interp
[0] = PSHR32(MULT16_16(QCONST16(-0.16667f
, 15),x
) + MULT16_16(QCONST16(0.16667f
, 15),x3
),15);
297 interp
[1] = EXTRACT16(EXTEND32(x
) + SHR32(SUB32(EXTEND32(x2
),EXTEND32(x3
)),1));
298 interp
[3] = PSHR32(MULT16_16(QCONST16(-0.33333f
, 15),x
) + MULT16_16(QCONST16(.5f
,15),x2
) - MULT16_16(QCONST16(0.16667f
, 15),x3
),15);
299 /* Just to make sure we don't have rounding problems */
300 interp
[2] = Q15_ONE
-interp
[0]-interp
[1]-interp
[3];
305 static void cubic_coef(spx_word16_t frac
, spx_word16_t interp
[4])
307 /* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation
308 but I know it's MMSE-optimal on a sinc */
309 interp
[0] = -0.16667f
*frac
+ 0.16667f
*frac
*frac
*frac
;
310 interp
[1] = frac
+ 0.5f
*frac
*frac
- 0.5f
*frac
*frac
*frac
;
311 /*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/
312 interp
[3] = -0.33333f
*frac
+ 0.5f
*frac
*frac
- 0.16667f
*frac
*frac
*frac
;
313 /* Just to make sure we don't have rounding problems */
314 interp
[2] = 1.-interp
[0]-interp
[1]-interp
[3];
318 static int resampler_basic_direct_single(SpeexResamplerState
*st
, spx_uint32_t channel_index
, const spx_word16_t
*in
, spx_uint32_t
*in_len
, spx_word16_t
*out
, spx_uint32_t
*out_len
)
320 int N
= st
->filt_len
;
323 int last_sample
= st
->last_sample
[channel_index
];
324 spx_uint32_t samp_frac_num
= st
->samp_frac_num
[channel_index
];
325 mem
= st
->mem
+ channel_index
* st
->mem_alloc_size
;
326 while (!(last_sample
>= (spx_int32_t
)*in_len
|| out_sample
>= (spx_int32_t
)*out_len
))
331 /* We already have all the filter coefficients pre-computed in the table */
332 const spx_word16_t
*ptr
;
333 /* Do the memory part */
334 for (j
=0;last_sample
-N
+1+j
< 0;j
++)
336 sum
+= MULT16_16(mem
[last_sample
+j
],st
->sinc_table
[samp_frac_num
*st
->filt_len
+j
]);
339 /* Do the new part */
342 ptr
= in
+st
->in_stride
*(last_sample
-N
+1+j
);
345 sum
+= MULT16_16(*ptr
,st
->sinc_table
[samp_frac_num
*st
->filt_len
+j
]);
346 ptr
+= st
->in_stride
;
350 *out
= PSHR32(sum
,15);
351 out
+= st
->out_stride
;
353 last_sample
+= st
->int_advance
;
354 samp_frac_num
+= st
->frac_advance
;
355 if (samp_frac_num
>= st
->den_rate
)
357 samp_frac_num
-= st
->den_rate
;
361 st
->last_sample
[channel_index
] = last_sample
;
362 st
->samp_frac_num
[channel_index
] = samp_frac_num
;
368 /* This is the same as the previous function, except with a double-precision accumulator */
369 static int resampler_basic_direct_double(SpeexResamplerState
*st
, spx_uint32_t channel_index
, const spx_word16_t
*in
, spx_uint32_t
*in_len
, spx_word16_t
*out
, spx_uint32_t
*out_len
)
371 int N
= st
->filt_len
;
374 int last_sample
= st
->last_sample
[channel_index
];
375 spx_uint32_t samp_frac_num
= st
->samp_frac_num
[channel_index
];
376 mem
= st
->mem
+ channel_index
* st
->mem_alloc_size
;
377 while (!(last_sample
>= (spx_int32_t
)*in_len
|| out_sample
>= (spx_int32_t
)*out_len
))
382 /* We already have all the filter coefficients pre-computed in the table */
383 const spx_word16_t
*ptr
;
384 /* Do the memory part */
385 for (j
=0;last_sample
-N
+1+j
< 0;j
++)
387 sum
+= MULT16_16(mem
[last_sample
+j
],(double)st
->sinc_table
[samp_frac_num
*st
->filt_len
+j
]);
390 /* Do the new part */
393 ptr
= in
+st
->in_stride
*(last_sample
-N
+1+j
);
396 sum
+= MULT16_16(*ptr
,(double)st
->sinc_table
[samp_frac_num
*st
->filt_len
+j
]);
397 ptr
+= st
->in_stride
;
402 out
+= st
->out_stride
;
404 last_sample
+= st
->int_advance
;
405 samp_frac_num
+= st
->frac_advance
;
406 if (samp_frac_num
>= st
->den_rate
)
408 samp_frac_num
-= st
->den_rate
;
412 st
->last_sample
[channel_index
] = last_sample
;
413 st
->samp_frac_num
[channel_index
] = samp_frac_num
;
418 static int resampler_basic_interpolate_single(SpeexResamplerState
*st
, spx_uint32_t channel_index
, const spx_word16_t
*in
, spx_uint32_t
*in_len
, spx_word16_t
*out
, spx_uint32_t
*out_len
)
420 int N
= st
->filt_len
;
423 int last_sample
= st
->last_sample
[channel_index
];
424 spx_uint32_t samp_frac_num
= st
->samp_frac_num
[channel_index
];
425 mem
= st
->mem
+ channel_index
* st
->mem_alloc_size
;
426 while (!(last_sample
>= (spx_int32_t
)*in_len
|| out_sample
>= (spx_int32_t
)*out_len
))
431 /* We need to interpolate the sinc filter */
432 spx_word32_t accum
[4] = {0.f
,0.f
, 0.f
, 0.f
};
433 spx_word16_t interp
[4];
434 const spx_word16_t
*ptr
;
437 offset
= samp_frac_num
*st
->oversample
/st
->den_rate
;
439 frac
= PDIV32(SHL32((samp_frac_num
*st
->oversample
) % st
->den_rate
,15),st
->den_rate
);
441 frac
= ((float)((samp_frac_num
*st
->oversample
) % st
->den_rate
))/st
->den_rate
;
443 /* This code is written like this to make it easy to optimise with SIMD.
444 For most DSPs, it would be best to split the loops in two because most DSPs
445 have only two accumulators */
446 for (j
=0;last_sample
-N
+1+j
< 0;j
++)
448 spx_word16_t curr_mem
= mem
[last_sample
+j
];
449 accum
[0] += MULT16_16(curr_mem
,st
->sinc_table
[4+(j
+1)*st
->oversample
-offset
-2]);
450 accum
[1] += MULT16_16(curr_mem
,st
->sinc_table
[4+(j
+1)*st
->oversample
-offset
-1]);
451 accum
[2] += MULT16_16(curr_mem
,st
->sinc_table
[4+(j
+1)*st
->oversample
-offset
]);
452 accum
[3] += MULT16_16(curr_mem
,st
->sinc_table
[4+(j
+1)*st
->oversample
-offset
+1]);
457 ptr
= in
+st
->in_stride
*(last_sample
-N
+1+j
);
458 /* Do the new part */
461 spx_word16_t curr_in
= *ptr
;
462 ptr
+= st
->in_stride
;
463 accum
[0] += MULT16_16(curr_in
,st
->sinc_table
[4+(j
+1)*st
->oversample
-offset
-2]);
464 accum
[1] += MULT16_16(curr_in
,st
->sinc_table
[4+(j
+1)*st
->oversample
-offset
-1]);
465 accum
[2] += MULT16_16(curr_in
,st
->sinc_table
[4+(j
+1)*st
->oversample
-offset
]);
466 accum
[3] += MULT16_16(curr_in
,st
->sinc_table
[4+(j
+1)*st
->oversample
-offset
+1]);
469 cubic_coef(frac
, interp
);
470 sum
= MULT16_32_Q15(interp
[0],accum
[0]) + MULT16_32_Q15(interp
[1],accum
[1]) + MULT16_32_Q15(interp
[2],accum
[2]) + MULT16_32_Q15(interp
[3],accum
[3]);
472 *out
= PSHR32(sum
,15);
473 out
+= st
->out_stride
;
475 last_sample
+= st
->int_advance
;
476 samp_frac_num
+= st
->frac_advance
;
477 if (samp_frac_num
>= st
->den_rate
)
479 samp_frac_num
-= st
->den_rate
;
483 st
->last_sample
[channel_index
] = last_sample
;
484 st
->samp_frac_num
[channel_index
] = samp_frac_num
;
490 /* This is the same as the previous function, except with a double-precision accumulator */
491 static int resampler_basic_interpolate_double(SpeexResamplerState
*st
, spx_uint32_t channel_index
, const spx_word16_t
*in
, spx_uint32_t
*in_len
, spx_word16_t
*out
, spx_uint32_t
*out_len
)
493 int N
= st
->filt_len
;
496 int last_sample
= st
->last_sample
[channel_index
];
497 spx_uint32_t samp_frac_num
= st
->samp_frac_num
[channel_index
];
498 mem
= st
->mem
+ channel_index
* st
->mem_alloc_size
;
499 while (!(last_sample
>= (spx_int32_t
)*in_len
|| out_sample
>= (spx_int32_t
)*out_len
))
504 /* We need to interpolate the sinc filter */
505 double accum
[4] = {0.f
,0.f
, 0.f
, 0.f
};
507 const spx_word16_t
*ptr
;
508 float alpha
= ((float)samp_frac_num
)/st
->den_rate
;
509 int offset
= samp_frac_num
*st
->oversample
/st
->den_rate
;
510 float frac
= alpha
*st
->oversample
- offset
;
511 /* This code is written like this to make it easy to optimise with SIMD.
512 For most DSPs, it would be best to split the loops in two because most DSPs
513 have only two accumulators */
514 for (j
=0;last_sample
-N
+1+j
< 0;j
++)
516 double curr_mem
= mem
[last_sample
+j
];
517 accum
[0] += MULT16_16(curr_mem
,st
->sinc_table
[4+(j
+1)*st
->oversample
-offset
-2]);
518 accum
[1] += MULT16_16(curr_mem
,st
->sinc_table
[4+(j
+1)*st
->oversample
-offset
-1]);
519 accum
[2] += MULT16_16(curr_mem
,st
->sinc_table
[4+(j
+1)*st
->oversample
-offset
]);
520 accum
[3] += MULT16_16(curr_mem
,st
->sinc_table
[4+(j
+1)*st
->oversample
-offset
+1]);
524 ptr
= in
+st
->in_stride
*(last_sample
-N
+1+j
);
525 /* Do the new part */
528 double curr_in
= *ptr
;
529 ptr
+= st
->in_stride
;
530 accum
[0] += MULT16_16(curr_in
,st
->sinc_table
[4+(j
+1)*st
->oversample
-offset
-2]);
531 accum
[1] += MULT16_16(curr_in
,st
->sinc_table
[4+(j
+1)*st
->oversample
-offset
-1]);
532 accum
[2] += MULT16_16(curr_in
,st
->sinc_table
[4+(j
+1)*st
->oversample
-offset
]);
533 accum
[3] += MULT16_16(curr_in
,st
->sinc_table
[4+(j
+1)*st
->oversample
-offset
+1]);
536 cubic_coef(frac
, interp
);
537 sum
= interp
[0]*accum
[0] + interp
[1]*accum
[1] + interp
[2]*accum
[2] + interp
[3]*accum
[3];
539 *out
= PSHR32(sum
,15);
540 out
+= st
->out_stride
;
542 last_sample
+= st
->int_advance
;
543 samp_frac_num
+= st
->frac_advance
;
544 if (samp_frac_num
>= st
->den_rate
)
546 samp_frac_num
-= st
->den_rate
;
550 st
->last_sample
[channel_index
] = last_sample
;
551 st
->samp_frac_num
[channel_index
] = samp_frac_num
;
556 static void update_filter(SpeexResamplerState
*st
)
558 spx_uint32_t old_length
;
560 old_length
= st
->filt_len
;
561 st
->oversample
= quality_map
[st
->quality
].oversample
;
562 st
->filt_len
= quality_map
[st
->quality
].base_length
;
564 if (st
->num_rate
> st
->den_rate
)
567 st
->cutoff
= quality_map
[st
->quality
].downsample_bandwidth
* st
->den_rate
/ st
->num_rate
;
568 /* FIXME: divide the numerator and denominator by a certain amount if they're too large */
569 st
->filt_len
= st
->filt_len
*st
->num_rate
/ st
->den_rate
;
570 /* Round down to make sure we have a multiple of 4 */
571 st
->filt_len
&= (~0x3);
572 if (2*st
->den_rate
< st
->num_rate
)
573 st
->oversample
>>= 1;
574 if (4*st
->den_rate
< st
->num_rate
)
575 st
->oversample
>>= 1;
576 if (8*st
->den_rate
< st
->num_rate
)
577 st
->oversample
>>= 1;
578 if (16*st
->den_rate
< st
->num_rate
)
579 st
->oversample
>>= 1;
580 if (st
->oversample
< 1)
584 st
->cutoff
= quality_map
[st
->quality
].upsample_bandwidth
;
587 /* Choose the resampling type that requires the least amount of memory */
588 if (st
->den_rate
<= st
->oversample
)
592 st
->sinc_table
= (spx_word16_t
*)speex_alloc(st
->filt_len
*st
->den_rate
*sizeof(spx_word16_t
));
593 else if (st
->sinc_table_length
< st
->filt_len
*st
->den_rate
)
595 st
->sinc_table
= (spx_word16_t
*)speex_realloc(st
->sinc_table
,st
->filt_len
*st
->den_rate
*sizeof(spx_word16_t
));
596 st
->sinc_table_length
= st
->filt_len
*st
->den_rate
;
598 for (i
=0;i
<st
->den_rate
;i
++)
601 for (j
=0;j
<st
->filt_len
;j
++)
603 st
->sinc_table
[i
*st
->filt_len
+j
] = sinc(st
->cutoff
,((j
-(spx_int32_t
)st
->filt_len
/2+1)-((float)i
)/st
->den_rate
), st
->filt_len
, quality_map
[st
->quality
].window_func
);
607 st
->resampler_ptr
= resampler_basic_direct_single
;
610 st
->resampler_ptr
= resampler_basic_direct_double
;
612 st
->resampler_ptr
= resampler_basic_direct_single
;
614 /*fprintf (stderr, "resampler uses direct sinc table and normalised cutoff %f\n", cutoff);*/
618 st
->sinc_table
= (spx_word16_t
*)speex_alloc((st
->filt_len
*st
->oversample
+8)*sizeof(spx_word16_t
));
619 else if (st
->sinc_table_length
< st
->filt_len
*st
->oversample
+8)
621 st
->sinc_table
= (spx_word16_t
*)speex_realloc(st
->sinc_table
,(st
->filt_len
*st
->oversample
+8)*sizeof(spx_word16_t
));
622 st
->sinc_table_length
= st
->filt_len
*st
->oversample
+8;
624 for (i
=-4;i
<(spx_int32_t
)(st
->oversample
*st
->filt_len
+4);i
++)
625 st
->sinc_table
[i
+4] = sinc(st
->cutoff
,(i
/(float)st
->oversample
- st
->filt_len
/2), st
->filt_len
, quality_map
[st
->quality
].window_func
);
627 st
->resampler_ptr
= resampler_basic_interpolate_single
;
630 st
->resampler_ptr
= resampler_basic_interpolate_double
;
632 st
->resampler_ptr
= resampler_basic_interpolate_single
;
634 /*fprintf (stderr, "resampler uses interpolated sinc table and normalised cutoff %f\n", cutoff);*/
636 st
->int_advance
= st
->num_rate
/st
->den_rate
;
637 st
->frac_advance
= st
->num_rate
%st
->den_rate
;
640 /* Here's the place where we update the filter memory to take into account
641 the change in filter length. It's probably the messiest part of the code
642 due to handling of lots of corner cases. */
646 st
->mem
= (spx_word16_t
*)speex_alloc(st
->nb_channels
*(st
->filt_len
-1) * sizeof(spx_word16_t
));
647 for (i
=0;i
<st
->nb_channels
*(st
->filt_len
-1);i
++)
649 st
->mem_alloc_size
= st
->filt_len
-1;
650 /*speex_warning("init filter");*/
651 } else if (!st
->started
)
654 st
->mem
= (spx_word16_t
*)speex_realloc(st
->mem
, st
->nb_channels
*(st
->filt_len
-1) * sizeof(spx_word16_t
));
655 for (i
=0;i
<st
->nb_channels
*(st
->filt_len
-1);i
++)
657 st
->mem_alloc_size
= st
->filt_len
-1;
658 /*speex_warning("reinit filter");*/
659 } else if (st
->filt_len
> old_length
)
662 /* Increase the filter length */
663 /*speex_warning("increase filter size");*/
664 int old_alloc_size
= st
->mem_alloc_size
;
665 if (st
->filt_len
-1 > st
->mem_alloc_size
)
667 st
->mem
= (spx_word16_t
*)speex_realloc(st
->mem
, st
->nb_channels
*(st
->filt_len
-1) * sizeof(spx_word16_t
));
668 st
->mem_alloc_size
= st
->filt_len
-1;
670 for (i
=st
->nb_channels
-1;i
>=0;i
--)
673 spx_uint32_t olen
= old_length
;
674 /*if (st->magic_samples[i])*/
676 /* Try and remove the magic samples as if nothing had happened */
678 /* FIXME: This is wrong but for now we need it to avoid going over the array bounds */
679 olen
= old_length
+ 2*st
->magic_samples
[i
];
680 for (j
=old_length
-2+st
->magic_samples
[i
];j
>=0;j
--)
681 st
->mem
[i
*st
->mem_alloc_size
+j
+st
->magic_samples
[i
]] = st
->mem
[i
*old_alloc_size
+j
];
682 for (j
=0;j
<st
->magic_samples
[i
];j
++)
683 st
->mem
[i
*st
->mem_alloc_size
+j
] = 0;
684 st
->magic_samples
[i
] = 0;
686 if (st
->filt_len
> olen
)
688 /* If the new filter length is still bigger than the "augmented" length */
689 /* Copy data going backward */
690 for (j
=0;j
<olen
-1;j
++)
691 st
->mem
[i
*st
->mem_alloc_size
+(st
->filt_len
-2-j
)] = st
->mem
[i
*st
->mem_alloc_size
+(olen
-2-j
)];
692 /* Then put zeros for lack of anything better */
693 for (;j
<st
->filt_len
-1;j
++)
694 st
->mem
[i
*st
->mem_alloc_size
+(st
->filt_len
-2-j
)] = 0;
695 /* Adjust last_sample */
696 st
->last_sample
[i
] += (st
->filt_len
- olen
)/2;
698 /* Put back some of the magic! */
699 st
->magic_samples
[i
] = (olen
- st
->filt_len
)/2;
700 for (j
=0;j
<st
->filt_len
-1+st
->magic_samples
[i
];j
++)
701 st
->mem
[i
*st
->mem_alloc_size
+j
] = st
->mem
[i
*st
->mem_alloc_size
+j
+st
->magic_samples
[i
]];
704 } else if (st
->filt_len
< old_length
)
707 /* Reduce filter length, this a bit tricky. We need to store some of the memory as "magic"
708 samples so they can be used directly as input the next time(s) */
709 for (i
=0;i
<st
->nb_channels
;i
++)
712 spx_uint32_t old_magic
= st
->magic_samples
[i
];
713 st
->magic_samples
[i
] = (old_length
- st
->filt_len
)/2;
714 /* We must copy some of the memory that's no longer used */
715 /* Copy data going backward */
716 for (j
=0;j
<st
->filt_len
-1+st
->magic_samples
[i
]+old_magic
;j
++)
717 st
->mem
[i
*st
->mem_alloc_size
+j
] = st
->mem
[i
*st
->mem_alloc_size
+j
+st
->magic_samples
[i
]];
718 st
->magic_samples
[i
] += old_magic
;
724 SpeexResamplerState
*speex_resampler_init(spx_uint32_t nb_channels
, spx_uint32_t in_rate
, spx_uint32_t out_rate
, int quality
, int *err
)
726 return speex_resampler_init_frac(nb_channels
, in_rate
, out_rate
, in_rate
, out_rate
, quality
, err
);
729 SpeexResamplerState
*speex_resampler_init_frac(spx_uint32_t nb_channels
, spx_uint32_t ratio_num
, spx_uint32_t ratio_den
, spx_uint32_t in_rate
, spx_uint32_t out_rate
, int quality
, int *err
)
732 SpeexResamplerState
*st
;
733 if (quality
> 10 || quality
< 0)
736 *err
= RESAMPLER_ERR_INVALID_ARG
;
739 st
= (SpeexResamplerState
*)speex_alloc(sizeof(SpeexResamplerState
));
747 st
->sinc_table_length
= 0;
748 st
->mem_alloc_size
= 0;
751 st
->resampler_ptr
= 0;
754 st
->nb_channels
= nb_channels
;
758 /* Per channel data */
759 st
->last_sample
= (spx_int32_t
*)speex_alloc(nb_channels
*sizeof(int));
760 st
->magic_samples
= (spx_uint32_t
*)speex_alloc(nb_channels
*sizeof(int));
761 st
->samp_frac_num
= (spx_uint32_t
*)speex_alloc(nb_channels
*sizeof(int));
762 for (i
=0;i
<nb_channels
;i
++)
764 st
->last_sample
[i
] = 0;
765 st
->magic_samples
[i
] = 0;
766 st
->samp_frac_num
[i
] = 0;
769 speex_resampler_set_quality(st
, quality
);
770 speex_resampler_set_rate_frac(st
, ratio_num
, ratio_den
, in_rate
, out_rate
);
777 *err
= RESAMPLER_ERR_SUCCESS
;
782 void speex_resampler_destroy(SpeexResamplerState
*st
)
785 speex_free(st
->sinc_table
);
786 speex_free(st
->last_sample
);
787 speex_free(st
->magic_samples
);
788 speex_free(st
->samp_frac_num
);
794 static int speex_resampler_process_native(SpeexResamplerState
*st
, spx_uint32_t channel_index
, const spx_word16_t
*in
, spx_uint32_t
*in_len
, spx_word16_t
*out
, spx_uint32_t
*out_len
)
797 int N
= st
->filt_len
;
800 spx_uint32_t tmp_out_len
= 0;
801 mem
= st
->mem
+ channel_index
* st
->mem_alloc_size
;
804 /* Handle the case where we have samples left from a reduction in filter length */
805 if (st
->magic_samples
[channel_index
])
808 spx_uint32_t tmp_in_len
;
809 spx_uint32_t tmp_magic
;
811 istride_save
= st
->in_stride
;
812 tmp_in_len
= st
->magic_samples
[channel_index
];
813 tmp_out_len
= *out_len
;
814 /* magic_samples needs to be set to zero to avoid infinite recursion */
815 tmp_magic
= st
->magic_samples
[channel_index
];
816 st
->magic_samples
[channel_index
] = 0;
818 speex_resampler_process_native(st
, channel_index
, mem
+N
-1, &tmp_in_len
, out
, &tmp_out_len
);
819 st
->in_stride
= istride_save
;
820 /*speex_warning_int("extra samples:", tmp_out_len);*/
821 /* If we couldn't process all "magic" input samples, save the rest for next time */
822 if (tmp_in_len
< tmp_magic
)
825 st
->magic_samples
[channel_index
] = tmp_magic
-tmp_in_len
;
826 for (i
=0;i
<st
->magic_samples
[channel_index
];i
++)
827 mem
[N
-1+i
]=mem
[N
-1+i
+tmp_in_len
];
829 out
+= tmp_out_len
*st
->out_stride
;
830 *out_len
-= tmp_out_len
;
833 /* Call the right resampler through the function ptr */
834 out_sample
= st
->resampler_ptr(st
, channel_index
, in
, in_len
, out
, out_len
);
836 if (st
->last_sample
[channel_index
] < (spx_int32_t
)*in_len
)
837 *in_len
= st
->last_sample
[channel_index
];
838 *out_len
= out_sample
+tmp_out_len
;
839 st
->last_sample
[channel_index
] -= *in_len
;
841 for (j
=0;j
<N
-1-(spx_int32_t
)*in_len
;j
++)
842 mem
[j
] = mem
[j
+*in_len
];
844 mem
[j
] = in
[st
->in_stride
*(j
+*in_len
-N
+1)];
846 return RESAMPLER_ERR_SUCCESS
;
849 #define FIXED_STACK_ALLOC 1024
852 int speex_resampler_process_float(SpeexResamplerState
*st
, spx_uint32_t channel_index
, const float *in
, spx_uint32_t
*in_len
, float *out
, spx_uint32_t
*out_len
)
855 int istride_save
, ostride_save
;
857 spx_word16_t x
[*in_len
];
858 spx_word16_t y
[*out_len
];
859 /*VARDECL(spx_word16_t *x);
860 VARDECL(spx_word16_t *y);
861 ALLOC(x, *in_len, spx_word16_t);
862 ALLOC(y, *out_len, spx_word16_t);*/
863 istride_save
= st
->in_stride
;
864 ostride_save
= st
->out_stride
;
865 for (i
=0;i
<*in_len
;i
++)
866 x
[i
] = WORD2INT(in
[i
*st
->in_stride
]);
867 st
->in_stride
= st
->out_stride
= 1;
868 speex_resampler_process_native(st
, channel_index
, x
, in_len
, y
, out_len
);
869 st
->in_stride
= istride_save
;
870 st
->out_stride
= ostride_save
;
871 for (i
=0;i
<*out_len
;i
++)
872 out
[i
*st
->out_stride
] = y
[i
];
874 spx_word16_t x
[FIXED_STACK_ALLOC
];
875 spx_word16_t y
[FIXED_STACK_ALLOC
];
876 spx_uint32_t ilen
=*in_len
, olen
=*out_len
;
877 istride_save
= st
->in_stride
;
878 ostride_save
= st
->out_stride
;
881 spx_uint32_t ichunk
, ochunk
;
884 if (ichunk
>FIXED_STACK_ALLOC
)
885 ichunk
=FIXED_STACK_ALLOC
;
886 if (ochunk
>FIXED_STACK_ALLOC
)
887 ochunk
=FIXED_STACK_ALLOC
;
888 for (i
=0;i
<ichunk
;i
++)
889 x
[i
] = WORD2INT(in
[i
*st
->in_stride
]);
890 st
->in_stride
= st
->out_stride
= 1;
891 speex_resampler_process_native(st
, channel_index
, x
, &ichunk
, y
, &ochunk
);
892 st
->in_stride
= istride_save
;
893 st
->out_stride
= ostride_save
;
894 for (i
=0;i
<ochunk
;i
++)
895 out
[i
*st
->out_stride
] = y
[i
];
904 return RESAMPLER_ERR_SUCCESS
;
906 int speex_resampler_process_int(SpeexResamplerState
*st
, spx_uint32_t channel_index
, const spx_int16_t
*in
, spx_uint32_t
*in_len
, spx_int16_t
*out
, spx_uint32_t
*out_len
)
908 return speex_resampler_process_native(st
, channel_index
, in
, in_len
, out
, out_len
);
911 int speex_resampler_process_float(SpeexResamplerState
*st
, spx_uint32_t channel_index
, const float *in
, spx_uint32_t
*in_len
, float *out
, spx_uint32_t
*out_len
)
913 return speex_resampler_process_native(st
, channel_index
, in
, in_len
, out
, out_len
);
915 int speex_resampler_process_int(SpeexResamplerState
*st
, spx_uint32_t channel_index
, const spx_int16_t
*in
, spx_uint32_t
*in_len
, spx_int16_t
*out
, spx_uint32_t
*out_len
)
918 int istride_save
, ostride_save
;
920 spx_word16_t x
[*in_len
];
921 spx_word16_t y
[*out_len
];
922 /*VARDECL(spx_word16_t *x);
923 VARDECL(spx_word16_t *y);
924 ALLOC(x, *in_len, spx_word16_t);
925 ALLOC(y, *out_len, spx_word16_t);*/
926 istride_save
= st
->in_stride
;
927 ostride_save
= st
->out_stride
;
928 for (i
=0;i
<*in_len
;i
++)
929 x
[i
] = in
[i
*st
->in_stride
];
930 st
->in_stride
= st
->out_stride
= 1;
931 speex_resampler_process_native(st
, channel_index
, x
, in_len
, y
, out_len
);
932 st
->in_stride
= istride_save
;
933 st
->out_stride
= ostride_save
;
934 for (i
=0;i
<*out_len
;i
++)
935 out
[i
*st
->out_stride
] = WORD2INT(y
[i
]);
937 spx_word16_t x
[FIXED_STACK_ALLOC
];
938 spx_word16_t y
[FIXED_STACK_ALLOC
];
939 spx_uint32_t ilen
=*in_len
, olen
=*out_len
;
940 istride_save
= st
->in_stride
;
941 ostride_save
= st
->out_stride
;
944 spx_uint32_t ichunk
, ochunk
;
947 if (ichunk
>FIXED_STACK_ALLOC
)
948 ichunk
=FIXED_STACK_ALLOC
;
949 if (ochunk
>FIXED_STACK_ALLOC
)
950 ochunk
=FIXED_STACK_ALLOC
;
951 for (i
=0;i
<ichunk
;i
++)
952 x
[i
] = in
[i
*st
->in_stride
];
953 st
->in_stride
= st
->out_stride
= 1;
954 speex_resampler_process_native(st
, channel_index
, x
, &ichunk
, y
, &ochunk
);
955 st
->in_stride
= istride_save
;
956 st
->out_stride
= ostride_save
;
957 for (i
=0;i
<ochunk
;i
++)
958 out
[i
*st
->out_stride
] = WORD2INT(y
[i
]);
967 return RESAMPLER_ERR_SUCCESS
;
971 int speex_resampler_process_interleaved_float(SpeexResamplerState
*st
, const float *in
, spx_uint32_t
*in_len
, float *out
, spx_uint32_t
*out_len
)
974 int istride_save
, ostride_save
;
975 spx_uint32_t bak_len
= *out_len
;
976 istride_save
= st
->in_stride
;
977 ostride_save
= st
->out_stride
;
978 st
->in_stride
= st
->out_stride
= st
->nb_channels
;
979 for (i
=0;i
<st
->nb_channels
;i
++)
983 speex_resampler_process_float(st
, i
, in
+i
, in_len
, out
+i
, out_len
);
985 speex_resampler_process_float(st
, i
, NULL
, in_len
, out
+i
, out_len
);
987 st
->in_stride
= istride_save
;
988 st
->out_stride
= ostride_save
;
989 return RESAMPLER_ERR_SUCCESS
;
993 int speex_resampler_process_interleaved_int(SpeexResamplerState
*st
, const spx_int16_t
*in
, spx_uint32_t
*in_len
, spx_int16_t
*out
, spx_uint32_t
*out_len
)
996 int istride_save
, ostride_save
;
997 spx_uint32_t bak_len
= *out_len
;
998 istride_save
= st
->in_stride
;
999 ostride_save
= st
->out_stride
;
1000 st
->in_stride
= st
->out_stride
= st
->nb_channels
;
1001 for (i
=0;i
<st
->nb_channels
;i
++)
1005 speex_resampler_process_int(st
, i
, in
+i
, in_len
, out
+i
, out_len
);
1007 speex_resampler_process_int(st
, i
, NULL
, in_len
, out
+i
, out_len
);
1009 st
->in_stride
= istride_save
;
1010 st
->out_stride
= ostride_save
;
1011 return RESAMPLER_ERR_SUCCESS
;
1014 int speex_resampler_set_rate(SpeexResamplerState
*st
, spx_uint32_t in_rate
, spx_uint32_t out_rate
)
1016 return speex_resampler_set_rate_frac(st
, in_rate
, out_rate
, in_rate
, out_rate
);
1019 void speex_resampler_get_rate(SpeexResamplerState
*st
, spx_uint32_t
*in_rate
, spx_uint32_t
*out_rate
)
1021 *in_rate
= st
->in_rate
;
1022 *out_rate
= st
->out_rate
;
1025 int speex_resampler_set_rate_frac(SpeexResamplerState
*st
, spx_uint32_t ratio_num
, spx_uint32_t ratio_den
, spx_uint32_t in_rate
, spx_uint32_t out_rate
)
1028 spx_uint32_t old_den
;
1030 if (st
->in_rate
== in_rate
&& st
->out_rate
== out_rate
&& st
->num_rate
== ratio_num
&& st
->den_rate
== ratio_den
)
1031 return RESAMPLER_ERR_SUCCESS
;
1033 old_den
= st
->den_rate
;
1034 st
->in_rate
= in_rate
;
1035 st
->out_rate
= out_rate
;
1036 st
->num_rate
= ratio_num
;
1037 st
->den_rate
= ratio_den
;
1038 /* FIXME: This is terribly inefficient, but who cares (at least for now)? */
1039 for (fact
=2;fact
<=IMIN(st
->num_rate
, st
->den_rate
);fact
++)
1041 while ((st
->num_rate
% fact
== 0) && (st
->den_rate
% fact
== 0))
1043 st
->num_rate
/= fact
;
1044 st
->den_rate
/= fact
;
1050 for (i
=0;i
<st
->nb_channels
;i
++)
1052 st
->samp_frac_num
[i
]=st
->samp_frac_num
[i
]*st
->den_rate
/old_den
;
1054 if (st
->samp_frac_num
[i
] >= st
->den_rate
)
1055 st
->samp_frac_num
[i
] = st
->den_rate
-1;
1059 if (st
->initialised
)
1061 return RESAMPLER_ERR_SUCCESS
;
1064 void speex_resampler_get_ratio(SpeexResamplerState
*st
, spx_uint32_t
*ratio_num
, spx_uint32_t
*ratio_den
)
1066 *ratio_num
= st
->num_rate
;
1067 *ratio_den
= st
->den_rate
;
1070 int speex_resampler_set_quality(SpeexResamplerState
*st
, int quality
)
1072 if (quality
> 10 || quality
< 0)
1073 return RESAMPLER_ERR_INVALID_ARG
;
1074 if (st
->quality
== quality
)
1075 return RESAMPLER_ERR_SUCCESS
;
1076 st
->quality
= quality
;
1077 if (st
->initialised
)
1079 return RESAMPLER_ERR_SUCCESS
;
1082 void speex_resampler_get_quality(SpeexResamplerState
*st
, int *quality
)
1084 *quality
= st
->quality
;
1087 void speex_resampler_set_input_stride(SpeexResamplerState
*st
, spx_uint32_t stride
)
1089 st
->in_stride
= stride
;
1092 void speex_resampler_get_input_stride(SpeexResamplerState
*st
, spx_uint32_t
*stride
)
1094 *stride
= st
->in_stride
;
1097 void speex_resampler_set_output_stride(SpeexResamplerState
*st
, spx_uint32_t stride
)
1099 st
->out_stride
= stride
;
1102 void speex_resampler_get_output_stride(SpeexResamplerState
*st
, spx_uint32_t
*stride
)
1104 *stride
= st
->out_stride
;
1107 int speex_resampler_skip_zeros(SpeexResamplerState
*st
)
1110 for (i
=0;i
<st
->nb_channels
;i
++)
1111 st
->last_sample
[i
] = st
->filt_len
/2;
1112 return RESAMPLER_ERR_SUCCESS
;
1115 int speex_resampler_reset_mem(SpeexResamplerState
*st
)
1118 for (i
=0;i
<st
->nb_channels
*(st
->filt_len
-1);i
++)
1120 return RESAMPLER_ERR_SUCCESS
;
1123 const char *speex_resampler_strerror(int err
)
1127 case RESAMPLER_ERR_SUCCESS
:
1129 case RESAMPLER_ERR_ALLOC_FAILED
:
1130 return "Memory allocation failed.";
1131 case RESAMPLER_ERR_BAD_STATE
:
1132 return "Bad resampler state.";
1133 case RESAMPLER_ERR_INVALID_ARG
:
1134 return "Invalid argument.";
1135 case RESAMPLER_ERR_PTR_OVERLAP
:
1136 return "Input and output buffers overlap.";
1138 return "Unknown error. Bad error code or strange version mismatch.";