diff options
Diffstat (limited to 'lib/rbcodec/codecs/libspeex/resample.c')
-rw-r--r-- | lib/rbcodec/codecs/libspeex/resample.c | 735 |
1 files changed, 363 insertions, 372 deletions
diff --git a/lib/rbcodec/codecs/libspeex/resample.c b/lib/rbcodec/codecs/libspeex/resample.c index 65dfef28a3..5f5b9c6b4d 100644 --- a/lib/rbcodec/codecs/libspeex/resample.c +++ b/lib/rbcodec/codecs/libspeex/resample.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* Copyright (C) 2007 Jean-Marc Valin | 1 | /* Copyright (C) 2007-2008 Jean-Marc Valin |
2 | 2 | Copyright (C) 2008 Thorvald Natvig | |
3 | |||
3 | File: resample.c | 4 | File: resample.c |
4 | Arbitrary resampling code | 5 | Arbitrary resampling code |
5 | 6 | ||
@@ -37,27 +38,27 @@ | |||
37 | - Low memory requirement | 38 | - Low memory requirement |
38 | - Good *perceptual* quality (and not best SNR) | 39 | - Good *perceptual* quality (and not best SNR) |
39 | 40 | ||
40 | Warning: This resampler is relatively new. Although I think I got rid of | 41 | Warning: This resampler is relatively new. Although I think I got rid of |
41 | all the major bugs and I don't expect the API to change anymore, there | 42 | all the major bugs and I don't expect the API to change anymore, there |
42 | may be something I've missed. So use with caution. | 43 | may be something I've missed. So use with caution. |
43 | 44 | ||
44 | This algorithm is based on this original resampling algorithm: | 45 | This algorithm is based on this original resampling algorithm: |
45 | Smith, Julius O. Digital Audio Resampling Home Page | 46 | Smith, Julius O. Digital Audio Resampling Home Page |
46 | Center for Computer Research in Music and Acoustics (CCRMA), | 47 | Center for Computer Research in Music and Acoustics (CCRMA), |
47 | Stanford University, 2007. | 48 | Stanford University, 2007. |
48 | Web published at http://www-ccrma.stanford.edu/~jos/resample/. | 49 | Web published at http://www-ccrma.stanford.edu/~jos/resample/. |
49 | 50 | ||
50 | There is one main difference, though. This resampler uses cubic | 51 | There is one main difference, though. This resampler uses cubic |
51 | interpolation instead of linear interpolation in the above paper. This | 52 | interpolation instead of linear interpolation in the above paper. This |
52 | makes the table much smaller and makes it possible to compute that table | 53 | makes the table much smaller and makes it possible to compute that table |
53 | on a per-stream basis. In turn, being able to tweak the table for each | 54 | on a per-stream basis. In turn, being able to tweak the table for each |
54 | stream makes it possible to both reduce complexity on simple ratios | 55 | stream makes it possible to both reduce complexity on simple ratios |
55 | (e.g. 2/3), and get rid of the rounding operations in the inner loop. | 56 | (e.g. 2/3), and get rid of the rounding operations in the inner loop. |
56 | The latter both reduces CPU time and makes the algorithm more SIMD-friendly. | 57 | The latter both reduces CPU time and makes the algorithm more SIMD-friendly. |
57 | */ | 58 | */ |
58 | 59 | ||
59 | #ifdef HAVE_CONFIG_H | 60 | #ifdef HAVE_CONFIG_H |
60 | #include "config-speex.h" | 61 | #include "config.h" |
61 | #endif | 62 | #endif |
62 | 63 | ||
63 | #ifdef OUTSIDE_SPEEX | 64 | #ifdef OUTSIDE_SPEEX |
@@ -68,12 +69,13 @@ static void speex_free (void *ptr) {free(ptr);} | |||
68 | #include "speex_resampler.h" | 69 | #include "speex_resampler.h" |
69 | #include "arch.h" | 70 | #include "arch.h" |
70 | #else /* OUTSIDE_SPEEX */ | 71 | #else /* OUTSIDE_SPEEX */ |
71 | 72 | ||
72 | #include "speex/speex_resampler.h" | 73 | #include "speex/speex_resampler.h" |
73 | #include "arch.h" | 74 | #include "arch.h" |
74 | #include "os_support.h" | 75 | #include "os_support.h" |
75 | #endif /* OUTSIDE_SPEEX */ | 76 | #endif /* OUTSIDE_SPEEX */ |
76 | 77 | ||
78 | #include "stack_alloc.h" | ||
77 | #include <math.h> | 79 | #include <math.h> |
78 | 80 | ||
79 | #ifndef M_PI | 81 | #ifndef M_PI |
@@ -81,14 +83,10 @@ static void speex_free (void *ptr) {free(ptr);} | |||
81 | #endif | 83 | #endif |
82 | 84 | ||
83 | #ifdef FIXED_POINT | 85 | #ifdef FIXED_POINT |
84 | #define WORD2INT(x) ((x) < -32767 ? -32768 : ((x) > 32766 ? 32767 : (x))) | 86 | #define WORD2INT(x) ((x) < -32767 ? -32768 : ((x) > 32766 ? 32767 : (x))) |
85 | #else | 87 | #else |
86 | #define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x)))) | 88 | #define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x)))) |
87 | #endif | 89 | #endif |
88 | |||
89 | /*#define float double*/ | ||
90 | #define FILTER_SIZE 64 | ||
91 | #define OVERSAMPLE 8 | ||
92 | 90 | ||
93 | #define IMAX(a,b) ((a) > (b) ? (a) : (b)) | 91 | #define IMAX(a,b) ((a) > (b) ? (a) : (b)) |
94 | #define IMIN(a,b) ((a) < (b) ? (a) : (b)) | 92 | #define IMIN(a,b) ((a) < (b) ? (a) : (b)) |
@@ -97,6 +95,17 @@ static void speex_free (void *ptr) {free(ptr);} | |||
97 | #define NULL 0 | 95 | #define NULL 0 |
98 | #endif | 96 | #endif |
99 | 97 | ||
98 | #ifdef _USE_SSE | ||
99 | #include "resample_sse.h" | ||
100 | #endif | ||
101 | |||
102 | /* Numer of elements to allocate on the stack */ | ||
103 | #ifdef VAR_ARRAYS | ||
104 | #define FIXED_STACK_ALLOC 8192 | ||
105 | #else | ||
106 | #define FIXED_STACK_ALLOC 1024 | ||
107 | #endif | ||
108 | |||
100 | typedef int (*resampler_basic_func)(SpeexResamplerState *, spx_uint32_t , const spx_word16_t *, spx_uint32_t *, spx_word16_t *, spx_uint32_t *); | 109 | typedef int (*resampler_basic_func)(SpeexResamplerState *, spx_uint32_t , const spx_word16_t *, spx_uint32_t *, spx_word16_t *, spx_uint32_t *); |
101 | 110 | ||
102 | struct SpeexResamplerState_ { | 111 | struct SpeexResamplerState_ { |
@@ -104,28 +113,29 @@ struct SpeexResamplerState_ { | |||
104 | spx_uint32_t out_rate; | 113 | spx_uint32_t out_rate; |
105 | spx_uint32_t num_rate; | 114 | spx_uint32_t num_rate; |
106 | spx_uint32_t den_rate; | 115 | spx_uint32_t den_rate; |
107 | 116 | ||
108 | int quality; | 117 | int quality; |
109 | spx_uint32_t nb_channels; | 118 | spx_uint32_t nb_channels; |
110 | spx_uint32_t filt_len; | 119 | spx_uint32_t filt_len; |
111 | spx_uint32_t mem_alloc_size; | 120 | spx_uint32_t mem_alloc_size; |
121 | spx_uint32_t buffer_size; | ||
112 | int int_advance; | 122 | int int_advance; |
113 | int frac_advance; | 123 | int frac_advance; |
114 | float cutoff; | 124 | float cutoff; |
115 | spx_uint32_t oversample; | 125 | spx_uint32_t oversample; |
116 | int initialised; | 126 | int initialised; |
117 | int started; | 127 | int started; |
118 | 128 | ||
119 | /* These are per-channel */ | 129 | /* These are per-channel */ |
120 | spx_int32_t *last_sample; | 130 | spx_int32_t *last_sample; |
121 | spx_uint32_t *samp_frac_num; | 131 | spx_uint32_t *samp_frac_num; |
122 | spx_uint32_t *magic_samples; | 132 | spx_uint32_t *magic_samples; |
123 | 133 | ||
124 | spx_word16_t *mem; | 134 | spx_word16_t *mem; |
125 | spx_word16_t *sinc_table; | 135 | spx_word16_t *sinc_table; |
126 | spx_uint32_t sinc_table_length; | 136 | spx_uint32_t sinc_table_length; |
127 | resampler_basic_func resampler_ptr; | 137 | resampler_basic_func resampler_ptr; |
128 | 138 | ||
129 | int in_stride; | 139 | int in_stride; |
130 | int out_stride; | 140 | int out_stride; |
131 | } ; | 141 | } ; |
@@ -167,7 +177,7 @@ static double kaiser8_table[36] = { | |||
167 | 0.32108304, 0.27619388, 0.23465776, 0.19672670, 0.16255380, 0.13219758, | 177 | 0.32108304, 0.27619388, 0.23465776, 0.19672670, 0.16255380, 0.13219758, |
168 | 0.10562887, 0.08273982, 0.06335451, 0.04724088, 0.03412321, 0.02369490, | 178 | 0.10562887, 0.08273982, 0.06335451, 0.04724088, 0.03412321, 0.02369490, |
169 | 0.01563093, 0.00959968, 0.00527363, 0.00233883, 0.00050000, 0.00000000}; | 179 | 0.01563093, 0.00959968, 0.00527363, 0.00233883, 0.00050000, 0.00000000}; |
170 | 180 | ||
171 | static double kaiser6_table[36] = { | 181 | static double kaiser6_table[36] = { |
172 | 0.99733006, 1.00000000, 0.99733006, 0.98935595, 0.97618418, 0.95799003, | 182 | 0.99733006, 1.00000000, 0.99733006, 0.98935595, 0.97618418, 0.95799003, |
173 | 0.93501423, 0.90755855, 0.87598009, 0.84068475, 0.80211977, 0.76076565, | 183 | 0.93501423, 0.90755855, 0.87598009, 0.84068475, 0.80211977, 0.76076565, |
@@ -180,7 +190,7 @@ struct FuncDef { | |||
180 | double *table; | 190 | double *table; |
181 | int oversample; | 191 | int oversample; |
182 | }; | 192 | }; |
183 | 193 | ||
184 | static struct FuncDef _KAISER12 = {kaiser12_table, 64}; | 194 | static struct FuncDef _KAISER12 = {kaiser12_table, 64}; |
185 | #define KAISER12 (&_KAISER12) | 195 | #define KAISER12 (&_KAISER12) |
186 | /*static struct FuncDef _KAISER12 = {kaiser12_table, 32}; | 196 | /*static struct FuncDef _KAISER12 = {kaiser12_table, 32}; |
@@ -202,7 +212,7 @@ struct QualityMapping { | |||
202 | 212 | ||
203 | 213 | ||
204 | /* This table maps conversion quality to internal parameters. There are two | 214 | /* This table maps conversion quality to internal parameters. There are two |
205 | reasons that explain why the up-sampling bandwidth is larger than the | 215 | reasons that explain why the up-sampling bandwidth is larger than the |
206 | down-sampling bandwidth: | 216 | down-sampling bandwidth: |
207 | 1) When up-sampling, we can assume that the spectrum is already attenuated | 217 | 1) When up-sampling, we can assume that the spectrum is already attenuated |
208 | close to the Nyquist rate (from an A/D or a previous resampling filter) | 218 | close to the Nyquist rate (from an A/D or a previous resampling filter) |
@@ -228,7 +238,7 @@ static double compute_func(float x, struct FuncDef *func) | |||
228 | { | 238 | { |
229 | float y, frac; | 239 | float y, frac; |
230 | double interp[4]; | 240 | double interp[4]; |
231 | int ind; | 241 | int ind; |
232 | y = x*func->oversample; | 242 | y = x*func->oversample; |
233 | ind = (int)floor(y); | 243 | ind = (int)floor(y); |
234 | frac = (y-ind); | 244 | frac = (y-ind); |
@@ -239,7 +249,7 @@ static double compute_func(float x, struct FuncDef *func) | |||
239 | interp[0] = -0.3333333333*frac + 0.5*(frac*frac) - 0.1666666667*(frac*frac*frac); | 249 | interp[0] = -0.3333333333*frac + 0.5*(frac*frac) - 0.1666666667*(frac*frac*frac); |
240 | /* Just to make sure we don't have rounding problems */ | 250 | /* Just to make sure we don't have rounding problems */ |
241 | interp[1] = 1.f-interp[3]-interp[2]-interp[0]; | 251 | interp[1] = 1.f-interp[3]-interp[2]-interp[0]; |
242 | 252 | ||
243 | /*sum = frac*accum[1] + (1-frac)*accum[2];*/ | 253 | /*sum = frac*accum[1] + (1-frac)*accum[2];*/ |
244 | return interp[0]*func->table[ind] + interp[1]*func->table[ind+1] + interp[2]*func->table[ind+2] + interp[3]*func->table[ind+3]; | 254 | return interp[0]*func->table[ind] + interp[1]*func->table[ind+1] + interp[2]*func->table[ind+2] + interp[3]*func->table[ind+3]; |
245 | } | 255 | } |
@@ -317,47 +327,47 @@ static void cubic_coef(spx_word16_t frac, spx_word16_t interp[4]) | |||
317 | 327 | ||
318 | 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) | 328 | static int resampler_basic_direct_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) |
319 | { | 329 | { |
320 | int N = st->filt_len; | 330 | const int N = st->filt_len; |
321 | int out_sample = 0; | 331 | int out_sample = 0; |
322 | spx_word16_t *mem; | ||
323 | int last_sample = st->last_sample[channel_index]; | 332 | int last_sample = st->last_sample[channel_index]; |
324 | spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; | 333 | spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; |
325 | mem = st->mem + channel_index * st->mem_alloc_size; | 334 | const spx_word16_t *sinc_table = st->sinc_table; |
335 | const int out_stride = st->out_stride; | ||
336 | const int int_advance = st->int_advance; | ||
337 | const int frac_advance = st->frac_advance; | ||
338 | const spx_uint32_t den_rate = st->den_rate; | ||
339 | spx_word32_t sum; | ||
340 | int j; | ||
341 | |||
326 | while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) | 342 | while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) |
327 | { | 343 | { |
328 | int j; | 344 | const spx_word16_t *sinc = & sinc_table[samp_frac_num*N]; |
329 | spx_word32_t sum=0; | 345 | const spx_word16_t *iptr = & in[last_sample]; |
330 | 346 | ||
331 | /* We already have all the filter coefficients pre-computed in the table */ | 347 | #ifndef OVERRIDE_INNER_PRODUCT_SINGLE |
332 | const spx_word16_t *ptr; | 348 | float accum[4] = {0,0,0,0}; |
333 | /* Do the memory part */ | 349 | |
334 | for (j=0;last_sample-N+1+j < 0;j++) | 350 | for(j=0;j<N;j+=4) { |
335 | { | 351 | accum[0] += sinc[j]*iptr[j]; |
336 | sum += MULT16_16(mem[last_sample+j],st->sinc_table[samp_frac_num*st->filt_len+j]); | 352 | accum[1] += sinc[j+1]*iptr[j+1]; |
337 | } | 353 | accum[2] += sinc[j+2]*iptr[j+2]; |
338 | 354 | accum[3] += sinc[j+3]*iptr[j+3]; | |
339 | /* Do the new part */ | ||
340 | if (in != NULL) | ||
341 | { | ||
342 | ptr = in+st->in_stride*(last_sample-N+1+j); | ||
343 | for (;j<N;j++) | ||
344 | { | ||
345 | sum += MULT16_16(*ptr,st->sinc_table[samp_frac_num*st->filt_len+j]); | ||
346 | ptr += st->in_stride; | ||
347 | } | ||
348 | } | 355 | } |
349 | 356 | sum = accum[0] + accum[1] + accum[2] + accum[3]; | |
350 | *out = PSHR32(sum,15); | 357 | #else |
351 | out += st->out_stride; | 358 | sum = inner_product_single(sinc, iptr, N); |
352 | out_sample++; | 359 | #endif |
353 | last_sample += st->int_advance; | 360 | |
354 | samp_frac_num += st->frac_advance; | 361 | out[out_stride * out_sample++] = PSHR32(sum, 15); |
355 | if (samp_frac_num >= st->den_rate) | 362 | last_sample += int_advance; |
363 | samp_frac_num += frac_advance; | ||
364 | if (samp_frac_num >= den_rate) | ||
356 | { | 365 | { |
357 | samp_frac_num -= st->den_rate; | 366 | samp_frac_num -= den_rate; |
358 | last_sample++; | 367 | last_sample++; |
359 | } | 368 | } |
360 | } | 369 | } |
370 | |||
361 | st->last_sample[channel_index] = last_sample; | 371 | st->last_sample[channel_index] = last_sample; |
362 | st->samp_frac_num[channel_index] = samp_frac_num; | 372 | st->samp_frac_num[channel_index] = samp_frac_num; |
363 | return out_sample; | 373 | return out_sample; |
@@ -368,47 +378,47 @@ static int resampler_basic_direct_single(SpeexResamplerState *st, spx_uint32_t c | |||
368 | /* This is the same as the previous function, except with a double-precision accumulator */ | 378 | /* This is the same as the previous function, except with a double-precision accumulator */ |
369 | 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) | 379 | static int resampler_basic_direct_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) |
370 | { | 380 | { |
371 | int N = st->filt_len; | 381 | const int N = st->filt_len; |
372 | int out_sample = 0; | 382 | int out_sample = 0; |
373 | spx_word16_t *mem; | ||
374 | int last_sample = st->last_sample[channel_index]; | 383 | int last_sample = st->last_sample[channel_index]; |
375 | spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; | 384 | spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; |
376 | mem = st->mem + channel_index * st->mem_alloc_size; | 385 | const spx_word16_t *sinc_table = st->sinc_table; |
386 | const int out_stride = st->out_stride; | ||
387 | const int int_advance = st->int_advance; | ||
388 | const int frac_advance = st->frac_advance; | ||
389 | const spx_uint32_t den_rate = st->den_rate; | ||
390 | double sum; | ||
391 | int j; | ||
392 | |||
377 | while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) | 393 | while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) |
378 | { | 394 | { |
379 | int j; | 395 | const spx_word16_t *sinc = & sinc_table[samp_frac_num*N]; |
380 | double sum=0; | 396 | const spx_word16_t *iptr = & in[last_sample]; |
381 | 397 | ||
382 | /* We already have all the filter coefficients pre-computed in the table */ | 398 | #ifndef OVERRIDE_INNER_PRODUCT_DOUBLE |
383 | const spx_word16_t *ptr; | 399 | double accum[4] = {0,0,0,0}; |
384 | /* Do the memory part */ | 400 | |
385 | for (j=0;last_sample-N+1+j < 0;j++) | 401 | for(j=0;j<N;j+=4) { |
386 | { | 402 | accum[0] += sinc[j]*iptr[j]; |
387 | sum += MULT16_16(mem[last_sample+j],(double)st->sinc_table[samp_frac_num*st->filt_len+j]); | 403 | accum[1] += sinc[j+1]*iptr[j+1]; |
388 | } | 404 | accum[2] += sinc[j+2]*iptr[j+2]; |
389 | 405 | accum[3] += sinc[j+3]*iptr[j+3]; | |
390 | /* Do the new part */ | ||
391 | if (in != NULL) | ||
392 | { | ||
393 | ptr = in+st->in_stride*(last_sample-N+1+j); | ||
394 | for (;j<N;j++) | ||
395 | { | ||
396 | sum += MULT16_16(*ptr,(double)st->sinc_table[samp_frac_num*st->filt_len+j]); | ||
397 | ptr += st->in_stride; | ||
398 | } | ||
399 | } | 406 | } |
400 | 407 | sum = accum[0] + accum[1] + accum[2] + accum[3]; | |
401 | *out = sum; | 408 | #else |
402 | out += st->out_stride; | 409 | sum = inner_product_double(sinc, iptr, N); |
403 | out_sample++; | 410 | #endif |
404 | last_sample += st->int_advance; | 411 | |
405 | samp_frac_num += st->frac_advance; | 412 | out[out_stride * out_sample++] = PSHR32(sum, 15); |
406 | if (samp_frac_num >= st->den_rate) | 413 | last_sample += int_advance; |
414 | samp_frac_num += frac_advance; | ||
415 | if (samp_frac_num >= den_rate) | ||
407 | { | 416 | { |
408 | samp_frac_num -= st->den_rate; | 417 | samp_frac_num -= den_rate; |
409 | last_sample++; | 418 | last_sample++; |
410 | } | 419 | } |
411 | } | 420 | } |
421 | |||
412 | st->last_sample[channel_index] = last_sample; | 422 | st->last_sample[channel_index] = last_sample; |
413 | st->samp_frac_num[channel_index] = samp_frac_num; | 423 | st->samp_frac_num[channel_index] = samp_frac_num; |
414 | return out_sample; | 424 | return out_sample; |
@@ -417,69 +427,58 @@ static int resampler_basic_direct_double(SpeexResamplerState *st, spx_uint32_t c | |||
417 | 427 | ||
418 | 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) | 428 | static int resampler_basic_interpolate_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) |
419 | { | 429 | { |
420 | int N = st->filt_len; | 430 | const int N = st->filt_len; |
421 | int out_sample = 0; | 431 | int out_sample = 0; |
422 | spx_word16_t *mem; | ||
423 | int last_sample = st->last_sample[channel_index]; | 432 | int last_sample = st->last_sample[channel_index]; |
424 | spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; | 433 | spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; |
425 | mem = st->mem + channel_index * st->mem_alloc_size; | 434 | const int out_stride = st->out_stride; |
435 | const int int_advance = st->int_advance; | ||
436 | const int frac_advance = st->frac_advance; | ||
437 | const spx_uint32_t den_rate = st->den_rate; | ||
438 | int j; | ||
439 | spx_word32_t sum; | ||
440 | |||
426 | while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) | 441 | while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) |
427 | { | 442 | { |
428 | int j; | 443 | const spx_word16_t *iptr = & in[last_sample]; |
429 | spx_word32_t sum=0; | 444 | |
430 | 445 | const int offset = samp_frac_num*st->oversample/st->den_rate; | |
431 | /* We need to interpolate the sinc filter */ | ||
432 | spx_word32_t accum[4] = {0.f,0.f, 0.f, 0.f}; | ||
433 | spx_word16_t interp[4]; | ||
434 | const spx_word16_t *ptr; | ||
435 | int offset; | ||
436 | spx_word16_t frac; | ||
437 | offset = samp_frac_num*st->oversample/st->den_rate; | ||
438 | #ifdef FIXED_POINT | 446 | #ifdef FIXED_POINT |
439 | frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate); | 447 | const spx_word16_t frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate); |
440 | #else | 448 | #else |
441 | frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate; | 449 | const spx_word16_t frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate; |
442 | #endif | 450 | #endif |
443 | /* This code is written like this to make it easy to optimise with SIMD. | 451 | spx_word16_t interp[4]; |
444 | For most DSPs, it would be best to split the loops in two because most DSPs | 452 | |
445 | have only two accumulators */ | 453 | |
446 | for (j=0;last_sample-N+1+j < 0;j++) | 454 | #ifndef OVERRIDE_INTERPOLATE_PRODUCT_SINGLE |
447 | { | 455 | spx_word32_t accum[4] = {0,0,0,0}; |
448 | spx_word16_t curr_mem = mem[last_sample+j]; | 456 | |
449 | accum[0] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-2]); | 457 | for(j=0;j<N;j++) { |
450 | accum[1] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-1]); | 458 | const spx_word16_t curr_in=iptr[j]; |
451 | accum[2] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset]); | 459 | accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]); |
452 | accum[3] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset+1]); | 460 | accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]); |
453 | } | 461 | accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]); |
454 | 462 | accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]); | |
455 | if (in != NULL) | ||
456 | { | ||
457 | ptr = in+st->in_stride*(last_sample-N+1+j); | ||
458 | /* Do the new part */ | ||
459 | for (;j<N;j++) | ||
460 | { | ||
461 | spx_word16_t curr_in = *ptr; | ||
462 | ptr += st->in_stride; | ||
463 | accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]); | ||
464 | accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]); | ||
465 | accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]); | ||
466 | accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]); | ||
467 | } | ||
468 | } | 463 | } |
464 | |||
469 | cubic_coef(frac, interp); | 465 | cubic_coef(frac, interp); |
470 | 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]); | 466 | sum = MULT16_32_Q15(interp[0],accum[0]) + MULT16_32_Q15(interp[1],accum[1]) + MULT16_32_Q15(interp[2],accum[2]) + MULT16_32_Q15(interp[3],accum[3]); |
471 | 467 | #else | |
472 | *out = PSHR32(sum,15); | 468 | cubic_coef(frac, interp); |
473 | out += st->out_stride; | 469 | sum = interpolate_product_single(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp); |
474 | out_sample++; | 470 | #endif |
475 | last_sample += st->int_advance; | 471 | |
476 | samp_frac_num += st->frac_advance; | 472 | out[out_stride * out_sample++] = PSHR32(sum,15); |
477 | if (samp_frac_num >= st->den_rate) | 473 | last_sample += int_advance; |
474 | samp_frac_num += frac_advance; | ||
475 | if (samp_frac_num >= den_rate) | ||
478 | { | 476 | { |
479 | samp_frac_num -= st->den_rate; | 477 | samp_frac_num -= den_rate; |
480 | last_sample++; | 478 | last_sample++; |
481 | } | 479 | } |
482 | } | 480 | } |
481 | |||
483 | st->last_sample[channel_index] = last_sample; | 482 | st->last_sample[channel_index] = last_sample; |
484 | st->samp_frac_num[channel_index] = samp_frac_num; | 483 | st->samp_frac_num[channel_index] = samp_frac_num; |
485 | return out_sample; | 484 | return out_sample; |
@@ -490,63 +489,58 @@ static int resampler_basic_interpolate_single(SpeexResamplerState *st, spx_uint3 | |||
490 | /* This is the same as the previous function, except with a double-precision accumulator */ | 489 | /* This is the same as the previous function, except with a double-precision accumulator */ |
491 | 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) | 490 | static int resampler_basic_interpolate_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) |
492 | { | 491 | { |
493 | int N = st->filt_len; | 492 | const int N = st->filt_len; |
494 | int out_sample = 0; | 493 | int out_sample = 0; |
495 | spx_word16_t *mem; | ||
496 | int last_sample = st->last_sample[channel_index]; | 494 | int last_sample = st->last_sample[channel_index]; |
497 | spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; | 495 | spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; |
498 | mem = st->mem + channel_index * st->mem_alloc_size; | 496 | const int out_stride = st->out_stride; |
497 | const int int_advance = st->int_advance; | ||
498 | const int frac_advance = st->frac_advance; | ||
499 | const spx_uint32_t den_rate = st->den_rate; | ||
500 | int j; | ||
501 | spx_word32_t sum; | ||
502 | |||
499 | while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) | 503 | while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) |
500 | { | 504 | { |
501 | int j; | 505 | const spx_word16_t *iptr = & in[last_sample]; |
502 | spx_word32_t sum=0; | 506 | |
503 | 507 | const int offset = samp_frac_num*st->oversample/st->den_rate; | |
504 | /* We need to interpolate the sinc filter */ | 508 | #ifdef FIXED_POINT |
505 | double accum[4] = {0.f,0.f, 0.f, 0.f}; | 509 | const spx_word16_t frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate); |
506 | float interp[4]; | 510 | #else |
507 | const spx_word16_t *ptr; | 511 | const spx_word16_t frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate; |
508 | float alpha = ((float)samp_frac_num)/st->den_rate; | 512 | #endif |
509 | int offset = samp_frac_num*st->oversample/st->den_rate; | 513 | spx_word16_t interp[4]; |
510 | float frac = alpha*st->oversample - offset; | 514 | |
511 | /* This code is written like this to make it easy to optimise with SIMD. | 515 | |
512 | For most DSPs, it would be best to split the loops in two because most DSPs | 516 | #ifndef OVERRIDE_INTERPOLATE_PRODUCT_DOUBLE |
513 | have only two accumulators */ | 517 | double accum[4] = {0,0,0,0}; |
514 | for (j=0;last_sample-N+1+j < 0;j++) | 518 | |
515 | { | 519 | for(j=0;j<N;j++) { |
516 | double curr_mem = mem[last_sample+j]; | 520 | const double curr_in=iptr[j]; |
517 | accum[0] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-2]); | 521 | accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]); |
518 | accum[1] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-1]); | 522 | accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]); |
519 | accum[2] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset]); | 523 | accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]); |
520 | accum[3] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset+1]); | 524 | accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]); |
521 | } | ||
522 | if (in != NULL) | ||
523 | { | ||
524 | ptr = in+st->in_stride*(last_sample-N+1+j); | ||
525 | /* Do the new part */ | ||
526 | for (;j<N;j++) | ||
527 | { | ||
528 | double curr_in = *ptr; | ||
529 | ptr += st->in_stride; | ||
530 | accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]); | ||
531 | accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]); | ||
532 | accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]); | ||
533 | accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]); | ||
534 | } | ||
535 | } | 525 | } |
526 | |||
536 | cubic_coef(frac, interp); | 527 | cubic_coef(frac, interp); |
537 | sum = interp[0]*accum[0] + interp[1]*accum[1] + interp[2]*accum[2] + interp[3]*accum[3]; | 528 | sum = MULT16_32_Q15(interp[0],accum[0]) + MULT16_32_Q15(interp[1],accum[1]) + MULT16_32_Q15(interp[2],accum[2]) + MULT16_32_Q15(interp[3],accum[3]); |
538 | 529 | #else | |
539 | *out = PSHR32(sum,15); | 530 | cubic_coef(frac, interp); |
540 | out += st->out_stride; | 531 | sum = interpolate_product_double(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp); |
541 | out_sample++; | 532 | #endif |
542 | last_sample += st->int_advance; | 533 | |
543 | samp_frac_num += st->frac_advance; | 534 | out[out_stride * out_sample++] = PSHR32(sum,15); |
544 | if (samp_frac_num >= st->den_rate) | 535 | last_sample += int_advance; |
536 | samp_frac_num += frac_advance; | ||
537 | if (samp_frac_num >= den_rate) | ||
545 | { | 538 | { |
546 | samp_frac_num -= st->den_rate; | 539 | samp_frac_num -= den_rate; |
547 | last_sample++; | 540 | last_sample++; |
548 | } | 541 | } |
549 | } | 542 | } |
543 | |||
550 | st->last_sample[channel_index] = last_sample; | 544 | st->last_sample[channel_index] = last_sample; |
551 | st->samp_frac_num[channel_index] = samp_frac_num; | 545 | st->samp_frac_num[channel_index] = samp_frac_num; |
552 | return out_sample; | 546 | return out_sample; |
@@ -556,11 +550,11 @@ static int resampler_basic_interpolate_double(SpeexResamplerState *st, spx_uint3 | |||
556 | static void update_filter(SpeexResamplerState *st) | 550 | static void update_filter(SpeexResamplerState *st) |
557 | { | 551 | { |
558 | spx_uint32_t old_length; | 552 | spx_uint32_t old_length; |
559 | 553 | ||
560 | old_length = st->filt_len; | 554 | old_length = st->filt_len; |
561 | st->oversample = quality_map[st->quality].oversample; | 555 | st->oversample = quality_map[st->quality].oversample; |
562 | st->filt_len = quality_map[st->quality].base_length; | 556 | st->filt_len = quality_map[st->quality].base_length; |
563 | 557 | ||
564 | if (st->num_rate > st->den_rate) | 558 | if (st->num_rate > st->den_rate) |
565 | { | 559 | { |
566 | /* down-sampling */ | 560 | /* down-sampling */ |
@@ -636,25 +630,25 @@ static void update_filter(SpeexResamplerState *st) | |||
636 | st->int_advance = st->num_rate/st->den_rate; | 630 | st->int_advance = st->num_rate/st->den_rate; |
637 | st->frac_advance = st->num_rate%st->den_rate; | 631 | st->frac_advance = st->num_rate%st->den_rate; |
638 | 632 | ||
639 | 633 | ||
640 | /* Here's the place where we update the filter memory to take into account | 634 | /* Here's the place where we update the filter memory to take into account |
641 | the change in filter length. It's probably the messiest part of the code | 635 | the change in filter length. It's probably the messiest part of the code |
642 | due to handling of lots of corner cases. */ | 636 | due to handling of lots of corner cases. */ |
643 | if (!st->mem) | 637 | if (!st->mem) |
644 | { | 638 | { |
645 | spx_uint32_t i; | 639 | spx_uint32_t i; |
646 | st->mem = (spx_word16_t*)speex_alloc(st->nb_channels*(st->filt_len-1) * sizeof(spx_word16_t)); | 640 | st->mem_alloc_size = st->filt_len-1 + st->buffer_size; |
647 | for (i=0;i<st->nb_channels*(st->filt_len-1);i++) | 641 | st->mem = (spx_word16_t*)speex_alloc(st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t)); |
642 | for (i=0;i<st->nb_channels*st->mem_alloc_size;i++) | ||
648 | st->mem[i] = 0; | 643 | st->mem[i] = 0; |
649 | st->mem_alloc_size = st->filt_len-1; | ||
650 | /*speex_warning("init filter");*/ | 644 | /*speex_warning("init filter");*/ |
651 | } else if (!st->started) | 645 | } else if (!st->started) |
652 | { | 646 | { |
653 | spx_uint32_t i; | 647 | spx_uint32_t i; |
654 | st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*(st->filt_len-1) * sizeof(spx_word16_t)); | 648 | st->mem_alloc_size = st->filt_len-1 + st->buffer_size; |
655 | for (i=0;i<st->nb_channels*(st->filt_len-1);i++) | 649 | st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t)); |
650 | for (i=0;i<st->nb_channels*st->mem_alloc_size;i++) | ||
656 | st->mem[i] = 0; | 651 | st->mem[i] = 0; |
657 | st->mem_alloc_size = st->filt_len-1; | ||
658 | /*speex_warning("reinit filter");*/ | 652 | /*speex_warning("reinit filter");*/ |
659 | } else if (st->filt_len > old_length) | 653 | } else if (st->filt_len > old_length) |
660 | { | 654 | { |
@@ -662,10 +656,10 @@ static void update_filter(SpeexResamplerState *st) | |||
662 | /* Increase the filter length */ | 656 | /* Increase the filter length */ |
663 | /*speex_warning("increase filter size");*/ | 657 | /*speex_warning("increase filter size");*/ |
664 | int old_alloc_size = st->mem_alloc_size; | 658 | int old_alloc_size = st->mem_alloc_size; |
665 | if (st->filt_len-1 > st->mem_alloc_size) | 659 | if ((st->filt_len-1 + st->buffer_size) > st->mem_alloc_size) |
666 | { | 660 | { |
667 | st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*(st->filt_len-1) * sizeof(spx_word16_t)); | 661 | st->mem_alloc_size = st->filt_len-1 + st->buffer_size; |
668 | st->mem_alloc_size = st->filt_len-1; | 662 | st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t)); |
669 | } | 663 | } |
670 | for (i=st->nb_channels-1;i>=0;i--) | 664 | for (i=st->nb_channels-1;i>=0;i--) |
671 | { | 665 | { |
@@ -674,7 +668,7 @@ static void update_filter(SpeexResamplerState *st) | |||
674 | /*if (st->magic_samples[i])*/ | 668 | /*if (st->magic_samples[i])*/ |
675 | { | 669 | { |
676 | /* Try and remove the magic samples as if nothing had happened */ | 670 | /* Try and remove the magic samples as if nothing had happened */ |
677 | 671 | ||
678 | /* FIXME: This is wrong but for now we need it to avoid going over the array bounds */ | 672 | /* FIXME: This is wrong but for now we need it to avoid going over the array bounds */ |
679 | olen = old_length + 2*st->magic_samples[i]; | 673 | olen = old_length + 2*st->magic_samples[i]; |
680 | for (j=old_length-2+st->magic_samples[i];j>=0;j--) | 674 | for (j=old_length-2+st->magic_samples[i];j>=0;j--) |
@@ -721,12 +715,12 @@ static void update_filter(SpeexResamplerState *st) | |||
721 | 715 | ||
722 | } | 716 | } |
723 | 717 | ||
724 | SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err) | 718 | EXPORT SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err) |
725 | { | 719 | { |
726 | return speex_resampler_init_frac(nb_channels, in_rate, out_rate, in_rate, out_rate, quality, err); | 720 | return speex_resampler_init_frac(nb_channels, in_rate, out_rate, in_rate, out_rate, quality, err); |
727 | } | 721 | } |
728 | 722 | ||
729 | 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) | 723 | EXPORT SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err) |
730 | { | 724 | { |
731 | spx_uint32_t i; | 725 | spx_uint32_t i; |
732 | SpeexResamplerState *st; | 726 | SpeexResamplerState *st; |
@@ -749,12 +743,18 @@ SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, spx_uin | |||
749 | st->filt_len = 0; | 743 | st->filt_len = 0; |
750 | st->mem = 0; | 744 | st->mem = 0; |
751 | st->resampler_ptr = 0; | 745 | st->resampler_ptr = 0; |
752 | 746 | ||
753 | st->cutoff = 1.f; | 747 | st->cutoff = 1.f; |
754 | st->nb_channels = nb_channels; | 748 | st->nb_channels = nb_channels; |
755 | st->in_stride = 1; | 749 | st->in_stride = 1; |
756 | st->out_stride = 1; | 750 | st->out_stride = 1; |
757 | 751 | ||
752 | #ifdef FIXED_POINT | ||
753 | st->buffer_size = 160; | ||
754 | #else | ||
755 | st->buffer_size = 160; | ||
756 | #endif | ||
757 | |||
758 | /* Per channel data */ | 758 | /* Per channel data */ |
759 | st->last_sample = (spx_int32_t*)speex_alloc(nb_channels*sizeof(int)); | 759 | st->last_sample = (spx_int32_t*)speex_alloc(nb_channels*sizeof(int)); |
760 | st->magic_samples = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int)); | 760 | st->magic_samples = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int)); |
@@ -769,9 +769,9 @@ SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, spx_uin | |||
769 | speex_resampler_set_quality(st, quality); | 769 | speex_resampler_set_quality(st, quality); |
770 | speex_resampler_set_rate_frac(st, ratio_num, ratio_den, in_rate, out_rate); | 770 | speex_resampler_set_rate_frac(st, ratio_num, ratio_den, in_rate, out_rate); |
771 | 771 | ||
772 | 772 | ||
773 | update_filter(st); | 773 | update_filter(st); |
774 | 774 | ||
775 | st->initialised = 1; | 775 | st->initialised = 1; |
776 | if (err) | 776 | if (err) |
777 | *err = RESAMPLER_ERR_SUCCESS; | 777 | *err = RESAMPLER_ERR_SUCCESS; |
@@ -779,7 +779,7 @@ SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, spx_uin | |||
779 | return st; | 779 | return st; |
780 | } | 780 | } |
781 | 781 | ||
782 | void speex_resampler_destroy(SpeexResamplerState *st) | 782 | EXPORT void speex_resampler_destroy(SpeexResamplerState *st) |
783 | { | 783 | { |
784 | speex_free(st->mem); | 784 | speex_free(st->mem); |
785 | speex_free(st->sinc_table); | 785 | speex_free(st->sinc_table); |
@@ -789,186 +789,168 @@ void speex_resampler_destroy(SpeexResamplerState *st) | |||
789 | speex_free(st); | 789 | speex_free(st); |
790 | } | 790 | } |
791 | 791 | ||
792 | 792 | static int speex_resampler_process_native(SpeexResamplerState *st, spx_uint32_t channel_index, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) | |
793 | |||
794 | static int speex_resampler_process_native(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) | ||
795 | { | 793 | { |
796 | int j=0; | 794 | int j=0; |
797 | int N = st->filt_len; | 795 | const int N = st->filt_len; |
798 | int out_sample = 0; | 796 | int out_sample = 0; |
799 | spx_word16_t *mem; | 797 | spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size; |
800 | spx_uint32_t tmp_out_len = 0; | 798 | spx_uint32_t ilen; |
801 | mem = st->mem + channel_index * st->mem_alloc_size; | 799 | |
802 | st->started = 1; | 800 | st->started = 1; |
803 | 801 | ||
804 | /* Handle the case where we have samples left from a reduction in filter length */ | ||
805 | if (st->magic_samples[channel_index]) | ||
806 | { | ||
807 | int istride_save; | ||
808 | spx_uint32_t tmp_in_len; | ||
809 | spx_uint32_t tmp_magic; | ||
810 | |||
811 | istride_save = st->in_stride; | ||
812 | tmp_in_len = st->magic_samples[channel_index]; | ||
813 | tmp_out_len = *out_len; | ||
814 | /* magic_samples needs to be set to zero to avoid infinite recursion */ | ||
815 | tmp_magic = st->magic_samples[channel_index]; | ||
816 | st->magic_samples[channel_index] = 0; | ||
817 | st->in_stride = 1; | ||
818 | speex_resampler_process_native(st, channel_index, mem+N-1, &tmp_in_len, out, &tmp_out_len); | ||
819 | st->in_stride = istride_save; | ||
820 | /*speex_warning_int("extra samples:", tmp_out_len);*/ | ||
821 | /* If we couldn't process all "magic" input samples, save the rest for next time */ | ||
822 | if (tmp_in_len < tmp_magic) | ||
823 | { | ||
824 | spx_uint32_t i; | ||
825 | st->magic_samples[channel_index] = tmp_magic-tmp_in_len; | ||
826 | for (i=0;i<st->magic_samples[channel_index];i++) | ||
827 | mem[N-1+i]=mem[N-1+i+tmp_in_len]; | ||
828 | } | ||
829 | out += tmp_out_len*st->out_stride; | ||
830 | *out_len -= tmp_out_len; | ||
831 | } | ||
832 | |||
833 | /* Call the right resampler through the function ptr */ | 802 | /* Call the right resampler through the function ptr */ |
834 | out_sample = st->resampler_ptr(st, channel_index, in, in_len, out, out_len); | 803 | out_sample = st->resampler_ptr(st, channel_index, mem, in_len, out, out_len); |
835 | 804 | ||
836 | if (st->last_sample[channel_index] < (spx_int32_t)*in_len) | 805 | if (st->last_sample[channel_index] < (spx_int32_t)*in_len) |
837 | *in_len = st->last_sample[channel_index]; | 806 | *in_len = st->last_sample[channel_index]; |
838 | *out_len = out_sample+tmp_out_len; | 807 | *out_len = out_sample; |
839 | st->last_sample[channel_index] -= *in_len; | 808 | st->last_sample[channel_index] -= *in_len; |
840 | 809 | ||
841 | for (j=0;j<N-1-(spx_int32_t)*in_len;j++) | 810 | ilen = *in_len; |
842 | mem[j] = mem[j+*in_len]; | 811 | |
843 | for (;j<N-1;j++) | 812 | for(j=0;j<N-1;++j) |
844 | mem[j] = in[st->in_stride*(j+*in_len-N+1)]; | 813 | mem[j] = mem[j+ilen]; |
845 | 814 | ||
846 | return RESAMPLER_ERR_SUCCESS; | 815 | return RESAMPLER_ERR_SUCCESS; |
847 | } | 816 | } |
848 | 817 | ||
849 | #define FIXED_STACK_ALLOC 1024 | 818 | static int speex_resampler_magic(SpeexResamplerState *st, spx_uint32_t channel_index, spx_word16_t **out, spx_uint32_t out_len) { |
819 | spx_uint32_t tmp_in_len = st->magic_samples[channel_index]; | ||
820 | spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size; | ||
821 | const int N = st->filt_len; | ||
822 | |||
823 | speex_resampler_process_native(st, channel_index, &tmp_in_len, *out, &out_len); | ||
824 | |||
825 | st->magic_samples[channel_index] -= tmp_in_len; | ||
826 | |||
827 | /* If we couldn't process all "magic" input samples, save the rest for next time */ | ||
828 | if (st->magic_samples[channel_index]) | ||
829 | { | ||
830 | spx_uint32_t i; | ||
831 | for (i=0;i<st->magic_samples[channel_index];i++) | ||
832 | mem[N-1+i]=mem[N-1+i+tmp_in_len]; | ||
833 | } | ||
834 | *out += out_len*st->out_stride; | ||
835 | return out_len; | ||
836 | } | ||
850 | 837 | ||
851 | #ifdef FIXED_POINT | 838 | #ifdef FIXED_POINT |
852 | 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) | 839 | EXPORT int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len) |
853 | { | ||
854 | spx_uint32_t i; | ||
855 | int istride_save, ostride_save; | ||
856 | #ifdef VAR_ARRAYS | ||
857 | spx_word16_t x[*in_len]; | ||
858 | spx_word16_t y[*out_len]; | ||
859 | /*VARDECL(spx_word16_t *x); | ||
860 | VARDECL(spx_word16_t *y); | ||
861 | ALLOC(x, *in_len, spx_word16_t); | ||
862 | ALLOC(y, *out_len, spx_word16_t);*/ | ||
863 | istride_save = st->in_stride; | ||
864 | ostride_save = st->out_stride; | ||
865 | for (i=0;i<*in_len;i++) | ||
866 | x[i] = WORD2INT(in[i*st->in_stride]); | ||
867 | st->in_stride = st->out_stride = 1; | ||
868 | speex_resampler_process_native(st, channel_index, x, in_len, y, out_len); | ||
869 | st->in_stride = istride_save; | ||
870 | st->out_stride = ostride_save; | ||
871 | for (i=0;i<*out_len;i++) | ||
872 | out[i*st->out_stride] = y[i]; | ||
873 | #else | 840 | #else |
874 | spx_word16_t x[FIXED_STACK_ALLOC]; | 841 | EXPORT int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) |
875 | spx_word16_t y[FIXED_STACK_ALLOC]; | 842 | #endif |
876 | spx_uint32_t ilen=*in_len, olen=*out_len; | 843 | { |
877 | istride_save = st->in_stride; | 844 | int j; |
878 | ostride_save = st->out_stride; | 845 | spx_uint32_t ilen = *in_len; |
879 | while (ilen && olen) | 846 | spx_uint32_t olen = *out_len; |
880 | { | 847 | spx_word16_t *x = st->mem + channel_index * st->mem_alloc_size; |
881 | spx_uint32_t ichunk, ochunk; | 848 | const int filt_offs = st->filt_len - 1; |
882 | ichunk = ilen; | 849 | const spx_uint32_t xlen = st->mem_alloc_size - filt_offs; |
883 | ochunk = olen; | 850 | const int istride = st->in_stride; |
884 | if (ichunk>FIXED_STACK_ALLOC) | 851 | |
885 | ichunk=FIXED_STACK_ALLOC; | 852 | if (st->magic_samples[channel_index]) |
886 | if (ochunk>FIXED_STACK_ALLOC) | 853 | olen -= speex_resampler_magic(st, channel_index, &out, olen); |
887 | ochunk=FIXED_STACK_ALLOC; | 854 | if (! st->magic_samples[channel_index]) { |
888 | for (i=0;i<ichunk;i++) | 855 | while (ilen && olen) { |
889 | x[i] = WORD2INT(in[i*st->in_stride]); | 856 | spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen; |
890 | st->in_stride = st->out_stride = 1; | 857 | spx_uint32_t ochunk = olen; |
891 | speex_resampler_process_native(st, channel_index, x, &ichunk, y, &ochunk); | 858 | |
892 | st->in_stride = istride_save; | 859 | if (in) { |
893 | st->out_stride = ostride_save; | 860 | for(j=0;j<ichunk;++j) |
894 | for (i=0;i<ochunk;i++) | 861 | x[j+filt_offs]=in[j*istride]; |
895 | out[i*st->out_stride] = y[i]; | 862 | } else { |
896 | out += ochunk; | 863 | for(j=0;j<ichunk;++j) |
897 | in += ichunk; | 864 | x[j+filt_offs]=0; |
898 | ilen -= ichunk; | 865 | } |
899 | olen -= ochunk; | 866 | speex_resampler_process_native(st, channel_index, &ichunk, out, &ochunk); |
867 | ilen -= ichunk; | ||
868 | olen -= ochunk; | ||
869 | out += ochunk * st->out_stride; | ||
870 | if (in) | ||
871 | in += ichunk * istride; | ||
872 | } | ||
900 | } | 873 | } |
901 | *in_len -= ilen; | 874 | *in_len -= ilen; |
902 | *out_len -= olen; | 875 | *out_len -= olen; |
903 | #endif | ||
904 | return RESAMPLER_ERR_SUCCESS; | 876 | return RESAMPLER_ERR_SUCCESS; |
905 | } | 877 | } |
906 | 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) | 878 | |
907 | { | 879 | #ifdef FIXED_POINT |
908 | return speex_resampler_process_native(st, channel_index, in, in_len, out, out_len); | 880 | EXPORT int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) |
909 | } | ||
910 | #else | 881 | #else |
911 | 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) | 882 | EXPORT int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len) |
912 | { | 883 | #endif |
913 | return speex_resampler_process_native(st, channel_index, in, in_len, out, out_len); | ||
914 | } | ||
915 | 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) | ||
916 | { | 884 | { |
917 | spx_uint32_t i; | 885 | int j; |
918 | int istride_save, ostride_save; | 886 | const int istride_save = st->in_stride; |
887 | const int ostride_save = st->out_stride; | ||
888 | spx_uint32_t ilen = *in_len; | ||
889 | spx_uint32_t olen = *out_len; | ||
890 | spx_word16_t *x = st->mem + channel_index * st->mem_alloc_size; | ||
891 | const spx_uint32_t xlen = st->mem_alloc_size - (st->filt_len - 1); | ||
919 | #ifdef VAR_ARRAYS | 892 | #ifdef VAR_ARRAYS |
920 | spx_word16_t x[*in_len]; | 893 | const unsigned int ylen = (olen < FIXED_STACK_ALLOC) ? olen : FIXED_STACK_ALLOC; |
921 | spx_word16_t y[*out_len]; | 894 | VARDECL(spx_word16_t *ystack); |
922 | /*VARDECL(spx_word16_t *x); | 895 | ALLOC(ystack, ylen, spx_word16_t); |
923 | VARDECL(spx_word16_t *y); | ||
924 | ALLOC(x, *in_len, spx_word16_t); | ||
925 | ALLOC(y, *out_len, spx_word16_t);*/ | ||
926 | istride_save = st->in_stride; | ||
927 | ostride_save = st->out_stride; | ||
928 | for (i=0;i<*in_len;i++) | ||
929 | x[i] = in[i*st->in_stride]; | ||
930 | st->in_stride = st->out_stride = 1; | ||
931 | speex_resampler_process_native(st, channel_index, x, in_len, y, out_len); | ||
932 | st->in_stride = istride_save; | ||
933 | st->out_stride = ostride_save; | ||
934 | for (i=0;i<*out_len;i++) | ||
935 | out[i*st->out_stride] = WORD2INT(y[i]); | ||
936 | #else | 896 | #else |
937 | spx_word16_t x[FIXED_STACK_ALLOC]; | 897 | const unsigned int ylen = FIXED_STACK_ALLOC; |
938 | spx_word16_t y[FIXED_STACK_ALLOC]; | 898 | spx_word16_t ystack[FIXED_STACK_ALLOC]; |
939 | spx_uint32_t ilen=*in_len, olen=*out_len; | 899 | #endif |
940 | istride_save = st->in_stride; | 900 | |
941 | ostride_save = st->out_stride; | 901 | st->out_stride = 1; |
942 | while (ilen && olen) | 902 | |
943 | { | 903 | while (ilen && olen) { |
944 | spx_uint32_t ichunk, ochunk; | 904 | spx_word16_t *y = ystack; |
945 | ichunk = ilen; | 905 | spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen; |
946 | ochunk = olen; | 906 | spx_uint32_t ochunk = (olen > ylen) ? ylen : olen; |
947 | if (ichunk>FIXED_STACK_ALLOC) | 907 | spx_uint32_t omagic = 0; |
948 | ichunk=FIXED_STACK_ALLOC; | 908 | |
949 | if (ochunk>FIXED_STACK_ALLOC) | 909 | if (st->magic_samples[channel_index]) { |
950 | ochunk=FIXED_STACK_ALLOC; | 910 | omagic = speex_resampler_magic(st, channel_index, &y, ochunk); |
951 | for (i=0;i<ichunk;i++) | 911 | ochunk -= omagic; |
952 | x[i] = in[i*st->in_stride]; | 912 | olen -= omagic; |
953 | st->in_stride = st->out_stride = 1; | 913 | } |
954 | speex_resampler_process_native(st, channel_index, x, &ichunk, y, &ochunk); | 914 | if (! st->magic_samples[channel_index]) { |
955 | st->in_stride = istride_save; | 915 | if (in) { |
956 | st->out_stride = ostride_save; | 916 | for(j=0;j<ichunk;++j) |
957 | for (i=0;i<ochunk;i++) | 917 | #ifdef FIXED_POINT |
958 | out[i*st->out_stride] = WORD2INT(y[i]); | 918 | x[j+st->filt_len-1]=WORD2INT(in[j*istride_save]); |
959 | out += ochunk; | 919 | #else |
960 | in += ichunk; | 920 | x[j+st->filt_len-1]=in[j*istride_save]; |
961 | ilen -= ichunk; | 921 | #endif |
962 | olen -= ochunk; | 922 | } else { |
923 | for(j=0;j<ichunk;++j) | ||
924 | x[j+st->filt_len-1]=0; | ||
925 | } | ||
926 | |||
927 | speex_resampler_process_native(st, channel_index, &ichunk, y, &ochunk); | ||
928 | } else { | ||
929 | ichunk = 0; | ||
930 | ochunk = 0; | ||
931 | } | ||
932 | |||
933 | for (j=0;j<ochunk+omagic;++j) | ||
934 | #ifdef FIXED_POINT | ||
935 | out[j*ostride_save] = ystack[j]; | ||
936 | #else | ||
937 | out[j*ostride_save] = WORD2INT(ystack[j]); | ||
938 | #endif | ||
939 | |||
940 | ilen -= ichunk; | ||
941 | olen -= ochunk; | ||
942 | out += (ochunk+omagic) * ostride_save; | ||
943 | if (in) | ||
944 | in += ichunk * istride_save; | ||
963 | } | 945 | } |
946 | st->out_stride = ostride_save; | ||
964 | *in_len -= ilen; | 947 | *in_len -= ilen; |
965 | *out_len -= olen; | 948 | *out_len -= olen; |
966 | #endif | 949 | |
967 | return RESAMPLER_ERR_SUCCESS; | 950 | return RESAMPLER_ERR_SUCCESS; |
968 | } | 951 | } |
969 | #endif | ||
970 | 952 | ||
971 | int speex_resampler_process_interleaved_float(SpeexResamplerState *st, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) | 953 | EXPORT int speex_resampler_process_interleaved_float(SpeexResamplerState *st, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) |
972 | { | 954 | { |
973 | spx_uint32_t i; | 955 | spx_uint32_t i; |
974 | int istride_save, ostride_save; | 956 | int istride_save, ostride_save; |
@@ -989,8 +971,7 @@ int speex_resampler_process_interleaved_float(SpeexResamplerState *st, const flo | |||
989 | return RESAMPLER_ERR_SUCCESS; | 971 | return RESAMPLER_ERR_SUCCESS; |
990 | } | 972 | } |
991 | 973 | ||
992 | 974 | EXPORT int speex_resampler_process_interleaved_int(SpeexResamplerState *st, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len) | |
993 | 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) | ||
994 | { | 975 | { |
995 | spx_uint32_t i; | 976 | spx_uint32_t i; |
996 | int istride_save, ostride_save; | 977 | int istride_save, ostride_save; |
@@ -1011,25 +992,25 @@ int speex_resampler_process_interleaved_int(SpeexResamplerState *st, const spx_i | |||
1011 | return RESAMPLER_ERR_SUCCESS; | 992 | return RESAMPLER_ERR_SUCCESS; |
1012 | } | 993 | } |
1013 | 994 | ||
1014 | int speex_resampler_set_rate(SpeexResamplerState *st, spx_uint32_t in_rate, spx_uint32_t out_rate) | 995 | EXPORT int speex_resampler_set_rate(SpeexResamplerState *st, spx_uint32_t in_rate, spx_uint32_t out_rate) |
1015 | { | 996 | { |
1016 | return speex_resampler_set_rate_frac(st, in_rate, out_rate, in_rate, out_rate); | 997 | return speex_resampler_set_rate_frac(st, in_rate, out_rate, in_rate, out_rate); |
1017 | } | 998 | } |
1018 | 999 | ||
1019 | void speex_resampler_get_rate(SpeexResamplerState *st, spx_uint32_t *in_rate, spx_uint32_t *out_rate) | 1000 | EXPORT void speex_resampler_get_rate(SpeexResamplerState *st, spx_uint32_t *in_rate, spx_uint32_t *out_rate) |
1020 | { | 1001 | { |
1021 | *in_rate = st->in_rate; | 1002 | *in_rate = st->in_rate; |
1022 | *out_rate = st->out_rate; | 1003 | *out_rate = st->out_rate; |
1023 | } | 1004 | } |
1024 | 1005 | ||
1025 | 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) | 1006 | EXPORT int speex_resampler_set_rate_frac(SpeexResamplerState *st, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate) |
1026 | { | 1007 | { |
1027 | spx_uint32_t fact; | 1008 | spx_uint32_t fact; |
1028 | spx_uint32_t old_den; | 1009 | spx_uint32_t old_den; |
1029 | spx_uint32_t i; | 1010 | spx_uint32_t i; |
1030 | if (st->in_rate == in_rate && st->out_rate == out_rate && st->num_rate == ratio_num && st->den_rate == ratio_den) | 1011 | if (st->in_rate == in_rate && st->out_rate == out_rate && st->num_rate == ratio_num && st->den_rate == ratio_den) |
1031 | return RESAMPLER_ERR_SUCCESS; | 1012 | return RESAMPLER_ERR_SUCCESS; |
1032 | 1013 | ||
1033 | old_den = st->den_rate; | 1014 | old_den = st->den_rate; |
1034 | st->in_rate = in_rate; | 1015 | st->in_rate = in_rate; |
1035 | st->out_rate = out_rate; | 1016 | st->out_rate = out_rate; |
@@ -1044,7 +1025,7 @@ int speex_resampler_set_rate_frac(SpeexResamplerState *st, spx_uint32_t ratio_nu | |||
1044 | st->den_rate /= fact; | 1025 | st->den_rate /= fact; |
1045 | } | 1026 | } |
1046 | } | 1027 | } |
1047 | 1028 | ||
1048 | if (old_den > 0) | 1029 | if (old_den > 0) |
1049 | { | 1030 | { |
1050 | for (i=0;i<st->nb_channels;i++) | 1031 | for (i=0;i<st->nb_channels;i++) |
@@ -1055,19 +1036,19 @@ int speex_resampler_set_rate_frac(SpeexResamplerState *st, spx_uint32_t ratio_nu | |||
1055 | st->samp_frac_num[i] = st->den_rate-1; | 1036 | st->samp_frac_num[i] = st->den_rate-1; |
1056 | } | 1037 | } |
1057 | } | 1038 | } |
1058 | 1039 | ||
1059 | if (st->initialised) | 1040 | if (st->initialised) |
1060 | update_filter(st); | 1041 | update_filter(st); |
1061 | return RESAMPLER_ERR_SUCCESS; | 1042 | return RESAMPLER_ERR_SUCCESS; |
1062 | } | 1043 | } |
1063 | 1044 | ||
1064 | void speex_resampler_get_ratio(SpeexResamplerState *st, spx_uint32_t *ratio_num, spx_uint32_t *ratio_den) | 1045 | EXPORT void speex_resampler_get_ratio(SpeexResamplerState *st, spx_uint32_t *ratio_num, spx_uint32_t *ratio_den) |
1065 | { | 1046 | { |
1066 | *ratio_num = st->num_rate; | 1047 | *ratio_num = st->num_rate; |
1067 | *ratio_den = st->den_rate; | 1048 | *ratio_den = st->den_rate; |
1068 | } | 1049 | } |
1069 | 1050 | ||
1070 | int speex_resampler_set_quality(SpeexResamplerState *st, int quality) | 1051 | EXPORT int speex_resampler_set_quality(SpeexResamplerState *st, int quality) |
1071 | { | 1052 | { |
1072 | if (quality > 10 || quality < 0) | 1053 | if (quality > 10 || quality < 0) |
1073 | return RESAMPLER_ERR_INVALID_ARG; | 1054 | return RESAMPLER_ERR_INVALID_ARG; |
@@ -1079,32 +1060,42 @@ int speex_resampler_set_quality(SpeexResamplerState *st, int quality) | |||
1079 | return RESAMPLER_ERR_SUCCESS; | 1060 | return RESAMPLER_ERR_SUCCESS; |
1080 | } | 1061 | } |
1081 | 1062 | ||
1082 | void speex_resampler_get_quality(SpeexResamplerState *st, int *quality) | 1063 | EXPORT void speex_resampler_get_quality(SpeexResamplerState *st, int *quality) |
1083 | { | 1064 | { |
1084 | *quality = st->quality; | 1065 | *quality = st->quality; |
1085 | } | 1066 | } |
1086 | 1067 | ||
1087 | void speex_resampler_set_input_stride(SpeexResamplerState *st, spx_uint32_t stride) | 1068 | EXPORT void speex_resampler_set_input_stride(SpeexResamplerState *st, spx_uint32_t stride) |
1088 | { | 1069 | { |
1089 | st->in_stride = stride; | 1070 | st->in_stride = stride; |
1090 | } | 1071 | } |
1091 | 1072 | ||
1092 | void speex_resampler_get_input_stride(SpeexResamplerState *st, spx_uint32_t *stride) | 1073 | EXPORT void speex_resampler_get_input_stride(SpeexResamplerState *st, spx_uint32_t *stride) |
1093 | { | 1074 | { |
1094 | *stride = st->in_stride; | 1075 | *stride = st->in_stride; |
1095 | } | 1076 | } |
1096 | 1077 | ||
1097 | void speex_resampler_set_output_stride(SpeexResamplerState *st, spx_uint32_t stride) | 1078 | EXPORT void speex_resampler_set_output_stride(SpeexResamplerState *st, spx_uint32_t stride) |
1098 | { | 1079 | { |
1099 | st->out_stride = stride; | 1080 | st->out_stride = stride; |
1100 | } | 1081 | } |
1101 | 1082 | ||
1102 | void speex_resampler_get_output_stride(SpeexResamplerState *st, spx_uint32_t *stride) | 1083 | EXPORT void speex_resampler_get_output_stride(SpeexResamplerState *st, spx_uint32_t *stride) |
1103 | { | 1084 | { |
1104 | *stride = st->out_stride; | 1085 | *stride = st->out_stride; |
1105 | } | 1086 | } |
1106 | 1087 | ||
1107 | int speex_resampler_skip_zeros(SpeexResamplerState *st) | 1088 | EXPORT int speex_resampler_get_input_latency(SpeexResamplerState *st) |
1089 | { | ||
1090 | return st->filt_len / 2; | ||
1091 | } | ||
1092 | |||
1093 | EXPORT int speex_resampler_get_output_latency(SpeexResamplerState *st) | ||
1094 | { | ||
1095 | return ((st->filt_len / 2) * st->den_rate + (st->num_rate >> 1)) / st->num_rate; | ||
1096 | } | ||
1097 | |||
1098 | EXPORT int speex_resampler_skip_zeros(SpeexResamplerState *st) | ||
1108 | { | 1099 | { |
1109 | spx_uint32_t i; | 1100 | spx_uint32_t i; |
1110 | for (i=0;i<st->nb_channels;i++) | 1101 | for (i=0;i<st->nb_channels;i++) |
@@ -1112,7 +1103,7 @@ int speex_resampler_skip_zeros(SpeexResamplerState *st) | |||
1112 | return RESAMPLER_ERR_SUCCESS; | 1103 | return RESAMPLER_ERR_SUCCESS; |
1113 | } | 1104 | } |
1114 | 1105 | ||
1115 | int speex_resampler_reset_mem(SpeexResamplerState *st) | 1106 | EXPORT int speex_resampler_reset_mem(SpeexResamplerState *st) |
1116 | { | 1107 | { |
1117 | spx_uint32_t i; | 1108 | spx_uint32_t i; |
1118 | for (i=0;i<st->nb_channels*(st->filt_len-1);i++) | 1109 | for (i=0;i<st->nb_channels*(st->filt_len-1);i++) |
@@ -1120,7 +1111,7 @@ int speex_resampler_reset_mem(SpeexResamplerState *st) | |||
1120 | return RESAMPLER_ERR_SUCCESS; | 1111 | return RESAMPLER_ERR_SUCCESS; |
1121 | } | 1112 | } |
1122 | 1113 | ||
1123 | const char *speex_resampler_strerror(int err) | 1114 | EXPORT const char *speex_resampler_strerror(int err) |
1124 | { | 1115 | { |
1125 | switch (err) | 1116 | switch (err) |
1126 | { | 1117 | { |