Path: blob/master/dep/cubeb/subprojects/speex/resample.c
4247 views
/* Copyright (C) 2007-2008 Jean-Marc Valin1Copyright (C) 2008 Thorvald Natvig23File: resample.c4Arbitrary resampling code56Redistribution and use in source and binary forms, with or without7modification, are permitted provided that the following conditions are8met:9101. Redistributions of source code must retain the above copyright notice,11this list of conditions and the following disclaimer.12132. Redistributions in binary form must reproduce the above copyright14notice, this list of conditions and the following disclaimer in the15documentation and/or other materials provided with the distribution.16173. The name of the author may not be used to endorse or promote products18derived from this software without specific prior written permission.1920THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR21IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES22OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE23DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,24INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES25(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR26SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)27HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,28STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN29ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE30POSSIBILITY OF SUCH DAMAGE.31*/3233/*34The design goals of this code are:35- Very fast algorithm36- SIMD-friendly algorithm37- Low memory requirement38- Good *perceptual* quality (and not best SNR)3940Warning: This resampler is relatively new. Although I think I got rid of41all the major bugs and I don't expect the API to change anymore, there42may be something I've missed. So use with caution.4344This algorithm is based on this original resampling algorithm:45Smith, Julius O. Digital Audio Resampling Home Page46Center for Computer Research in Music and Acoustics (CCRMA),47Stanford University, 2007.48Web published at http://ccrma.stanford.edu/~jos/resample/.4950There is one main difference, though. This resampler uses cubic51interpolation instead of linear interpolation in the above paper. This52makes the table much smaller and makes it possible to compute that table53on a per-stream basis. In turn, being able to tweak the table for each54stream makes it possible to both reduce complexity on simple ratios55(e.g. 2/3), and get rid of the rounding operations in the inner loop.56The latter both reduces CPU time and makes the algorithm more SIMD-friendly.57*/5859#ifdef HAVE_CONFIG_H60#include "config.h"61#endif6263#ifdef OUTSIDE_SPEEX64#include <stdlib.h>65static void *speex_alloc (int size) {return calloc(size,1);}66static void *speex_realloc (void *ptr, int size) {return realloc(ptr, size);}67static void speex_free (void *ptr) {free(ptr);}68#include "speex_resampler.h"69#include "arch.h"70#else /* OUTSIDE_SPEEX */7172#include "speex/speex_resampler.h"73#include "arch.h"74#include "os_support.h"75#endif /* OUTSIDE_SPEEX */7677#include "stack_alloc.h"78#include <math.h>79#include <limits.h>8081#ifndef M_PI82#define M_PI 3.1415926535897932384683#endif8485#define IMAX(a,b) ((a) > (b) ? (a) : (b))86#define IMIN(a,b) ((a) < (b) ? (a) : (b))8788#ifndef NULL89#define NULL 090#endif9192#ifndef UINT32_MAX93#define UINT32_MAX 4294967296U94#endif9596#ifdef _USE_SSE97#include "resample_sse.h"98#endif99100#ifdef _USE_NEON101#include "resample_neon.h"102#endif103104/* Numer of elements to allocate on the stack */105#ifdef VAR_ARRAYS106#define FIXED_STACK_ALLOC 8192107#else108#define FIXED_STACK_ALLOC 1024109#endif110111typedef int (*resampler_basic_func)(SpeexResamplerState *, spx_uint32_t , const spx_word16_t *, spx_uint32_t *, spx_word16_t *, spx_uint32_t *);112113struct SpeexResamplerState_ {114spx_uint32_t in_rate;115spx_uint32_t out_rate;116spx_uint32_t num_rate;117spx_uint32_t den_rate;118119int quality;120spx_uint32_t nb_channels;121spx_uint32_t filt_len;122spx_uint32_t mem_alloc_size;123spx_uint32_t buffer_size;124int int_advance;125int frac_advance;126float cutoff;127spx_uint32_t oversample;128int initialised;129int started;130131/* These are per-channel */132spx_int32_t *last_sample;133spx_uint32_t *samp_frac_num;134spx_uint32_t *magic_samples;135136spx_word16_t *mem;137spx_word16_t *sinc_table;138spx_uint32_t sinc_table_length;139resampler_basic_func resampler_ptr;140141int in_stride;142int out_stride;143} ;144145static const double kaiser12_table[68] = {1460.99859849, 1.00000000, 0.99859849, 0.99440475, 0.98745105, 0.97779076,1470.96549770, 0.95066529, 0.93340547, 0.91384741, 0.89213598, 0.86843014,1480.84290116, 0.81573067, 0.78710866, 0.75723148, 0.72629970, 0.69451601,1490.66208321, 0.62920216, 0.59606986, 0.56287762, 0.52980938, 0.49704014,1500.46473455, 0.43304576, 0.40211431, 0.37206735, 0.34301800, 0.31506490,1510.28829195, 0.26276832, 0.23854851, 0.21567274, 0.19416736, 0.17404546,1520.15530766, 0.13794294, 0.12192957, 0.10723616, 0.09382272, 0.08164178,1530.07063950, 0.06075685, 0.05193064, 0.04409466, 0.03718069, 0.03111947,1540.02584161, 0.02127838, 0.01736250, 0.01402878, 0.01121463, 0.00886058,1550.00691064, 0.00531256, 0.00401805, 0.00298291, 0.00216702, 0.00153438,1560.00105297, 0.00069463, 0.00043489, 0.00025272, 0.00013031, 0.0000527734,1570.00001000, 0.00000000};158/*159static const double kaiser12_table[36] = {1600.99440475, 1.00000000, 0.99440475, 0.97779076, 0.95066529, 0.91384741,1610.86843014, 0.81573067, 0.75723148, 0.69451601, 0.62920216, 0.56287762,1620.49704014, 0.43304576, 0.37206735, 0.31506490, 0.26276832, 0.21567274,1630.17404546, 0.13794294, 0.10723616, 0.08164178, 0.06075685, 0.04409466,1640.03111947, 0.02127838, 0.01402878, 0.00886058, 0.00531256, 0.00298291,1650.00153438, 0.00069463, 0.00025272, 0.0000527734, 0.00000500, 0.00000000};166*/167static const double kaiser10_table[36] = {1680.99537781, 1.00000000, 0.99537781, 0.98162644, 0.95908712, 0.92831446,1690.89005583, 0.84522401, 0.79486424, 0.74011713, 0.68217934, 0.62226347,1700.56155915, 0.50119680, 0.44221549, 0.38553619, 0.33194107, 0.28205962,1710.23636152, 0.19515633, 0.15859932, 0.12670280, 0.09935205, 0.07632451,1720.05731132, 0.04193980, 0.02979584, 0.02044510, 0.01345224, 0.00839739,1730.00488951, 0.00257636, 0.00115101, 0.00035515, 0.00000000, 0.00000000};174175static const double kaiser8_table[36] = {1760.99635258, 1.00000000, 0.99635258, 0.98548012, 0.96759014, 0.94302200,1770.91223751, 0.87580811, 0.83439927, 0.78875245, 0.73966538, 0.68797126,1780.63451750, 0.58014482, 0.52566725, 0.47185369, 0.41941150, 0.36897272,1790.32108304, 0.27619388, 0.23465776, 0.19672670, 0.16255380, 0.13219758,1800.10562887, 0.08273982, 0.06335451, 0.04724088, 0.03412321, 0.02369490,1810.01563093, 0.00959968, 0.00527363, 0.00233883, 0.00050000, 0.00000000};182183static const double kaiser6_table[36] = {1840.99733006, 1.00000000, 0.99733006, 0.98935595, 0.97618418, 0.95799003,1850.93501423, 0.90755855, 0.87598009, 0.84068475, 0.80211977, 0.76076565,1860.71712752, 0.67172623, 0.62508937, 0.57774224, 0.53019925, 0.48295561,1870.43647969, 0.39120616, 0.34752997, 0.30580127, 0.26632152, 0.22934058,1880.19505503, 0.16360756, 0.13508755, 0.10953262, 0.08693120, 0.06722600,1890.05031820, 0.03607231, 0.02432151, 0.01487334, 0.00752000, 0.00000000};190191struct FuncDef {192const double *table;193int oversample;194};195196static const struct FuncDef _KAISER12 = {kaiser12_table, 64};197#define KAISER12 (&_KAISER12)198/*static struct FuncDef _KAISER12 = {kaiser12_table, 32};199#define KAISER12 (&_KAISER12)*/200static const struct FuncDef _KAISER10 = {kaiser10_table, 32};201#define KAISER10 (&_KAISER10)202static const struct FuncDef _KAISER8 = {kaiser8_table, 32};203#define KAISER8 (&_KAISER8)204static const struct FuncDef _KAISER6 = {kaiser6_table, 32};205#define KAISER6 (&_KAISER6)206207struct QualityMapping {208int base_length;209int oversample;210float downsample_bandwidth;211float upsample_bandwidth;212const struct FuncDef *window_func;213};214215216/* This table maps conversion quality to internal parameters. There are two217reasons that explain why the up-sampling bandwidth is larger than the218down-sampling bandwidth:2191) When up-sampling, we can assume that the spectrum is already attenuated220close to the Nyquist rate (from an A/D or a previous resampling filter)2212) Any aliasing that occurs very close to the Nyquist rate will be masked222by the sinusoids/noise just below the Nyquist rate (guaranteed only for223up-sampling).224*/225static const struct QualityMapping quality_map[11] = {226{ 8, 4, 0.830f, 0.860f, KAISER6 }, /* Q0 */227{ 16, 4, 0.850f, 0.880f, KAISER6 }, /* Q1 */228{ 32, 4, 0.882f, 0.910f, KAISER6 }, /* Q2 */ /* 82.3% cutoff ( ~60 dB stop) 6 */229{ 48, 8, 0.895f, 0.917f, KAISER8 }, /* Q3 */ /* 84.9% cutoff ( ~80 dB stop) 8 */230{ 64, 8, 0.921f, 0.940f, KAISER8 }, /* Q4 */ /* 88.7% cutoff ( ~80 dB stop) 8 */231{ 80, 16, 0.922f, 0.940f, KAISER10}, /* Q5 */ /* 89.1% cutoff (~100 dB stop) 10 */232{ 96, 16, 0.940f, 0.945f, KAISER10}, /* Q6 */ /* 91.5% cutoff (~100 dB stop) 10 */233{128, 16, 0.950f, 0.950f, KAISER10}, /* Q7 */ /* 93.1% cutoff (~100 dB stop) 10 */234{160, 16, 0.960f, 0.960f, KAISER10}, /* Q8 */ /* 94.5% cutoff (~100 dB stop) 10 */235{192, 32, 0.968f, 0.968f, KAISER12}, /* Q9 */ /* 95.5% cutoff (~100 dB stop) 10 */236{256, 32, 0.975f, 0.975f, KAISER12}, /* Q10 */ /* 96.6% cutoff (~100 dB stop) 10 */237};238/*8,24,40,56,80,104,128,160,200,256,320*/239static double compute_func(float x, const struct FuncDef *func)240{241float y, frac;242double interp[4];243int ind;244y = x*func->oversample;245ind = (int)floor(y);246frac = (y-ind);247/* CSE with handle the repeated powers */248interp[3] = -0.1666666667*frac + 0.1666666667*(frac*frac*frac);249interp[2] = frac + 0.5*(frac*frac) - 0.5*(frac*frac*frac);250/*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/251interp[0] = -0.3333333333*frac + 0.5*(frac*frac) - 0.1666666667*(frac*frac*frac);252/* Just to make sure we don't have rounding problems */253interp[1] = 1.f-interp[3]-interp[2]-interp[0];254255/*sum = frac*accum[1] + (1-frac)*accum[2];*/256return interp[0]*func->table[ind] + interp[1]*func->table[ind+1] + interp[2]*func->table[ind+2] + interp[3]*func->table[ind+3];257}258259#if 0260#include <stdio.h>261int main(int argc, char **argv)262{263int i;264for (i=0;i<256;i++)265{266printf ("%f\n", compute_func(i/256., KAISER12));267}268return 0;269}270#endif271272#ifdef FIXED_POINT273/* The slow way of computing a sinc for the table. Should improve that some day */274static spx_word16_t sinc(float cutoff, float x, int N, const struct FuncDef *window_func)275{276/*fprintf (stderr, "%f ", x);*/277float xx = x * cutoff;278if (fabs(x)<1e-6f)279return WORD2INT(32768.*cutoff);280else if (fabs(x) > .5f*N)281return 0;282/*FIXME: Can it really be any slower than this? */283return WORD2INT(32768.*cutoff*sin(M_PI*xx)/(M_PI*xx) * compute_func(fabs(2.*x/N), window_func));284}285#else286/* The slow way of computing a sinc for the table. Should improve that some day */287static spx_word16_t sinc(float cutoff, float x, int N, const struct FuncDef *window_func)288{289/*fprintf (stderr, "%f ", x);*/290float xx = x * cutoff;291if (fabs(x)<1e-6)292return cutoff;293else if (fabs(x) > .5*N)294return 0;295/*FIXME: Can it really be any slower than this? */296return cutoff*sin(M_PI*xx)/(M_PI*xx) * compute_func(fabs(2.*x/N), window_func);297}298#endif299300#ifdef FIXED_POINT301static void cubic_coef(spx_word16_t x, spx_word16_t interp[4])302{303/* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation304but I know it's MMSE-optimal on a sinc */305spx_word16_t x2, x3;306x2 = MULT16_16_P15(x, x);307x3 = MULT16_16_P15(x, x2);308interp[0] = PSHR32(MULT16_16(QCONST16(-0.16667f, 15),x) + MULT16_16(QCONST16(0.16667f, 15),x3),15);309interp[1] = EXTRACT16(EXTEND32(x) + SHR32(SUB32(EXTEND32(x2),EXTEND32(x3)),1));310interp[3] = PSHR32(MULT16_16(QCONST16(-0.33333f, 15),x) + MULT16_16(QCONST16(.5f,15),x2) - MULT16_16(QCONST16(0.16667f, 15),x3),15);311/* Just to make sure we don't have rounding problems */312interp[2] = Q15_ONE-interp[0]-interp[1]-interp[3];313if (interp[2]<32767)314interp[2]+=1;315}316#else317static void cubic_coef(spx_word16_t frac, spx_word16_t interp[4])318{319/* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation320but I know it's MMSE-optimal on a sinc */321interp[0] = -0.16667f*frac + 0.16667f*frac*frac*frac;322interp[1] = frac + 0.5f*frac*frac - 0.5f*frac*frac*frac;323/*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/324interp[3] = -0.33333f*frac + 0.5f*frac*frac - 0.16667f*frac*frac*frac;325/* Just to make sure we don't have rounding problems */326interp[2] = 1.-interp[0]-interp[1]-interp[3];327}328#endif329330static 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)331{332const int N = st->filt_len;333int out_sample = 0;334int last_sample = st->last_sample[channel_index];335spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];336const spx_word16_t *sinc_table = st->sinc_table;337const int out_stride = st->out_stride;338const int int_advance = st->int_advance;339const int frac_advance = st->frac_advance;340const spx_uint32_t den_rate = st->den_rate;341spx_word32_t sum;342343while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))344{345const spx_word16_t *sinct = & sinc_table[samp_frac_num*N];346const spx_word16_t *iptr = & in[last_sample];347348#ifndef OVERRIDE_INNER_PRODUCT_SINGLE349int j;350sum = 0;351for(j=0;j<N;j++) sum += MULT16_16(sinct[j], iptr[j]);352353/* This code is slower on most DSPs which have only 2 accumulators.354Plus this this forces truncation to 32 bits and you lose the HW guard bits.355I think we can trust the compiler and let it vectorize and/or unroll itself.356spx_word32_t accum[4] = {0,0,0,0};357for(j=0;j<N;j+=4) {358accum[0] += MULT16_16(sinct[j], iptr[j]);359accum[1] += MULT16_16(sinct[j+1], iptr[j+1]);360accum[2] += MULT16_16(sinct[j+2], iptr[j+2]);361accum[3] += MULT16_16(sinct[j+3], iptr[j+3]);362}363sum = accum[0] + accum[1] + accum[2] + accum[3];364*/365sum = SATURATE32PSHR(sum, 15, 32767);366#else367sum = inner_product_single(sinct, iptr, N);368#endif369370out[out_stride * out_sample++] = sum;371last_sample += int_advance;372samp_frac_num += frac_advance;373if (samp_frac_num >= den_rate)374{375samp_frac_num -= den_rate;376last_sample++;377}378}379380st->last_sample[channel_index] = last_sample;381st->samp_frac_num[channel_index] = samp_frac_num;382return out_sample;383}384385#ifdef FIXED_POINT386#else387/* This is the same as the previous function, except with a double-precision accumulator */388static 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)389{390const int N = st->filt_len;391int out_sample = 0;392int last_sample = st->last_sample[channel_index];393spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];394const spx_word16_t *sinc_table = st->sinc_table;395const int out_stride = st->out_stride;396const int int_advance = st->int_advance;397const int frac_advance = st->frac_advance;398const spx_uint32_t den_rate = st->den_rate;399double sum;400401while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))402{403const spx_word16_t *sinct = & sinc_table[samp_frac_num*N];404const spx_word16_t *iptr = & in[last_sample];405406#ifndef OVERRIDE_INNER_PRODUCT_DOUBLE407int j;408double accum[4] = {0,0,0,0};409410for(j=0;j<N;j+=4) {411accum[0] += sinct[j]*iptr[j];412accum[1] += sinct[j+1]*iptr[j+1];413accum[2] += sinct[j+2]*iptr[j+2];414accum[3] += sinct[j+3]*iptr[j+3];415}416sum = accum[0] + accum[1] + accum[2] + accum[3];417#else418sum = inner_product_double(sinct, iptr, N);419#endif420421out[out_stride * out_sample++] = PSHR32(sum, 15);422last_sample += int_advance;423samp_frac_num += frac_advance;424if (samp_frac_num >= den_rate)425{426samp_frac_num -= den_rate;427last_sample++;428}429}430431st->last_sample[channel_index] = last_sample;432st->samp_frac_num[channel_index] = samp_frac_num;433return out_sample;434}435#endif436437static 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)438{439const int N = st->filt_len;440int out_sample = 0;441int last_sample = st->last_sample[channel_index];442spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];443const int out_stride = st->out_stride;444const int int_advance = st->int_advance;445const int frac_advance = st->frac_advance;446const spx_uint32_t den_rate = st->den_rate;447spx_word32_t sum;448449while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))450{451const spx_word16_t *iptr = & in[last_sample];452453const int offset = samp_frac_num*st->oversample/st->den_rate;454#ifdef FIXED_POINT455const spx_word16_t frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate);456#else457const spx_word16_t frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate;458#endif459spx_word16_t interp[4];460461462#ifndef OVERRIDE_INTERPOLATE_PRODUCT_SINGLE463int j;464spx_word32_t accum[4] = {0,0,0,0};465466for(j=0;j<N;j++) {467const spx_word16_t curr_in=iptr[j];468accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]);469accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]);470accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]);471accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]);472}473474cubic_coef(frac, interp);475sum = MULT16_32_Q15(interp[0],SHR32(accum[0], 1)) + MULT16_32_Q15(interp[1],SHR32(accum[1], 1)) + MULT16_32_Q15(interp[2],SHR32(accum[2], 1)) + MULT16_32_Q15(interp[3],SHR32(accum[3], 1));476sum = SATURATE32PSHR(sum, 15, 32767);477#else478cubic_coef(frac, interp);479sum = interpolate_product_single(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp);480#endif481482out[out_stride * out_sample++] = sum;483last_sample += int_advance;484samp_frac_num += frac_advance;485if (samp_frac_num >= den_rate)486{487samp_frac_num -= den_rate;488last_sample++;489}490}491492st->last_sample[channel_index] = last_sample;493st->samp_frac_num[channel_index] = samp_frac_num;494return out_sample;495}496497#ifdef FIXED_POINT498#else499/* This is the same as the previous function, except with a double-precision accumulator */500static 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)501{502const int N = st->filt_len;503int out_sample = 0;504int last_sample = st->last_sample[channel_index];505spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];506const int out_stride = st->out_stride;507const int int_advance = st->int_advance;508const int frac_advance = st->frac_advance;509const spx_uint32_t den_rate = st->den_rate;510spx_word32_t sum;511512while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))513{514const spx_word16_t *iptr = & in[last_sample];515516const int offset = samp_frac_num*st->oversample/st->den_rate;517#ifdef FIXED_POINT518const spx_word16_t frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate);519#else520const spx_word16_t frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate;521#endif522spx_word16_t interp[4];523524525#ifndef OVERRIDE_INTERPOLATE_PRODUCT_DOUBLE526int j;527double accum[4] = {0,0,0,0};528529for(j=0;j<N;j++) {530const double curr_in=iptr[j];531accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]);532accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]);533accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]);534accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]);535}536537cubic_coef(frac, interp);538sum = 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]);539#else540cubic_coef(frac, interp);541sum = interpolate_product_double(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp);542#endif543544out[out_stride * out_sample++] = PSHR32(sum,15);545last_sample += int_advance;546samp_frac_num += frac_advance;547if (samp_frac_num >= den_rate)548{549samp_frac_num -= den_rate;550last_sample++;551}552}553554st->last_sample[channel_index] = last_sample;555st->samp_frac_num[channel_index] = samp_frac_num;556return out_sample;557}558#endif559560/* This resampler is used to produce zero output in situations where memory561for the filter could not be allocated. The expected numbers of input and562output samples are still processed so that callers failing to check error563codes are not surprised, possibly getting into infinite loops. */564static int resampler_basic_zero(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)565{566int out_sample = 0;567int last_sample = st->last_sample[channel_index];568spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];569const int out_stride = st->out_stride;570const int int_advance = st->int_advance;571const int frac_advance = st->frac_advance;572const spx_uint32_t den_rate = st->den_rate;573574while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))575{576out[out_stride * out_sample++] = 0;577last_sample += int_advance;578samp_frac_num += frac_advance;579if (samp_frac_num >= den_rate)580{581samp_frac_num -= den_rate;582last_sample++;583}584}585586st->last_sample[channel_index] = last_sample;587st->samp_frac_num[channel_index] = samp_frac_num;588return out_sample;589}590591static int _muldiv(spx_uint32_t *result, spx_uint32_t value, spx_uint32_t mul, spx_uint32_t div)592{593speex_assert(result);594spx_uint32_t major = value / div;595spx_uint32_t remainder = value % div;596/* TODO: Could use 64 bits operation to check for overflow. But only guaranteed in C99+ */597if (remainder > UINT32_MAX / mul || major > UINT32_MAX / mul598|| major * mul > UINT32_MAX - remainder * mul / div)599return RESAMPLER_ERR_OVERFLOW;600*result = remainder * mul / div + major * mul;601return RESAMPLER_ERR_SUCCESS;602}603604static int update_filter(SpeexResamplerState *st)605{606spx_uint32_t old_length = st->filt_len;607spx_uint32_t old_alloc_size = st->mem_alloc_size;608int use_direct;609spx_uint32_t min_sinc_table_length;610spx_uint32_t min_alloc_size;611612st->int_advance = st->num_rate/st->den_rate;613st->frac_advance = st->num_rate%st->den_rate;614st->oversample = quality_map[st->quality].oversample;615st->filt_len = quality_map[st->quality].base_length;616617if (st->num_rate > st->den_rate)618{619/* down-sampling */620st->cutoff = quality_map[st->quality].downsample_bandwidth * st->den_rate / st->num_rate;621if (_muldiv(&st->filt_len,st->filt_len,st->num_rate,st->den_rate) != RESAMPLER_ERR_SUCCESS)622goto fail;623/* Round up to make sure we have a multiple of 8 for SSE */624st->filt_len = ((st->filt_len-1)&(~0x7))+8;625if (2*st->den_rate < st->num_rate)626st->oversample >>= 1;627if (4*st->den_rate < st->num_rate)628st->oversample >>= 1;629if (8*st->den_rate < st->num_rate)630st->oversample >>= 1;631if (16*st->den_rate < st->num_rate)632st->oversample >>= 1;633if (st->oversample < 1)634st->oversample = 1;635} else {636/* up-sampling */637st->cutoff = quality_map[st->quality].upsample_bandwidth;638}639640/* Choose the resampling type that requires the least amount of memory */641#ifdef RESAMPLE_FULL_SINC_TABLE642use_direct = 1;643if (INT_MAX/sizeof(spx_word16_t)/st->den_rate < st->filt_len)644goto fail;645#else646use_direct = st->filt_len*st->den_rate <= st->filt_len*st->oversample+8647&& INT_MAX/sizeof(spx_word16_t)/st->den_rate >= st->filt_len;648#endif649if (use_direct)650{651min_sinc_table_length = st->filt_len*st->den_rate;652} else {653if ((INT_MAX/sizeof(spx_word16_t)-8)/st->oversample < st->filt_len)654goto fail;655656min_sinc_table_length = st->filt_len*st->oversample+8;657}658if (st->sinc_table_length < min_sinc_table_length)659{660spx_word16_t *sinc_table = (spx_word16_t *)speex_realloc(st->sinc_table,min_sinc_table_length*sizeof(spx_word16_t));661if (!sinc_table)662goto fail;663664st->sinc_table = sinc_table;665st->sinc_table_length = min_sinc_table_length;666}667if (use_direct)668{669spx_uint32_t i;670for (i=0;i<st->den_rate;i++)671{672spx_int32_t j;673for (j=0;j<st->filt_len;j++)674{675st->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);676}677}678#ifdef FIXED_POINT679st->resampler_ptr = resampler_basic_direct_single;680#else681if (st->quality>8)682st->resampler_ptr = resampler_basic_direct_double;683else684st->resampler_ptr = resampler_basic_direct_single;685#endif686/*fprintf (stderr, "resampler uses direct sinc table and normalised cutoff %f\n", cutoff);*/687} else {688spx_int32_t i;689for (i=-4;i<(spx_int32_t)(st->oversample*st->filt_len+4);i++)690st->sinc_table[i+4] = sinc(st->cutoff,(i/(float)st->oversample - st->filt_len/2), st->filt_len, quality_map[st->quality].window_func);691#ifdef FIXED_POINT692st->resampler_ptr = resampler_basic_interpolate_single;693#else694if (st->quality>8)695st->resampler_ptr = resampler_basic_interpolate_double;696else697st->resampler_ptr = resampler_basic_interpolate_single;698#endif699/*fprintf (stderr, "resampler uses interpolated sinc table and normalised cutoff %f\n", cutoff);*/700}701702/* Here's the place where we update the filter memory to take into account703the change in filter length. It's probably the messiest part of the code704due to handling of lots of corner cases. */705706/* Adding buffer_size to filt_len won't overflow here because filt_len707could be multiplied by sizeof(spx_word16_t) above. */708min_alloc_size = st->filt_len-1 + st->buffer_size;709if (min_alloc_size > st->mem_alloc_size)710{711spx_word16_t *mem;712if (INT_MAX/sizeof(spx_word16_t)/st->nb_channels < min_alloc_size)713goto fail;714else if (!(mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*min_alloc_size * sizeof(*mem))))715goto fail;716717st->mem = mem;718st->mem_alloc_size = min_alloc_size;719}720if (!st->started)721{722spx_uint32_t i;723for (i=0;i<st->nb_channels*st->mem_alloc_size;i++)724st->mem[i] = 0;725/*speex_warning("reinit filter");*/726} else if (st->filt_len > old_length)727{728spx_uint32_t i;729/* Increase the filter length */730/*speex_warning("increase filter size");*/731for (i=st->nb_channels;i--;)732{733spx_uint32_t j;734spx_uint32_t olen = old_length;735/*if (st->magic_samples[i])*/736{737/* Try and remove the magic samples as if nothing had happened */738739/* FIXME: This is wrong but for now we need it to avoid going over the array bounds */740olen = old_length + 2*st->magic_samples[i];741for (j=old_length-1+st->magic_samples[i];j--;)742st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]] = st->mem[i*old_alloc_size+j];743for (j=0;j<st->magic_samples[i];j++)744st->mem[i*st->mem_alloc_size+j] = 0;745st->magic_samples[i] = 0;746}747if (st->filt_len > olen)748{749/* If the new filter length is still bigger than the "augmented" length */750/* Copy data going backward */751for (j=0;j<olen-1;j++)752st->mem[i*st->mem_alloc_size+(st->filt_len-2-j)] = st->mem[i*st->mem_alloc_size+(olen-2-j)];753/* Then put zeros for lack of anything better */754for (;j<st->filt_len-1;j++)755st->mem[i*st->mem_alloc_size+(st->filt_len-2-j)] = 0;756/* Adjust last_sample */757st->last_sample[i] += (st->filt_len - olen)/2;758} else {759/* Put back some of the magic! */760st->magic_samples[i] = (olen - st->filt_len)/2;761for (j=0;j<st->filt_len-1+st->magic_samples[i];j++)762st->mem[i*st->mem_alloc_size+j] = st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]];763}764}765} else if (st->filt_len < old_length)766{767spx_uint32_t i;768/* Reduce filter length, this a bit tricky. We need to store some of the memory as "magic"769samples so they can be used directly as input the next time(s) */770for (i=0;i<st->nb_channels;i++)771{772spx_uint32_t j;773spx_uint32_t old_magic = st->magic_samples[i];774st->magic_samples[i] = (old_length - st->filt_len)/2;775/* We must copy some of the memory that's no longer used */776/* Copy data going backward */777for (j=0;j<st->filt_len-1+st->magic_samples[i]+old_magic;j++)778st->mem[i*st->mem_alloc_size+j] = st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]];779st->magic_samples[i] += old_magic;780}781}782return RESAMPLER_ERR_SUCCESS;783784fail:785st->resampler_ptr = resampler_basic_zero;786/* st->mem may still contain consumed input samples for the filter.787Restore filt_len so that filt_len - 1 still points to the position after788the last of these samples. */789st->filt_len = old_length;790return RESAMPLER_ERR_ALLOC_FAILED;791}792793EXPORT SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err)794{795return speex_resampler_init_frac(nb_channels, in_rate, out_rate, in_rate, out_rate, quality, err);796}797798EXPORT 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)799{800SpeexResamplerState *st;801int filter_err;802803if (nb_channels == 0 || ratio_num == 0 || ratio_den == 0 || quality > 10 || quality < 0)804{805if (err)806*err = RESAMPLER_ERR_INVALID_ARG;807return NULL;808}809st = (SpeexResamplerState *)speex_alloc(sizeof(SpeexResamplerState));810if (!st)811{812if (err)813*err = RESAMPLER_ERR_ALLOC_FAILED;814return NULL;815}816st->initialised = 0;817st->started = 0;818st->in_rate = 0;819st->out_rate = 0;820st->num_rate = 0;821st->den_rate = 0;822st->quality = -1;823st->sinc_table_length = 0;824st->mem_alloc_size = 0;825st->filt_len = 0;826st->mem = 0;827st->resampler_ptr = 0;828829st->cutoff = 1.f;830st->nb_channels = nb_channels;831st->in_stride = 1;832st->out_stride = 1;833834st->buffer_size = 160;835836/* Per channel data */837if (!(st->last_sample = (spx_int32_t*)speex_alloc(nb_channels*sizeof(spx_int32_t))))838goto fail;839if (!(st->magic_samples = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(spx_uint32_t))))840goto fail;841if (!(st->samp_frac_num = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(spx_uint32_t))))842goto fail;843844speex_resampler_set_quality(st, quality);845speex_resampler_set_rate_frac(st, ratio_num, ratio_den, in_rate, out_rate);846847filter_err = update_filter(st);848if (filter_err == RESAMPLER_ERR_SUCCESS)849{850st->initialised = 1;851} else {852speex_resampler_destroy(st);853st = NULL;854}855if (err)856*err = filter_err;857858return st;859860fail:861if (err)862*err = RESAMPLER_ERR_ALLOC_FAILED;863speex_resampler_destroy(st);864return NULL;865}866867EXPORT void speex_resampler_destroy(SpeexResamplerState *st)868{869speex_free(st->mem);870speex_free(st->sinc_table);871speex_free(st->last_sample);872speex_free(st->magic_samples);873speex_free(st->samp_frac_num);874speex_free(st);875}876877static 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)878{879int j=0;880const int N = st->filt_len;881int out_sample = 0;882spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size;883spx_uint32_t ilen;884885st->started = 1;886887/* Call the right resampler through the function ptr */888out_sample = st->resampler_ptr(st, channel_index, mem, in_len, out, out_len);889890if (st->last_sample[channel_index] < (spx_int32_t)*in_len)891*in_len = st->last_sample[channel_index];892*out_len = out_sample;893st->last_sample[channel_index] -= *in_len;894895ilen = *in_len;896897for(j=0;j<N-1;++j)898mem[j] = mem[j+ilen];899900return RESAMPLER_ERR_SUCCESS;901}902903static int speex_resampler_magic(SpeexResamplerState *st, spx_uint32_t channel_index, spx_word16_t **out, spx_uint32_t out_len) {904spx_uint32_t tmp_in_len = st->magic_samples[channel_index];905spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size;906const int N = st->filt_len;907908speex_resampler_process_native(st, channel_index, &tmp_in_len, *out, &out_len);909910st->magic_samples[channel_index] -= tmp_in_len;911912/* If we couldn't process all "magic" input samples, save the rest for next time */913if (st->magic_samples[channel_index])914{915spx_uint32_t i;916for (i=0;i<st->magic_samples[channel_index];i++)917mem[N-1+i]=mem[N-1+i+tmp_in_len];918}919*out += out_len*st->out_stride;920return out_len;921}922923#ifdef FIXED_POINT924EXPORT 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)925#else926EXPORT 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)927#endif928{929int j;930spx_uint32_t ilen = *in_len;931spx_uint32_t olen = *out_len;932spx_word16_t *x = st->mem + channel_index * st->mem_alloc_size;933const int filt_offs = st->filt_len - 1;934const spx_uint32_t xlen = st->mem_alloc_size - filt_offs;935const int istride = st->in_stride;936937if (st->magic_samples[channel_index])938olen -= speex_resampler_magic(st, channel_index, &out, olen);939if (! st->magic_samples[channel_index]) {940while (ilen && olen) {941spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen;942spx_uint32_t ochunk = olen;943944if (in) {945for(j=0;j<ichunk;++j)946x[j+filt_offs]=in[j*istride];947} else {948for(j=0;j<ichunk;++j)949x[j+filt_offs]=0;950}951speex_resampler_process_native(st, channel_index, &ichunk, out, &ochunk);952ilen -= ichunk;953olen -= ochunk;954out += ochunk * st->out_stride;955if (in)956in += ichunk * istride;957}958}959*in_len -= ilen;960*out_len -= olen;961return st->resampler_ptr == resampler_basic_zero ? RESAMPLER_ERR_ALLOC_FAILED : RESAMPLER_ERR_SUCCESS;962}963964#ifdef FIXED_POINT965EXPORT 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)966#else967EXPORT 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)968#endif969{970int j;971const int istride_save = st->in_stride;972const int ostride_save = st->out_stride;973spx_uint32_t ilen = *in_len;974spx_uint32_t olen = *out_len;975spx_word16_t *x = st->mem + channel_index * st->mem_alloc_size;976const spx_uint32_t xlen = st->mem_alloc_size - (st->filt_len - 1);977#ifdef VAR_ARRAYS978const unsigned int ylen = (olen < FIXED_STACK_ALLOC) ? olen : FIXED_STACK_ALLOC;979VARDECL(spx_word16_t *ystack);980ALLOC(ystack, ylen, spx_word16_t);981#else982const unsigned int ylen = FIXED_STACK_ALLOC;983spx_word16_t ystack[FIXED_STACK_ALLOC];984#endif985986st->out_stride = 1;987988while (ilen && olen) {989spx_word16_t *y = ystack;990spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen;991spx_uint32_t ochunk = (olen > ylen) ? ylen : olen;992spx_uint32_t omagic = 0;993994if (st->magic_samples[channel_index]) {995omagic = speex_resampler_magic(st, channel_index, &y, ochunk);996ochunk -= omagic;997olen -= omagic;998}999if (! st->magic_samples[channel_index]) {1000if (in) {1001for(j=0;j<ichunk;++j)1002#ifdef FIXED_POINT1003x[j+st->filt_len-1]=WORD2INT(in[j*istride_save]);1004#else1005x[j+st->filt_len-1]=in[j*istride_save];1006#endif1007} else {1008for(j=0;j<ichunk;++j)1009x[j+st->filt_len-1]=0;1010}10111012speex_resampler_process_native(st, channel_index, &ichunk, y, &ochunk);1013} else {1014ichunk = 0;1015ochunk = 0;1016}10171018for (j=0;j<ochunk+omagic;++j)1019#ifdef FIXED_POINT1020out[j*ostride_save] = ystack[j];1021#else1022out[j*ostride_save] = WORD2INT(ystack[j]);1023#endif10241025ilen -= ichunk;1026olen -= ochunk;1027out += (ochunk+omagic) * ostride_save;1028if (in)1029in += ichunk * istride_save;1030}1031st->out_stride = ostride_save;1032*in_len -= ilen;1033*out_len -= olen;10341035return st->resampler_ptr == resampler_basic_zero ? RESAMPLER_ERR_ALLOC_FAILED : RESAMPLER_ERR_SUCCESS;1036}10371038EXPORT int speex_resampler_process_interleaved_float(SpeexResamplerState *st, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len)1039{1040spx_uint32_t i;1041int istride_save, ostride_save;1042spx_uint32_t bak_out_len = *out_len;1043spx_uint32_t bak_in_len = *in_len;1044istride_save = st->in_stride;1045ostride_save = st->out_stride;1046st->in_stride = st->out_stride = st->nb_channels;1047for (i=0;i<st->nb_channels;i++)1048{1049*out_len = bak_out_len;1050*in_len = bak_in_len;1051if (in != NULL)1052speex_resampler_process_float(st, i, in+i, in_len, out+i, out_len);1053else1054speex_resampler_process_float(st, i, NULL, in_len, out+i, out_len);1055}1056st->in_stride = istride_save;1057st->out_stride = ostride_save;1058return st->resampler_ptr == resampler_basic_zero ? RESAMPLER_ERR_ALLOC_FAILED : RESAMPLER_ERR_SUCCESS;1059}10601061EXPORT 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)1062{1063spx_uint32_t i;1064int istride_save, ostride_save;1065spx_uint32_t bak_out_len = *out_len;1066spx_uint32_t bak_in_len = *in_len;1067istride_save = st->in_stride;1068ostride_save = st->out_stride;1069st->in_stride = st->out_stride = st->nb_channels;1070for (i=0;i<st->nb_channels;i++)1071{1072*out_len = bak_out_len;1073*in_len = bak_in_len;1074if (in != NULL)1075speex_resampler_process_int(st, i, in+i, in_len, out+i, out_len);1076else1077speex_resampler_process_int(st, i, NULL, in_len, out+i, out_len);1078}1079st->in_stride = istride_save;1080st->out_stride = ostride_save;1081return st->resampler_ptr == resampler_basic_zero ? RESAMPLER_ERR_ALLOC_FAILED : RESAMPLER_ERR_SUCCESS;1082}10831084EXPORT int speex_resampler_set_rate(SpeexResamplerState *st, spx_uint32_t in_rate, spx_uint32_t out_rate)1085{1086return speex_resampler_set_rate_frac(st, in_rate, out_rate, in_rate, out_rate);1087}10881089EXPORT void speex_resampler_get_rate(SpeexResamplerState *st, spx_uint32_t *in_rate, spx_uint32_t *out_rate)1090{1091*in_rate = st->in_rate;1092*out_rate = st->out_rate;1093}10941095static inline spx_uint32_t _gcd(spx_uint32_t a, spx_uint32_t b)1096{1097while (b != 0)1098{1099spx_uint32_t temp = a;11001101a = b;1102b = temp % b;1103}1104return a;1105}11061107EXPORT 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)1108{1109spx_uint32_t fact;1110spx_uint32_t old_den;1111spx_uint32_t i;11121113if (ratio_num == 0 || ratio_den == 0)1114return RESAMPLER_ERR_INVALID_ARG;11151116if (st->in_rate == in_rate && st->out_rate == out_rate && st->num_rate == ratio_num && st->den_rate == ratio_den)1117return RESAMPLER_ERR_SUCCESS;11181119old_den = st->den_rate;1120st->in_rate = in_rate;1121st->out_rate = out_rate;1122st->num_rate = ratio_num;1123st->den_rate = ratio_den;11241125fact = _gcd (st->num_rate, st->den_rate);11261127st->num_rate /= fact;1128st->den_rate /= fact;11291130if (old_den > 0)1131{1132for (i=0;i<st->nb_channels;i++)1133{1134if (_muldiv(&st->samp_frac_num[i],st->samp_frac_num[i],st->den_rate,old_den) != RESAMPLER_ERR_SUCCESS)1135return RESAMPLER_ERR_OVERFLOW;1136/* Safety net */1137if (st->samp_frac_num[i] >= st->den_rate)1138st->samp_frac_num[i] = st->den_rate-1;1139}1140}11411142if (st->initialised)1143return update_filter(st);1144return RESAMPLER_ERR_SUCCESS;1145}11461147EXPORT void speex_resampler_get_ratio(SpeexResamplerState *st, spx_uint32_t *ratio_num, spx_uint32_t *ratio_den)1148{1149*ratio_num = st->num_rate;1150*ratio_den = st->den_rate;1151}11521153EXPORT int speex_resampler_set_quality(SpeexResamplerState *st, int quality)1154{1155if (quality > 10 || quality < 0)1156return RESAMPLER_ERR_INVALID_ARG;1157if (st->quality == quality)1158return RESAMPLER_ERR_SUCCESS;1159st->quality = quality;1160if (st->initialised)1161return update_filter(st);1162return RESAMPLER_ERR_SUCCESS;1163}11641165EXPORT void speex_resampler_get_quality(SpeexResamplerState *st, int *quality)1166{1167*quality = st->quality;1168}11691170EXPORT void speex_resampler_set_input_stride(SpeexResamplerState *st, spx_uint32_t stride)1171{1172st->in_stride = stride;1173}11741175EXPORT void speex_resampler_get_input_stride(SpeexResamplerState *st, spx_uint32_t *stride)1176{1177*stride = st->in_stride;1178}11791180EXPORT void speex_resampler_set_output_stride(SpeexResamplerState *st, spx_uint32_t stride)1181{1182st->out_stride = stride;1183}11841185EXPORT void speex_resampler_get_output_stride(SpeexResamplerState *st, spx_uint32_t *stride)1186{1187*stride = st->out_stride;1188}11891190EXPORT int speex_resampler_get_input_latency(SpeexResamplerState *st)1191{1192return st->filt_len / 2;1193}11941195EXPORT int speex_resampler_get_output_latency(SpeexResamplerState *st)1196{1197return ((st->filt_len / 2) * st->den_rate + (st->num_rate >> 1)) / st->num_rate;1198}11991200EXPORT int speex_resampler_skip_zeros(SpeexResamplerState *st)1201{1202spx_uint32_t i;1203for (i=0;i<st->nb_channels;i++)1204st->last_sample[i] = st->filt_len/2;1205return RESAMPLER_ERR_SUCCESS;1206}12071208EXPORT int speex_resampler_reset_mem(SpeexResamplerState *st)1209{1210spx_uint32_t i;1211for (i=0;i<st->nb_channels;i++)1212{1213st->last_sample[i] = 0;1214st->magic_samples[i] = 0;1215st->samp_frac_num[i] = 0;1216}1217for (i=0;i<st->nb_channels*(st->filt_len-1);i++)1218st->mem[i] = 0;1219return RESAMPLER_ERR_SUCCESS;1220}12211222EXPORT const char *speex_resampler_strerror(int err)1223{1224switch (err)1225{1226case RESAMPLER_ERR_SUCCESS:1227return "Success.";1228case RESAMPLER_ERR_ALLOC_FAILED:1229return "Memory allocation failed.";1230case RESAMPLER_ERR_BAD_STATE:1231return "Bad resampler state.";1232case RESAMPLER_ERR_INVALID_ARG:1233return "Invalid argument.";1234case RESAMPLER_ERR_PTR_OVERLAP:1235return "Input and output buffers overlap.";1236default:1237return "Unknown error. Bad error code or strange version mismatch.";1238}1239}124012411242