blob: fa72d8550e932316b9afe7ec67e57f2d6e2e6c89 [file] [log] [blame]
Alexandre Savard0a32ed72012-08-07 19:26:46 -04001/* 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}