Index: include/speex/speex_block_resampler.h =================================================================== --- include/speex/speex_block_resampler.h (revision 0) +++ include/speex/speex_block_resampler.h (revision 0) @@ -0,0 +1,101 @@ +/* Copyright (C) 2008 Jean-Marc Valin + Copyright (C) 2008 Thorvald Natvig + + File: speex_block_resampler.h + Resampling code using FFT + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. 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. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 SPEEX_BLOCK_RESAMPLER_H +#define SPEEX_BLOCK_RESAMPLER_H + +#include "speex/speex_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct SpeexBlockResamplerState_; +typedef struct SpeexBlockResamplerState_ SpeexBlockResamplerState; + +/** Create a new resampler. The resulting resampler will resample fixed block lengths. + * @param in_len Length of input block (in samples). + * @param out_len Length of output block (in samples). + * @param overlap Length of overlap. + * @return Newly created resampler state + * @retval NULL Error: invalid parameters. + */ +SpeexBlockResamplerState *speex_block_resampler_init(spx_uint32_t in_len, + spx_uint32_t out_len, + spx_int32_t overlap); + +/** Destroy a resampler state. + * @param st Resampler state + */ +void speex_block_resampler_destroy(SpeexBlockResamplerState *st); + +/** Resample a float array. The input and output buffers must *not* overlap. + * @param st Resampler state + * @param in Input buffer + * @param out Output buffer + */ +void speex_block_resampler_process_float(SpeexBlockResamplerState *st, + const float *in, + float *out); + +/** Resample an int array. The input and output buffers must *not* overlap. + * @param st Resampler state + * @param in Input buffer + * @param out Output buffer + */ +void speex_block_resampler_process_int(SpeexBlockResamplerState *st, + const spx_int16_t *in, + spx_int16_t *out); + +/** Get the latency in input samples introduced by the resampler. + * @param st Resampler state + * @return Latency in input samples. + */ +int speex_block_resampler_get_input_latency(SpeexBlockResamplerState *st); + +/** Get the latency in output samples introduced by the resampler. + * @param st Resampler state + * @return Latency in output samples. + */ +int speex_block_resampler_get_output_latency(SpeexBlockResamplerState *st); + +/** Reset a resampler so a new (unrelated) stream can be processed. + * @param st Resampler state + */ +void speex_block_resampler_reset_mem(SpeexBlockResamplerState *st); + +#ifdef __cplusplus +} +#endif + +#endif Index: libspeex/blockresample.c =================================================================== --- libspeex/blockresample.c (revision 0) +++ libspeex/blockresample.c (revision 0) @@ -0,0 +1,225 @@ +/* Copyright (C) 2007-2008 Jean-Marc Valin + Copyright (C) 2008 Thorvald Natvig + + File: blockresample.c + FFT resampling code + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. 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. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. +*/ + +/* + The design goals of this code are: + - Speed. + - Good quality. + + This code uses FFT to do the resampling. With a proper FFT implementation, + this can be very fast. Unfortunately, it means this code only works with + a subset of transforms. + Specifically, (out_len * overlap ) / in_len must be an integer. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "speex/speex_block_resampler.h" +#include "arch.h" +#include "fftwrap.h" +#include "os_support.h" + +#include + +#ifndef M_PI +#define M_PI 3.14159263 +#endif + +#ifdef FIXED_POINT +#define WORD2INT(x) ((x) < -32767 ? -32768 : ((x) > 32766 ? 32767 : (x))) +#else +#define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x)))) +#endif + +#define IMAX(a,b) ((a) > (b) ? (a) : (b)) +#define IMIN(a,b) ((a) < (b) ? (a) : (b)) + +#ifndef NULL +#define NULL 0 +#endif + +struct SpeexBlockResamplerState_ { + void *fft_in; + void *fft_out; + spx_word16_t *tmp; + spx_word16_t *mem_in, *mem_out; + spx_word16_t *win_in, *win_out; + spx_word16_t *in, *out; + + spx_uint32_t N_in, N_out; /* Length + Overlap */ + spx_uint32_t L_in, L_out; /* Base length */ + spx_uint32_t N_max; +}; + +extern void conj_window(spx_word16_t *w, int len); + +static void window_init(spx_word16_t *w, int N, int L) +{ + int winlen = 2 * (N - L); + int HL = winlen >> 1; + int i; + conj_window(w, winlen); + for(i=HL-1;i>=0;i--) + w[N-HL+i] = w[HL+i]; + for(i=HL;i<(N-HL);i++) + w[i] = 1; +} + +EXPORT SpeexBlockResamplerState *speex_block_resampler_init(spx_uint32_t in_len, spx_uint32_t out_len, spx_int32_t overlap) +{ + spx_uint32_t in_overlap = ABS32(overlap); + spx_uint32_t out_overlap = (out_len * overlap) / in_len; + + if ((in_overlap > in_len) || (overlap==0) || ((overlap > 0) && ((out_len * in_overlap) % in_len))) { + speex_warning("I'm sorry Dave, I'm afraid you can't do that"); + return NULL; + } + + SpeexBlockResamplerState *st=(SpeexBlockResamplerState *) speex_alloc(sizeof(SpeexBlockResamplerState)); + st->N_in = in_len + overlap; + st->N_out = out_len + out_overlap; + st->N_max = IMAX(st->N_in, st->N_out); + st->L_in = in_len; + st->L_out = out_len; + st->in = (spx_word16_t *) speex_alloc(sizeof(spx_word16_t) * st->N_in); + st->out = (spx_word16_t *) speex_alloc(sizeof(spx_word16_t) * st->N_out); + st->tmp = (spx_word16_t *) speex_alloc(sizeof(spx_word16_t) * st->N_max); + st->mem_in = (spx_word16_t *) speex_alloc(sizeof(spx_word16_t) * in_overlap); + st->mem_out = (spx_word16_t *) speex_alloc(sizeof(spx_word16_t) * out_overlap); + st->win_in = (spx_word16_t *) speex_alloc(sizeof(spx_word16_t) * st->N_in); + st->win_out = (spx_word16_t *) speex_alloc(sizeof(spx_word16_t) * st->N_out); + + st->fft_in = spx_fft_init(st->N_in); + st->fft_out = spx_fft_init(st->N_out); + + window_init(st->win_in, st->N_in, st->L_in); + window_init(st->win_out, st->N_out, st->L_out); + + return st; +} + +EXPORT void speex_block_resampler_destroy(SpeexBlockResamplerState *st) +{ + spx_fft_destroy(st->fft_out); + spx_fft_destroy(st->fft_in); + speex_free(st->win_out); + speex_free(st->win_in); + speex_free(st->mem_out); + speex_free(st->mem_in); + speex_free(st->tmp); + speex_free(st->out); + speex_free(st->in); + +} + +EXPORT void speex_block_resampler_reset_mem(SpeexBlockResamplerState *st) +{ + int i; + for(i=0;i<(st->N_in-st->L_in);i++) + st->mem_in[i] = 0; + for(i=0;i<(st->N_out-st->L_out);i++) + st->mem_out[i] = 0; +} + +EXPORT void speex_block_resampler_process_float(SpeexBlockResamplerState * restrict st, const float * restrict in, float * restrict out) +{ + const spx_uint32_t OL_in = st->N_in - st->L_in; + const spx_uint32_t OL_out = st->N_out - st->L_out; + int i; + + for(i=0;iin[i] = st->mem_in[i] * st->win_in[i]; + for(i=0;iL_in;i++) + st->in[i+OL_in] = in[i] * st->win_in[i+OL_in]; + + for(i=0;imem_in[i] = in[st->L_in - OL_in + i]; + + spx_fft(st->fft_in, st->in, st->tmp); + + for(i=st->N_in+1;iN_max;i++) + st->tmp[i]=0; + + spx_ifft(st->fft_out, st->tmp, st->out); + + for(i=0;iout[i] * st->win_out[i] + st->mem_out[i]; + for(i=OL_out;iL_out;i++) + out[i] = st->out[i]; + + for(i=0;imem_out[i] = st->out[st->N_out - OL_out + i] * st->win_out[st->N_out - OL_out + i]; +} + +EXPORT void speex_block_resampler_process_int(SpeexBlockResamplerState * restrict st, const short * restrict in, short * restrict out) +{ + const spx_uint32_t OL_in = st->N_in - st->L_in; + const spx_uint32_t OL_out = st->N_out - st->L_out; + int i; + + for(i=0;iin[i] = st->mem_in[i] * st->win_in[i]; + for(i=0;iL_in;i++) + st->in[i+OL_in] = in[i] * st->win_in[i+OL_in]; + + for(i=0;imem_in[i] = in[st->L_in - OL_in + i]; + + spx_fft(st->fft_in, st->in, st->tmp); + + for(i=st->N_in+1;iN_max;i++) + st->tmp[i]=0; + + spx_ifft(st->fft_out, st->tmp, st->out); + + for(i=0;iout[i] * st->win_out[i] + st->mem_out[i]; + for(i=OL_out;iL_out;i++) + out[i] = st->out[i]; + + for(i=0;imem_out[i] = st->out[st->N_out - OL_out + i] * st->win_out[st->N_out - OL_out + i]; +} + + +EXPORT int speex_block_resampler_get_input_latency(SpeexBlockResamplerState *st) +{ + return st->N_in - st->L_in; +} + +EXPORT int speex_block_resampler_get_output_latency(SpeexBlockResamplerState *st) +{ + return st->N_out - st->L_out; +} Index: libspeex/preprocess.c =================================================================== --- libspeex/preprocess.c (revision 14978) +++ libspeex/preprocess.c (working copy) @@ -252,7 +252,7 @@ }; -static void conj_window(spx_word16_t *w, int len) +void conj_window(spx_word16_t *w, int len) { int i; for (i=0;i