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