7d9dae55f682efc078f0b49c7c24ce67ac96c685
[speexdsp.git] / libspeex / resample.c
1 /* Copyright (C) 2007 Jean-Marc Valin
2       
3    File: resample.c
4    Arbitrary resampling code
5
6    Redistribution and use in source and binary forms, with or without
7    modification, are permitted provided that the following conditions are
8    met:
9
10    1. Redistributions of source code must retain the above copyright notice,
11    this list of conditions and the following disclaimer.
12
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.
16
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.
19
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.
31 */
32
33 /*
34    The design goals of this code are:
35       - Very fast algorithm
36       - SIMD-friendly algorithm
37       - Low memory requirement
38       - Good *perceptual* quality (and not best SNR)
39
40    The code is working, but it's in a very early stage, so it may have
41    artifacts, noise or subliminal messages from satan. Also, the API 
42    isn't stable and I can actually promise that I *will* change the API
43    some time in the future.
44
45 TODO list:
46       - Variable calculation resolution depending on quality setting
47          - Single vs double in float mode
48          - 16-bit vs 32-bit (sinc only) in fixed-point mode
49       - Make sure the filter update works even when changing params 
50              after only a few samples procesed
51 */
52
53 #ifdef HAVE_CONFIG_H
54 #include "config.h"
55 #endif
56
57 #ifdef OUTSIDE_SPEEX
58 #include <stdlib.h>
59 static void *speex_alloc (int size) {return calloc(size,1);}
60 static void *speex_realloc (void *ptr, int size) {return realloc(ptr, size);}
61 static void speex_free (void *ptr) {free(ptr);}
62 #include "speex_resampler.h"
63 #include "arch.h"
64 #else /* OUTSIDE_SPEEX */
65                
66 #include "speex/speex_resampler.h"
67 #include "misc.h"
68 #endif /* OUTSIDE_SPEEX */
69
70 #include <math.h>
71
72 #ifndef M_PI
73 #define M_PI 3.14159263
74 #endif
75
76 #ifdef FIXED_POINT
77 #define WORD2INT(x) ((x) < -32767 ? -32768 : ((x) > 32766 ? 32767 : (x)))  
78 #else
79 #define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x))))  
80 #endif
81                
82 /*#define float double*/
83 #define FILTER_SIZE 64
84 #define OVERSAMPLE 8
85
86 #define IMAX(a,b) ((a) > (b) ? (a) : (b))
87
88 #ifndef NULL
89 #define NULL 0
90 #endif
91
92 typedef int (*resampler_basic_func)(SpeexResamplerState *, spx_uint32_t , const spx_word16_t *, spx_uint32_t *, spx_word16_t *, spx_uint32_t *);
93
94 struct SpeexResamplerState_ {
95    spx_uint32_t in_rate;
96    spx_uint32_t out_rate;
97    spx_uint32_t num_rate;
98    spx_uint32_t den_rate;
99    
100    int    quality;
101    spx_uint32_t nb_channels;
102    spx_uint32_t filt_len;
103    spx_uint32_t mem_alloc_size;
104    int          int_advance;
105    int          frac_advance;
106    float  cutoff;
107    spx_uint32_t oversample;
108    int          initialised;
109    int          started;
110    
111    /* These are per-channel */
112    spx_int32_t  *last_sample;
113    spx_uint32_t *samp_frac_num;
114    spx_uint32_t *magic_samples;
115    
116    spx_word16_t *mem;
117    spx_word16_t *sinc_table;
118    spx_uint32_t sinc_table_length;
119    resampler_basic_func resampler_ptr;
120          
121    int    in_stride;
122    int    out_stride;
123 } ;
124
125 static double kaiser12_table[68] = {
126    0.99859849, 1.00000000, 0.99859849, 0.99440475, 0.98745105, 0.97779076,
127    0.96549770, 0.95066529, 0.93340547, 0.91384741, 0.89213598, 0.86843014,
128    0.84290116, 0.81573067, 0.78710866, 0.75723148, 0.72629970, 0.69451601,
129    0.66208321, 0.62920216, 0.59606986, 0.56287762, 0.52980938, 0.49704014,
130    0.46473455, 0.43304576, 0.40211431, 0.37206735, 0.34301800, 0.31506490,
131    0.28829195, 0.26276832, 0.23854851, 0.21567274, 0.19416736, 0.17404546,
132    0.15530766, 0.13794294, 0.12192957, 0.10723616, 0.09382272, 0.08164178,
133    0.07063950, 0.06075685, 0.05193064, 0.04409466, 0.03718069, 0.03111947,
134    0.02584161, 0.02127838, 0.01736250, 0.01402878, 0.01121463, 0.00886058,
135    0.00691064, 0.00531256, 0.00401805, 0.00298291, 0.00216702, 0.00153438,
136    0.00105297, 0.00069463, 0.00043489, 0.00025272, 0.00013031, 0.0000527734,
137    0.00001000, 0.00000000};
138 /*
139 static double kaiser12_table[36] = {
140    0.99440475, 1.00000000, 0.99440475, 0.97779076, 0.95066529, 0.91384741,
141    0.86843014, 0.81573067, 0.75723148, 0.69451601, 0.62920216, 0.56287762,
142    0.49704014, 0.43304576, 0.37206735, 0.31506490, 0.26276832, 0.21567274,
143    0.17404546, 0.13794294, 0.10723616, 0.08164178, 0.06075685, 0.04409466,
144    0.03111947, 0.02127838, 0.01402878, 0.00886058, 0.00531256, 0.00298291,
145    0.00153438, 0.00069463, 0.00025272, 0.0000527734, 0.00000500, 0.00000000};
146 */
147 static double kaiser10_table[36] = {
148    0.99537781, 1.00000000, 0.99537781, 0.98162644, 0.95908712, 0.92831446,
149    0.89005583, 0.84522401, 0.79486424, 0.74011713, 0.68217934, 0.62226347,
150    0.56155915, 0.50119680, 0.44221549, 0.38553619, 0.33194107, 0.28205962,
151    0.23636152, 0.19515633, 0.15859932, 0.12670280, 0.09935205, 0.07632451,
152    0.05731132, 0.04193980, 0.02979584, 0.02044510, 0.01345224, 0.00839739,
153    0.00488951, 0.00257636, 0.00115101, 0.00035515, 0.00000000, 0.00000000};
154
155 static double kaiser8_table[36] = {
156    0.99635258, 1.00000000, 0.99635258, 0.98548012, 0.96759014, 0.94302200,
157    0.91223751, 0.87580811, 0.83439927, 0.78875245, 0.73966538, 0.68797126,
158    0.63451750, 0.58014482, 0.52566725, 0.47185369, 0.41941150, 0.36897272,
159    0.32108304, 0.27619388, 0.23465776, 0.19672670, 0.16255380, 0.13219758,
160    0.10562887, 0.08273982, 0.06335451, 0.04724088, 0.03412321, 0.02369490,
161    0.01563093, 0.00959968, 0.00527363, 0.00233883, 0.00050000, 0.00000000};
162    
163 static double kaiser6_table[36] = {
164    0.99733006, 1.00000000, 0.99733006, 0.98935595, 0.97618418, 0.95799003,
165    0.93501423, 0.90755855, 0.87598009, 0.84068475, 0.80211977, 0.76076565,
166    0.71712752, 0.67172623, 0.62508937, 0.57774224, 0.53019925, 0.48295561,
167    0.43647969, 0.39120616, 0.34752997, 0.30580127, 0.26632152, 0.22934058,
168    0.19505503, 0.16360756, 0.13508755, 0.10953262, 0.08693120, 0.06722600,
169    0.05031820, 0.03607231, 0.02432151, 0.01487334, 0.00752000, 0.00000000};
170
171 struct FuncDef {
172    double *table;
173    int oversample;
174 };
175       
176 static struct FuncDef _KAISER12 = {kaiser12_table, 64};
177 #define KAISER12 (&_KAISER12)
178 /*static struct FuncDef _KAISER12 = {kaiser12_table, 32};
179 #define KAISER12 (&_KAISER12)*/
180 static struct FuncDef _KAISER10 = {kaiser10_table, 32};
181 #define KAISER10 (&_KAISER10)
182 static struct FuncDef _KAISER8 = {kaiser8_table, 32};
183 #define KAISER8 (&_KAISER8)
184 static struct FuncDef _KAISER6 = {kaiser6_table, 32};
185 #define KAISER6 (&_KAISER6)
186
187 struct QualityMapping {
188    int base_length;
189    int oversample;
190    float downsample_bandwidth;
191    float upsample_bandwidth;
192    struct FuncDef *window_func;
193 };
194
195
196 /* This table maps conversion quality to internal parameters. There are two
197    reasons that explain why the up-sampling bandwidth is larger than the 
198    down-sampling bandwidth:
199    1) When up-sampling, we can assume that the spectrum is already attenuated
200       close to the Nyquist rate (from an A/D or a previous resampling filter)
201    2) Any aliasing that occurs very close to the Nyquist rate will be masked
202       by the sinusoids/noise just below the Nyquist rate (guaranteed only for
203       up-sampling).
204 */
205 static const struct QualityMapping quality_map[11] = {
206    {  8,  4, 0.830f, 0.860f, KAISER6 }, /* Q0 */
207    { 16,  4, 0.850f, 0.880f, KAISER6 }, /* Q1 */
208    { 32,  4, 0.882f, 0.910f, KAISER6 }, /* Q2 */  /* 82.3% cutoff ( ~60 dB stop) 6  */
209    { 48,  8, 0.895f, 0.917f, KAISER8 }, /* Q3 */  /* 84.9% cutoff ( ~80 dB stop) 8  */
210    { 64,  8, 0.921f, 0.940f, KAISER8 }, /* Q4 */  /* 88.7% cutoff ( ~80 dB stop) 8  */
211    { 80, 16, 0.922f, 0.940f, KAISER10}, /* Q5 */  /* 89.1% cutoff (~100 dB stop) 10 */
212    { 96, 16, 0.940f, 0.945f, KAISER10}, /* Q6 */  /* 91.5% cutoff (~100 dB stop) 10 */
213    {128, 16, 0.950f, 0.950f, KAISER10}, /* Q7 */  /* 93.1% cutoff (~100 dB stop) 10 */
214    {160, 16, 0.960f, 0.960f, KAISER10}, /* Q8 */  /* 94.5% cutoff (~100 dB stop) 10 */
215    {192, 32, 0.968f, 0.968f, KAISER12}, /* Q9 */  /* 95.5% cutoff (~100 dB stop) 10 */
216    {256, 32, 0.975f, 0.975f, KAISER12}, /* Q10 */ /* 96.6% cutoff (~100 dB stop) 10 */
217 };
218 /*8,24,40,56,80,104,128,160,200,256,320*/
219 static double compute_func(float x, struct FuncDef *func)
220 {
221    float y, frac;
222    double interp[4];
223    int ind; 
224    y = x*func->oversample;
225    ind = (int)floor(y);
226    frac = (y-ind);
227    /* CSE with handle the repeated powers */
228    interp[3] =  -0.1666666667*frac + 0.1666666667*(frac*frac*frac);
229    interp[2] = frac + 0.5*(frac*frac) - 0.5*(frac*frac*frac);
230    /*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/
231    interp[0] = -0.3333333333*frac + 0.5*(frac*frac) - 0.1666666667*(frac*frac*frac);
232    /* Just to make sure we don't have rounding problems */
233    interp[1] = 1.f-interp[3]-interp[2]-interp[0];
234    
235    /*sum = frac*accum[1] + (1-frac)*accum[2];*/
236    return interp[0]*func->table[ind] + interp[1]*func->table[ind+1] + interp[2]*func->table[ind+2] + interp[3]*func->table[ind+3];
237 }
238
239 #if 0
240 #include <stdio.h>
241 int main(int argc, char **argv)
242 {
243    int i;
244    for (i=0;i<256;i++)
245    {
246       printf ("%f\n", compute_func(i/256., KAISER12));
247    }
248    return 0;
249 }
250 #endif
251
252 #ifdef FIXED_POINT
253 /* The slow way of computing a sinc for the table. Should improve that some day */
254 static spx_word16_t sinc(float cutoff, float x, int N, struct FuncDef *window_func)
255 {
256    /*fprintf (stderr, "%f ", x);*/
257    float xx = x * cutoff;
258    if (fabs(x)<1e-6f)
259       return WORD2INT(32768.*cutoff);
260    else if (fabs(x) > .5f*N)
261       return 0;
262    /*FIXME: Can it really be any slower than this? */
263    return WORD2INT(32768.*cutoff*sin(M_PI*xx)/(M_PI*xx) * compute_func(fabs(2.*x/N), window_func));
264 }
265 #else
266 /* The slow way of computing a sinc for the table. Should improve that some day */
267 static spx_word16_t sinc(float cutoff, float x, int N, struct FuncDef *window_func)
268 {
269    /*fprintf (stderr, "%f ", x);*/
270    float xx = x * cutoff;
271    if (fabs(x)<1e-6)
272       return cutoff;
273    else if (fabs(x) > .5*N)
274       return 0;
275    /*FIXME: Can it really be any slower than this? */
276    return cutoff*sin(M_PI*xx)/(M_PI*xx) * compute_func(fabs(2.*x/N), window_func);
277 }
278 #endif
279
280 #ifdef FIXED_POINT
281 static void cubic_coef(spx_word16_t x, spx_word16_t interp[4])
282 {
283    /* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation
284    but I know it's MMSE-optimal on a sinc */
285    spx_word16_t x2, x3;
286    x2 = MULT16_16_P15(x, x);
287    x3 = MULT16_16_P15(x, x2);
288    interp[0] = PSHR32(MULT16_16(QCONST16(-0.16667f, 15),x) + MULT16_16(QCONST16(0.16667f, 15),x3),15);
289    interp[1] = EXTRACT16(EXTEND32(x) + SHR32(SUB32(EXTEND32(x2),EXTEND32(x3)),1));
290    interp[3] = PSHR32(MULT16_16(QCONST16(-0.33333f, 15),x) + MULT16_16(QCONST16(.5f,15),x2) - MULT16_16(QCONST16(0.16667f, 15),x3),15);
291    /* Just to make sure we don't have rounding problems */
292    interp[2] = Q15_ONE-interp[0]-interp[1]-interp[3];
293    if (interp[2]<32767)
294       interp[2]+=1;
295 }
296 #else
297 static void cubic_coef(spx_word16_t frac, spx_word16_t interp[4])
298 {
299    /* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation
300    but I know it's MMSE-optimal on a sinc */
301    interp[0] =  -0.16667f*frac + 0.16667f*frac*frac*frac;
302    interp[1] = frac + 0.5f*frac*frac - 0.5f*frac*frac*frac;
303    /*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/
304    interp[3] = -0.33333f*frac + 0.5f*frac*frac - 0.16667f*frac*frac*frac;
305    /* Just to make sure we don't have rounding problems */
306    interp[2] = 1.-interp[0]-interp[1]-interp[3];
307 }
308 #endif
309
310 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)
311 {
312    int N = st->filt_len;
313    int out_sample = 0;
314    spx_word16_t *mem;
315    int last_sample = st->last_sample[channel_index];
316    spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];
317    mem = st->mem + channel_index * st->mem_alloc_size;
318    while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))
319    {
320       int j;
321       spx_word32_t sum=0;
322       
323       /* We already have all the filter coefficients pre-computed in the table */
324       const spx_word16_t *ptr;
325       /* Do the memory part */
326       for (j=0;last_sample-N+1+j < 0;j++)
327       {
328          sum += MULT16_16(mem[last_sample+j],st->sinc_table[samp_frac_num*st->filt_len+j]);
329       }
330       
331       /* Do the new part */
332       ptr = in+st->in_stride*(last_sample-N+1+j);
333       for (;j<N;j++)
334       {
335          sum += MULT16_16(*ptr,st->sinc_table[samp_frac_num*st->filt_len+j]);
336          ptr += st->in_stride;
337       }
338    
339       *out = PSHR32(sum,15);
340       out += st->out_stride;
341       out_sample++;
342       last_sample += st->int_advance;
343       samp_frac_num += st->frac_advance;
344       if (samp_frac_num >= st->den_rate)
345       {
346          samp_frac_num -= st->den_rate;
347          last_sample++;
348       }
349    }
350    st->last_sample[channel_index] = last_sample;
351    st->samp_frac_num[channel_index] = samp_frac_num;
352    return out_sample;
353 }
354
355 #ifdef FIXED_POINT
356 #else
357 /* This is the same as the previous function, except with a double-precision accumulator */
358 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)
359 {
360    int N = st->filt_len;
361    int out_sample = 0;
362    spx_word16_t *mem;
363    int last_sample = st->last_sample[channel_index];
364    spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];
365    mem = st->mem + channel_index * st->mem_alloc_size;
366    while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))
367    {
368       int j;
369       double sum=0;
370       
371       /* We already have all the filter coefficients pre-computed in the table */
372       const spx_word16_t *ptr;
373       /* Do the memory part */
374       for (j=0;last_sample-N+1+j < 0;j++)
375       {
376          sum += MULT16_16(mem[last_sample+j],(double)st->sinc_table[samp_frac_num*st->filt_len+j]);
377       }
378       
379       /* Do the new part */
380       ptr = in+st->in_stride*(last_sample-N+1+j);
381       for (;j<N;j++)
382       {
383          sum += MULT16_16(*ptr,(double)st->sinc_table[samp_frac_num*st->filt_len+j]);
384          ptr += st->in_stride;
385       }
386    
387       *out = sum;
388       out += st->out_stride;
389       out_sample++;
390       last_sample += st->int_advance;
391       samp_frac_num += st->frac_advance;
392       if (samp_frac_num >= st->den_rate)
393       {
394          samp_frac_num -= st->den_rate;
395          last_sample++;
396       }
397    }
398    st->last_sample[channel_index] = last_sample;
399    st->samp_frac_num[channel_index] = samp_frac_num;
400    return out_sample;
401 }
402 #endif
403
404 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)
405 {
406    int N = st->filt_len;
407    int out_sample = 0;
408    spx_word16_t *mem;
409    int last_sample = st->last_sample[channel_index];
410    spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];
411    mem = st->mem + channel_index * st->mem_alloc_size;
412    while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))
413    {
414       int j;
415       spx_word32_t sum=0;
416       
417       /* We need to interpolate the sinc filter */
418       spx_word32_t accum[4] = {0.f,0.f, 0.f, 0.f};
419       spx_word16_t interp[4];
420       const spx_word16_t *ptr;
421       int offset;
422       spx_word16_t frac;
423       offset = samp_frac_num*st->oversample/st->den_rate;
424 #ifdef FIXED_POINT
425       frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate);
426 #else
427       frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate;
428 #endif
429          /* This code is written like this to make it easy to optimise with SIMD.
430       For most DSPs, it would be best to split the loops in two because most DSPs 
431       have only two accumulators */
432       for (j=0;last_sample-N+1+j < 0;j++)
433       {
434          spx_word16_t curr_mem = mem[last_sample+j];
435          accum[0] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-2]);
436          accum[1] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-1]);
437          accum[2] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset]);
438          accum[3] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset+1]);
439       }
440       ptr = in+st->in_stride*(last_sample-N+1+j);
441       /* Do the new part */
442       for (;j<N;j++)
443       {
444          spx_word16_t curr_in = *ptr;
445          ptr += st->in_stride;
446          accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]);
447          accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]);
448          accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]);
449          accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]);
450       }
451       cubic_coef(frac, interp);
452       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]);
453    
454       *out = PSHR32(sum,15);
455       out += st->out_stride;
456       out_sample++;
457       last_sample += st->int_advance;
458       samp_frac_num += st->frac_advance;
459       if (samp_frac_num >= st->den_rate)
460       {
461          samp_frac_num -= st->den_rate;
462          last_sample++;
463       }
464    }
465    st->last_sample[channel_index] = last_sample;
466    st->samp_frac_num[channel_index] = samp_frac_num;
467    return out_sample;
468 }
469
470 #ifdef FIXED_POINT
471 #else
472 /* This is the same as the previous function, except with a double-precision accumulator */
473 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)
474 {
475    int N = st->filt_len;
476    int out_sample = 0;
477    spx_word16_t *mem;
478    int last_sample = st->last_sample[channel_index];
479    spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];
480    mem = st->mem + channel_index * st->mem_alloc_size;
481    while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))
482    {
483       int j;
484       spx_word32_t sum=0;
485       
486       /* We need to interpolate the sinc filter */
487       double accum[4] = {0.f,0.f, 0.f, 0.f};
488       float interp[4];
489       const spx_word16_t *ptr;
490       float alpha = ((float)samp_frac_num)/st->den_rate;
491       int offset = samp_frac_num*st->oversample/st->den_rate;
492       float frac = alpha*st->oversample - offset;
493          /* This code is written like this to make it easy to optimise with SIMD.
494       For most DSPs, it would be best to split the loops in two because most DSPs 
495       have only two accumulators */
496       for (j=0;last_sample-N+1+j < 0;j++)
497       {
498          double curr_mem = mem[last_sample+j];
499          accum[0] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-2]);
500          accum[1] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-1]);
501          accum[2] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset]);
502          accum[3] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset+1]);
503       }
504       ptr = in+st->in_stride*(last_sample-N+1+j);
505       /* Do the new part */
506       for (;j<N;j++)
507       {
508          double curr_in = *ptr;
509          ptr += st->in_stride;
510          accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]);
511          accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]);
512          accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]);
513          accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]);
514       }
515       cubic_coef(frac, interp);
516       sum = interp[0]*accum[0] + interp[1]*accum[1] + interp[2]*accum[2] + interp[3]*accum[3];
517    
518       *out = PSHR32(sum,15);
519       out += st->out_stride;
520       out_sample++;
521       last_sample += st->int_advance;
522       samp_frac_num += st->frac_advance;
523       if (samp_frac_num >= st->den_rate)
524       {
525          samp_frac_num -= st->den_rate;
526          last_sample++;
527       }
528    }
529    st->last_sample[channel_index] = last_sample;
530    st->samp_frac_num[channel_index] = samp_frac_num;
531    return out_sample;
532 }
533 #endif
534
535 static void update_filter(SpeexResamplerState *st)
536 {
537    spx_uint32_t old_length;
538    
539    old_length = st->filt_len;
540    st->oversample = quality_map[st->quality].oversample;
541    st->filt_len = quality_map[st->quality].base_length;
542    
543    if (st->num_rate > st->den_rate)
544    {
545       /* down-sampling */
546       st->cutoff = quality_map[st->quality].downsample_bandwidth * st->den_rate / st->num_rate;
547       /* FIXME: divide the numerator and denominator by a certain amount if they're too large */
548       st->filt_len = st->filt_len*st->num_rate / st->den_rate;
549       /* Round down to make sure we have a multiple of 4 */
550       st->filt_len &= (~0x3);
551       if (2*st->den_rate < st->num_rate)
552          st->oversample >>= 1;
553       if (4*st->den_rate < st->num_rate)
554          st->oversample >>= 1;
555       if (8*st->den_rate < st->num_rate)
556          st->oversample >>= 1;
557       if (16*st->den_rate < st->num_rate)
558          st->oversample >>= 1;
559       if (st->oversample < 1)
560          st->oversample = 1;
561    } else {
562       /* up-sampling */
563       st->cutoff = quality_map[st->quality].upsample_bandwidth;
564    }
565
566    /* Choose the resampling type that requires the least amount of memory */
567    if (st->den_rate <= st->oversample)
568    {
569       spx_uint32_t i;
570       if (!st->sinc_table)
571          st->sinc_table = (spx_word16_t *)speex_alloc(st->filt_len*st->den_rate*sizeof(spx_word16_t));
572       else if (st->sinc_table_length < st->filt_len*st->den_rate)
573       {
574          st->sinc_table = (spx_word16_t *)speex_realloc(st->sinc_table,st->filt_len*st->den_rate*sizeof(spx_word16_t));
575          st->sinc_table_length = st->filt_len*st->den_rate;
576       }
577       for (i=0;i<st->den_rate;i++)
578       {
579          spx_uint32_t j;
580          for (j=0;j<st->filt_len;j++)
581          {
582             st->sinc_table[i*st->filt_len+j] = sinc(st->cutoff,((j-st->filt_len/2+1)-((float)i)/st->den_rate), st->filt_len, quality_map[st->quality].window_func);
583          }
584       }
585 #ifdef FIXED_POINT
586       st->resampler_ptr = resampler_basic_direct_single;
587 #else
588       if (st->quality>8)
589          st->resampler_ptr = resampler_basic_direct_double;
590       else
591          st->resampler_ptr = resampler_basic_direct_single;
592 #endif
593       /*fprintf (stderr, "resampler uses direct sinc table and normalised cutoff %f\n", cutoff);*/
594    } else {
595       spx_int32_t i;
596       if (!st->sinc_table)
597          st->sinc_table = (spx_word16_t *)speex_alloc((st->filt_len*st->oversample+8)*sizeof(spx_word16_t));
598       else if (st->sinc_table_length < st->filt_len*st->oversample+8)
599       {
600          st->sinc_table = (spx_word16_t *)speex_realloc(st->sinc_table,(st->filt_len*st->oversample+8)*sizeof(spx_word16_t));
601          st->sinc_table_length = st->filt_len*st->oversample+8;
602       }
603       for (i=-4;i<(spx_int32_t)(st->oversample*st->filt_len+4);i++)
604          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);
605 #ifdef FIXED_POINT
606       st->resampler_ptr = resampler_basic_interpolate_single;
607 #else
608       if (st->quality>8)
609          st->resampler_ptr = resampler_basic_interpolate_double;
610       else
611          st->resampler_ptr = resampler_basic_interpolate_single;
612 #endif
613       /*fprintf (stderr, "resampler uses interpolated sinc table and normalised cutoff %f\n", cutoff);*/
614    }
615    st->int_advance = st->num_rate/st->den_rate;
616    st->frac_advance = st->num_rate%st->den_rate;
617
618    if (!st->mem)
619    {
620       spx_uint32_t i;
621       st->mem = (spx_word16_t*)speex_alloc(st->nb_channels*(st->filt_len-1) * sizeof(spx_word16_t));
622       for (i=0;i<st->nb_channels*(st->filt_len-1);i++)
623          st->mem[i] = 0;
624       st->mem_alloc_size = st->filt_len-1;
625       /*speex_warning("init filter");*/
626    } else if (!st->started)
627    {
628       spx_uint32_t i;
629       st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*(st->filt_len-1) * sizeof(spx_word16_t));
630       for (i=0;i<st->nb_channels*(st->filt_len-1);i++)
631          st->mem[i] = 0;
632       st->mem_alloc_size = st->filt_len-1;
633       /*speex_warning("reinit filter");*/
634    } else if (st->filt_len > old_length)
635    {
636       spx_uint32_t i;
637       /* Increase the filter length */
638       /*speex_warning("increase filter size");*/
639       int old_alloc_size = st->mem_alloc_size;
640       if (st->filt_len-1 > st->mem_alloc_size)
641       {
642          st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*(st->filt_len-1) * sizeof(spx_word16_t));
643          st->mem_alloc_size = st->filt_len-1;
644       }
645       for (i=0;i<st->nb_channels;i++)
646       {
647          spx_uint32_t j;
648          /* Copy data going backward */
649          for (j=0;j<old_length-1;j++)
650             st->mem[i*st->mem_alloc_size+(st->filt_len-2-j)] = st->mem[i*old_alloc_size+(old_length-2-j)];
651          /* Then put zeros for lack of anything better */
652          for (;j<st->filt_len-1;j++)
653             st->mem[i*st->mem_alloc_size+(st->filt_len-2-j)] = 0;
654          /* Adjust last_sample */
655          st->last_sample[i] += (st->filt_len - old_length)/2;
656       }
657    } else if (st->filt_len < old_length)
658    {
659       spx_uint32_t i;
660       /* Reduce filter length, this a bit tricky */
661       /* We must copy the memory that's no longer used into a new "magic" 
662          section that will be used directly as input the next time(s)*/
663       for (i=0;i<st->nb_channels;i++)
664       {
665          spx_uint32_t j;
666          st->magic_samples[i] = (old_length - st->filt_len)/2;
667          /* Copy data going backward */
668          for (j=0;j<st->filt_len-1+st->magic_samples[i];j++)
669             st->mem[i*st->mem_alloc_size+j] = st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]];
670       }
671    }
672
673 }
674
675 SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err)
676 {
677    return speex_resampler_init_frac(nb_channels, in_rate, out_rate, in_rate, out_rate, quality, err);
678 }
679
680 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)
681 {
682    spx_uint32_t i;
683    SpeexResamplerState *st;
684    if (quality > 10 || quality < 0)
685    {
686       if (err)
687          *err = RESAMPLER_ERR_INVALID_ARG;
688       return NULL;
689    }
690    st = (SpeexResamplerState *)speex_alloc(sizeof(SpeexResamplerState));
691    st->initialised = 0;
692    st->started = 0;
693    st->in_rate = 0;
694    st->out_rate = 0;
695    st->num_rate = 0;
696    st->den_rate = 0;
697    st->quality = -1;
698    st->sinc_table_length = 0;
699    st->mem_alloc_size = 0;
700    st->filt_len = 0;
701    st->mem = 0;
702    st->resampler_ptr = 0;
703          
704    st->cutoff = 1.f;
705    st->nb_channels = nb_channels;
706    st->in_stride = 1;
707    st->out_stride = 1;
708    
709    /* Per channel data */
710    st->last_sample = (spx_int32_t*)speex_alloc(nb_channels*sizeof(int));
711    st->magic_samples = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int));
712    st->samp_frac_num = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int));
713    for (i=0;i<nb_channels;i++)
714    {
715       st->last_sample[i] = 0;
716       st->magic_samples[i] = 0;
717       st->samp_frac_num[i] = 0;
718    }
719
720    speex_resampler_set_quality(st, quality);
721    speex_resampler_set_rate_frac(st, ratio_num, ratio_den, in_rate, out_rate);
722
723    
724    update_filter(st);
725    
726    st->initialised = 1;
727    if (err)
728       *err = RESAMPLER_ERR_SUCCESS;
729
730    return st;
731 }
732
733 void speex_resampler_destroy(SpeexResamplerState *st)
734 {
735    speex_free(st->mem);
736    speex_free(st->sinc_table);
737    speex_free(st->last_sample);
738    speex_free(st->magic_samples);
739    speex_free(st->samp_frac_num);
740    speex_free(st);
741 }
742
743
744
745 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)
746 {
747    int j=0;
748    int N = st->filt_len;
749    int out_sample = 0;
750    spx_word16_t *mem;
751    spx_uint32_t tmp_out_len = 0;
752    mem = st->mem + channel_index * st->mem_alloc_size;
753    st->started = 1;
754    
755    /* Handle the case where we have samples left from a reduction in filter length */
756    if (st->magic_samples[channel_index])
757    {
758       spx_uint32_t tmp_in_len;
759       spx_uint32_t tmp_magic;
760       tmp_in_len = st->magic_samples[channel_index];
761       tmp_out_len = *out_len;
762       /* FIXME: Need to handle the case where the out array is too small */
763       /* magic_samples needs to be set to zero to avoid infinite recursion */
764       tmp_magic = st->magic_samples[channel_index];
765       st->magic_samples[channel_index] = 0;
766       speex_resampler_process_native(st, channel_index, mem+N-1, &tmp_in_len, out, &tmp_out_len);
767       /*speex_warning_int("extra samples:", tmp_out_len);*/
768       /* If we couldn't process all "magic" input samples, save the rest for next time */
769       if (tmp_in_len < tmp_magic)
770       {
771          spx_uint32_t i;
772          st->magic_samples[channel_index] = tmp_magic-tmp_in_len;
773          for (i=0;i<st->magic_samples[channel_index];i++)
774             mem[N-1+i]=mem[N-1+i+tmp_in_len];
775       }
776       out += tmp_out_len;
777       *out_len -= tmp_out_len;
778    }
779    
780    /* Call the right resampler through the function ptr */
781    out_sample = st->resampler_ptr(st, channel_index, in, in_len, out, out_len);
782    
783    if (st->last_sample[channel_index] < (spx_int32_t)*in_len)
784       *in_len = st->last_sample[channel_index];
785    *out_len = out_sample+tmp_out_len;
786    st->last_sample[channel_index] -= *in_len;
787    
788    for (j=0;j<N-1-(spx_int32_t)*in_len;j++)
789       mem[j] = mem[j+*in_len];
790    for (;j<N-1;j++)
791       mem[j] = in[st->in_stride*(j+*in_len-N+1)];
792    
793    return RESAMPLER_ERR_SUCCESS;
794 }
795
796 #define FIXED_STACK_ALLOC 1024
797
798 #ifdef FIXED_POINT
799 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)
800 {
801    spx_uint32_t i;
802    int istride_save, ostride_save;
803 #ifdef VAR_ARRAYS
804    spx_word16_t x[*in_len];
805    spx_word16_t y[*out_len];
806    /*VARDECL(spx_word16_t *x);
807    VARDECL(spx_word16_t *y);
808    ALLOC(x, *in_len, spx_word16_t);
809    ALLOC(y, *out_len, spx_word16_t);*/
810    istride_save = st->in_stride;
811    ostride_save = st->out_stride;
812    for (i=0;i<*in_len;i++)
813       x[i] = WORD2INT(in[i*st->in_stride]);
814    st->in_stride = st->out_stride = 1;
815    speex_resampler_process_native(st, channel_index, x, in_len, y, out_len);
816    st->in_stride = istride_save;
817    st->out_stride = ostride_save;
818    for (i=0;i<*out_len;i++)
819       out[i*st->out_stride] = y[i];
820 #else
821    spx_word16_t x[FIXED_STACK_ALLOC];
822    spx_word16_t y[FIXED_STACK_ALLOC];
823    spx_uint32_t ilen=*in_len, olen=*out_len;
824    istride_save = st->in_stride;
825    ostride_save = st->out_stride;
826    while (ilen && olen)
827    {
828       spx_uint32_t ichunk, ochunk;
829       ichunk = ilen;
830       ochunk = olen;
831       if (ichunk>FIXED_STACK_ALLOC)
832          ichunk=FIXED_STACK_ALLOC;
833       if (ochunk>FIXED_STACK_ALLOC)
834          ochunk=FIXED_STACK_ALLOC;
835       for (i=0;i<ichunk;i++)
836          x[i] = WORD2INT(in[i*st->in_stride]);
837       st->in_stride = st->out_stride = 1;
838       speex_resampler_process_native(st, channel_index, x, &ichunk, y, &ochunk);
839       st->in_stride = istride_save;
840       st->out_stride = ostride_save;
841       for (i=0;i<ochunk;i++)
842          out[i*st->out_stride] = y[i];
843       out += ochunk;
844       in += ichunk;
845       ilen -= ichunk;
846       olen -= ochunk;
847    }
848    *in_len -= ilen;
849    *out_len -= olen;   
850 #endif
851    return RESAMPLER_ERR_SUCCESS;
852 }
853 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)
854 {
855    return speex_resampler_process_native(st, channel_index, in, in_len, out, out_len);
856 }
857 #else
858 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)
859 {
860    return speex_resampler_process_native(st, channel_index, in, in_len, out, out_len);
861 }
862 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)
863 {
864    spx_uint32_t i;
865    int istride_save, ostride_save;
866 #ifdef VAR_ARRAYS
867    spx_word16_t x[*in_len];
868    spx_word16_t y[*out_len];
869    /*VARDECL(spx_word16_t *x);
870    VARDECL(spx_word16_t *y);
871    ALLOC(x, *in_len, spx_word16_t);
872    ALLOC(y, *out_len, spx_word16_t);*/
873    istride_save = st->in_stride;
874    ostride_save = st->out_stride;
875    for (i=0;i<*in_len;i++)
876       x[i] = in[i*st->in_stride];
877    st->in_stride = st->out_stride = 1;
878    speex_resampler_process_native(st, channel_index, x, in_len, y, out_len);
879    st->in_stride = istride_save;
880    st->out_stride = ostride_save;
881    for (i=0;i<*out_len;i++)
882       out[i*st->out_stride] = WORD2INT(y[i]);
883 #else
884    spx_word16_t x[FIXED_STACK_ALLOC];
885    spx_word16_t y[FIXED_STACK_ALLOC];
886    spx_uint32_t ilen=*in_len, olen=*out_len;
887    istride_save = st->in_stride;
888    ostride_save = st->out_stride;
889    while (ilen && olen)
890    {
891       spx_uint32_t ichunk, ochunk;
892       ichunk = ilen;
893       ochunk = olen;
894       if (ichunk>FIXED_STACK_ALLOC)
895          ichunk=FIXED_STACK_ALLOC;
896       if (ochunk>FIXED_STACK_ALLOC)
897          ochunk=FIXED_STACK_ALLOC;
898       for (i=0;i<ichunk;i++)
899          x[i] = in[i*st->in_stride];
900       st->in_stride = st->out_stride = 1;
901       speex_resampler_process_native(st, channel_index, x, &ichunk, y, &ochunk);
902       st->in_stride = istride_save;
903       st->out_stride = ostride_save;
904       for (i=0;i<ochunk;i++)
905          out[i*st->out_stride] = WORD2INT(y[i]);
906       out += ochunk;
907       in += ichunk;
908       ilen -= ichunk;
909       olen -= ochunk;
910    }
911    *in_len -= ilen;
912    *out_len -= olen;   
913 #endif
914    return RESAMPLER_ERR_SUCCESS;
915 }
916 #endif
917
918 int speex_resampler_process_interleaved_float(SpeexResamplerState *st, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len)
919 {
920    spx_uint32_t i;
921    int istride_save, ostride_save;
922    istride_save = st->in_stride;
923    ostride_save = st->out_stride;
924    st->in_stride = st->out_stride = st->nb_channels;
925    for (i=0;i<st->nb_channels;i++)
926    {
927       speex_resampler_process_float(st, i, in+i, in_len, out+i, out_len);
928    }
929    st->in_stride = istride_save;
930    st->out_stride = ostride_save;
931    return RESAMPLER_ERR_SUCCESS;
932 }
933
934 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)
935 {
936    spx_uint32_t i;
937    int istride_save, ostride_save;
938    istride_save = st->in_stride;
939    ostride_save = st->out_stride;
940    st->in_stride = st->out_stride = st->nb_channels;
941    for (i=0;i<st->nb_channels;i++)
942    {
943       speex_resampler_process_int(st, i, in+i, in_len, out+i, out_len);
944    }
945    st->in_stride = istride_save;
946    st->out_stride = ostride_save;
947    return RESAMPLER_ERR_SUCCESS;
948 }
949
950 int speex_resampler_set_rate(SpeexResamplerState *st, spx_uint32_t in_rate, spx_uint32_t out_rate)
951 {
952    return speex_resampler_set_rate_frac(st, in_rate, out_rate, in_rate, out_rate);
953 }
954
955 void speex_resampler_get_rate(SpeexResamplerState *st, spx_uint32_t *in_rate, spx_uint32_t *out_rate)
956 {
957    *in_rate = st->in_rate;
958    *out_rate = st->out_rate;
959 }
960
961 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)
962 {
963    int fact;
964    if (st->in_rate == in_rate && st->out_rate == out_rate && st->num_rate == ratio_num && st->den_rate == ratio_den)
965       return RESAMPLER_ERR_SUCCESS;
966    
967    st->in_rate = in_rate;
968    st->out_rate = out_rate;
969    st->num_rate = ratio_num;
970    st->den_rate = ratio_den;
971    /* FIXME: This is terribly inefficient, but who cares (at least for now)? */
972    for (fact=2;fact<=sqrt(IMAX(in_rate, out_rate));fact++)
973    {
974       while ((st->num_rate % fact == 0) && (st->den_rate % fact == 0))
975       {
976          st->num_rate /= fact;
977          st->den_rate /= fact;
978       }
979    }
980       
981    if (st->initialised)
982       update_filter(st);
983    return RESAMPLER_ERR_SUCCESS;
984 }
985
986 void speex_resampler_get_ratio(SpeexResamplerState *st, spx_uint32_t *ratio_num, spx_uint32_t *ratio_den)
987 {
988    *ratio_num = st->num_rate;
989    *ratio_den = st->den_rate;
990 }
991
992 int speex_resampler_set_quality(SpeexResamplerState *st, int quality)
993 {
994    if (quality > 10 || quality < 0)
995       return RESAMPLER_ERR_INVALID_ARG;
996    if (st->quality == quality)
997       return RESAMPLER_ERR_SUCCESS;
998    st->quality = quality;
999    if (st->initialised)
1000       update_filter(st);
1001    return RESAMPLER_ERR_SUCCESS;
1002 }
1003
1004 void speex_resampler_get_quality(SpeexResamplerState *st, int *quality)
1005 {
1006    *quality = st->quality;
1007 }
1008
1009 void speex_resampler_set_input_stride(SpeexResamplerState *st, spx_uint32_t stride)
1010 {
1011    st->in_stride = stride;
1012 }
1013
1014 void speex_resampler_get_input_stride(SpeexResamplerState *st, spx_uint32_t *stride)
1015 {
1016    *stride = st->in_stride;
1017 }
1018
1019 void speex_resampler_set_output_stride(SpeexResamplerState *st, spx_uint32_t stride)
1020 {
1021    st->out_stride = stride;
1022 }
1023
1024 void speex_resampler_get_output_stride(SpeexResamplerState *st, spx_uint32_t *stride)
1025 {
1026    *stride = st->out_stride;
1027 }
1028
1029 int speex_resampler_skip_zeros(SpeexResamplerState *st)
1030 {
1031    spx_uint32_t i;
1032    for (i=0;i<st->nb_channels;i++)
1033       st->last_sample[i] = st->filt_len/2;
1034    return RESAMPLER_ERR_SUCCESS;
1035 }
1036
1037 int speex_resampler_reset_mem(SpeexResamplerState *st)
1038 {
1039    spx_uint32_t i;
1040    for (i=0;i<st->nb_channels*(st->filt_len-1);i++)
1041       st->mem[i] = 0;
1042    return RESAMPLER_ERR_SUCCESS;
1043 }
1044
1045 const char *speex_resampler_strerror(int err)
1046 {
1047    switch (err)
1048    {
1049       case RESAMPLER_ERR_SUCCESS:
1050          return "Success.";
1051       case RESAMPLER_ERR_ALLOC_FAILED:
1052          return "Memory allocation failed.";
1053       case RESAMPLER_ERR_BAD_STATE:
1054          return "Bad resampler state.";
1055       case RESAMPLER_ERR_INVALID_ARG:
1056          return "Invalid argument.";
1057       case RESAMPLER_ERR_PTR_OVERLAP:
1058          return "Input and output buffers overlap.";
1059       default:
1060          return "Unknown error. Bad error code or strange version mismatch.";
1061    }
1062 }