• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>
speex_alloc(int size)66 static void *speex_alloc (int size) {return calloc(size,1);}
speex_realloc(void * ptr,int size)67 static void *speex_realloc (void *ptr, int size) {return realloc(ptr, size);}
speex_free(void * ptr)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 #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 
113 typedef int (*resampler_basic_func)(SpeexResamplerState *, spx_uint32_t , const spx_word16_t *, spx_uint32_t *, spx_word16_t *, spx_uint32_t *);
114 
115 struct 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 
147 static 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 /*
161 static 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 */
169 static 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 
177 static 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 
185 static 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 
193 struct FuncDef {
194    double *table;
195    int oversample;
196 };
197 
198 static struct FuncDef _KAISER12 = {kaiser12_table, 64};
199 #define KAISER12 (&_KAISER12)
200 /*static struct FuncDef _KAISER12 = {kaiser12_table, 32};
201 #define KAISER12 (&_KAISER12)*/
202 static struct FuncDef _KAISER10 = {kaiser10_table, 32};
203 #define KAISER10 (&_KAISER10)
204 static struct FuncDef _KAISER8 = {kaiser8_table, 32};
205 #define KAISER8 (&_KAISER8)
206 static struct FuncDef _KAISER6 = {kaiser6_table, 32};
207 #define KAISER6 (&_KAISER6)
208 
209 struct 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 */
227 static 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*/
compute_func(float x,struct FuncDef * func)241 static 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>
263 int 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 */
sinc(float cutoff,float x,int N,struct FuncDef * window_func)276 static 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 */
sinc(float cutoff,float x,int N,struct FuncDef * window_func)289 static 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
cubic_coef(spx_word16_t x,spx_word16_t interp[4])303 static 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
cubic_coef(spx_word16_t frac,spx_word16_t interp[4])319 static 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 
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)332 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)
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 */
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)384 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)
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 
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)433 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)
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 */
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)496 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)
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 
update_filter(SpeexResamplerState * st)556 static 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_uint32_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_uint32_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             spx_int32_t k;
685             for (k=old_length-2+st->magic_samples[i];k>=0;k--)
686                st->mem[i*st->mem_alloc_size+k+st->magic_samples[i]] = st->mem[i*old_alloc_size+k];
687             for (j=0;j<st->magic_samples[i];j++)
688                st->mem[i*st->mem_alloc_size+j] = 0;
689             st->magic_samples[i] = 0;
690          }
691          if (st->filt_len > olen)
692          {
693             /* If the new filter length is still bigger than the "augmented" length */
694             /* Copy data going backward */
695             for (j=0;j<olen-1;j++)
696                st->mem[i*st->mem_alloc_size+(st->filt_len-2-j)] = st->mem[i*st->mem_alloc_size+(olen-2-j)];
697             /* Then put zeros for lack of anything better */
698             for (;j<st->filt_len-1;j++)
699                st->mem[i*st->mem_alloc_size+(st->filt_len-2-j)] = 0;
700             /* Adjust last_sample */
701             st->last_sample[i] += (st->filt_len - olen)/2;
702          } else {
703             /* Put back some of the magic! */
704             st->magic_samples[i] = (olen - st->filt_len)/2;
705             for (j=0;j<st->filt_len-1+st->magic_samples[i];j++)
706                st->mem[i*st->mem_alloc_size+j] = st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]];
707          }
708       }
709    } else if (st->filt_len < old_length)
710    {
711       spx_uint32_t i;
712       /* Reduce filter length, this a bit tricky. We need to store some of the memory as "magic"
713          samples so they can be used directly as input the next time(s) */
714       for (i=0;i<st->nb_channels;i++)
715       {
716          spx_uint32_t j;
717          spx_uint32_t old_magic = st->magic_samples[i];
718          st->magic_samples[i] = (old_length - st->filt_len)/2;
719          /* We must copy some of the memory that's no longer used */
720          /* Copy data going backward */
721          for (j=0;j<st->filt_len-1+st->magic_samples[i]+old_magic;j++)
722             st->mem[i*st->mem_alloc_size+j] = st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]];
723          st->magic_samples[i] += old_magic;
724       }
725    }
726 
727 }
728 
speex_resampler_init(spx_uint32_t nb_channels,spx_uint32_t in_rate,spx_uint32_t out_rate,int quality,int * err)729 EXPORT SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err)
730 {
731    return speex_resampler_init_frac(nb_channels, in_rate, out_rate, in_rate, out_rate, quality, err);
732 }
733 
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 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)
735 {
736    spx_uint32_t i;
737    SpeexResamplerState *st;
738    if (quality > 10 || quality < 0)
739    {
740       if (err)
741          *err = RESAMPLER_ERR_INVALID_ARG;
742       return NULL;
743    }
744    st = (SpeexResamplerState *)speex_alloc(sizeof(SpeexResamplerState));
745    st->initialised = 0;
746    st->started = 0;
747    st->in_rate = 0;
748    st->out_rate = 0;
749    st->num_rate = 0;
750    st->den_rate = 0;
751    st->quality = -1;
752    st->sinc_table_length = 0;
753    st->mem_alloc_size = 0;
754    st->filt_len = 0;
755    st->mem = 0;
756    st->resampler_ptr = 0;
757 
758    st->cutoff = 1.f;
759    st->nb_channels = nb_channels;
760    st->in_stride = 1;
761    st->out_stride = 1;
762 
763 #ifdef FIXED_POINT
764    st->buffer_size = 160;
765 #else
766    st->buffer_size = 160;
767 #endif
768 
769    /* Per channel data */
770    st->last_sample = (spx_int32_t*)speex_alloc(nb_channels*sizeof(int));
771    st->magic_samples = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int));
772    st->samp_frac_num = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int));
773    for (i=0;i<nb_channels;i++)
774    {
775       st->last_sample[i] = 0;
776       st->magic_samples[i] = 0;
777       st->samp_frac_num[i] = 0;
778    }
779 
780    speex_resampler_set_quality(st, quality);
781    speex_resampler_set_rate_frac(st, ratio_num, ratio_den, in_rate, out_rate);
782 
783 
784    update_filter(st);
785 
786    st->initialised = 1;
787    if (err)
788       *err = RESAMPLER_ERR_SUCCESS;
789 
790    return st;
791 }
792 
speex_resampler_destroy(SpeexResamplerState * st)793 EXPORT void speex_resampler_destroy(SpeexResamplerState *st)
794 {
795    speex_free(st->mem);
796    speex_free(st->sinc_table);
797    speex_free(st->last_sample);
798    speex_free(st->magic_samples);
799    speex_free(st->samp_frac_num);
800    speex_free(st);
801 }
802 
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 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)
804 {
805    int j=0;
806    const int N = st->filt_len;
807    int out_sample = 0;
808    spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size;
809    spx_uint32_t ilen;
810 
811    st->started = 1;
812 
813    /* Call the right resampler through the function ptr */
814    out_sample = st->resampler_ptr(st, channel_index, mem, in_len, out, out_len);
815 
816    if (st->last_sample[channel_index] < (spx_int32_t)*in_len)
817       *in_len = st->last_sample[channel_index];
818    *out_len = out_sample;
819    st->last_sample[channel_index] -= *in_len;
820 
821    ilen = *in_len;
822 
823    for(j=0;j<N-1;++j)
824      mem[j] = mem[j+ilen];
825 
826    return RESAMPLER_ERR_SUCCESS;
827 }
828 
speex_resampler_magic(SpeexResamplerState * st,spx_uint32_t channel_index,spx_word16_t ** out,spx_uint32_t out_len)829 static int speex_resampler_magic(SpeexResamplerState *st, spx_uint32_t channel_index, spx_word16_t **out, spx_uint32_t out_len) {
830    spx_uint32_t tmp_in_len = st->magic_samples[channel_index];
831    spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size;
832    const int N = st->filt_len;
833 
834    speex_resampler_process_native(st, channel_index, &tmp_in_len, *out, &out_len);
835 
836    st->magic_samples[channel_index] -= tmp_in_len;
837 
838    /* If we couldn't process all "magic" input samples, save the rest for next time */
839    if (st->magic_samples[channel_index])
840    {
841       spx_uint32_t i;
842       for (i=0;i<st->magic_samples[channel_index];i++)
843          mem[N-1+i]=mem[N-1+i+tmp_in_len];
844    }
845    *out += out_len*st->out_stride;
846    return out_len;
847 }
848 
849 #ifdef FIXED_POINT
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 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)
851 #else
852 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)
853 #endif
854 {
855    spx_uint32_t j;
856    spx_uint32_t ilen = *in_len;
857    spx_uint32_t olen = *out_len;
858    spx_word16_t *x = st->mem + channel_index * st->mem_alloc_size;
859    const int filt_offs = st->filt_len - 1;
860    const spx_uint32_t xlen = st->mem_alloc_size - filt_offs;
861    const int istride = st->in_stride;
862 
863    if (st->magic_samples[channel_index])
864       olen -= speex_resampler_magic(st, channel_index, &out, olen);
865    if (! st->magic_samples[channel_index]) {
866       while (ilen && olen) {
867         spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen;
868         spx_uint32_t ochunk = olen;
869 
870         if (in) {
871            for(j=0;j<ichunk;++j)
872               x[j+filt_offs]=in[j*istride];
873         } else {
874           for(j=0;j<ichunk;++j)
875             x[j+filt_offs]=0;
876         }
877         speex_resampler_process_native(st, channel_index, &ichunk, out, &ochunk);
878         ilen -= ichunk;
879         olen -= ochunk;
880         out += ochunk * st->out_stride;
881         if (in)
882            in += ichunk * istride;
883       }
884    }
885    *in_len -= ilen;
886    *out_len -= olen;
887    return RESAMPLER_ERR_SUCCESS;
888 }
889 
890 #ifdef FIXED_POINT
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 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)
892 #else
893 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)
894 #endif
895 {
896    spx_uint32_t j;
897    const int istride_save = st->in_stride;
898    const int ostride_save = st->out_stride;
899    spx_uint32_t ilen = *in_len;
900    spx_uint32_t olen = *out_len;
901    spx_word16_t *x = st->mem + channel_index * st->mem_alloc_size;
902    const spx_uint32_t xlen = st->mem_alloc_size - (st->filt_len - 1);
903 #ifdef VAR_ARRAYS
904    const unsigned int ylen = (olen < FIXED_STACK_ALLOC) ? olen : FIXED_STACK_ALLOC;
905    VARDECL(spx_word16_t *ystack);
906    ALLOC(ystack, ylen, spx_word16_t);
907 #else
908    const unsigned int ylen = FIXED_STACK_ALLOC;
909    spx_word16_t ystack[FIXED_STACK_ALLOC];
910 #endif
911 
912    st->out_stride = 1;
913 
914    while (ilen && olen) {
915      spx_word16_t *y = ystack;
916      spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen;
917      spx_uint32_t ochunk = (olen > ylen) ? ylen : olen;
918      spx_uint32_t omagic = 0;
919 
920      if (st->magic_samples[channel_index]) {
921        omagic = speex_resampler_magic(st, channel_index, &y, ochunk);
922        ochunk -= omagic;
923        olen -= omagic;
924      }
925      if (! st->magic_samples[channel_index]) {
926        if (in) {
927          for(j=0;j<ichunk;++j)
928 #ifdef FIXED_POINT
929            x[j+st->filt_len-1]=WORD2INT(in[j*istride_save]);
930 #else
931            x[j+st->filt_len-1]=in[j*istride_save];
932 #endif
933        } else {
934          for(j=0;j<ichunk;++j)
935            x[j+st->filt_len-1]=0;
936        }
937 
938        speex_resampler_process_native(st, channel_index, &ichunk, y, &ochunk);
939      } else {
940        ichunk = 0;
941        ochunk = 0;
942      }
943 
944      for (j=0;j<ochunk+omagic;++j)
945 #ifdef FIXED_POINT
946         out[j*ostride_save] = ystack[j];
947 #else
948         out[j*ostride_save] = WORD2INT(ystack[j]);
949 #endif
950 
951      ilen -= ichunk;
952      olen -= ochunk;
953      out += (ochunk+omagic) * ostride_save;
954      if (in)
955        in += ichunk * istride_save;
956    }
957    st->out_stride = ostride_save;
958    *in_len -= ilen;
959    *out_len -= olen;
960 
961    return RESAMPLER_ERR_SUCCESS;
962 }
963 
speex_resampler_process_interleaved_float(SpeexResamplerState * st,const float * in,spx_uint32_t * in_len,float * out,spx_uint32_t * out_len)964 EXPORT int speex_resampler_process_interleaved_float(SpeexResamplerState *st, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len)
965 {
966    spx_uint32_t i;
967    int istride_save, ostride_save;
968    spx_uint32_t bak_len = *out_len;
969    istride_save = st->in_stride;
970    ostride_save = st->out_stride;
971    st->in_stride = st->out_stride = st->nb_channels;
972    for (i=0;i<st->nb_channels;i++)
973    {
974       *out_len = bak_len;
975       if (in != NULL)
976          speex_resampler_process_float(st, i, in+i, in_len, out+i, out_len);
977       else
978          speex_resampler_process_float(st, i, NULL, in_len, out+i, out_len);
979    }
980    st->in_stride = istride_save;
981    st->out_stride = ostride_save;
982    return RESAMPLER_ERR_SUCCESS;
983 }
984 
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 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)
986 {
987    spx_uint32_t i;
988    int istride_save, ostride_save;
989    spx_uint32_t bak_len = *out_len;
990    istride_save = st->in_stride;
991    ostride_save = st->out_stride;
992    st->in_stride = st->out_stride = st->nb_channels;
993    for (i=0;i<st->nb_channels;i++)
994    {
995       *out_len = bak_len;
996       if (in != NULL)
997          speex_resampler_process_int(st, i, in+i, in_len, out+i, out_len);
998       else
999          speex_resampler_process_int(st, i, NULL, in_len, out+i, out_len);
1000    }
1001    st->in_stride = istride_save;
1002    st->out_stride = ostride_save;
1003    return RESAMPLER_ERR_SUCCESS;
1004 }
1005 
speex_resampler_set_rate(SpeexResamplerState * st,spx_uint32_t in_rate,spx_uint32_t out_rate)1006 EXPORT int speex_resampler_set_rate(SpeexResamplerState *st, spx_uint32_t in_rate, spx_uint32_t out_rate)
1007 {
1008    return speex_resampler_set_rate_frac(st, in_rate, out_rate, in_rate, out_rate);
1009 }
1010 
speex_resampler_get_rate(SpeexResamplerState * st,spx_uint32_t * in_rate,spx_uint32_t * out_rate)1011 EXPORT void speex_resampler_get_rate(SpeexResamplerState *st, spx_uint32_t *in_rate, spx_uint32_t *out_rate)
1012 {
1013    *in_rate = st->in_rate;
1014    *out_rate = st->out_rate;
1015 }
1016 
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 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)
1018 {
1019    spx_uint32_t fact;
1020    spx_uint32_t old_den;
1021    spx_uint32_t i;
1022    if (st->in_rate == in_rate && st->out_rate == out_rate && st->num_rate == ratio_num && st->den_rate == ratio_den)
1023       return RESAMPLER_ERR_SUCCESS;
1024 
1025    old_den = st->den_rate;
1026    st->in_rate = in_rate;
1027    st->out_rate = out_rate;
1028    st->num_rate = ratio_num;
1029    st->den_rate = ratio_den;
1030    /* FIXME: This is terribly inefficient, but who cares (at least for now)? */
1031    for (fact=2;fact<=IMIN(st->num_rate, st->den_rate);fact++)
1032    {
1033       while ((st->num_rate % fact == 0) && (st->den_rate % fact == 0))
1034       {
1035          st->num_rate /= fact;
1036          st->den_rate /= fact;
1037       }
1038    }
1039 
1040    if (old_den > 0)
1041    {
1042       for (i=0;i<st->nb_channels;i++)
1043       {
1044          st->samp_frac_num[i]=st->samp_frac_num[i]*st->den_rate/old_den;
1045          /* Safety net */
1046          if (st->samp_frac_num[i] >= st->den_rate)
1047             st->samp_frac_num[i] = st->den_rate-1;
1048       }
1049    }
1050 
1051    if (st->initialised)
1052       update_filter(st);
1053    return RESAMPLER_ERR_SUCCESS;
1054 }
1055 
speex_resampler_get_ratio(SpeexResamplerState * st,spx_uint32_t * ratio_num,spx_uint32_t * ratio_den)1056 EXPORT void speex_resampler_get_ratio(SpeexResamplerState *st, spx_uint32_t *ratio_num, spx_uint32_t *ratio_den)
1057 {
1058    *ratio_num = st->num_rate;
1059    *ratio_den = st->den_rate;
1060 }
1061 
speex_resampler_set_quality(SpeexResamplerState * st,int quality)1062 EXPORT int speex_resampler_set_quality(SpeexResamplerState *st, int quality)
1063 {
1064    if (quality > 10 || quality < 0)
1065       return RESAMPLER_ERR_INVALID_ARG;
1066    if (st->quality == quality)
1067       return RESAMPLER_ERR_SUCCESS;
1068    st->quality = quality;
1069    if (st->initialised)
1070       update_filter(st);
1071    return RESAMPLER_ERR_SUCCESS;
1072 }
1073 
speex_resampler_get_quality(SpeexResamplerState * st,int * quality)1074 EXPORT void speex_resampler_get_quality(SpeexResamplerState *st, int *quality)
1075 {
1076    *quality = st->quality;
1077 }
1078 
speex_resampler_set_input_stride(SpeexResamplerState * st,spx_uint32_t stride)1079 EXPORT void speex_resampler_set_input_stride(SpeexResamplerState *st, spx_uint32_t stride)
1080 {
1081    st->in_stride = stride;
1082 }
1083 
speex_resampler_get_input_stride(SpeexResamplerState * st,spx_uint32_t * stride)1084 EXPORT void speex_resampler_get_input_stride(SpeexResamplerState *st, spx_uint32_t *stride)
1085 {
1086    *stride = st->in_stride;
1087 }
1088 
speex_resampler_set_output_stride(SpeexResamplerState * st,spx_uint32_t stride)1089 EXPORT void speex_resampler_set_output_stride(SpeexResamplerState *st, spx_uint32_t stride)
1090 {
1091    st->out_stride = stride;
1092 }
1093 
speex_resampler_get_output_stride(SpeexResamplerState * st,spx_uint32_t * stride)1094 EXPORT void speex_resampler_get_output_stride(SpeexResamplerState *st, spx_uint32_t *stride)
1095 {
1096    *stride = st->out_stride;
1097 }
1098 
speex_resampler_get_input_latency(SpeexResamplerState * st)1099 EXPORT int speex_resampler_get_input_latency(SpeexResamplerState *st)
1100 {
1101   return st->filt_len / 2;
1102 }
1103 
speex_resampler_get_output_latency(SpeexResamplerState * st)1104 EXPORT int speex_resampler_get_output_latency(SpeexResamplerState *st)
1105 {
1106   return ((st->filt_len / 2) * st->den_rate + (st->num_rate >> 1)) / st->num_rate;
1107 }
1108 
speex_resampler_skip_zeros(SpeexResamplerState * st)1109 EXPORT int speex_resampler_skip_zeros(SpeexResamplerState *st)
1110 {
1111    spx_uint32_t i;
1112    for (i=0;i<st->nb_channels;i++)
1113       st->last_sample[i] = st->filt_len/2;
1114    return RESAMPLER_ERR_SUCCESS;
1115 }
1116 
speex_resampler_reset_mem(SpeexResamplerState * st)1117 EXPORT int speex_resampler_reset_mem(SpeexResamplerState *st)
1118 {
1119    spx_uint32_t i;
1120    for (i=0;i<st->nb_channels*(st->filt_len-1);i++)
1121       st->mem[i] = 0;
1122    return RESAMPLER_ERR_SUCCESS;
1123 }
1124 
speex_resampler_strerror(int err)1125 EXPORT const char *speex_resampler_strerror(int err)
1126 {
1127    switch (err)
1128    {
1129       case RESAMPLER_ERR_SUCCESS:
1130          return "Success.";
1131       case RESAMPLER_ERR_ALLOC_FAILED:
1132          return "Memory allocation failed.";
1133       case RESAMPLER_ERR_BAD_STATE:
1134          return "Bad resampler state.";
1135       case RESAMPLER_ERR_INVALID_ARG:
1136          return "Invalid argument.";
1137       case RESAMPLER_ERR_PTR_OVERLAP:
1138          return "Input and output buffers overlap.";
1139       default:
1140          return "Unknown error. Bad error code or strange version mismatch.";
1141    }
1142 }
1143