From a8cd8e0c7fb1fa7df59d27823997fc6ca2cbb051 Mon Sep 17 00:00:00 2001 From: Andy Wingo Date: Wed, 29 May 2002 06:13:26 +0000 Subject: add float support to resampling lib clean up header file Original commit message from CVS: * add float support to resampling lib * clean up header file --- gst-libs/gst/resample/Makefile.am | 7 +- gst-libs/gst/resample/dtof.c | 65 ++++++ gst-libs/gst/resample/functable.c | 2 +- gst-libs/gst/resample/private.h | 110 +++++++++++ gst-libs/gst/resample/resample.c | 405 ++++++++++++++++++++++++++++++++++---- gst-libs/gst/resample/resample.h | 91 ++------- 6 files changed, 567 insertions(+), 113 deletions(-) create mode 100644 gst-libs/gst/resample/dtof.c create mode 100644 gst-libs/gst/resample/private.h (limited to 'gst-libs/gst/resample') diff --git a/gst-libs/gst/resample/Makefile.am b/gst-libs/gst/resample/Makefile.am index f7056789..47a42bd1 100644 --- a/gst-libs/gst/resample/Makefile.am +++ b/gst-libs/gst/resample/Makefile.am @@ -12,12 +12,15 @@ ARCHCFLAGS = endif endif -libgstresample_la_SOURCES = dtos.c functable.c resample.c resample.h +libgstresample_la_SOURCES = dtos.c dtof.c functable.c resample.c resample.h libgstresample_la_LIBADD = libgstresample_la_CFLAGS = $(GST_CFLAGS) -ffast-math $(ARCHCFLAGS) libgstresample_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -noinst_HEADERS = resample.h +libgstresampleincludedir = $(includedir)/gst/resample +libgstresampleinclude_HEADERS = resample.h + +noinst_HEADERS = private.h #check_PROGRAMS = test #test_SOURCES = test.c diff --git a/gst-libs/gst/resample/dtof.c b/gst-libs/gst/resample/dtof.c new file mode 100644 index 00000000..c392e676 --- /dev/null +++ b/gst-libs/gst/resample/dtof.c @@ -0,0 +1,65 @@ +/* Resampling library + * Copyright (C) <2001> David A. Schleef + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#include +#include +#include +#include + +/*#include */ +#include "private.h" + +void conv_double_float_ref(double *dest, float *src, int n) +{ + int i; + for(i=0;i #include -#include +#include "private.h" diff --git a/gst-libs/gst/resample/private.h b/gst-libs/gst/resample/private.h new file mode 100644 index 00000000..fb8ba87f --- /dev/null +++ b/gst-libs/gst/resample/private.h @@ -0,0 +1,110 @@ +/* Resampling library + * Copyright (C) <2001> David Schleef + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifndef __PRIVATE_H__ +#define __PRIVATE_H__ + +#include "resample.h" +#include "config.h" + +void resample_nearest_s16(resample_t *r); +void resample_bilinear_s16(resample_t *r); +void resample_sinc_s16(resample_t *r); +void resample_sinc_slow_s16(resample_t *r); +void resample_sinc_ft_s16(resample_t * r); + +void resample_nearest_float(resample_t *r); +void resample_bilinear_float(resample_t *r); +void resample_sinc_float(resample_t *r); +void resample_sinc_slow_float(resample_t *r); +void resample_sinc_ft_float(resample_t * r); + + +typedef struct functable_s functable_t; +struct functable_s { + double start; + double offset; + int len; + + double invoffset; + + double scale; + double scale2; + + double (*func_x)(void *,double x); + double (*func_dx)(void *,double x); + + double (*func2_x)(void *,double x); + double (*func2_dx)(void *,double x); + + double *fx; + double *fdx; + + void *priv; +}; + +void functable_init(functable_t *t); +double functable_eval(functable_t *t,double x); + +double functable_fir(functable_t *t,double x0,int n,double *data,int len); +void functable_fir2(functable_t *t,double *r0, double *r1, double x0, + int n,double *data,int len); + +double functable_sinc(void *p, double x); +double functable_dsinc(void *p, double x); +double functable_window_std(void *p, double x); +double functable_window_dstd(void *p, double x); +double functable_window_boxcar(void *p, double x); +double functable_window_dboxcar(void *p, double x); + +/* math lib stuff */ + +void conv_double_short_table(double *dest, short *src, int n); +void conv_double_short_unroll(double *dest, short *src, int n); +void conv_double_short_ref(double *dest, short *src, int n); +#ifdef HAVE_CPU_PPC +void conv_double_short_altivec(double *dest, short *src, int n); +#endif + +void conv_short_double_ref(short *dest, double *src, int n); +#ifdef HAVE_CPU_PPC +void conv_short_double_ppcasm(short *dest, double *src, int n); +#endif + +#ifdef HAVE_CPU_PPC +#define conv_double_short conv_double_short_table +#define conv_short_double conv_short_double_ppcasm +#else +#define conv_double_short conv_double_short_ref +#define conv_short_double conv_short_double_ref +#endif + +#define conv_double_float conv_double_float_ref +#define conv_float_double conv_float_double_ref + +void conv_double_short_dstr(double *dest, short *src, int n, int dstr); +void conv_short_double_sstr(short *dest, double *src, int n, int dstr); + +void conv_double_float_ref(double *dest, float *src, int n); +void conv_float_double_ref(float *dest, double *src, int n); +void conv_double_float_dstr(double *dest, float *src, int n, int dstr); +void conv_float_double_sstr(float *dest, double *src, int n, int sstr); + +#endif /* __PRIVATE_H__ */ diff --git a/gst-libs/gst/resample/resample.c b/gst-libs/gst/resample/resample.c index b78ceb49..3d944843 100644 --- a/gst-libs/gst/resample/resample.c +++ b/gst-libs/gst/resample/resample.c @@ -23,7 +23,7 @@ #include #include -#include +#include "private.h" #include #include @@ -63,8 +63,6 @@ signed short double_to_s16_ppcasm(double x) return rint(x); } -static void resample_sinc_ft(resample_t * r); - void resample_init(resample_t * r) { r->i_start = 0; @@ -88,20 +86,40 @@ void resample_reinit(resample_t * r) r->halftaps = (r->filter_length - 1.0) * 0.5; - switch (r->method) { - default: - case RESAMPLE_NEAREST: - r->scale = resample_nearest; - break; - case RESAMPLE_BILINEAR: - r->scale = resample_bilinear; - break; - case RESAMPLE_SINC_SLOW: - r->scale = resample_sinc; - break; - case RESAMPLE_SINC: - r->scale = resample_sinc_ft; - break; + if (r->format == RESAMPLE_S16) { + switch (r->method) { + default: + case RESAMPLE_NEAREST: + r->scale = resample_nearest_s16; + break; + case RESAMPLE_BILINEAR: + r->scale = resample_bilinear_s16; + break; + case RESAMPLE_SINC_SLOW: + r->scale = resample_sinc_s16; + break; + case RESAMPLE_SINC: + r->scale = resample_sinc_ft_s16; + break; + } + } else if (r->format == RESAMPLE_FLOAT) { + switch (r->method) { + default: + case RESAMPLE_NEAREST: + r->scale = resample_nearest_float; + break; + case RESAMPLE_BILINEAR: + r->scale = resample_bilinear_float; + break; + case RESAMPLE_SINC_SLOW: + r->scale = resample_sinc_float; + break; + case RESAMPLE_SINC: + r->scale = resample_sinc_ft_float; + break; + } + } else { + fprintf (stderr, "resample: Unexpected format \"%d\"\n", r->format); } } @@ -159,14 +177,26 @@ void resample_scale(resample_t * r, void *i_buf, unsigned int i_size) memset(r->buffer, 0, size); } - if(r->channels==2){ - conv_double_short( - r->buffer + r->filter_length * sizeof(double) * 2, - r->i_buf, r->i_samples * 2); - }else{ - conv_double_short_dstr( - r->buffer + r->filter_length * sizeof(double) * 2, - r->i_buf, r->i_samples, sizeof(double) * 2); + if (r->format==RESAMPLE_S16) { + if(r->channels==2){ + conv_double_short( + r->buffer + r->filter_length * sizeof(double) * 2, + r->i_buf, r->i_samples * 2); + } else { + conv_double_short_dstr( + r->buffer + r->filter_length * sizeof(double) * 2, + r->i_buf, r->i_samples, sizeof(double) * 2); + } + } else if (r->format==RESAMPLE_FLOAT) { + if(r->channels==2){ + conv_double_float( + r->buffer + r->filter_length * sizeof(double) * 2, + r->i_buf, r->i_samples * 2); + } else { + conv_double_float_dstr( + r->buffer + r->filter_length * sizeof(double) * 2, + r->i_buf, r->i_samples, sizeof(double) * 2); + } } r->scale(r); @@ -183,7 +213,7 @@ void resample_scale(resample_t * r, void *i_buf, unsigned int i_size) r->i_start -= r->o_samples; } -void resample_nearest(resample_t * r) +void resample_nearest_s16(resample_t * r) { signed short *i_ptr, *o_ptr; int i_count = 0; @@ -229,7 +259,7 @@ void resample_nearest(resample_t * r) } } -void resample_bilinear(resample_t * r) +void resample_bilinear_s16(resample_t * r) { signed short *i_ptr, *o_ptr; int o_count = 0; @@ -278,7 +308,7 @@ void resample_bilinear(resample_t * r) } } -void resample_sinc_slow(resample_t * r) +void resample_sinc_slow_s16(resample_t * r) { signed short *i_ptr, *o_ptr; int i, j; @@ -336,13 +366,15 @@ void resample_sinc_slow(resample_t * r) a += r->o_inc; } } +#undef GETBUF memcpy(r->buffer, i_ptr + (r->i_samples - r->filter_length) * r->channels, r->filter_length * 2 * r->channels); } -void resample_sinc(resample_t * r) +/* only works for channels == 2 ???? */ +void resample_sinc_s16(resample_t * r) { double *ptr; signed short *o_ptr; @@ -392,9 +424,6 @@ void resample_sinc(resample_t * r) } } - - - /* * Resampling audio is best done using a sinc() filter. * @@ -436,7 +465,7 @@ static functable_t *ft; double out_tmp[10000]; -static void resample_sinc_ft(resample_t * r) +void resample_sinc_ft_s16(resample_t * r) { double *ptr; signed short *o_ptr; @@ -530,6 +559,316 @@ static void resample_sinc_ft(resample_t * r) } } +/******** + ** float code below + ********/ + + +void resample_nearest_float(resample_t * r) +{ + float *i_ptr, *o_ptr; + int i_count = 0; + double a; + int i; + + i_ptr = (float *) r->i_buf; + o_ptr = (float *) r->o_buf; + + a = r->o_start; + i_count = 0; +#define SCALE_LOOP(COPY,INC) \ + for (i = 0; i < r->o_samples; i++) { \ + COPY; \ + a += r->o_inc; \ + while (a >= 1) { \ + a -= 1; \ + i_ptr+=INC; \ + i_count++; \ + } \ + o_ptr+=INC; \ + } + + switch (r->channels) { + case 1: + SCALE_LOOP(o_ptr[0] = i_ptr[0], 1); + break; + case 2: + SCALE_LOOP(o_ptr[0] = i_ptr[0]; + o_ptr[1] = i_ptr[1], 2); + break; + default: + { + int n, n_chan = r->channels; + + SCALE_LOOP(for (n = 0; n < n_chan; n++) o_ptr[n] = + i_ptr[n], n_chan); + } + } + if (i_count != r->i_samples) { + printf("handled %d in samples (expected %d)\n", i_count, + r->i_samples); + } +} + +void resample_bilinear_float(resample_t * r) +{ + float *i_ptr, *o_ptr; + int o_count = 0; + double b; + int i; + double acc0, acc1; + + i_ptr = (float *) r->i_buf; + o_ptr = (float *) r->o_buf; + + acc0 = r->acc[0]; + acc1 = r->acc[1]; + b = r->i_start; + for (i = 0; i < r->i_samples; i++) { + b += r->i_inc; + /*printf("in %d\n",i_ptr[0]); */ + if(b>=2){ + printf("not expecting b>=2\n"); + } + if (b >= 1) { + acc0 += (1.0 - (b-r->i_inc)) * i_ptr[0]; + acc1 += (1.0 - (b-r->i_inc)) * i_ptr[1]; + + o_ptr[0] = acc0; + /*printf("out %d\n",o_ptr[0]); */ + o_ptr[1] = acc1; + o_ptr += 2; + o_count++; + + b -= 1.0; + + acc0 = b * i_ptr[0]; + acc1 = b * i_ptr[1]; + } else { + acc0 += i_ptr[0] * r->i_inc; + acc1 += i_ptr[1] * r->i_inc; + } + i_ptr += 2; + } + r->acc[0] = acc0; + r->acc[1] = acc1; + + if (o_count != r->o_samples) { + printf("handled %d out samples (expected %d)\n", o_count, + r->o_samples); + } +} + +void resample_sinc_slow_float(resample_t * r) +{ + float *i_ptr, *o_ptr; + int i, j; + double c0, c1; + double a; + int start; + double center; + double weight; + + if (!r->buffer) { + int size = r->filter_length * sizeof(float) * r->channels; + + printf("resample temp buffer\n"); + r->buffer = malloc(size); + memset(r->buffer, 0, size); + } + + i_ptr = (float *) r->i_buf; + o_ptr = (float *) r->o_buf; + + a = r->i_start; +#define GETBUF(index,chan) (((index)<0) \ + ? ((float *)(r->buffer))[((index)+r->filter_length)*2+(chan)] \ + : i_ptr[(index)*2+(chan)]) + { + double sinx, cosx, sind, cosd; + double x, d; + double t; + + for (i = 0; i < r->o_samples; i++) { + start = floor(a) - r->filter_length; + center = a - r->halftaps; + x = M_PI * (start - center) * r->o_inc; + sinx = sin(M_PI * (start - center) * r->o_inc); + cosx = cos(M_PI * (start - center) * r->o_inc); + d = M_PI * r->o_inc; + sind = sin(M_PI * r->o_inc); + cosd = cos(M_PI * r->o_inc); + c0 = 0; + c1 = 0; + for (j = 0; j < r->filter_length; j++) { + weight = (x==0)?1:(sinx/x); +/*printf("j %d sin %g cos %g\n",j,sinx,cosx); */ +/*printf("j %d sin %g x %g sinc %g\n",j,sinx,x,weight); */ + c0 += weight * GETBUF((start + j), 0); + c1 += weight * GETBUF((start + j), 1); + t = cosx * cosd - sinx * sind; + sinx = cosx * sind + sinx * cosd; + cosx = t; + x += d; + } + o_ptr[0] = c0; + o_ptr[1] = c1; + o_ptr += 2; + a += r->o_inc; + } + } +#undef GETBUF + + memcpy(r->buffer, + i_ptr + (r->i_samples - r->filter_length) * r->channels, + r->filter_length * sizeof(float) * r->channels); +} + +/* only works for channels == 2 ???? */ +void resample_sinc_float(resample_t * r) +{ + double *ptr; + float *o_ptr; + int i, j; + double c0, c1; + double a; + int start; + double center; + double weight; + double x0, x, d; + double scale; + + ptr = (double *) r->buffer; + o_ptr = (float *) r->o_buf; + + /* scale provides a cutoff frequency for the low + * pass filter aspects of sinc(). scale=M_PI + * will cut off at the input frequency, which is + * good for up-sampling, but will cause aliasing + * for downsampling. Downsampling needs to be + * cut off at o_rate, thus scale=M_PI*r->i_inc. */ + /* actually, it needs to be M_PI*r->i_inc*r->i_inc. + * Need to research why. */ + scale = M_PI*r->i_inc; + for (i = 0; i < r->o_samples; i++) { + a = r->o_start + i * r->o_inc; + start = floor(a - r->halftaps); +/*printf("%d: a=%g start=%d end=%d\n",i,a,start,start+r->filter_length-1); */ + center = a; + /*x = M_PI * (start - center) * r->o_inc; */ + /*d = M_PI * r->o_inc; */ + /*x = (start - center) * r->o_inc; */ + x0 = (start - center) * r->o_inc; + d = r->o_inc; + c0 = 0; + c1 = 0; + for (j = 0; j < r->filter_length; j++) { + x = x0 + d * j; + weight = sinc(x*scale*r->i_inc)*scale/M_PI; + weight *= window_func(x/r->halftaps*r->i_inc); + c0 += weight * ptr[(start + j + r->filter_length)*2 + 0]; + c1 += weight * ptr[(start + j + r->filter_length)*2 + 1]; + } + o_ptr[0] = c0; + o_ptr[1] = c1; + o_ptr += 2; + } +} + +void resample_sinc_ft_float(resample_t * r) +{ + double *ptr; + float *o_ptr; + int i; + /*int j; */ + double c0, c1; + /*double a; */ + double start_f, start_x; + int start; + double center; + /*double weight; */ + double x, d; + double scale; + int n = 4; + + scale = r->i_inc; /* cutoff at 22050 */ + /*scale = 1.0; // cutoff at 24000 */ + /*scale = r->i_inc * 0.5; // cutoff at 11025 */ + + if(!ft){ + ft = malloc(sizeof(*ft)); + memset(ft,0,sizeof(*ft)); + + ft->len = (r->filter_length + 2) * n; + ft->offset = 1.0 / n; + ft->start = - ft->len * 0.5 * ft->offset; + + ft->func_x = functable_sinc; + ft->func_dx = functable_dsinc; + ft->scale = M_PI * scale; + + ft->func2_x = functable_window_std; + ft->func2_dx = functable_window_dstd; + ft->scale2 = 1.0 / r->halftaps; + + functable_init(ft); + + /*printf("len=%d offset=%g start=%g\n",ft->len,ft->offset,ft->start); */ + } + + ptr = r->buffer; + o_ptr = (float *) r->o_buf; + + center = r->o_start; + start_x = center - r->halftaps; + start_f = floor(start_x); + start_x -= start_f; + start = start_f; + for (i = 0; i < r->o_samples; i++) { + /*start_f = floor(center - r->halftaps); */ +/*printf("%d: a=%g start=%d end=%d\n",i,a,start,start+r->filter_length-1); */ + x = start_f - center; + d = 1; + c0 = 0; + c1 = 0; +/*#define slow */ +#ifdef slow + for (j = 0; j < r->filter_length; j++) { + weight = functable_eval(ft,x)*scale; + /*weight = sinc(M_PI * scale * x)*scale*r->i_inc; */ + /*weight *= window_func(x / r->halftaps); */ + c0 += weight * ptr[(start + j + r->filter_length)*2 + 0]; + c1 += weight * ptr[(start + j + r->filter_length)*2 + 1]; + x += d; + } +#else + functable_fir2(ft, + &c0,&c1, + x, n, + ptr+(start + r->filter_length)*2, + r->filter_length); + c0 *= scale; + c1 *= scale; +#endif + + out_tmp[2 * i + 0] = c0; + out_tmp[2 * i + 1] = c1; + center += r->o_inc; + start_x += r->o_inc; + while(start_x>=1.0){ + start_f++; + start_x -= 1.0; + start++; + } + } + + if(r->channels==2){ + conv_float_double(r->o_buf,out_tmp,2 * r->o_samples); + }else{ + conv_float_double_sstr(r->o_buf,out_tmp,r->o_samples,2 * sizeof(double)); + } +} + static gboolean plugin_init (GModule *module, GstPlugin *plugin) { diff --git a/gst-libs/gst/resample/resample.h b/gst-libs/gst/resample/resample.h index 1cc36edd..ac6c1547 100644 --- a/gst-libs/gst/resample/resample.h +++ b/gst-libs/gst/resample/resample.h @@ -21,16 +21,27 @@ #ifndef __RESAMPLE_H__ #define __RESAMPLE_H__ -#include +typedef enum { + RESAMPLE_NEAREST = 0, + RESAMPLE_BILINEAR, + RESAMPLE_SINC_SLOW, + RESAMPLE_SINC, +} resample_method; + +typedef enum { + RESAMPLE_S16 = 0, + RESAMPLE_FLOAT +} resample_format; typedef struct resample_s resample_t; struct resample_s { /* parameters */ - int method; + resample_method method; int channels; int verbose; + resample_format format; int filter_length; @@ -75,85 +86,11 @@ struct resample_s { double ack; }; -enum{ - RESAMPLE_NEAREST = 0, - RESAMPLE_BILINEAR, - RESAMPLE_SINC_SLOW, - RESAMPLE_SINC, -}; - void resample_init(resample_t *r); + void resample_reinit(resample_t *r); void resample_scale(resample_t *r, void *i_buf, unsigned int size); -void resample_nearest(resample_t *r); -void resample_bilinear(resample_t *r); -void resample_sinc(resample_t *r); -void resample_sinc_slow(resample_t *r); - - -typedef struct functable_s functable_t; -struct functable_s { - double start; - double offset; - int len; - - double invoffset; - - double scale; - double scale2; - - double (*func_x)(void *,double x); - double (*func_dx)(void *,double x); - - double (*func2_x)(void *,double x); - double (*func2_dx)(void *,double x); - - double *fx; - double *fdx; - - void *priv; -}; - -void functable_init(functable_t *t); -double functable_eval(functable_t *t,double x); - -double functable_fir(functable_t *t,double x0,int n,double *data,int len); -void functable_fir2(functable_t *t,double *r0, double *r1, double x0, - int n,double *data,int len); - -double functable_sinc(void *p, double x); -double functable_dsinc(void *p, double x); -double functable_window_std(void *p, double x); -double functable_window_dstd(void *p, double x); -double functable_window_boxcar(void *p, double x); -double functable_window_dboxcar(void *p, double x); - -/* math lib stuff */ - -void conv_double_short_table(double *dest, short *src, int n); -void conv_double_short_unroll(double *dest, short *src, int n); -void conv_double_short_ref(double *dest, short *src, int n); -#ifdef HAVE_CPU_PPC -void conv_double_short_altivec(double *dest, short *src, int n); -#endif - -void conv_short_double_ref(short *dest, double *src, int n); -#ifdef HAVE_CPU_PPC -void conv_short_double_ppcasm(short *dest, double *src, int n); -#endif - -#ifdef HAVE_CPU_PPC -#define conv_double_short conv_double_short_table -#define conv_short_double conv_short_double_ppcasm -#else -#define conv_double_short conv_double_short_ref -#define conv_short_double conv_short_double_ref -#endif - -void conv_double_short_dstr(double *dest, short *src, int n, int dstr); -void conv_short_double_sstr(short *dest, double *src, int n, int dstr); - #endif /* __RESAMPLE_H__ */ -- cgit v1.2.1