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.
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 */
340 ptr
= in
+st
->in_stride
*(last_sample
-N
+1+j
);
343 sum
+= MULT16_16(*ptr
,st
->sinc_table
[samp_frac_num
*st
->filt_len
+j
]);
344 ptr
+= st
->in_stride
;
347 *out
= PSHR32(sum
,15);
348 out
+= st
->out_stride
;
350 last_sample
+= st
->int_advance
;
351 samp_frac_num
+= st
->frac_advance
;
352 if (samp_frac_num
>= st
->den_rate
)
354 samp_frac_num
-= st
->den_rate
;
358 st
->last_sample
[channel_index
] = last_sample
;
359 st
->samp_frac_num
[channel_index
] = samp_frac_num
;
365 /* This is the same as the previous function, except with a double-precision accumulator */
366 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
)
368 int N
= st
->filt_len
;
371 int last_sample
= st
->last_sample
[channel_index
];
372 spx_uint32_t samp_frac_num
= st
->samp_frac_num
[channel_index
];
373 mem
= st
->mem
+ channel_index
* st
->mem_alloc_size
;
374 while (!(last_sample
>= (spx_int32_t
)*in_len
|| out_sample
>= (spx_int32_t
)*out_len
))
379 /* We already have all the filter coefficients pre-computed in the table */
380 const spx_word16_t
*ptr
;
381 /* Do the memory part */
382 for (j
=0;last_sample
-N
+1+j
< 0;j
++)
384 sum
+= MULT16_16(mem
[last_sample
+j
],(double)st
->sinc_table
[samp_frac_num
*st
->filt_len
+j
]);
387 /* Do the new part */
388 ptr
= in
+st
->in_stride
*(last_sample
-N
+1+j
);
391 sum
+= MULT16_16(*ptr
,(double)st
->sinc_table
[samp_frac_num
*st
->filt_len
+j
]);
392 ptr
+= st
->in_stride
;
396 out
+= st
->out_stride
;
398 last_sample
+= st
->int_advance
;
399 samp_frac_num
+= st
->frac_advance
;
400 if (samp_frac_num
>= st
->den_rate
)
402 samp_frac_num
-= st
->den_rate
;
406 st
->last_sample
[channel_index
] = last_sample
;
407 st
->samp_frac_num
[channel_index
] = samp_frac_num
;
412 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
)
414 int N
= st
->filt_len
;
417 int last_sample
= st
->last_sample
[channel_index
];
418 spx_uint32_t samp_frac_num
= st
->samp_frac_num
[channel_index
];
419 mem
= st
->mem
+ channel_index
* st
->mem_alloc_size
;
420 while (!(last_sample
>= (spx_int32_t
)*in_len
|| out_sample
>= (spx_int32_t
)*out_len
))
425 /* We need to interpolate the sinc filter */
426 spx_word32_t accum
[4] = {0.f
,0.f
, 0.f
, 0.f
};
427 spx_word16_t interp
[4];
428 const spx_word16_t
*ptr
;
431 offset
= samp_frac_num
*st
->oversample
/st
->den_rate
;
433 frac
= PDIV32(SHL32((samp_frac_num
*st
->oversample
) % st
->den_rate
,15),st
->den_rate
);
435 frac
= ((float)((samp_frac_num
*st
->oversample
) % st
->den_rate
))/st
->den_rate
;
437 /* This code is written like this to make it easy to optimise with SIMD.
438 For most DSPs, it would be best to split the loops in two because most DSPs
439 have only two accumulators */
440 for (j
=0;last_sample
-N
+1+j
< 0;j
++)
442 spx_word16_t curr_mem
= mem
[last_sample
+j
];
443 accum
[0] += MULT16_16(curr_mem
,st
->sinc_table
[4+(j
+1)*st
->oversample
-offset
-2]);
444 accum
[1] += MULT16_16(curr_mem
,st
->sinc_table
[4+(j
+1)*st
->oversample
-offset
-1]);
445 accum
[2] += MULT16_16(curr_mem
,st
->sinc_table
[4+(j
+1)*st
->oversample
-offset
]);
446 accum
[3] += MULT16_16(curr_mem
,st
->sinc_table
[4+(j
+1)*st
->oversample
-offset
+1]);
448 ptr
= in
+st
->in_stride
*(last_sample
-N
+1+j
);
449 /* Do the new part */
452 spx_word16_t curr_in
= *ptr
;
453 ptr
+= st
->in_stride
;
454 accum
[0] += MULT16_16(curr_in
,st
->sinc_table
[4+(j
+1)*st
->oversample
-offset
-2]);
455 accum
[1] += MULT16_16(curr_in
,st
->sinc_table
[4+(j
+1)*st
->oversample
-offset
-1]);
456 accum
[2] += MULT16_16(curr_in
,st
->sinc_table
[4+(j
+1)*st
->oversample
-offset
]);
457 accum
[3] += MULT16_16(curr_in
,st
->sinc_table
[4+(j
+1)*st
->oversample
-offset
+1]);
459 cubic_coef(frac
, interp
);
460 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]);
462 *out
= PSHR32(sum
,15);
463 out
+= st
->out_stride
;
465 last_sample
+= st
->int_advance
;
466 samp_frac_num
+= st
->frac_advance
;
467 if (samp_frac_num
>= st
->den_rate
)
469 samp_frac_num
-= st
->den_rate
;
473 st
->last_sample
[channel_index
] = last_sample
;
474 st
->samp_frac_num
[channel_index
] = samp_frac_num
;
480 /* This is the same as the previous function, except with a double-precision accumulator */
481 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
)
483 int N
= st
->filt_len
;
486 int last_sample
= st
->last_sample
[channel_index
];
487 spx_uint32_t samp_frac_num
= st
->samp_frac_num
[channel_index
];
488 mem
= st
->mem
+ channel_index
* st
->mem_alloc_size
;
489 while (!(last_sample
>= (spx_int32_t
)*in_len
|| out_sample
>= (spx_int32_t
)*out_len
))
494 /* We need to interpolate the sinc filter */
495 double accum
[4] = {0.f
,0.f
, 0.f
, 0.f
};
497 const spx_word16_t
*ptr
;
498 float alpha
= ((float)samp_frac_num
)/st
->den_rate
;
499 int offset
= samp_frac_num
*st
->oversample
/st
->den_rate
;
500 float frac
= alpha
*st
->oversample
- offset
;
501 /* This code is written like this to make it easy to optimise with SIMD.
502 For most DSPs, it would be best to split the loops in two because most DSPs
503 have only two accumulators */
504 for (j
=0;last_sample
-N
+1+j
< 0;j
++)
506 double curr_mem
= mem
[last_sample
+j
];
507 accum
[0] += MULT16_16(curr_mem
,st
->sinc_table
[4+(j
+1)*st
->oversample
-offset
-2]);
508 accum
[1] += MULT16_16(curr_mem
,st
->sinc_table
[4+(j
+1)*st
->oversample
-offset
-1]);
509 accum
[2] += MULT16_16(curr_mem
,st
->sinc_table
[4+(j
+1)*st
->oversample
-offset
]);
510 accum
[3] += MULT16_16(curr_mem
,st
->sinc_table
[4+(j
+1)*st
->oversample
-offset
+1]);
512 ptr
= in
+st
->in_stride
*(last_sample
-N
+1+j
);
513 /* Do the new part */
516 double curr_in
= *ptr
;
517 ptr
+= st
->in_stride
;
518 accum
[0] += MULT16_16(curr_in
,st
->sinc_table
[4+(j
+1)*st
->oversample
-offset
-2]);
519 accum
[1] += MULT16_16(curr_in
,st
->sinc_table
[4+(j
+1)*st
->oversample
-offset
-1]);
520 accum
[2] += MULT16_16(curr_in
,st
->sinc_table
[4+(j
+1)*st
->oversample
-offset
]);
521 accum
[3] += MULT16_16(curr_in
,st
->sinc_table
[4+(j
+1)*st
->oversample
-offset
+1]);
523 cubic_coef(frac
, interp
);
524 sum
= interp
[0]*accum
[0] + interp
[1]*accum
[1] + interp
[2]*accum
[2] + interp
[3]*accum
[3];
526 *out
= PSHR32(sum
,15);
527 out
+= st
->out_stride
;
529 last_sample
+= st
->int_advance
;
530 samp_frac_num
+= st
->frac_advance
;
531 if (samp_frac_num
>= st
->den_rate
)
533 samp_frac_num
-= st
->den_rate
;
537 st
->last_sample
[channel_index
] = last_sample
;
538 st
->samp_frac_num
[channel_index
] = samp_frac_num
;
543 static void update_filter(SpeexResamplerState
*st
)
545 spx_uint32_t old_length
;
547 old_length
= st
->filt_len
;
548 st
->oversample
= quality_map
[st
->quality
].oversample
;
549 st
->filt_len
= quality_map
[st
->quality
].base_length
;
551 if (st
->num_rate
> st
->den_rate
)
554 st
->cutoff
= quality_map
[st
->quality
].downsample_bandwidth
* st
->den_rate
/ st
->num_rate
;
555 /* FIXME: divide the numerator and denominator by a certain amount if they're too large */
556 st
->filt_len
= st
->filt_len
*st
->num_rate
/ st
->den_rate
;
557 /* Round down to make sure we have a multiple of 4 */
558 st
->filt_len
&= (~0x3);
559 if (2*st
->den_rate
< st
->num_rate
)
560 st
->oversample
>>= 1;
561 if (4*st
->den_rate
< st
->num_rate
)
562 st
->oversample
>>= 1;
563 if (8*st
->den_rate
< st
->num_rate
)
564 st
->oversample
>>= 1;
565 if (16*st
->den_rate
< st
->num_rate
)
566 st
->oversample
>>= 1;
567 if (st
->oversample
< 1)
571 st
->cutoff
= quality_map
[st
->quality
].upsample_bandwidth
;
574 /* Choose the resampling type that requires the least amount of memory */
575 if (st
->den_rate
<= st
->oversample
)
579 st
->sinc_table
= (spx_word16_t
*)speex_alloc(st
->filt_len
*st
->den_rate
*sizeof(spx_word16_t
));
580 else if (st
->sinc_table_length
< st
->filt_len
*st
->den_rate
)
582 st
->sinc_table
= (spx_word16_t
*)speex_realloc(st
->sinc_table
,st
->filt_len
*st
->den_rate
*sizeof(spx_word16_t
));
583 st
->sinc_table_length
= st
->filt_len
*st
->den_rate
;
585 for (i
=0;i
<st
->den_rate
;i
++)
588 for (j
=0;j
<st
->filt_len
;j
++)
590 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
);
594 st
->resampler_ptr
= resampler_basic_direct_single
;
597 st
->resampler_ptr
= resampler_basic_direct_double
;
599 st
->resampler_ptr
= resampler_basic_direct_single
;
601 /*fprintf (stderr, "resampler uses direct sinc table and normalised cutoff %f\n", cutoff);*/
605 st
->sinc_table
= (spx_word16_t
*)speex_alloc((st
->filt_len
*st
->oversample
+8)*sizeof(spx_word16_t
));
606 else if (st
->sinc_table_length
< st
->filt_len
*st
->oversample
+8)
608 st
->sinc_table
= (spx_word16_t
*)speex_realloc(st
->sinc_table
,(st
->filt_len
*st
->oversample
+8)*sizeof(spx_word16_t
));
609 st
->sinc_table_length
= st
->filt_len
*st
->oversample
+8;
611 for (i
=-4;i
<(spx_int32_t
)(st
->oversample
*st
->filt_len
+4);i
++)
612 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
);
614 st
->resampler_ptr
= resampler_basic_interpolate_single
;
617 st
->resampler_ptr
= resampler_basic_interpolate_double
;
619 st
->resampler_ptr
= resampler_basic_interpolate_single
;
621 /*fprintf (stderr, "resampler uses interpolated sinc table and normalised cutoff %f\n", cutoff);*/
623 st
->int_advance
= st
->num_rate
/st
->den_rate
;
624 st
->frac_advance
= st
->num_rate
%st
->den_rate
;
627 /* Here's the place where we update the filter memory to take into account
628 the change in filter length. It's probably the messiest part of the code
629 due to handling of lots of corner cases. */
633 st
->mem
= (spx_word16_t
*)speex_alloc(st
->nb_channels
*(st
->filt_len
-1) * sizeof(spx_word16_t
));
634 for (i
=0;i
<st
->nb_channels
*(st
->filt_len
-1);i
++)
636 st
->mem_alloc_size
= st
->filt_len
-1;
637 /*speex_warning("init filter");*/
638 } else if (!st
->started
)
641 st
->mem
= (spx_word16_t
*)speex_realloc(st
->mem
, st
->nb_channels
*(st
->filt_len
-1) * sizeof(spx_word16_t
));
642 for (i
=0;i
<st
->nb_channels
*(st
->filt_len
-1);i
++)
644 st
->mem_alloc_size
= st
->filt_len
-1;
645 /*speex_warning("reinit filter");*/
646 } else if (st
->filt_len
> old_length
)
649 /* Increase the filter length */
650 /*speex_warning("increase filter size");*/
651 int old_alloc_size
= st
->mem_alloc_size
;
652 if (st
->filt_len
-1 > st
->mem_alloc_size
)
654 st
->mem
= (spx_word16_t
*)speex_realloc(st
->mem
, st
->nb_channels
*(st
->filt_len
-1) * sizeof(spx_word16_t
));
655 st
->mem_alloc_size
= st
->filt_len
-1;
657 for (i
=st
->nb_channels
-1;i
>=0;i
--)
660 spx_uint32_t olen
= old_length
;
661 /*if (st->magic_samples[i])*/
663 /* Try and remove the magic samples as if nothing had happened */
665 /* FIXME: This is wrong but for now we need it to avoid going over the array bounds */
666 olen
= old_length
+ 2*st
->magic_samples
[i
];
667 for (j
=old_length
-2+st
->magic_samples
[i
];j
>=0;j
--)
668 st
->mem
[i
*st
->mem_alloc_size
+j
+st
->magic_samples
[i
]] = st
->mem
[i
*old_alloc_size
+j
];
669 for (j
=0;j
<st
->magic_samples
[i
];j
++)
670 st
->mem
[i
*st
->mem_alloc_size
+j
] = 0;
671 st
->magic_samples
[i
] = 0;
673 if (st
->filt_len
> olen
)
675 /* If the new filter length is still bigger than the "augmented" length */
676 /* Copy data going backward */
677 for (j
=0;j
<olen
-1;j
++)
678 st
->mem
[i
*st
->mem_alloc_size
+(st
->filt_len
-2-j
)] = st
->mem
[i
*st
->mem_alloc_size
+(olen
-2-j
)];
679 /* Then put zeros for lack of anything better */
680 for (;j
<st
->filt_len
-1;j
++)
681 st
->mem
[i
*st
->mem_alloc_size
+(st
->filt_len
-2-j
)] = 0;
682 /* Adjust last_sample */
683 st
->last_sample
[i
] += (st
->filt_len
- olen
)/2;
685 /* Put back some of the magic! */
686 st
->magic_samples
[i
] = (olen
- st
->filt_len
)/2;
687 for (j
=0;j
<st
->filt_len
-1+st
->magic_samples
[i
];j
++)
688 st
->mem
[i
*st
->mem_alloc_size
+j
] = st
->mem
[i
*st
->mem_alloc_size
+j
+st
->magic_samples
[i
]];
691 } else if (st
->filt_len
< old_length
)
694 /* Reduce filter length, this a bit tricky. We need to store some of the memory as "magic"
695 samples so they can be used directly as input the next time(s) */
696 for (i
=0;i
<st
->nb_channels
;i
++)
699 spx_uint32_t old_magic
= st
->magic_samples
[i
];
700 st
->magic_samples
[i
] = (old_length
- st
->filt_len
)/2;
701 /* We must copy some of the memory that's no longer used */
702 /* Copy data going backward */
703 for (j
=0;j
<st
->filt_len
-1+st
->magic_samples
[i
]+old_magic
;j
++)
704 st
->mem
[i
*st
->mem_alloc_size
+j
] = st
->mem
[i
*st
->mem_alloc_size
+j
+st
->magic_samples
[i
]];
705 st
->magic_samples
[i
] += old_magic
;
711 SpeexResamplerState
*speex_resampler_init(spx_uint32_t nb_channels
, spx_uint32_t in_rate
, spx_uint32_t out_rate
, int quality
, int *err
)
713 return speex_resampler_init_frac(nb_channels
, in_rate
, out_rate
, in_rate
, out_rate
, quality
, err
);
716 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
)
719 SpeexResamplerState
*st
;
720 if (quality
> 10 || quality
< 0)
723 *err
= RESAMPLER_ERR_INVALID_ARG
;
726 st
= (SpeexResamplerState
*)speex_alloc(sizeof(SpeexResamplerState
));
734 st
->sinc_table_length
= 0;
735 st
->mem_alloc_size
= 0;
738 st
->resampler_ptr
= 0;
741 st
->nb_channels
= nb_channels
;
745 /* Per channel data */
746 st
->last_sample
= (spx_int32_t
*)speex_alloc(nb_channels
*sizeof(int));
747 st
->magic_samples
= (spx_uint32_t
*)speex_alloc(nb_channels
*sizeof(int));
748 st
->samp_frac_num
= (spx_uint32_t
*)speex_alloc(nb_channels
*sizeof(int));
749 for (i
=0;i
<nb_channels
;i
++)
751 st
->last_sample
[i
] = 0;
752 st
->magic_samples
[i
] = 0;
753 st
->samp_frac_num
[i
] = 0;
756 speex_resampler_set_quality(st
, quality
);
757 speex_resampler_set_rate_frac(st
, ratio_num
, ratio_den
, in_rate
, out_rate
);
764 *err
= RESAMPLER_ERR_SUCCESS
;
769 void speex_resampler_destroy(SpeexResamplerState
*st
)
772 speex_free(st
->sinc_table
);
773 speex_free(st
->last_sample
);
774 speex_free(st
->magic_samples
);
775 speex_free(st
->samp_frac_num
);
781 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
)
784 int N
= st
->filt_len
;
787 spx_uint32_t tmp_out_len
= 0;
788 mem
= st
->mem
+ channel_index
* st
->mem_alloc_size
;
791 /* Handle the case where we have samples left from a reduction in filter length */
792 if (st
->magic_samples
[channel_index
])
795 spx_uint32_t tmp_in_len
;
796 spx_uint32_t tmp_magic
;
798 istride_save
= st
->in_stride
;
799 tmp_in_len
= st
->magic_samples
[channel_index
];
800 tmp_out_len
= *out_len
;
801 /* magic_samples needs to be set to zero to avoid infinite recursion */
802 tmp_magic
= st
->magic_samples
[channel_index
];
803 st
->magic_samples
[channel_index
] = 0;
805 speex_resampler_process_native(st
, channel_index
, mem
+N
-1, &tmp_in_len
, out
, &tmp_out_len
);
806 st
->in_stride
= istride_save
;
807 /*speex_warning_int("extra samples:", tmp_out_len);*/
808 /* If we couldn't process all "magic" input samples, save the rest for next time */
809 if (tmp_in_len
< tmp_magic
)
812 st
->magic_samples
[channel_index
] = tmp_magic
-tmp_in_len
;
813 for (i
=0;i
<st
->magic_samples
[channel_index
];i
++)
814 mem
[N
-1+i
]=mem
[N
-1+i
+tmp_in_len
];
816 out
+= tmp_out_len
*st
->out_stride
;
817 *out_len
-= tmp_out_len
;
820 /* Call the right resampler through the function ptr */
821 out_sample
= st
->resampler_ptr(st
, channel_index
, in
, in_len
, out
, out_len
);
823 if (st
->last_sample
[channel_index
] < (spx_int32_t
)*in_len
)
824 *in_len
= st
->last_sample
[channel_index
];
825 *out_len
= out_sample
+tmp_out_len
;
826 st
->last_sample
[channel_index
] -= *in_len
;
828 for (j
=0;j
<N
-1-(spx_int32_t
)*in_len
;j
++)
829 mem
[j
] = mem
[j
+*in_len
];
831 mem
[j
] = in
[st
->in_stride
*(j
+*in_len
-N
+1)];
833 return RESAMPLER_ERR_SUCCESS
;
836 #define FIXED_STACK_ALLOC 1024
839 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
)
842 int istride_save
, ostride_save
;
844 spx_word16_t x
[*in_len
];
845 spx_word16_t y
[*out_len
];
846 /*VARDECL(spx_word16_t *x);
847 VARDECL(spx_word16_t *y);
848 ALLOC(x, *in_len, spx_word16_t);
849 ALLOC(y, *out_len, spx_word16_t);*/
850 istride_save
= st
->in_stride
;
851 ostride_save
= st
->out_stride
;
852 for (i
=0;i
<*in_len
;i
++)
853 x
[i
] = WORD2INT(in
[i
*st
->in_stride
]);
854 st
->in_stride
= st
->out_stride
= 1;
855 speex_resampler_process_native(st
, channel_index
, x
, in_len
, y
, out_len
);
856 st
->in_stride
= istride_save
;
857 st
->out_stride
= ostride_save
;
858 for (i
=0;i
<*out_len
;i
++)
859 out
[i
*st
->out_stride
] = y
[i
];
861 spx_word16_t x
[FIXED_STACK_ALLOC
];
862 spx_word16_t y
[FIXED_STACK_ALLOC
];
863 spx_uint32_t ilen
=*in_len
, olen
=*out_len
;
864 istride_save
= st
->in_stride
;
865 ostride_save
= st
->out_stride
;
868 spx_uint32_t ichunk
, ochunk
;
871 if (ichunk
>FIXED_STACK_ALLOC
)
872 ichunk
=FIXED_STACK_ALLOC
;
873 if (ochunk
>FIXED_STACK_ALLOC
)
874 ochunk
=FIXED_STACK_ALLOC
;
875 for (i
=0;i
<ichunk
;i
++)
876 x
[i
] = WORD2INT(in
[i
*st
->in_stride
]);
877 st
->in_stride
= st
->out_stride
= 1;
878 speex_resampler_process_native(st
, channel_index
, x
, &ichunk
, y
, &ochunk
);
879 st
->in_stride
= istride_save
;
880 st
->out_stride
= ostride_save
;
881 for (i
=0;i
<ochunk
;i
++)
882 out
[i
*st
->out_stride
] = y
[i
];
891 return RESAMPLER_ERR_SUCCESS
;
893 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
)
895 return speex_resampler_process_native(st
, channel_index
, in
, in_len
, out
, out_len
);
898 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
)
900 return speex_resampler_process_native(st
, channel_index
, in
, in_len
, out
, out_len
);
902 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
)
905 int istride_save
, ostride_save
;
907 spx_word16_t x
[*in_len
];
908 spx_word16_t y
[*out_len
];
909 /*VARDECL(spx_word16_t *x);
910 VARDECL(spx_word16_t *y);
911 ALLOC(x, *in_len, spx_word16_t);
912 ALLOC(y, *out_len, spx_word16_t);*/
913 istride_save
= st
->in_stride
;
914 ostride_save
= st
->out_stride
;
915 for (i
=0;i
<*in_len
;i
++)
916 x
[i
] = in
[i
*st
->in_stride
];
917 st
->in_stride
= st
->out_stride
= 1;
918 speex_resampler_process_native(st
, channel_index
, x
, in_len
, y
, out_len
);
919 st
->in_stride
= istride_save
;
920 st
->out_stride
= ostride_save
;
921 for (i
=0;i
<*out_len
;i
++)
922 out
[i
*st
->out_stride
] = WORD2INT(y
[i
]);
924 spx_word16_t x
[FIXED_STACK_ALLOC
];
925 spx_word16_t y
[FIXED_STACK_ALLOC
];
926 spx_uint32_t ilen
=*in_len
, olen
=*out_len
;
927 istride_save
= st
->in_stride
;
928 ostride_save
= st
->out_stride
;
931 spx_uint32_t ichunk
, ochunk
;
934 if (ichunk
>FIXED_STACK_ALLOC
)
935 ichunk
=FIXED_STACK_ALLOC
;
936 if (ochunk
>FIXED_STACK_ALLOC
)
937 ochunk
=FIXED_STACK_ALLOC
;
938 for (i
=0;i
<ichunk
;i
++)
939 x
[i
] = in
[i
*st
->in_stride
];
940 st
->in_stride
= st
->out_stride
= 1;
941 speex_resampler_process_native(st
, channel_index
, x
, &ichunk
, y
, &ochunk
);
942 st
->in_stride
= istride_save
;
943 st
->out_stride
= ostride_save
;
944 for (i
=0;i
<ochunk
;i
++)
945 out
[i
*st
->out_stride
] = WORD2INT(y
[i
]);
954 return RESAMPLER_ERR_SUCCESS
;
958 int speex_resampler_process_interleaved_float(SpeexResamplerState
*st
, const float *in
, spx_uint32_t
*in_len
, float *out
, spx_uint32_t
*out_len
)
961 int istride_save
, ostride_save
;
962 spx_uint32_t bak_len
= *out_len
;
963 istride_save
= st
->in_stride
;
964 ostride_save
= st
->out_stride
;
965 st
->in_stride
= st
->out_stride
= st
->nb_channels
;
966 for (i
=0;i
<st
->nb_channels
;i
++)
969 speex_resampler_process_float(st
, i
, in
+i
, in_len
, out
+i
, out_len
);
971 st
->in_stride
= istride_save
;
972 st
->out_stride
= ostride_save
;
973 return RESAMPLER_ERR_SUCCESS
;
977 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
)
980 int istride_save
, ostride_save
;
981 spx_uint32_t bak_len
= *out_len
;
982 istride_save
= st
->in_stride
;
983 ostride_save
= st
->out_stride
;
984 st
->in_stride
= st
->out_stride
= st
->nb_channels
;
985 for (i
=0;i
<st
->nb_channels
;i
++)
988 speex_resampler_process_int(st
, i
, in
+i
, in_len
, out
+i
, out_len
);
990 st
->in_stride
= istride_save
;
991 st
->out_stride
= ostride_save
;
992 return RESAMPLER_ERR_SUCCESS
;
995 int speex_resampler_set_rate(SpeexResamplerState
*st
, spx_uint32_t in_rate
, spx_uint32_t out_rate
)
997 return speex_resampler_set_rate_frac(st
, in_rate
, out_rate
, in_rate
, out_rate
);
1000 void speex_resampler_get_rate(SpeexResamplerState
*st
, spx_uint32_t
*in_rate
, spx_uint32_t
*out_rate
)
1002 *in_rate
= st
->in_rate
;
1003 *out_rate
= st
->out_rate
;
1006 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
)
1009 spx_uint32_t old_den
;
1011 if (st
->in_rate
== in_rate
&& st
->out_rate
== out_rate
&& st
->num_rate
== ratio_num
&& st
->den_rate
== ratio_den
)
1012 return RESAMPLER_ERR_SUCCESS
;
1014 old_den
= st
->den_rate
;
1015 st
->in_rate
= in_rate
;
1016 st
->out_rate
= out_rate
;
1017 st
->num_rate
= ratio_num
;
1018 st
->den_rate
= ratio_den
;
1019 /* FIXME: This is terribly inefficient, but who cares (at least for now)? */
1020 for (fact
=2;fact
<=IMIN(st
->num_rate
, st
->den_rate
);fact
++)
1022 while ((st
->num_rate
% fact
== 0) && (st
->den_rate
% fact
== 0))
1024 st
->num_rate
/= fact
;
1025 st
->den_rate
/= fact
;
1031 for (i
=0;i
<st
->nb_channels
;i
++)
1033 st
->samp_frac_num
[i
]=st
->samp_frac_num
[i
]*st
->den_rate
/old_den
;
1035 if (st
->samp_frac_num
[i
] >= st
->den_rate
)
1036 st
->samp_frac_num
[i
] = st
->den_rate
-1;
1040 if (st
->initialised
)
1042 return RESAMPLER_ERR_SUCCESS
;
1045 void speex_resampler_get_ratio(SpeexResamplerState
*st
, spx_uint32_t
*ratio_num
, spx_uint32_t
*ratio_den
)
1047 *ratio_num
= st
->num_rate
;
1048 *ratio_den
= st
->den_rate
;
1051 int speex_resampler_set_quality(SpeexResamplerState
*st
, int quality
)
1053 if (quality
> 10 || quality
< 0)
1054 return RESAMPLER_ERR_INVALID_ARG
;
1055 if (st
->quality
== quality
)
1056 return RESAMPLER_ERR_SUCCESS
;
1057 st
->quality
= quality
;
1058 if (st
->initialised
)
1060 return RESAMPLER_ERR_SUCCESS
;
1063 void speex_resampler_get_quality(SpeexResamplerState
*st
, int *quality
)
1065 *quality
= st
->quality
;
1068 void speex_resampler_set_input_stride(SpeexResamplerState
*st
, spx_uint32_t stride
)
1070 st
->in_stride
= stride
;
1073 void speex_resampler_get_input_stride(SpeexResamplerState
*st
, spx_uint32_t
*stride
)
1075 *stride
= st
->in_stride
;
1078 void speex_resampler_set_output_stride(SpeexResamplerState
*st
, spx_uint32_t stride
)
1080 st
->out_stride
= stride
;
1083 void speex_resampler_get_output_stride(SpeexResamplerState
*st
, spx_uint32_t
*stride
)
1085 *stride
= st
->out_stride
;
1088 int speex_resampler_skip_zeros(SpeexResamplerState
*st
)
1091 for (i
=0;i
<st
->nb_channels
;i
++)
1092 st
->last_sample
[i
] = st
->filt_len
/2;
1093 return RESAMPLER_ERR_SUCCESS
;
1096 int speex_resampler_reset_mem(SpeexResamplerState
*st
)
1099 for (i
=0;i
<st
->nb_channels
*(st
->filt_len
-1);i
++)
1101 return RESAMPLER_ERR_SUCCESS
;
1104 const char *speex_resampler_strerror(int err
)
1108 case RESAMPLER_ERR_SUCCESS
:
1110 case RESAMPLER_ERR_ALLOC_FAILED
:
1111 return "Memory allocation failed.";
1112 case RESAMPLER_ERR_BAD_STATE
:
1113 return "Bad resampler state.";
1114 case RESAMPLER_ERR_INVALID_ARG
:
1115 return "Invalid argument.";
1116 case RESAMPLER_ERR_PTR_OVERLAP
:
1117 return "Input and output buffers overlap.";
1119 return "Unknown error. Bad error code or strange version mismatch.";