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