summaryrefslogtreecommitdiffstats
path: root/gst/speexresample/resample.c
diff options
context:
space:
mode:
Diffstat (limited to 'gst/speexresample/resample.c')
-rw-r--r--gst/speexresample/resample.c784
1 files changed, 408 insertions, 376 deletions
diff --git a/gst/speexresample/resample.c b/gst/speexresample/resample.c
index f29e6144..29b95f23 100644
--- a/gst/speexresample/resample.c
+++ b/gst/speexresample/resample.c
@@ -1,5 +1,4 @@
-/* Copyright (C) 2007-2008 Jean-Marc Valin
- Copyright (C) 2008 Thorvald Natvig
+/* Copyright (C) 2007 Jean-Marc Valin
File: resample.c
Arbitrary resampling code
@@ -63,17 +62,13 @@
#ifdef OUTSIDE_SPEEX
#include <stdlib.h>
-
#include <glib.h>
-#define EXPORT G_GNUC_INTERNAL
-
static inline void *
speex_alloc (int size)
{
return g_malloc0 (size);
}
-
static inline void *
speex_realloc (void *ptr, int size)
{
@@ -90,7 +85,7 @@ speex_free (void *ptr)
#include "arch.h"
#else /* OUTSIDE_SPEEX */
-#include "../include/speex/speex_resampler.h"
+#include "speex/speex_resampler.h"
#include "arch.h"
#include "os_support.h"
#endif /* OUTSIDE_SPEEX */
@@ -107,6 +102,10 @@ speex_free (void *ptr)
#define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x))))
#endif
+/*#define float double*/
+#define FILTER_SIZE 64
+#define OVERSAMPLE 8
+
#define IMAX(a,b) ((a) > (b) ? (a) : (b))
#define IMIN(a,b) ((a) < (b) ? (a) : (b))
@@ -114,17 +113,6 @@ speex_free (void *ptr)
#define NULL 0
#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 *);
@@ -139,7 +127,6 @@ struct SpeexResamplerState_
spx_uint32_t nb_channels;
spx_uint32_t filt_len;
spx_uint32_t mem_alloc_size;
- spx_uint32_t buffer_size;
int int_advance;
int frac_advance;
float cutoff;
@@ -267,19 +254,13 @@ static const struct QualityMapping quality_map[11] = {
};
/*8,24,40,56,80,104,128,160,200,256,320*/
-#ifdef DOUBLE_PRECISION
-static double
-compute_func (double x, struct FuncDef *func)
-{
- double y, frac;
-#else
static double
compute_func (float x, struct FuncDef *func)
{
float y, frac;
-#endif
double interp[4];
int ind;
+
y = x * func->oversample;
ind = (int) floor (y);
frac = (y - ind);
@@ -304,6 +285,7 @@ int
main (int argc, char **argv)
{
int i;
+
for (i = 0; i < 256; i++) {
printf ("%f\n", compute_func (i / 256., KAISER12));
}
@@ -318,6 +300,7 @@ sinc (float cutoff, float x, int N, struct FuncDef *window_func)
{
/*fprintf (stderr, "%f ", x); */
float xx = x * cutoff;
+
if (fabs (x) < 1e-6f)
return WORD2INT (32768. * cutoff);
else if (fabs (x) > .5f * N)
@@ -328,19 +311,12 @@ sinc (float cutoff, float x, int N, struct FuncDef *window_func)
}
#else
/* The slow way of computing a sinc for the table. Should improve that some day */
-#ifdef DOUBLE_PRECISION
-static spx_word16_t
-sinc (double cutoff, double x, int N, struct FuncDef *window_func)
-{
- /*fprintf (stderr, "%f ", x); */
- double xx = x * cutoff;
-#else
static spx_word16_t
sinc (float cutoff, float x, int N, struct FuncDef *window_func)
{
/*fprintf (stderr, "%f ", x); */
float xx = x * cutoff;
-#endif
+
if (fabs (x) < 1e-6)
return cutoff;
else if (fabs (x) > .5 * N)
@@ -358,6 +334,7 @@ cubic_coef (spx_word16_t x, spx_word16_t interp[4])
/* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation
but I know it's MMSE-optimal on a sinc */
spx_word16_t x2, x3;
+
x2 = MULT16_16_P15 (x, x);
x3 = MULT16_16_P15 (x, x2);
interp[0] =
@@ -391,57 +368,57 @@ cubic_coef (spx_word16_t frac, spx_word16_t interp[4])
}
#endif
-#ifndef DOUBLE_PRECISION
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)
{
- const int N = st->filt_len;
+ int N = st->filt_len;
int out_sample = 0;
+ spx_word16_t *mem;
int last_sample = st->last_sample[channel_index];
spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];
- 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;
+ mem = st->mem + channel_index * st->mem_alloc_size;
while (!(last_sample >= (spx_int32_t) * in_len
|| out_sample >= (spx_int32_t) * out_len)) {
- const spx_word16_t *sinc = &sinc_table[samp_frac_num * N];
- const spx_word16_t *iptr = &in[last_sample];
+ int j;
+ spx_word32_t sum = 0;
-#ifndef OVERRIDE_INNER_PRODUCT_SINGLE
- float accum[4] = { 0, 0, 0, 0 };
+ /* We already have all the filter coefficients pre-computed in the table */
+ const spx_word16_t *ptr;
- for (j = 0; j < N; j += 4) {
- accum[0] += sinc[j] * iptr[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];
+ /* Do the memory part */
+ for (j = 0; last_sample - N + 1 + j < 0; j++) {
+ sum +=
+ MULT16_16 (mem[last_sample + j],
+ st->sinc_table[samp_frac_num * st->filt_len + j]);
}
- sum = accum[0] + accum[1] + accum[2] + accum[3];
-#else
- sum = inner_product_single (sinc, iptr, N);
-#endif
- out[out_stride * out_sample++] = PSHR32 (sum, 15);
- last_sample += int_advance;
- samp_frac_num += frac_advance;
- if (samp_frac_num >= den_rate) {
- samp_frac_num -= den_rate;
+ /* Do the new part */
+ if (in != NULL) {
+ ptr = in + st->in_stride * (last_sample - N + 1 + j);
+ for (; j < N; j++) {
+ sum +=
+ MULT16_16 (*ptr, st->sinc_table[samp_frac_num * st->filt_len + j]);
+ 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++;
}
}
-
st->last_sample[channel_index] = last_sample;
st->samp_frac_num[channel_index] = samp_frac_num;
return out_sample;
}
-#endif
#ifdef FIXED_POINT
#else
@@ -451,132 +428,150 @@ 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)
{
- const int N = st->filt_len;
+ int N = st->filt_len;
int out_sample = 0;
+ spx_word16_t *mem;
int last_sample = st->last_sample[channel_index];
spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];
- 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;
+ mem = st->mem + channel_index * st->mem_alloc_size;
while (!(last_sample >= (spx_int32_t) * in_len
|| out_sample >= (spx_int32_t) * out_len)) {
- const spx_word16_t *sinc = &sinc_table[samp_frac_num * N];
- const spx_word16_t *iptr = &in[last_sample];
+ int j;
+ double sum = 0;
-#ifndef OVERRIDE_INNER_PRODUCT_DOUBLE
- double accum[4] = { 0, 0, 0, 0 };
+ /* We already have all the filter coefficients pre-computed in the table */
+ const spx_word16_t *ptr;
- for (j = 0; j < N; j += 4) {
- accum[0] += sinc[j] * iptr[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];
+ /* Do the memory part */
+ for (j = 0; last_sample - N + 1 + j < 0; j++) {
+ sum +=
+ MULT16_16 (mem[last_sample + j],
+ (double) st->sinc_table[samp_frac_num * st->filt_len + j]);
+ }
+
+ /* Do the new part */
+ if (in != NULL) {
+ ptr = in + st->in_stride * (last_sample - N + 1 + j);
+ for (; j < N; j++) {
+ sum +=
+ MULT16_16 (*ptr,
+ (double) st->sinc_table[samp_frac_num * st->filt_len + j]);
+ ptr += st->in_stride;
+ }
}
- sum = accum[0] + accum[1] + accum[2] + accum[3];
-#else
- sum = inner_product_double (sinc, iptr, N);
-#endif
- out[out_stride * out_sample++] = PSHR32 (sum, 15);
- last_sample += int_advance;
- samp_frac_num += frac_advance;
- if (samp_frac_num >= den_rate) {
- samp_frac_num -= den_rate;
+ *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++;
}
}
-
st->last_sample[channel_index] = last_sample;
st->samp_frac_num[channel_index] = samp_frac_num;
return out_sample;
}
#endif
-#ifndef DOUBLE_PRECISION
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)
{
- const int N = st->filt_len;
+ int N = st->filt_len;
int out_sample = 0;
+ spx_word16_t *mem;
int last_sample = st->last_sample[channel_index];
spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];
- 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;
+ mem = st->mem + channel_index * st->mem_alloc_size;
while (!(last_sample >= (spx_int32_t) * in_len
|| out_sample >= (spx_int32_t) * out_len)) {
- const spx_word16_t *iptr = &in[last_sample];
+ int j;
+ spx_word32_t sum = 0;
+
+ /* We need to interpolate the sinc filter */
+ 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;
- const int offset = samp_frac_num * st->oversample / st->den_rate;
+ offset = samp_frac_num * st->oversample / st->den_rate;
#ifdef FIXED_POINT
- const spx_word16_t frac =
+ frac =
PDIV32 (SHL32 ((samp_frac_num * st->oversample) % st->den_rate, 15),
st->den_rate);
#else
- const spx_word16_t frac =
+ frac =
((float) ((samp_frac_num * st->oversample) % st->den_rate)) /
st->den_rate;
#endif
- spx_word16_t interp[4];
-
-
-#ifndef OVERRIDE_INTERPOLATE_PRODUCT_SINGLE
- spx_word32_t accum[4] = { 0, 0, 0, 0 };
+ /* 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 */
+ for (j = 0; last_sample - N + 1 + j < 0; j++) {
+ spx_word16_t curr_mem = mem[last_sample + j];
- for (j = 0; j < N; j++) {
- const spx_word16_t curr_in = iptr[j];
accum[0] +=
- MULT16_16 (curr_in,
+ MULT16_16 (curr_mem,
st->sinc_table[4 + (j + 1) * st->oversample - offset - 2]);
accum[1] +=
- MULT16_16 (curr_in,
+ MULT16_16 (curr_mem,
st->sinc_table[4 + (j + 1) * st->oversample - offset - 1]);
accum[2] +=
- MULT16_16 (curr_in,
+ MULT16_16 (curr_mem,
st->sinc_table[4 + (j + 1) * st->oversample - offset]);
accum[3] +=
- MULT16_16 (curr_in,
+ MULT16_16 (curr_mem,
st->sinc_table[4 + (j + 1) * st->oversample - offset + 1]);
}
+ if (in != NULL) {
+ ptr = in + st->in_stride * (last_sample - N + 1 + j);
+ /* 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);
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[out_stride * out_sample++] = PSHR32 (sum, 15);
- last_sample += int_advance;
- samp_frac_num += frac_advance;
- if (samp_frac_num >= den_rate) {
- samp_frac_num -= den_rate;
+ *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++;
}
}
-
st->last_sample[channel_index] = last_sample;
st->samp_frac_num[channel_index] = samp_frac_num;
return out_sample;
}
-#endif
#ifdef FIXED_POINT
#else
@@ -586,81 +581,81 @@ 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)
{
- const int N = st->filt_len;
+ int N = st->filt_len;
int out_sample = 0;
+ spx_word16_t *mem;
int last_sample = st->last_sample[channel_index];
spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];
- 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;
+ mem = st->mem + channel_index * st->mem_alloc_size;
while (!(last_sample >= (spx_int32_t) * in_len
|| out_sample >= (spx_int32_t) * out_len)) {
- const spx_word16_t *iptr = &in[last_sample];
+ int j;
+ spx_word32_t sum = 0;
+
+ /* We need to interpolate the sinc filter */
+ double accum[4] = { 0.f, 0.f, 0.f, 0.f };
+ float interp[4];
+ const spx_word16_t *ptr;
+ float alpha = ((float) samp_frac_num) / st->den_rate;
+ int offset = samp_frac_num * st->oversample / st->den_rate;
+ float frac = alpha * st->oversample - offset;
+
+ /* 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 */
+ for (j = 0; last_sample - N + 1 + j < 0; j++) {
+ double curr_mem = mem[last_sample + j];
- const int offset = samp_frac_num * st->oversample / st->den_rate;
-#ifdef FIXED_POINT
- const spx_word16_t frac =
- PDIV32 (SHL32 ((samp_frac_num * st->oversample) % st->den_rate, 15),
- st->den_rate);
-#else
-#ifdef DOUBLE_PRECISION
- const spx_word16_t frac =
- ((double) ((samp_frac_num * st->oversample) % st->den_rate)) /
- st->den_rate;
-#else
- const spx_word16_t frac =
- ((float) ((samp_frac_num * st->oversample) % st->den_rate)) /
- st->den_rate;
-#endif
-#endif
- spx_word16_t interp[4];
-
-
-#ifndef OVERRIDE_INTERPOLATE_PRODUCT_DOUBLE
- double accum[4] = { 0, 0, 0, 0 };
-
- for (j = 0; j < N; j++) {
- const double curr_in = iptr[j];
accum[0] +=
- MULT16_16 (curr_in,
+ MULT16_16 (curr_mem,
st->sinc_table[4 + (j + 1) * st->oversample - offset - 2]);
accum[1] +=
- MULT16_16 (curr_in,
+ MULT16_16 (curr_mem,
st->sinc_table[4 + (j + 1) * st->oversample - offset - 1]);
accum[2] +=
- MULT16_16 (curr_in,
+ MULT16_16 (curr_mem,
st->sinc_table[4 + (j + 1) * st->oversample - offset]);
accum[3] +=
- MULT16_16 (curr_in,
+ MULT16_16 (curr_mem,
st->sinc_table[4 + (j + 1) * st->oversample - offset + 1]);
}
-
- 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]);
-#else
+ if (in != NULL) {
+ 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);
sum =
- interpolate_product_double (iptr,
- st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample,
- interp);
-#endif
-
- out[out_stride * out_sample++] = PSHR32 (sum, 15);
- last_sample += int_advance;
- samp_frac_num += frac_advance;
- if (samp_frac_num >= den_rate) {
- samp_frac_num -= den_rate;
+ interp[0] * accum[0] + interp[1] * accum[1] + interp[2] * accum[2] +
+ interp[3] * accum[3];
+
+ *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++;
}
}
-
st->last_sample[channel_index] = last_sample;
st->samp_frac_num[channel_index] = samp_frac_num;
return out_sample;
@@ -703,6 +698,7 @@ update_filter (SpeexResamplerState * st)
/* Choose the resampling type that requires the least amount of memory */
if (st->den_rate <= st->oversample) {
spx_uint32_t i;
+
if (!st->sinc_table)
st->sinc_table =
(spx_word16_t *) speex_alloc (st->filt_len * st->den_rate *
@@ -715,32 +711,27 @@ update_filter (SpeexResamplerState * st)
}
for (i = 0; i < st->den_rate; i++) {
spx_int32_t j;
+
for (j = 0; j < st->filt_len; j++) {
st->sinc_table[i * st->filt_len + j] =
- sinc (st->cutoff, ((j - (spx_int32_t) st->filt_len / 2 + 1) -
-#ifdef DOUBLE_PRECISION
- ((double) i) / st->den_rate), st->filt_len,
-#else
+ sinc (st->cutoff,
+ ((j - (spx_int32_t) st->filt_len / 2 + 1) -
((float) i) / st->den_rate), st->filt_len,
-#endif
quality_map[st->quality].window_func);
}
}
#ifdef FIXED_POINT
st->resampler_ptr = resampler_basic_direct_single;
#else
-#ifdef DOUBLE_PRECISION
- st->resampler_ptr = resampler_basic_direct_double;
-#else
if (st->quality > 8)
st->resampler_ptr = resampler_basic_direct_double;
else
st->resampler_ptr = resampler_basic_direct_single;
#endif
-#endif
/*fprintf (stderr, "resampler uses direct sinc table and normalised cutoff %f\n", cutoff); */
} else {
spx_int32_t i;
+
if (!st->sinc_table)
st->sinc_table =
(spx_word16_t *) speex_alloc ((st->filt_len * st->oversample +
@@ -753,24 +744,16 @@ update_filter (SpeexResamplerState * st)
}
for (i = -4; i < (spx_int32_t) (st->oversample * st->filt_len + 4); i++)
st->sinc_table[i + 4] =
-#ifdef DOUBLE_PRECISION
- sinc (st->cutoff, (i / (double) st->oversample - st->filt_len / 2),
-#else
sinc (st->cutoff, (i / (float) st->oversample - st->filt_len / 2),
-#endif
st->filt_len, quality_map[st->quality].window_func);
#ifdef FIXED_POINT
st->resampler_ptr = resampler_basic_interpolate_single;
#else
-#ifdef DOUBLE_PRECISION
- st->resampler_ptr = resampler_basic_interpolate_double;
-#else
if (st->quality > 8)
st->resampler_ptr = resampler_basic_interpolate_double;
else
st->resampler_ptr = resampler_basic_interpolate_single;
#endif
-#endif
/*fprintf (stderr, "resampler uses interpolated sinc table and normalised cutoff %f\n", cutoff); */
}
st->int_advance = st->num_rate / st->den_rate;
@@ -782,36 +765,41 @@ update_filter (SpeexResamplerState * st)
due to handling of lots of corner cases. */
if (!st->mem) {
spx_uint32_t i;
- st->mem_alloc_size = st->filt_len - 1 + st->buffer_size;
+
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++)
+ (spx_word16_t *) speex_alloc (st->nb_channels * (st->filt_len -
+ 1) * sizeof (spx_word16_t));
+ for (i = 0; i < st->nb_channels * (st->filt_len - 1); i++)
st->mem[i] = 0;
+ st->mem_alloc_size = st->filt_len - 1;
/*speex_warning("init filter"); */
} else if (!st->started) {
spx_uint32_t i;
- st->mem_alloc_size = st->filt_len - 1 + st->buffer_size;
+
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->nb_channels * (st->filt_len - 1) * sizeof (spx_word16_t));
+ for (i = 0; i < st->nb_channels * (st->filt_len - 1); i++)
st->mem[i] = 0;
+ st->mem_alloc_size = st->filt_len - 1;
/*speex_warning("reinit filter"); */
} else if (st->filt_len > old_length) {
spx_int32_t i;
+
/* Increase the filter length */
/*speex_warning("increase filter size"); */
int old_alloc_size = st->mem_alloc_size;
- if ((st->filt_len - 1 + st->buffer_size) > st->mem_alloc_size) {
- st->mem_alloc_size = st->filt_len - 1 + st->buffer_size;
+
+ if (st->filt_len - 1 > st->mem_alloc_size) {
st->mem =
(spx_word16_t *) speex_realloc (st->mem,
- st->nb_channels * st->mem_alloc_size * sizeof (spx_word16_t));
+ st->nb_channels * (st->filt_len - 1) * sizeof (spx_word16_t));
+ st->mem_alloc_size = st->filt_len - 1;
}
for (i = st->nb_channels - 1; i >= 0; i--) {
spx_int32_t j;
spx_uint32_t olen = old_length;
+
/*if (st->magic_samples[i]) */
{
/* Try and remove the magic samples as if nothing had happened */
@@ -846,11 +834,13 @@ update_filter (SpeexResamplerState * st)
}
} else if (st->filt_len < old_length) {
spx_uint32_t i;
+
/* Reduce filter length, this a bit tricky. We need to store some of the memory as "magic"
samples so they can be used directly as input the next time(s) */
for (i = 0; i < st->nb_channels; i++) {
spx_uint32_t j;
spx_uint32_t old_magic = st->magic_samples[i];
+
st->magic_samples[i] = (old_length - st->filt_len) / 2;
/* We must copy some of the memory that's no longer used */
/* Copy data going backward */
@@ -863,7 +853,7 @@ update_filter (SpeexResamplerState * st)
}
-EXPORT SpeexResamplerState *
+SpeexResamplerState *
speex_resampler_init (spx_uint32_t nb_channels, spx_uint32_t in_rate,
spx_uint32_t out_rate, int quality, int *err)
{
@@ -871,13 +861,14 @@ speex_resampler_init (spx_uint32_t nb_channels, spx_uint32_t in_rate,
out_rate, quality, err);
}
-EXPORT SpeexResamplerState *
+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;
SpeexResamplerState *st;
+
if (quality > 10 || quality < 0) {
if (err)
*err = RESAMPLER_ERR_INVALID_ARG;
@@ -902,12 +893,6 @@ speex_resampler_init_frac (spx_uint32_t nb_channels, spx_uint32_t ratio_num,
st->in_stride = 1;
st->out_stride = 1;
-#ifdef FIXED_POINT
- st->buffer_size = 160;
-#else
- st->buffer_size = 160;
-#endif
-
/* Per channel data */
st->last_sample = (spx_int32_t *) speex_alloc (nb_channels * sizeof (int));
st->magic_samples = (spx_uint32_t *) speex_alloc (nb_channels * sizeof (int));
@@ -931,7 +916,7 @@ speex_resampler_init_frac (spx_uint32_t nb_channels, spx_uint32_t ratio_num,
return st;
}
-EXPORT void
+void
speex_resampler_destroy (SpeexResamplerState * st)
{
speex_free (st->mem);
@@ -942,207 +927,249 @@ speex_resampler_destroy (SpeexResamplerState * 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)
+ 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;
- const int N = st->filt_len;
+ int N = st->filt_len;
int out_sample = 0;
- spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size;
- spx_uint32_t ilen;
+ spx_word16_t *mem;
+ spx_uint32_t tmp_out_len = 0;
+ mem = st->mem + channel_index * st->mem_alloc_size;
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 */
- out_sample = st->resampler_ptr (st, channel_index, mem, in_len, out, out_len);
+ out_sample = st->resampler_ptr (st, channel_index, in, in_len, out, out_len);
if (st->last_sample[channel_index] < (spx_int32_t) * in_len)
*in_len = st->last_sample[channel_index];
- *out_len = out_sample;
+ *out_len = out_sample + tmp_out_len;
st->last_sample[channel_index] -= *in_len;
- ilen = *in_len;
-
- for (j = 0; j < N - 1; ++j)
- mem[j] = mem[j + ilen];
-
+ for (j = 0; j < N - 1 - (spx_int32_t) * in_len; j++)
+ mem[j] = mem[j + *in_len];
+ if (in != NULL) {
+ for (; j < N - 1; j++)
+ mem[j] = in[st->in_stride * (j + *in_len - N + 1)];
+ } else {
+ for (; j < N - 1; j++)
+ mem[j] = 0;
+ }
return RESAMPLER_ERR_SUCCESS;
}
-static int
-speex_resampler_magic (SpeexResamplerState * st, spx_uint32_t channel_index,
- spx_word16_t ** out, spx_uint32_t out_len)
+#define FIXED_STACK_ALLOC 1024
+
+#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)
{
- 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;
+ spx_uint32_t i;
+ int istride_save, ostride_save;
- speex_resampler_process_native (st, channel_index, &tmp_in_len, *out,
- &out_len);
+#ifdef VAR_ARRAYS
+ spx_word16_t x[*in_len];
+ spx_word16_t y[*out_len];
- st->magic_samples[channel_index] -= tmp_in_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;
+ if (in != NULL) {
+ 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);
+ } else {
+ st->in_stride = st->out_stride = 1;
+ speex_resampler_process_native (st, channel_index, NULL, 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
+ spx_word16_t x[FIXED_STACK_ALLOC];
+ spx_word16_t y[FIXED_STACK_ALLOC];
+ spx_uint32_t ilen = *in_len, olen = *out_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];
+ 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;
+ if (in != NULL) {
+ for (i = 0; i < ichunk; i++)
+ x[i] = WORD2INT (in[i * st->in_stride]);
+ st->in_stride = st->out_stride = 1;
+ speex_resampler_process_native (st, channel_index, x, &ichunk, y,
+ &ochunk);
+ } else {
+ st->in_stride = st->out_stride = 1;
+ speex_resampler_process_native (st, channel_index, NULL, &ichunk, y,
+ &ochunk);
+ }
+ st->in_stride = istride_save;
+ st->out_stride = ostride_save;
+ for (i = 0; i < ochunk; i++)
+ out[i * st->out_stride] = y[i];
+ out += ochunk;
+ in += ichunk;
+ ilen -= ichunk;
+ olen -= ochunk;
}
- *out += out_len * st->out_stride;
- return out_len;
+ *in_len -= ilen;
+ *out_len -= olen;
+#endif
+ return RESAMPLER_ERR_SUCCESS;
}
-#ifdef FIXED_POINT
-EXPORT int
+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)
+{
+ return speex_resampler_process_native (st, channel_index, in, in_len, out,
+ out_len);
+}
#else
-#ifdef DOUBLE_PRECISION
-EXPORT int
-speex_resampler_process_float (SpeexResamplerState * st,
- spx_uint32_t channel_index, const double *in, spx_uint32_t * in_len,
- double *out, spx_uint32_t * out_len)
-#else
-EXPORT int
+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)
-#endif
-#endif
{
- int j;
- spx_uint32_t ilen = *in_len;
- spx_uint32_t olen = *out_len;
- spx_word16_t *x = st->mem + channel_index * st->mem_alloc_size;
- const int filt_offs = st->filt_len - 1;
- const spx_uint32_t xlen = st->mem_alloc_size - filt_offs;
- const int istride = st->in_stride;
-
- if (st->magic_samples[channel_index])
- olen -= speex_resampler_magic (st, channel_index, &out, olen);
- if (!st->magic_samples[channel_index]) {
- while (ilen && olen) {
- spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen;
- spx_uint32_t ochunk = olen;
-
- if (in) {
- for (j = 0; j < ichunk; ++j)
- x[j + filt_offs] = in[j * istride];
- } else {
- for (j = 0; j < ichunk; ++j)
- x[j + filt_offs] = 0;
- }
- 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;
- *out_len -= olen;
- return RESAMPLER_ERR_SUCCESS;
+ return speex_resampler_process_native (st, channel_index, in, in_len, out,
+ out_len);
}
-#ifdef FIXED_POINT
-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
-EXPORT int
+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
{
- int j;
- const int istride_save = st->in_stride;
- const int ostride_save = st->out_stride;
- spx_uint32_t ilen = *in_len;
- spx_uint32_t olen = *out_len;
- 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
- const unsigned int ylen =
- (olen < FIXED_STACK_ALLOC) ? olen : FIXED_STACK_ALLOC;
- VARDECL (spx_word16_t * ystack);
- ALLOC (ystack, ylen, spx_word16_t);
-#else
- const unsigned int ylen = FIXED_STACK_ALLOC;
- spx_word16_t ystack[FIXED_STACK_ALLOC];
-#endif
+ spx_uint32_t i;
+ int istride_save, ostride_save;
- st->out_stride = 1;
+#ifdef VAR_ARRAYS
+ spx_word16_t x[*in_len];
+ spx_word16_t y[*out_len];
- 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]);
+ /*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;
+ if (in != NULL) {
+ 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);
+ } else {
+ st->in_stride = st->out_stride = 1;
+ speex_resampler_process_native (st, channel_index, NULL, 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
- 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;
- }
+ spx_word16_t x[FIXED_STACK_ALLOC];
+ spx_word16_t y[FIXED_STACK_ALLOC];
+ spx_uint32_t ilen = *in_len, olen = *out_len;
- speex_resampler_process_native (st, channel_index, &ichunk, y, &ochunk);
+ 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;
+ if (in != NULL) {
+ 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);
} else {
- ichunk = 0;
- ochunk = 0;
+ st->in_stride = st->out_stride = 1;
+ speex_resampler_process_native (st, channel_index, NULL, &ichunk, y,
+ &ochunk);
}
-
- 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
-
+ 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;
- out += (ochunk + omagic) * ostride_save;
- if (in)
- in += ichunk * istride_save;
}
- st->out_stride = ostride_save;
*in_len -= ilen;
*out_len -= olen;
-
+#endif
return RESAMPLER_ERR_SUCCESS;
}
+#endif
-#ifdef DOUBLE_PRECISION
-EXPORT int
-speex_resampler_process_interleaved_float (SpeexResamplerState * st,
- const double *in, spx_uint32_t * in_len, double *out,
- spx_uint32_t * out_len)
-#else
-EXPORT int
+int
speex_resampler_process_interleaved_float (SpeexResamplerState * st,
const float *in, spx_uint32_t * in_len, float *out, spx_uint32_t * out_len)
-#endif
{
spx_uint32_t i;
int istride_save, ostride_save;
spx_uint32_t bak_len = *out_len;
+
istride_save = st->in_stride;
ostride_save = st->out_stride;
st->in_stride = st->out_stride = st->nb_channels;
@@ -1158,7 +1185,8 @@ speex_resampler_process_interleaved_float (SpeexResamplerState * st,
return RESAMPLER_ERR_SUCCESS;
}
-EXPORT int
+
+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)
@@ -1166,6 +1194,7 @@ speex_resampler_process_interleaved_int (SpeexResamplerState * st,
spx_uint32_t i;
int istride_save, ostride_save;
spx_uint32_t bak_len = *out_len;
+
istride_save = st->in_stride;
ostride_save = st->out_stride;
st->in_stride = st->out_stride = st->nb_channels;
@@ -1181,7 +1210,7 @@ speex_resampler_process_interleaved_int (SpeexResamplerState * st,
return RESAMPLER_ERR_SUCCESS;
}
-EXPORT int
+int
speex_resampler_set_rate (SpeexResamplerState * st, spx_uint32_t in_rate,
spx_uint32_t out_rate)
{
@@ -1189,7 +1218,7 @@ speex_resampler_set_rate (SpeexResamplerState * st, spx_uint32_t in_rate,
out_rate);
}
-EXPORT void
+void
speex_resampler_get_rate (SpeexResamplerState * st, spx_uint32_t * in_rate,
spx_uint32_t * out_rate)
{
@@ -1197,13 +1226,14 @@ speex_resampler_get_rate (SpeexResamplerState * st, spx_uint32_t * in_rate,
*out_rate = st->out_rate;
}
-EXPORT int
+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 old_den;
spx_uint32_t i;
+
if (st->in_rate == in_rate && st->out_rate == out_rate
&& st->num_rate == ratio_num && st->den_rate == ratio_den)
return RESAMPLER_ERR_SUCCESS;
@@ -1235,7 +1265,7 @@ speex_resampler_set_rate_frac (SpeexResamplerState * st, spx_uint32_t ratio_num,
return RESAMPLER_ERR_SUCCESS;
}
-EXPORT void
+void
speex_resampler_get_ratio (SpeexResamplerState * st, spx_uint32_t * ratio_num,
spx_uint32_t * ratio_den)
{
@@ -1243,7 +1273,7 @@ speex_resampler_get_ratio (SpeexResamplerState * st, spx_uint32_t * ratio_num,
*ratio_den = st->den_rate;
}
-EXPORT int
+int
speex_resampler_set_quality (SpeexResamplerState * st, int quality)
{
if (quality > 10 || quality < 0)
@@ -1256,71 +1286,73 @@ speex_resampler_set_quality (SpeexResamplerState * st, int quality)
return RESAMPLER_ERR_SUCCESS;
}
-EXPORT void
+void
speex_resampler_get_quality (SpeexResamplerState * st, int *quality)
{
*quality = st->quality;
}
-EXPORT void
+void
speex_resampler_set_input_stride (SpeexResamplerState * st, spx_uint32_t stride)
{
st->in_stride = stride;
}
-EXPORT void
+void
speex_resampler_get_input_stride (SpeexResamplerState * st,
spx_uint32_t * stride)
{
*stride = st->in_stride;
}
-EXPORT void
+void
speex_resampler_set_output_stride (SpeexResamplerState * st,
spx_uint32_t stride)
{
st->out_stride = stride;
}
-EXPORT void
+void
speex_resampler_get_output_stride (SpeexResamplerState * st,
spx_uint32_t * stride)
{
*stride = st->out_stride;
}
-EXPORT int
+int
speex_resampler_get_input_latency (SpeexResamplerState * st)
{
return st->filt_len / 2;
}
-EXPORT int
+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
+int
speex_resampler_skip_zeros (SpeexResamplerState * st)
{
spx_uint32_t i;
+
for (i = 0; i < st->nb_channels; i++)
st->last_sample[i] = st->filt_len / 2;
return RESAMPLER_ERR_SUCCESS;
}
-EXPORT int
+int
speex_resampler_reset_mem (SpeexResamplerState * st)
{
spx_uint32_t i;
+
for (i = 0; i < st->nb_channels * (st->filt_len - 1); i++)
st->mem[i] = 0;
return RESAMPLER_ERR_SUCCESS;
}
-EXPORT const char *
+const char *
speex_resampler_strerror (int err)
{
switch (err) {