update speex resampler

This commit is contained in:
Lennart Poettering 2008-06-27 22:26:00 +02:00
parent 2490f698c0
commit 32fce4debb
7 changed files with 464 additions and 327 deletions

View file

@ -411,6 +411,8 @@ AC_CHECK_FUNCS([lstat])
AC_CHECK_FUNCS([setresuid setresgid setreuid setregid seteuid setegid ppoll strsignal sig2str strtof_l]) AC_CHECK_FUNCS([setresuid setresgid setreuid setregid seteuid setegid ppoll strsignal sig2str strtof_l])
AC_FUNC_ALLOCA
AC_MSG_CHECKING([for PTHREAD_PRIO_INHERIT]) AC_MSG_CHECKING([for PTHREAD_PRIO_INHERIT])
AC_LANG_CONFTEST([AC_LANG_SOURCE([[ AC_LANG_CONFTEST([AC_LANG_SOURCE([[
#include <pthread.h> #include <pthread.h>

View file

@ -648,10 +648,10 @@ libpulsedsp_la_LDFLAGS = -avoid-version
noinst_LTLIBRARIES = libspeex-resampler-fixed.la libspeex-resampler-float.la libffmpeg-resampler.la noinst_LTLIBRARIES = libspeex-resampler-fixed.la libspeex-resampler-float.la libffmpeg-resampler.la
libspeex_resampler_fixed_la_CPPFLAGS = $(AM_CPPFLAGS) -DRANDOM_PREFIX=paspfx -DOUTSIDE_SPEEX -DFIXED_POINT libspeex_resampler_fixed_la_CPPFLAGS = $(AM_CPPFLAGS) -DRANDOM_PREFIX=paspfx -DOUTSIDE_SPEEX -DFIXED_POINT -DEXPORT= -DUSE_ALLOCA
libspeex_resampler_fixed_la_SOURCES = pulsecore/speex/resample.c pulsecore/speex/speex_resampler.h pulsecore/speex/arch.h pulsecore/speex/fixed_generic.h pulsecore/speexwrap.h libspeex_resampler_fixed_la_SOURCES = pulsecore/speex/resample.c pulsecore/speex/speex_resampler.h pulsecore/speex/arch.h pulsecore/speex/fixed_generic.h pulsecore/speexwrap.h
libspeex_resampler_float_la_CPPFLAGS = $(AM_CPPFLAGS) -DRANDOM_PREFIX=paspfl -DOUTSIDE_SPEEX -DFLOATING_POINT libspeex_resampler_float_la_CPPFLAGS = $(AM_CPPFLAGS) -DRANDOM_PREFIX=paspfl -DOUTSIDE_SPEEX -DFLOATING_POINT -DEXPORT= -DUSE_ALLOCA
libspeex_resampler_float_la_SOURCES = pulsecore/speex/resample.c pulsecore/speex/speex_resampler.h pulsecore/speex/arch.h libspeex_resampler_float_la_SOURCES = pulsecore/speex/resample.c pulsecore/speex/speex_resampler.h pulsecore/speex/arch.h
libffmpeg_resampler_la_CPPFLAGS = $(AM_CPPFLAGS) libffmpeg_resampler_la_CPPFLAGS = $(AM_CPPFLAGS)

View file

@ -125,8 +125,6 @@ typedef spx_word32_t spx_sig_t;
#include "fixed_arm5e.h" #include "fixed_arm5e.h"
#elif defined (ARM4_ASM) #elif defined (ARM4_ASM)
#include "fixed_arm4.h" #include "fixed_arm4.h"
#elif defined (ARM5E_ASM)
#include "fixed_arm5e.h"
#elif defined (BFIN_ASM) #elif defined (BFIN_ASM)
#include "fixed_bfin.h" #include "fixed_bfin.h"
#endif #endif
@ -234,7 +232,7 @@ typedef float spx_word32_t;
#ifdef FIXED_DEBUG #ifdef FIXED_DEBUG
long long spx_mips=0; extern long long spx_mips;
#endif #endif

View file

@ -47,14 +47,14 @@
#define SHR32(a,shift) ((a) >> (shift)) #define SHR32(a,shift) ((a) >> (shift))
#define SHL32(a,shift) ((a) << (shift)) #define SHL32(a,shift) ((a) << (shift))
#define PSHR16(a,shift) (SHR16((a)+((1<<((shift))>>1)),shift)) #define PSHR16(a,shift) (SHR16((a)+((1<<((shift))>>1)),shift))
#define PSHR32(a,shift) (SHR32((a)+((1<<((shift))>>1)),shift)) #define PSHR32(a,shift) (SHR32((a)+((EXTEND32(1)<<((shift))>>1)),shift))
#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift))) #define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift)))
#define SATURATE16(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) #define SATURATE16(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
#define SATURATE32(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) #define SATURATE32(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
#define SHR(a,shift) ((a) >> (shift)) #define SHR(a,shift) ((a) >> (shift))
#define SHL(a,shift) ((spx_word32_t)(a) << (shift)) #define SHL(a,shift) ((spx_word32_t)(a) << (shift))
#define PSHR(a,shift) (SHR((a)+((1<<((shift))>>1)),shift)) #define PSHR(a,shift) (SHR((a)+((EXTEND32(1)<<((shift))>>1)),shift))
#define SATURATE(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) #define SATURATE(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))

View file

@ -1,4 +1,5 @@
/* Copyright (C) 2007 Jean-Marc Valin /* Copyright (C) 2007-2008 Jean-Marc Valin
Copyright (C) 2008 Thorvald Natvig
File: resample.c File: resample.c
Arbitrary resampling code Arbitrary resampling code
@ -74,6 +75,7 @@ static void speex_free (void *ptr) {free(ptr);}
#include "os_support.h" #include "os_support.h"
#endif /* OUTSIDE_SPEEX */ #endif /* OUTSIDE_SPEEX */
#include "stack_alloc.h"
#include <math.h> #include <math.h>
#ifndef M_PI #ifndef M_PI
@ -86,10 +88,6 @@ static void speex_free (void *ptr) {free(ptr);}
#define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x)))) #define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x))))
#endif #endif
/*#define float double*/
#define FILTER_SIZE 64
#define OVERSAMPLE 8
#define IMAX(a,b) ((a) > (b) ? (a) : (b)) #define IMAX(a,b) ((a) > (b) ? (a) : (b))
#define IMIN(a,b) ((a) < (b) ? (a) : (b)) #define IMIN(a,b) ((a) < (b) ? (a) : (b))
@ -97,6 +95,17 @@ static void speex_free (void *ptr) {free(ptr);}
#define NULL 0 #define NULL 0
#endif #endif
#ifdef _USE_SSE
#include "resample_sse.h"
#endif
/* Numer of elements to allocate on the stack */
#ifdef VAR_ARRAYS
#define FIXED_STACK_ALLOC 8192
#else
#define FIXED_STACK_ALLOC 1024
#endif
typedef int (*resampler_basic_func)(SpeexResamplerState *, spx_uint32_t , const spx_word16_t *, spx_uint32_t *, spx_word16_t *, spx_uint32_t *); typedef int (*resampler_basic_func)(SpeexResamplerState *, spx_uint32_t , const spx_word16_t *, spx_uint32_t *, spx_word16_t *, spx_uint32_t *);
struct SpeexResamplerState_ { struct SpeexResamplerState_ {
@ -109,6 +118,7 @@ struct SpeexResamplerState_ {
spx_uint32_t nb_channels; spx_uint32_t nb_channels;
spx_uint32_t filt_len; spx_uint32_t filt_len;
spx_uint32_t mem_alloc_size; spx_uint32_t mem_alloc_size;
spx_uint32_t buffer_size;
int int_advance; int int_advance;
int frac_advance; int frac_advance;
float cutoff; float cutoff;
@ -317,44 +327,47 @@ static void cubic_coef(spx_word16_t frac, spx_word16_t interp[4])
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) 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)
{ {
int N = st->filt_len; const int N = st->filt_len;
int out_sample = 0; int out_sample = 0;
spx_word16_t *mem;
int last_sample = st->last_sample[channel_index]; int last_sample = st->last_sample[channel_index];
spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];
mem = st->mem + channel_index * st->mem_alloc_size; const spx_word16_t *sinc_table = st->sinc_table;
const int out_stride = st->out_stride;
const int int_advance = st->int_advance;
const int frac_advance = st->frac_advance;
const spx_uint32_t den_rate = st->den_rate;
spx_word32_t sum;
int j;
while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))
{ {
int j; const spx_word16_t *sinc = & sinc_table[samp_frac_num*N];
spx_word32_t sum=0; const spx_word16_t *iptr = & in[last_sample];
/* We already have all the filter coefficients pre-computed in the table */ #ifndef OVERRIDE_INNER_PRODUCT_SINGLE
const spx_word16_t *ptr; float accum[4] = {0,0,0,0};
/* Do the memory part */
for (j=0;last_sample-N+1+j < 0;j++) for(j=0;j<N;j+=4) {
{ accum[0] += sinc[j]*iptr[j];
sum += MULT16_16(mem[last_sample+j],st->sinc_table[samp_frac_num*st->filt_len+j]); accum[1] += sinc[j+1]*iptr[j+1];
accum[2] += sinc[j+2]*iptr[j+2];
accum[3] += sinc[j+3]*iptr[j+3];
} }
sum = accum[0] + accum[1] + accum[2] + accum[3];
#else
sum = inner_product_single(sinc, iptr, N);
#endif
/* Do the new part */ out[out_stride * out_sample++] = PSHR32(sum, 15);
ptr = in+st->in_stride*(last_sample-N+1+j); last_sample += int_advance;
for (;j<N;j++) samp_frac_num += frac_advance;
if (samp_frac_num >= den_rate)
{ {
sum += MULT16_16(*ptr,st->sinc_table[samp_frac_num*st->filt_len+j]); samp_frac_num -= den_rate;
ptr += st->in_stride;
}
*out = PSHR32(sum,15);
out += st->out_stride;
out_sample++;
last_sample += st->int_advance;
samp_frac_num += st->frac_advance;
if (samp_frac_num >= st->den_rate)
{
samp_frac_num -= st->den_rate;
last_sample++; last_sample++;
} }
} }
st->last_sample[channel_index] = last_sample; st->last_sample[channel_index] = last_sample;
st->samp_frac_num[channel_index] = samp_frac_num; st->samp_frac_num[channel_index] = samp_frac_num;
return out_sample; return out_sample;
@ -365,44 +378,47 @@ static int resampler_basic_direct_single(SpeexResamplerState *st, spx_uint32_t c
/* This is the same as the previous function, except with a double-precision accumulator */ /* This is the same as the previous function, except with a double-precision accumulator */
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) 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)
{ {
int N = st->filt_len; const int N = st->filt_len;
int out_sample = 0; int out_sample = 0;
spx_word16_t *mem;
int last_sample = st->last_sample[channel_index]; int last_sample = st->last_sample[channel_index];
spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];
mem = st->mem + channel_index * st->mem_alloc_size; const spx_word16_t *sinc_table = st->sinc_table;
const int out_stride = st->out_stride;
const int int_advance = st->int_advance;
const int frac_advance = st->frac_advance;
const spx_uint32_t den_rate = st->den_rate;
double sum;
int j;
while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))
{ {
int j; const spx_word16_t *sinc = & sinc_table[samp_frac_num*N];
double sum=0; const spx_word16_t *iptr = & in[last_sample];
/* We already have all the filter coefficients pre-computed in the table */ #ifndef OVERRIDE_INNER_PRODUCT_DOUBLE
const spx_word16_t *ptr; double accum[4] = {0,0,0,0};
/* Do the memory part */
for (j=0;last_sample-N+1+j < 0;j++) for(j=0;j<N;j+=4) {
{ accum[0] += sinc[j]*iptr[j];
sum += MULT16_16(mem[last_sample+j],(double)st->sinc_table[samp_frac_num*st->filt_len+j]); accum[1] += sinc[j+1]*iptr[j+1];
accum[2] += sinc[j+2]*iptr[j+2];
accum[3] += sinc[j+3]*iptr[j+3];
} }
sum = accum[0] + accum[1] + accum[2] + accum[3];
#else
sum = inner_product_double(sinc, iptr, N);
#endif
/* Do the new part */ out[out_stride * out_sample++] = PSHR32(sum, 15);
ptr = in+st->in_stride*(last_sample-N+1+j); last_sample += int_advance;
for (;j<N;j++) samp_frac_num += frac_advance;
if (samp_frac_num >= den_rate)
{ {
sum += MULT16_16(*ptr,(double)st->sinc_table[samp_frac_num*st->filt_len+j]); samp_frac_num -= den_rate;
ptr += st->in_stride;
}
*out = sum;
out += st->out_stride;
out_sample++;
last_sample += st->int_advance;
samp_frac_num += st->frac_advance;
if (samp_frac_num >= st->den_rate)
{
samp_frac_num -= st->den_rate;
last_sample++; last_sample++;
} }
} }
st->last_sample[channel_index] = last_sample; st->last_sample[channel_index] = last_sample;
st->samp_frac_num[channel_index] = samp_frac_num; st->samp_frac_num[channel_index] = samp_frac_num;
return out_sample; return out_sample;
@ -411,65 +427,58 @@ static int resampler_basic_direct_double(SpeexResamplerState *st, spx_uint32_t c
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) 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)
{ {
int N = st->filt_len; const int N = st->filt_len;
int out_sample = 0; int out_sample = 0;
spx_word16_t *mem;
int last_sample = st->last_sample[channel_index]; int last_sample = st->last_sample[channel_index];
spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];
mem = st->mem + channel_index * st->mem_alloc_size; const int out_stride = st->out_stride;
const int int_advance = st->int_advance;
const int frac_advance = st->frac_advance;
const spx_uint32_t den_rate = st->den_rate;
int j;
spx_word32_t sum;
while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))
{ {
int j; const spx_word16_t *iptr = & in[last_sample];
spx_word32_t sum=0;
/* We need to interpolate the sinc filter */ const int offset = samp_frac_num*st->oversample/st->den_rate;
spx_word32_t accum[4] = {0.f,0.f, 0.f, 0.f};
spx_word16_t interp[4];
const spx_word16_t *ptr;
int offset;
spx_word16_t frac;
offset = samp_frac_num*st->oversample/st->den_rate;
#ifdef FIXED_POINT #ifdef FIXED_POINT
frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate); const spx_word16_t frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate);
#else #else
frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate; const spx_word16_t frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate;
#endif #endif
/* This code is written like this to make it easy to optimise with SIMD. spx_word16_t interp[4];
For most DSPs, it would be best to split the loops in two because most DSPs
have only two accumulators */
for (j=0;last_sample-N+1+j < 0;j++) #ifndef OVERRIDE_INTERPOLATE_PRODUCT_SINGLE
{ spx_word32_t accum[4] = {0,0,0,0};
spx_word16_t curr_mem = mem[last_sample+j];
accum[0] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-2]); for(j=0;j<N;j++) {
accum[1] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-1]); const spx_word16_t curr_in=iptr[j];
accum[2] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset]); accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]);
accum[3] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset+1]); accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]);
} accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]);
ptr = in+st->in_stride*(last_sample-N+1+j); accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]);
/* Do the new part */
for (;j<N;j++)
{
spx_word16_t curr_in = *ptr;
ptr += st->in_stride;
accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]);
accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]);
accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]);
accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]);
} }
cubic_coef(frac, interp); cubic_coef(frac, interp);
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]); 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]);
#else
cubic_coef(frac, interp);
sum = interpolate_product_single(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp);
#endif
*out = PSHR32(sum,15); out[out_stride * out_sample++] = PSHR32(sum,15);
out += st->out_stride; last_sample += int_advance;
out_sample++; samp_frac_num += frac_advance;
last_sample += st->int_advance; if (samp_frac_num >= den_rate)
samp_frac_num += st->frac_advance;
if (samp_frac_num >= st->den_rate)
{ {
samp_frac_num -= st->den_rate; samp_frac_num -= den_rate;
last_sample++; last_sample++;
} }
} }
st->last_sample[channel_index] = last_sample; st->last_sample[channel_index] = last_sample;
st->samp_frac_num[channel_index] = samp_frac_num; st->samp_frac_num[channel_index] = samp_frac_num;
return out_sample; return out_sample;
@ -480,60 +489,58 @@ static int resampler_basic_interpolate_single(SpeexResamplerState *st, spx_uint3
/* This is the same as the previous function, except with a double-precision accumulator */ /* This is the same as the previous function, except with a double-precision accumulator */
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) 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)
{ {
int N = st->filt_len; const int N = st->filt_len;
int out_sample = 0; int out_sample = 0;
spx_word16_t *mem;
int last_sample = st->last_sample[channel_index]; int last_sample = st->last_sample[channel_index];
spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];
mem = st->mem + channel_index * st->mem_alloc_size; const int out_stride = st->out_stride;
const int int_advance = st->int_advance;
const int frac_advance = st->frac_advance;
const spx_uint32_t den_rate = st->den_rate;
int j;
spx_word32_t sum;
while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))
{ {
int j; const spx_word16_t *iptr = & in[last_sample];
spx_word32_t sum=0;
/* We need to interpolate the sinc filter */ const int offset = samp_frac_num*st->oversample/st->den_rate;
double accum[4] = {0.f,0.f, 0.f, 0.f}; #ifdef FIXED_POINT
float interp[4]; const spx_word16_t frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate);
const spx_word16_t *ptr; #else
float alpha = ((float)samp_frac_num)/st->den_rate; const spx_word16_t frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate;
int offset = samp_frac_num*st->oversample/st->den_rate; #endif
float frac = alpha*st->oversample - offset; spx_word16_t interp[4];
/* This code is written like this to make it easy to optimise with SIMD.
For most DSPs, it would be best to split the loops in two because most DSPs
have only two accumulators */ #ifndef OVERRIDE_INTERPOLATE_PRODUCT_DOUBLE
for (j=0;last_sample-N+1+j < 0;j++) double accum[4] = {0,0,0,0};
{
double curr_mem = mem[last_sample+j]; for(j=0;j<N;j++) {
accum[0] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-2]); const double curr_in=iptr[j];
accum[1] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-1]); accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]);
accum[2] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset]); accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]);
accum[3] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset+1]); accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]);
} accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]);
ptr = in+st->in_stride*(last_sample-N+1+j);
/* Do the new part */
for (;j<N;j++)
{
double curr_in = *ptr;
ptr += st->in_stride;
accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]);
accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]);
accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]);
accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]);
} }
cubic_coef(frac, interp); cubic_coef(frac, interp);
sum = interp[0]*accum[0] + interp[1]*accum[1] + interp[2]*accum[2] + interp[3]*accum[3]; 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]);
#else
cubic_coef(frac, interp);
sum = interpolate_product_double(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp);
#endif
*out = PSHR32(sum,15); out[out_stride * out_sample++] = PSHR32(sum,15);
out += st->out_stride; last_sample += int_advance;
out_sample++; samp_frac_num += frac_advance;
last_sample += st->int_advance; if (samp_frac_num >= den_rate)
samp_frac_num += st->frac_advance;
if (samp_frac_num >= st->den_rate)
{ {
samp_frac_num -= st->den_rate; samp_frac_num -= den_rate;
last_sample++; last_sample++;
} }
} }
st->last_sample[channel_index] = last_sample; st->last_sample[channel_index] = last_sample;
st->samp_frac_num[channel_index] = samp_frac_num; st->samp_frac_num[channel_index] = samp_frac_num;
return out_sample; return out_sample;
@ -630,18 +637,18 @@ static void update_filter(SpeexResamplerState *st)
if (!st->mem) if (!st->mem)
{ {
spx_uint32_t i; spx_uint32_t i;
st->mem = (spx_word16_t*)speex_alloc(st->nb_channels*(st->filt_len-1) * sizeof(spx_word16_t)); st->mem_alloc_size = st->filt_len-1 + st->buffer_size;
for (i=0;i<st->nb_channels*(st->filt_len-1);i++) st->mem = (spx_word16_t*)speex_alloc(st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t));
for (i=0;i<st->nb_channels*st->mem_alloc_size;i++)
st->mem[i] = 0; st->mem[i] = 0;
st->mem_alloc_size = st->filt_len-1;
/*speex_warning("init filter");*/ /*speex_warning("init filter");*/
} else if (!st->started) } else if (!st->started)
{ {
spx_uint32_t i; spx_uint32_t i;
st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*(st->filt_len-1) * sizeof(spx_word16_t)); st->mem_alloc_size = st->filt_len-1 + st->buffer_size;
for (i=0;i<st->nb_channels*(st->filt_len-1);i++) st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t));
for (i=0;i<st->nb_channels*st->mem_alloc_size;i++)
st->mem[i] = 0; st->mem[i] = 0;
st->mem_alloc_size = st->filt_len-1;
/*speex_warning("reinit filter");*/ /*speex_warning("reinit filter");*/
} else if (st->filt_len > old_length) } else if (st->filt_len > old_length)
{ {
@ -649,10 +656,10 @@ static void update_filter(SpeexResamplerState *st)
/* Increase the filter length */ /* Increase the filter length */
/*speex_warning("increase filter size");*/ /*speex_warning("increase filter size");*/
int old_alloc_size = st->mem_alloc_size; int old_alloc_size = st->mem_alloc_size;
if (st->filt_len-1 > st->mem_alloc_size) if ((st->filt_len-1 + st->buffer_size) > st->mem_alloc_size)
{ {
st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*(st->filt_len-1) * sizeof(spx_word16_t)); st->mem_alloc_size = st->filt_len-1 + st->buffer_size;
st->mem_alloc_size = st->filt_len-1; st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t));
} }
for (i=st->nb_channels-1;i>=0;i--) for (i=st->nb_channels-1;i>=0;i--)
{ {
@ -708,12 +715,12 @@ static void update_filter(SpeexResamplerState *st)
} }
SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err) EXPORT SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err)
{ {
return speex_resampler_init_frac(nb_channels, in_rate, out_rate, in_rate, out_rate, quality, err); return speex_resampler_init_frac(nb_channels, in_rate, out_rate, in_rate, out_rate, quality, err);
} }
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) 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)
{ {
spx_uint32_t i; spx_uint32_t i;
SpeexResamplerState *st; SpeexResamplerState *st;
@ -742,6 +749,12 @@ SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, spx_uin
st->in_stride = 1; st->in_stride = 1;
st->out_stride = 1; st->out_stride = 1;
#ifdef FIXED_POINT
st->buffer_size = 160;
#else
st->buffer_size = 160;
#endif
/* Per channel data */ /* Per channel data */
st->last_sample = (spx_int32_t*)speex_alloc(nb_channels*sizeof(int)); st->last_sample = (spx_int32_t*)speex_alloc(nb_channels*sizeof(int));
st->magic_samples = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int)); st->magic_samples = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int));
@ -766,7 +779,7 @@ SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, spx_uin
return st; return st;
} }
void speex_resampler_destroy(SpeexResamplerState *st) EXPORT void speex_resampler_destroy(SpeexResamplerState *st)
{ {
speex_free(st->mem); speex_free(st->mem);
speex_free(st->sinc_table); speex_free(st->sinc_table);
@ -776,186 +789,168 @@ void speex_resampler_destroy(SpeexResamplerState *st)
speex_free(st); speex_free(st);
} }
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)
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)
{ {
int j=0; int j=0;
int N = st->filt_len; const int N = st->filt_len;
int out_sample = 0; int out_sample = 0;
spx_word16_t *mem; spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size;
spx_uint32_t tmp_out_len = 0; spx_uint32_t ilen;
mem = st->mem + channel_index * st->mem_alloc_size;
st->started = 1; st->started = 1;
/* Handle the case where we have samples left from a reduction in filter length */
if (st->magic_samples[channel_index])
{
int istride_save;
spx_uint32_t tmp_in_len;
spx_uint32_t tmp_magic;
istride_save = st->in_stride;
tmp_in_len = st->magic_samples[channel_index];
tmp_out_len = *out_len;
/* magic_samples needs to be set to zero to avoid infinite recursion */
tmp_magic = st->magic_samples[channel_index];
st->magic_samples[channel_index] = 0;
st->in_stride = 1;
speex_resampler_process_native(st, channel_index, mem+N-1, &tmp_in_len, out, &tmp_out_len);
st->in_stride = istride_save;
/*speex_warning_int("extra samples:", tmp_out_len);*/
/* If we couldn't process all "magic" input samples, save the rest for next time */
if (tmp_in_len < tmp_magic)
{
spx_uint32_t i;
st->magic_samples[channel_index] = tmp_magic-tmp_in_len;
for (i=0;i<st->magic_samples[channel_index];i++)
mem[N-1+i]=mem[N-1+i+tmp_in_len];
}
out += tmp_out_len*st->out_stride;
*out_len -= tmp_out_len;
}
/* Call the right resampler through the function ptr */ /* Call the right resampler through the function ptr */
out_sample = st->resampler_ptr(st, channel_index, in, in_len, out, out_len); out_sample = st->resampler_ptr(st, channel_index, mem, in_len, out, out_len);
if (st->last_sample[channel_index] < (spx_int32_t)*in_len) if (st->last_sample[channel_index] < (spx_int32_t)*in_len)
*in_len = st->last_sample[channel_index]; *in_len = st->last_sample[channel_index];
*out_len = out_sample+tmp_out_len; *out_len = out_sample;
st->last_sample[channel_index] -= *in_len; st->last_sample[channel_index] -= *in_len;
for (j=0;j<N-1-(spx_int32_t)*in_len;j++) ilen = *in_len;
mem[j] = mem[j+*in_len];
for (;j<N-1;j++) for(j=0;j<N-1;++j)
mem[j] = in[st->in_stride*(j+*in_len-N+1)]; mem[j] = mem[j+ilen];
return RESAMPLER_ERR_SUCCESS; return RESAMPLER_ERR_SUCCESS;
} }
#define FIXED_STACK_ALLOC 1024 static int speex_resampler_magic(SpeexResamplerState *st, spx_uint32_t channel_index, spx_word16_t **out, spx_uint32_t out_len) {
spx_uint32_t tmp_in_len = st->magic_samples[channel_index];
spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size;
const int N = st->filt_len;
speex_resampler_process_native(st, channel_index, &tmp_in_len, *out, &out_len);
st->magic_samples[channel_index] -= tmp_in_len;
/* If we couldn't process all "magic" input samples, save the rest for next time */
if (st->magic_samples[channel_index])
{
spx_uint32_t i;
for (i=0;i<st->magic_samples[channel_index];i++)
mem[N-1+i]=mem[N-1+i+tmp_in_len];
}
*out += out_len*st->out_stride;
return out_len;
}
#ifdef FIXED_POINT #ifdef FIXED_POINT
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) 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)
{
spx_uint32_t i;
int istride_save, ostride_save;
#ifdef VAR_ARRAYS
spx_word16_t x[*in_len];
spx_word16_t y[*out_len];
/*VARDECL(spx_word16_t *x);
VARDECL(spx_word16_t *y);
ALLOC(x, *in_len, spx_word16_t);
ALLOC(y, *out_len, spx_word16_t);*/
istride_save = st->in_stride;
ostride_save = st->out_stride;
for (i=0;i<*in_len;i++)
x[i] = WORD2INT(in[i*st->in_stride]);
st->in_stride = st->out_stride = 1;
speex_resampler_process_native(st, channel_index, x, in_len, y, out_len);
st->in_stride = istride_save;
st->out_stride = ostride_save;
for (i=0;i<*out_len;i++)
out[i*st->out_stride] = y[i];
#else #else
spx_word16_t x[FIXED_STACK_ALLOC]; 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)
spx_word16_t y[FIXED_STACK_ALLOC]; #endif
spx_uint32_t ilen=*in_len, olen=*out_len; {
istride_save = st->in_stride; int j;
ostride_save = st->out_stride; spx_uint32_t ilen = *in_len;
while (ilen && olen) spx_uint32_t olen = *out_len;
{ spx_word16_t *x = st->mem + channel_index * st->mem_alloc_size;
spx_uint32_t ichunk, ochunk; const int filt_offs = st->filt_len - 1;
ichunk = ilen; const spx_uint32_t xlen = st->mem_alloc_size - filt_offs;
ochunk = olen; const int istride = st->in_stride;
if (ichunk>FIXED_STACK_ALLOC)
ichunk=FIXED_STACK_ALLOC; if (st->magic_samples[channel_index])
if (ochunk>FIXED_STACK_ALLOC) olen -= speex_resampler_magic(st, channel_index, &out, olen);
ochunk=FIXED_STACK_ALLOC; if (! st->magic_samples[channel_index]) {
for (i=0;i<ichunk;i++) while (ilen && olen) {
x[i] = WORD2INT(in[i*st->in_stride]); spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen;
st->in_stride = st->out_stride = 1; spx_uint32_t ochunk = olen;
speex_resampler_process_native(st, channel_index, x, &ichunk, y, &ochunk);
st->in_stride = istride_save; if (in) {
st->out_stride = ostride_save; for(j=0;j<ichunk;++j)
for (i=0;i<ochunk;i++) x[j+filt_offs]=in[j*istride];
out[i*st->out_stride] = y[i]; } else {
out += ochunk; for(j=0;j<ichunk;++j)
in += ichunk; x[j+filt_offs]=0;
ilen -= ichunk; }
olen -= ochunk; speex_resampler_process_native(st, channel_index, &ichunk, out, &ochunk);
ilen -= ichunk;
olen -= ochunk;
out += ochunk * st->out_stride;
if (in)
in += ichunk * istride;
}
} }
*in_len -= ilen; *in_len -= ilen;
*out_len -= olen; *out_len -= olen;
#endif
return RESAMPLER_ERR_SUCCESS; return RESAMPLER_ERR_SUCCESS;
} }
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)
{ #ifdef FIXED_POINT
return speex_resampler_process_native(st, channel_index, in, in_len, out, out_len); 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)
}
#else #else
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) 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)
#endif
{ {
return speex_resampler_process_native(st, channel_index, in, in_len, out, out_len); int j;
} const int istride_save = st->in_stride;
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) const int ostride_save = st->out_stride;
{ spx_uint32_t ilen = *in_len;
spx_uint32_t i; spx_uint32_t olen = *out_len;
int istride_save, ostride_save; spx_word16_t *x = st->mem + channel_index * st->mem_alloc_size;
const spx_uint32_t xlen = st->mem_alloc_size - (st->filt_len - 1);
#ifdef VAR_ARRAYS #ifdef VAR_ARRAYS
spx_word16_t x[*in_len]; const unsigned int ylen = (olen < FIXED_STACK_ALLOC) ? olen : FIXED_STACK_ALLOC;
spx_word16_t y[*out_len]; VARDECL(spx_word16_t *ystack);
/*VARDECL(spx_word16_t *x); ALLOC(ystack, ylen, spx_word16_t);
VARDECL(spx_word16_t *y);
ALLOC(x, *in_len, spx_word16_t);
ALLOC(y, *out_len, spx_word16_t);*/
istride_save = st->in_stride;
ostride_save = st->out_stride;
for (i=0;i<*in_len;i++)
x[i] = in[i*st->in_stride];
st->in_stride = st->out_stride = 1;
speex_resampler_process_native(st, channel_index, x, in_len, y, out_len);
st->in_stride = istride_save;
st->out_stride = ostride_save;
for (i=0;i<*out_len;i++)
out[i*st->out_stride] = WORD2INT(y[i]);
#else #else
spx_word16_t x[FIXED_STACK_ALLOC]; const unsigned int ylen = FIXED_STACK_ALLOC;
spx_word16_t y[FIXED_STACK_ALLOC]; spx_word16_t ystack[FIXED_STACK_ALLOC];
spx_uint32_t ilen=*in_len, olen=*out_len;
istride_save = st->in_stride;
ostride_save = st->out_stride;
while (ilen && olen)
{
spx_uint32_t ichunk, ochunk;
ichunk = ilen;
ochunk = olen;
if (ichunk>FIXED_STACK_ALLOC)
ichunk=FIXED_STACK_ALLOC;
if (ochunk>FIXED_STACK_ALLOC)
ochunk=FIXED_STACK_ALLOC;
for (i=0;i<ichunk;i++)
x[i] = in[i*st->in_stride];
st->in_stride = st->out_stride = 1;
speex_resampler_process_native(st, channel_index, x, &ichunk, y, &ochunk);
st->in_stride = istride_save;
st->out_stride = ostride_save;
for (i=0;i<ochunk;i++)
out[i*st->out_stride] = WORD2INT(y[i]);
out += ochunk;
in += ichunk;
ilen -= ichunk;
olen -= ochunk;
}
*in_len -= ilen;
*out_len -= olen;
#endif
return RESAMPLER_ERR_SUCCESS;
}
#endif #endif
int speex_resampler_process_interleaved_float(SpeexResamplerState *st, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) st->out_stride = 1;
while (ilen && olen) {
spx_word16_t *y = ystack;
spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen;
spx_uint32_t ochunk = (olen > ylen) ? ylen : olen;
spx_uint32_t omagic = 0;
if (st->magic_samples[channel_index]) {
omagic = speex_resampler_magic(st, channel_index, &y, ochunk);
ochunk -= omagic;
olen -= omagic;
}
if (! st->magic_samples[channel_index]) {
if (in) {
for(j=0;j<ichunk;++j)
#ifdef FIXED_POINT
x[j+st->filt_len-1]=WORD2INT(in[j*istride_save]);
#else
x[j+st->filt_len-1]=in[j*istride_save];
#endif
} else {
for(j=0;j<ichunk;++j)
x[j+st->filt_len-1]=0;
}
speex_resampler_process_native(st, channel_index, &ichunk, y, &ochunk);
} else {
ichunk = 0;
ochunk = 0;
}
for (j=0;j<ochunk+omagic;++j)
#ifdef FIXED_POINT
out[j*ostride_save] = ystack[j];
#else
out[j*ostride_save] = WORD2INT(ystack[j]);
#endif
ilen -= ichunk;
olen -= ochunk;
out += (ochunk+omagic) * ostride_save;
if (in)
in += ichunk * istride_save;
}
st->out_stride = ostride_save;
*in_len -= ilen;
*out_len -= olen;
return RESAMPLER_ERR_SUCCESS;
}
EXPORT int speex_resampler_process_interleaved_float(SpeexResamplerState *st, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len)
{ {
spx_uint32_t i; spx_uint32_t i;
int istride_save, ostride_save; int istride_save, ostride_save;
@ -966,15 +961,17 @@ int speex_resampler_process_interleaved_float(SpeexResamplerState *st, const flo
for (i=0;i<st->nb_channels;i++) for (i=0;i<st->nb_channels;i++)
{ {
*out_len = bak_len; *out_len = bak_len;
speex_resampler_process_float(st, i, in+i, in_len, out+i, out_len); if (in != NULL)
speex_resampler_process_float(st, i, in+i, in_len, out+i, out_len);
else
speex_resampler_process_float(st, i, NULL, in_len, out+i, out_len);
} }
st->in_stride = istride_save; st->in_stride = istride_save;
st->out_stride = ostride_save; st->out_stride = ostride_save;
return RESAMPLER_ERR_SUCCESS; return RESAMPLER_ERR_SUCCESS;
} }
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)
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)
{ {
spx_uint32_t i; spx_uint32_t i;
int istride_save, ostride_save; int istride_save, ostride_save;
@ -985,25 +982,28 @@ int speex_resampler_process_interleaved_int(SpeexResamplerState *st, const spx_i
for (i=0;i<st->nb_channels;i++) for (i=0;i<st->nb_channels;i++)
{ {
*out_len = bak_len; *out_len = bak_len;
speex_resampler_process_int(st, i, in+i, in_len, out+i, out_len); if (in != NULL)
speex_resampler_process_int(st, i, in+i, in_len, out+i, out_len);
else
speex_resampler_process_int(st, i, NULL, in_len, out+i, out_len);
} }
st->in_stride = istride_save; st->in_stride = istride_save;
st->out_stride = ostride_save; st->out_stride = ostride_save;
return RESAMPLER_ERR_SUCCESS; return RESAMPLER_ERR_SUCCESS;
} }
int speex_resampler_set_rate(SpeexResamplerState *st, spx_uint32_t in_rate, spx_uint32_t out_rate) EXPORT int speex_resampler_set_rate(SpeexResamplerState *st, spx_uint32_t in_rate, spx_uint32_t out_rate)
{ {
return speex_resampler_set_rate_frac(st, in_rate, out_rate, in_rate, out_rate); return speex_resampler_set_rate_frac(st, in_rate, out_rate, in_rate, out_rate);
} }
void speex_resampler_get_rate(SpeexResamplerState *st, spx_uint32_t *in_rate, spx_uint32_t *out_rate) EXPORT void speex_resampler_get_rate(SpeexResamplerState *st, spx_uint32_t *in_rate, spx_uint32_t *out_rate)
{ {
*in_rate = st->in_rate; *in_rate = st->in_rate;
*out_rate = st->out_rate; *out_rate = st->out_rate;
} }
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) 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)
{ {
spx_uint32_t fact; spx_uint32_t fact;
spx_uint32_t old_den; spx_uint32_t old_den;
@ -1042,13 +1042,13 @@ int speex_resampler_set_rate_frac(SpeexResamplerState *st, spx_uint32_t ratio_nu
return RESAMPLER_ERR_SUCCESS; return RESAMPLER_ERR_SUCCESS;
} }
void speex_resampler_get_ratio(SpeexResamplerState *st, spx_uint32_t *ratio_num, spx_uint32_t *ratio_den) EXPORT void speex_resampler_get_ratio(SpeexResamplerState *st, spx_uint32_t *ratio_num, spx_uint32_t *ratio_den)
{ {
*ratio_num = st->num_rate; *ratio_num = st->num_rate;
*ratio_den = st->den_rate; *ratio_den = st->den_rate;
} }
int speex_resampler_set_quality(SpeexResamplerState *st, int quality) EXPORT int speex_resampler_set_quality(SpeexResamplerState *st, int quality)
{ {
if (quality > 10 || quality < 0) if (quality > 10 || quality < 0)
return RESAMPLER_ERR_INVALID_ARG; return RESAMPLER_ERR_INVALID_ARG;
@ -1060,32 +1060,42 @@ int speex_resampler_set_quality(SpeexResamplerState *st, int quality)
return RESAMPLER_ERR_SUCCESS; return RESAMPLER_ERR_SUCCESS;
} }
void speex_resampler_get_quality(SpeexResamplerState *st, int *quality) EXPORT void speex_resampler_get_quality(SpeexResamplerState *st, int *quality)
{ {
*quality = st->quality; *quality = st->quality;
} }
void speex_resampler_set_input_stride(SpeexResamplerState *st, spx_uint32_t stride) EXPORT void speex_resampler_set_input_stride(SpeexResamplerState *st, spx_uint32_t stride)
{ {
st->in_stride = stride; st->in_stride = stride;
} }
void speex_resampler_get_input_stride(SpeexResamplerState *st, spx_uint32_t *stride) EXPORT void speex_resampler_get_input_stride(SpeexResamplerState *st, spx_uint32_t *stride)
{ {
*stride = st->in_stride; *stride = st->in_stride;
} }
void speex_resampler_set_output_stride(SpeexResamplerState *st, spx_uint32_t stride) EXPORT void speex_resampler_set_output_stride(SpeexResamplerState *st, spx_uint32_t stride)
{ {
st->out_stride = stride; st->out_stride = stride;
} }
void speex_resampler_get_output_stride(SpeexResamplerState *st, spx_uint32_t *stride) EXPORT void speex_resampler_get_output_stride(SpeexResamplerState *st, spx_uint32_t *stride)
{ {
*stride = st->out_stride; *stride = st->out_stride;
} }
int speex_resampler_skip_zeros(SpeexResamplerState *st) EXPORT int speex_resampler_get_input_latency(SpeexResamplerState *st)
{
return st->filt_len / 2;
}
EXPORT int speex_resampler_get_output_latency(SpeexResamplerState *st)
{
return ((st->filt_len / 2) * st->den_rate + (st->num_rate >> 1)) / st->num_rate;
}
EXPORT int speex_resampler_skip_zeros(SpeexResamplerState *st)
{ {
spx_uint32_t i; spx_uint32_t i;
for (i=0;i<st->nb_channels;i++) for (i=0;i<st->nb_channels;i++)
@ -1093,7 +1103,7 @@ int speex_resampler_skip_zeros(SpeexResamplerState *st)
return RESAMPLER_ERR_SUCCESS; return RESAMPLER_ERR_SUCCESS;
} }
int speex_resampler_reset_mem(SpeexResamplerState *st) EXPORT int speex_resampler_reset_mem(SpeexResamplerState *st)
{ {
spx_uint32_t i; spx_uint32_t i;
for (i=0;i<st->nb_channels*(st->filt_len-1);i++) for (i=0;i<st->nb_channels*(st->filt_len-1);i++)
@ -1101,7 +1111,7 @@ int speex_resampler_reset_mem(SpeexResamplerState *st)
return RESAMPLER_ERR_SUCCESS; return RESAMPLER_ERR_SUCCESS;
} }
const char *speex_resampler_strerror(int err) EXPORT const char *speex_resampler_strerror(int err)
{ {
switch (err) switch (err)
{ {

View file

@ -71,6 +71,8 @@
#define speex_resampler_get_input_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_get_input_stride) #define speex_resampler_get_input_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_get_input_stride)
#define speex_resampler_set_output_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_set_output_stride) #define speex_resampler_set_output_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_set_output_stride)
#define speex_resampler_get_output_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_get_output_stride) #define speex_resampler_get_output_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_get_output_stride)
#define speex_resampler_get_input_latency CAT_PREFIX(RANDOM_PREFIX,_resampler_get_input_latency)
#define speex_resampler_get_output_latency CAT_PREFIX(RANDOM_PREFIX,_resampler_get_output_latency)
#define speex_resampler_skip_zeros CAT_PREFIX(RANDOM_PREFIX,_resampler_skip_zeros) #define speex_resampler_skip_zeros CAT_PREFIX(RANDOM_PREFIX,_resampler_skip_zeros)
#define speex_resampler_reset_mem CAT_PREFIX(RANDOM_PREFIX,_resampler_reset_mem) #define speex_resampler_reset_mem CAT_PREFIX(RANDOM_PREFIX,_resampler_reset_mem)
#define speex_resampler_strerror CAT_PREFIX(RANDOM_PREFIX,_resampler_strerror) #define speex_resampler_strerror CAT_PREFIX(RANDOM_PREFIX,_resampler_strerror)
@ -300,6 +302,16 @@ void speex_resampler_set_output_stride(SpeexResamplerState *st,
void speex_resampler_get_output_stride(SpeexResamplerState *st, void speex_resampler_get_output_stride(SpeexResamplerState *st,
spx_uint32_t *stride); spx_uint32_t *stride);
/** Get the latency in input samples introduced by the resampler.
* @param st Resampler state
*/
int speex_resampler_get_input_latency(SpeexResamplerState *st);
/** Get the latency in output samples introduced by the resampler.
* @param st Resampler state
*/
int speex_resampler_get_output_latency(SpeexResamplerState *st);
/** Make sure that the first samples to go out of the resamplers don't have /** Make sure that the first samples to go out of the resamplers don't have
* leading zeros. This is only useful before starting to use a newly created * leading zeros. This is only useful before starting to use a newly created
* resampler. It is recommended to use that when resampling an audio file, as * resampler. It is recommended to use that when resampling an audio file, as

View file

@ -0,0 +1,115 @@
/* Copyright (C) 2002 Jean-Marc Valin */
/**
@file stack_alloc.h
@brief Temporary memory allocation on stack
*/
/*
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of the Xiph.org Foundation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef STACK_ALLOC_H
#define STACK_ALLOC_H
#ifdef USE_ALLOCA
# ifdef WIN32
# include <malloc.h>
# else
# ifdef HAVE_ALLOCA_H
# include <alloca.h>
# else
# include <stdlib.h>
# endif
# endif
#endif
/**
* @def ALIGN(stack, size)
*
* Aligns the stack to a 'size' boundary
*
* @param stack Stack
* @param size New size boundary
*/
/**
* @def PUSH(stack, size, type)
*
* Allocates 'size' elements of type 'type' on the stack
*
* @param stack Stack
* @param size Number of elements
* @param type Type of element
*/
/**
* @def VARDECL(var)
*
* Declare variable on stack
*
* @param var Variable to declare
*/
/**
* @def ALLOC(var, size, type)
*
* Allocate 'size' elements of 'type' on stack
*
* @param var Name of variable to allocate
* @param size Number of elements
* @param type Type of element
*/
#ifdef ENABLE_VALGRIND
#include <valgrind/memcheck.h>
#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1))
#define PUSH(stack, size, type) (VALGRIND_MAKE_NOACCESS(stack, 1000),ALIGN((stack),sizeof(type)),VALGRIND_MAKE_WRITABLE(stack, ((size)*sizeof(type))),(stack)+=((size)*sizeof(type)),(type*)((stack)-((size)*sizeof(type))))
#else
#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1))
#define PUSH(stack, size, type) (ALIGN((stack),sizeof(type)),(stack)+=((size)*sizeof(type)),(type*)((stack)-((size)*sizeof(type))))
#endif
#if defined(VAR_ARRAYS)
#define VARDECL(var)
#define ALLOC(var, size, type) type var[size]
#elif defined(USE_ALLOCA)
#define VARDECL(var) var
#define ALLOC(var, size, type) var = alloca(sizeof(type)*(size))
#else
#define VARDECL(var) var
#define ALLOC(var, size, type) var = PUSH(stack, size, type)
#endif
#endif