2 * Copyright (C) <2001> David A. Schleef <ds@schleef.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
27 #include <gst/gstplugin.h>
28 #include <gst/gstversion.h>
30 inline double sinc(double x)
36 inline double window_func(double x)
42 signed short double_to_s16(double x)
55 signed short double_to_s16_ppcasm(double x)
66 void resample_init(resample_t * r)
69 if(r->filter_length&1){
72 r->o_start = r->o_inc * 0.5;
75 memset(r->acc, 0, sizeof(r->acc));
80 void resample_reinit(resample_t * r)
82 /* i_inc is the number of samples that the output increments for
83 * each input sample. o_inc is the opposite. */
84 r->i_inc = (double) r->o_rate / r->i_rate;
85 r->o_inc = (double) r->i_rate / r->o_rate;
87 r->halftaps = (r->filter_length - 1.0) * 0.5;
89 if (r->format == RESAMPLE_S16) {
92 case RESAMPLE_NEAREST:
93 r->scale = resample_nearest_s16;
95 case RESAMPLE_BILINEAR:
96 r->scale = resample_bilinear_s16;
98 case RESAMPLE_SINC_SLOW:
99 r->scale = resample_sinc_s16;
102 r->scale = resample_sinc_ft_s16;
105 } else if (r->format == RESAMPLE_FLOAT) {
108 case RESAMPLE_NEAREST:
109 r->scale = resample_nearest_float;
111 case RESAMPLE_BILINEAR:
112 r->scale = resample_bilinear_float;
114 case RESAMPLE_SINC_SLOW:
115 r->scale = resample_sinc_float;
118 r->scale = resample_sinc_ft_float;
122 fprintf (stderr, "resample: Unexpected format \"%d\"\n", r->format);
127 * Prepare to be confused.
129 * We keep a "timebase" that is based on output samples. The zero
130 * of the timebase cooresponds to the next output sample that will
133 * i_start is the "time" that corresponds to the first input sample
134 * in an incoming buffer. Since the output depends on input samples
135 * ahead in time, i_start will tend to be around halftaps.
137 * i_start_buf is the time of the first sample in the temporary
140 void resample_scale(resample_t * r, void *i_buf, unsigned int i_size)
146 r->i_samples = i_size / 2 / r->channels;
148 r->i_start_buf = r->i_start - r->filter_length * r->i_inc;
150 /* i_start is the offset (in a given output sample) that is the
151 * beginning of the current input buffer */
152 r->i_end = r->i_start + r->i_inc * r->i_samples;
154 r->o_samples = floor(r->i_end - r->halftaps * r->i_inc);
156 o_size = r->o_samples * r->channels * 2;
157 r->o_buf = r->get_buffer(r->priv, o_size);
160 printf("resample_scale: i_buf=%p i_size=%d\n",
162 printf("resample_scale: i_samples=%d o_samples=%d i_inc=%g o_buf=%p\n",
163 r->i_samples, r->o_samples, r->i_inc, r->o_buf);
164 printf("resample_scale: i_start=%g i_end=%g o_start=%g\n",
165 r->i_start, r->i_end, r->o_start);
168 if ((r->filter_length + r->i_samples)*sizeof(double)*2 > r->buffer_len) {
169 int size = (r->filter_length + r->i_samples) * sizeof(double) * 2;
172 printf("resample temp buffer size=%d\n",size);
174 if(r->buffer)free(r->buffer);
175 r->buffer_len = size;
176 r->buffer = malloc(size);
177 memset(r->buffer, 0, size);
180 if (r->format==RESAMPLE_S16) {
183 r->buffer + r->filter_length * sizeof(double) * 2,
184 r->i_buf, r->i_samples * 2);
186 conv_double_short_dstr(
187 r->buffer + r->filter_length * sizeof(double) * 2,
188 r->i_buf, r->i_samples, sizeof(double) * 2);
190 } else if (r->format==RESAMPLE_FLOAT) {
193 r->buffer + r->filter_length * sizeof(double) * 2,
194 r->i_buf, r->i_samples * 2);
196 conv_double_float_dstr(
197 r->buffer + r->filter_length * sizeof(double) * 2,
198 r->i_buf, r->i_samples, sizeof(double) * 2);
205 r->buffer + r->i_samples * sizeof(double) * 2,
206 r->filter_length * sizeof(double) * 2);
209 r->i_start += r->i_samples * r->i_inc;
210 r->o_start += r->o_samples * r->o_inc - r->i_samples;
212 /* adjusting timebase zero */
213 r->i_start -= r->o_samples;
216 void resample_nearest_s16(resample_t * r)
218 signed short *i_ptr, *o_ptr;
223 i_ptr = (signed short *) r->i_buf;
224 o_ptr = (signed short *) r->o_buf;
228 #define SCALE_LOOP(COPY,INC) \
229 for (i = 0; i < r->o_samples; i++) { \
240 switch (r->channels) {
242 SCALE_LOOP(o_ptr[0] = i_ptr[0], 1);
245 SCALE_LOOP(o_ptr[0] = i_ptr[0];
246 o_ptr[1] = i_ptr[1], 2);
250 int n, n_chan = r->channels;
252 SCALE_LOOP(for (n = 0; n < n_chan; n++) o_ptr[n] =
256 if (i_count != r->i_samples) {
257 printf("handled %d in samples (expected %d)\n", i_count,
262 void resample_bilinear_s16(resample_t * r)
264 signed short *i_ptr, *o_ptr;
270 i_ptr = (signed short *) r->i_buf;
271 o_ptr = (signed short *) r->o_buf;
276 for (i = 0; i < r->i_samples; i++) {
278 /*printf("in %d\n",i_ptr[0]); */
280 printf("not expecting b>=2\n");
283 acc0 += (1.0 - (b-r->i_inc)) * i_ptr[0];
284 acc1 += (1.0 - (b-r->i_inc)) * i_ptr[1];
286 o_ptr[0] = rint(acc0);
287 /*printf("out %d\n",o_ptr[0]); */
288 o_ptr[1] = rint(acc1);
297 acc0 += i_ptr[0] * r->i_inc;
298 acc1 += i_ptr[1] * r->i_inc;
305 if (o_count != r->o_samples) {
306 printf("handled %d out samples (expected %d)\n", o_count,
311 void resample_sinc_slow_s16(resample_t * r)
313 signed short *i_ptr, *o_ptr;
322 int size = r->filter_length * 2 * r->channels;
324 printf("resample temp buffer\n");
325 r->buffer = malloc(size);
326 memset(r->buffer, 0, size);
329 i_ptr = (signed short *) r->i_buf;
330 o_ptr = (signed short *) r->o_buf;
333 #define GETBUF(index,chan) (((index)<0) \
334 ? ((short *)(r->buffer))[((index)+r->filter_length)*2+(chan)] \
335 : i_ptr[(index)*2+(chan)])
337 double sinx, cosx, sind, cosd;
341 for (i = 0; i < r->o_samples; i++) {
342 start = floor(a) - r->filter_length;
343 center = a - r->halftaps;
344 x = M_PI * (start - center) * r->o_inc;
345 sinx = sin(M_PI * (start - center) * r->o_inc);
346 cosx = cos(M_PI * (start - center) * r->o_inc);
348 sind = sin(M_PI * r->o_inc);
349 cosd = cos(M_PI * r->o_inc);
352 for (j = 0; j < r->filter_length; j++) {
353 weight = (x==0)?1:(sinx/x);
354 /*printf("j %d sin %g cos %g\n",j,sinx,cosx); */
355 /*printf("j %d sin %g x %g sinc %g\n",j,sinx,x,weight); */
356 c0 += weight * GETBUF((start + j), 0);
357 c1 += weight * GETBUF((start + j), 1);
358 t = cosx * cosd - sinx * sind;
359 sinx = cosx * sind + sinx * cosd;
372 i_ptr + (r->i_samples - r->filter_length) * r->channels,
373 r->filter_length * 2 * r->channels);
376 /* only works for channels == 2 ???? */
377 void resample_sinc_s16(resample_t * r)
390 ptr = (double *) r->buffer;
391 o_ptr = (signed short *) r->o_buf;
393 /* scale provides a cutoff frequency for the low
394 * pass filter aspects of sinc(). scale=M_PI
395 * will cut off at the input frequency, which is
396 * good for up-sampling, but will cause aliasing
397 * for downsampling. Downsampling needs to be
398 * cut off at o_rate, thus scale=M_PI*r->i_inc. */
399 /* actually, it needs to be M_PI*r->i_inc*r->i_inc.
400 * Need to research why. */
401 scale = M_PI*r->i_inc;
402 for (i = 0; i < r->o_samples; i++) {
403 a = r->o_start + i * r->o_inc;
404 start = floor(a - r->halftaps);
405 /*printf("%d: a=%g start=%d end=%d\n",i,a,start,start+r->filter_length-1); */
407 /*x = M_PI * (start - center) * r->o_inc; */
408 /*d = M_PI * r->o_inc; */
409 /*x = (start - center) * r->o_inc; */
410 x0 = (start - center) * r->o_inc;
414 for (j = 0; j < r->filter_length; j++) {
416 weight = sinc(x*scale*r->i_inc)*scale/M_PI;
417 weight *= window_func(x/r->halftaps*r->i_inc);
418 c0 += weight * ptr[(start + j + r->filter_length)*2 + 0];
419 c1 += weight * ptr[(start + j + r->filter_length)*2 + 1];
421 o_ptr[0] = double_to_s16(c0);
422 o_ptr[1] = double_to_s16(c1);
428 * Resampling audio is best done using a sinc() filter.
431 * out[t] = Sum( in[t'] * sinc((t-t')/delta_t), all t')
433 * The immediate problem with this algorithm is that it involves a
434 * sum over an infinite number of input samples, both in the past
435 * and future. Note that even though sinc(x) is bounded by 1/x,
436 * and thus decays to 0 for large x, since sum(x,{x=0,1..,n}) diverges
437 * as log(n), we need to be careful about convergence. This is
438 * typically done by using a windowing function, which also makes
439 * the sum over a finite number of input samples.
441 * The next problem is computational: sinc(), and especially
442 * sinc() multiplied by a non-trivial windowing function is expensive
443 * to calculate, and also difficult to find SIMD optimizations. Since
444 * the time increment on input and output is different, it is not
445 * possible to use a FIR filter, because the taps would have to be
446 * recalculated for every t.
448 * To get around the expense of calculating sinc() for every point,
449 * we pre-calculate sinc() at a number of points, and then interpolate
450 * for the values we want in calculations. The interpolation method
451 * chosen is bi-cubic, which requires both the evalated function and
452 * its derivative at every pre-sampled point. Also, if the sampled
453 * points are spaced commensurate with the input delta_t, we notice
454 * that the interpolating weights are the same for every input point.
455 * This decreases the number of operations to 4 multiplies and 4 adds
456 * for each tap, regardless of the complexity of the filtering function.
458 * At this point, it is possible to rearrange the problem as the sum
459 * of 4 properly weghted FIR filters. Typical SIMD computation units
460 * are highly optimized for FIR filters, making long filter lengths
464 static functable_t *ft;
466 double out_tmp[10000];
468 void resample_sinc_ft_s16(resample_t * r)
476 double start_f, start_x;
484 scale = r->i_inc; /* cutoff at 22050 */
485 /*scale = 1.0; // cutoff at 24000 */
486 /*scale = r->i_inc * 0.5; // cutoff at 11025 */
489 ft = malloc(sizeof(*ft));
490 memset(ft,0,sizeof(*ft));
492 ft->len = (r->filter_length + 2) * n;
493 ft->offset = 1.0 / n;
494 ft->start = - ft->len * 0.5 * ft->offset;
496 ft->func_x = functable_sinc;
497 ft->func_dx = functable_dsinc;
498 ft->scale = M_PI * scale;
500 ft->func2_x = functable_window_std;
501 ft->func2_dx = functable_window_dstd;
502 ft->scale2 = 1.0 / r->halftaps;
506 /*printf("len=%d offset=%g start=%g\n",ft->len,ft->offset,ft->start); */
510 o_ptr = (signed short *) r->o_buf;
513 start_x = center - r->halftaps;
514 start_f = floor(start_x);
517 for (i = 0; i < r->o_samples; i++) {
518 /*start_f = floor(center - r->halftaps); */
519 /*printf("%d: a=%g start=%d end=%d\n",i,a,start,start+r->filter_length-1); */
520 x = start_f - center;
526 for (j = 0; j < r->filter_length; j++) {
527 weight = functable_eval(ft,x)*scale;
528 /*weight = sinc(M_PI * scale * x)*scale*r->i_inc; */
529 /*weight *= window_func(x / r->halftaps); */
530 c0 += weight * ptr[(start + j + r->filter_length)*2 + 0];
531 c1 += weight * ptr[(start + j + r->filter_length)*2 + 1];
538 ptr+(start + r->filter_length)*2,
544 out_tmp[2 * i + 0] = c0;
545 out_tmp[2 * i + 1] = c1;
556 conv_short_double(r->o_buf,out_tmp,2 * r->o_samples);
558 conv_short_double_sstr(r->o_buf,out_tmp,r->o_samples,2 * sizeof(double));
567 void resample_nearest_float(resample_t * r)
569 float *i_ptr, *o_ptr;
574 i_ptr = (float *) r->i_buf;
575 o_ptr = (float *) r->o_buf;
579 #define SCALE_LOOP(COPY,INC) \
580 for (i = 0; i < r->o_samples; i++) { \
591 switch (r->channels) {
593 SCALE_LOOP(o_ptr[0] = i_ptr[0], 1);
596 SCALE_LOOP(o_ptr[0] = i_ptr[0];
597 o_ptr[1] = i_ptr[1], 2);
601 int n, n_chan = r->channels;
603 SCALE_LOOP(for (n = 0; n < n_chan; n++) o_ptr[n] =
607 if (i_count != r->i_samples) {
608 printf("handled %d in samples (expected %d)\n", i_count,
613 void resample_bilinear_float(resample_t * r)
615 float *i_ptr, *o_ptr;
621 i_ptr = (float *) r->i_buf;
622 o_ptr = (float *) r->o_buf;
627 for (i = 0; i < r->i_samples; i++) {
629 /*printf("in %d\n",i_ptr[0]); */
631 printf("not expecting b>=2\n");
634 acc0 += (1.0 - (b-r->i_inc)) * i_ptr[0];
635 acc1 += (1.0 - (b-r->i_inc)) * i_ptr[1];
638 /*printf("out %d\n",o_ptr[0]); */
648 acc0 += i_ptr[0] * r->i_inc;
649 acc1 += i_ptr[1] * r->i_inc;
656 if (o_count != r->o_samples) {
657 printf("handled %d out samples (expected %d)\n", o_count,
662 void resample_sinc_slow_float(resample_t * r)
664 float *i_ptr, *o_ptr;
673 int size = r->filter_length * sizeof(float) * r->channels;
675 printf("resample temp buffer\n");
676 r->buffer = malloc(size);
677 memset(r->buffer, 0, size);
680 i_ptr = (float *) r->i_buf;
681 o_ptr = (float *) r->o_buf;
684 #define GETBUF(index,chan) (((index)<0) \
685 ? ((float *)(r->buffer))[((index)+r->filter_length)*2+(chan)] \
686 : i_ptr[(index)*2+(chan)])
688 double sinx, cosx, sind, cosd;
692 for (i = 0; i < r->o_samples; i++) {
693 start = floor(a) - r->filter_length;
694 center = a - r->halftaps;
695 x = M_PI * (start - center) * r->o_inc;
696 sinx = sin(M_PI * (start - center) * r->o_inc);
697 cosx = cos(M_PI * (start - center) * r->o_inc);
699 sind = sin(M_PI * r->o_inc);
700 cosd = cos(M_PI * r->o_inc);
703 for (j = 0; j < r->filter_length; j++) {
704 weight = (x==0)?1:(sinx/x);
705 /*printf("j %d sin %g cos %g\n",j,sinx,cosx); */
706 /*printf("j %d sin %g x %g sinc %g\n",j,sinx,x,weight); */
707 c0 += weight * GETBUF((start + j), 0);
708 c1 += weight * GETBUF((start + j), 1);
709 t = cosx * cosd - sinx * sind;
710 sinx = cosx * sind + sinx * cosd;
723 i_ptr + (r->i_samples - r->filter_length) * r->channels,
724 r->filter_length * sizeof(float) * r->channels);
727 /* only works for channels == 2 ???? */
728 void resample_sinc_float(resample_t * r)
741 ptr = (double *) r->buffer;
742 o_ptr = (float *) r->o_buf;
744 /* scale provides a cutoff frequency for the low
745 * pass filter aspects of sinc(). scale=M_PI
746 * will cut off at the input frequency, which is
747 * good for up-sampling, but will cause aliasing
748 * for downsampling. Downsampling needs to be
749 * cut off at o_rate, thus scale=M_PI*r->i_inc. */
750 /* actually, it needs to be M_PI*r->i_inc*r->i_inc.
751 * Need to research why. */
752 scale = M_PI*r->i_inc;
753 for (i = 0; i < r->o_samples; i++) {
754 a = r->o_start + i * r->o_inc;
755 start = floor(a - r->halftaps);
756 /*printf("%d: a=%g start=%d end=%d\n",i,a,start,start+r->filter_length-1); */
758 /*x = M_PI * (start - center) * r->o_inc; */
759 /*d = M_PI * r->o_inc; */
760 /*x = (start - center) * r->o_inc; */
761 x0 = (start - center) * r->o_inc;
765 for (j = 0; j < r->filter_length; j++) {
767 weight = sinc(x*scale*r->i_inc)*scale/M_PI;
768 weight *= window_func(x/r->halftaps*r->i_inc);
769 c0 += weight * ptr[(start + j + r->filter_length)*2 + 0];
770 c1 += weight * ptr[(start + j + r->filter_length)*2 + 1];
778 void resample_sinc_ft_float(resample_t * r)
786 double start_f, start_x;
794 scale = r->i_inc; /* cutoff at 22050 */
795 /*scale = 1.0; // cutoff at 24000 */
796 /*scale = r->i_inc * 0.5; // cutoff at 11025 */
799 ft = malloc(sizeof(*ft));
800 memset(ft,0,sizeof(*ft));
802 ft->len = (r->filter_length + 2) * n;
803 ft->offset = 1.0 / n;
804 ft->start = - ft->len * 0.5 * ft->offset;
806 ft->func_x = functable_sinc;
807 ft->func_dx = functable_dsinc;
808 ft->scale = M_PI * scale;
810 ft->func2_x = functable_window_std;
811 ft->func2_dx = functable_window_dstd;
812 ft->scale2 = 1.0 / r->halftaps;
816 /*printf("len=%d offset=%g start=%g\n",ft->len,ft->offset,ft->start); */
820 o_ptr = (float *) r->o_buf;
823 start_x = center - r->halftaps;
824 start_f = floor(start_x);
827 for (i = 0; i < r->o_samples; i++) {
828 /*start_f = floor(center - r->halftaps); */
829 /*printf("%d: a=%g start=%d end=%d\n",i,a,start,start+r->filter_length-1); */
830 x = start_f - center;
836 for (j = 0; j < r->filter_length; j++) {
837 weight = functable_eval(ft,x)*scale;
838 /*weight = sinc(M_PI * scale * x)*scale*r->i_inc; */
839 /*weight *= window_func(x / r->halftaps); */
840 c0 += weight * ptr[(start + j + r->filter_length)*2 + 0];
841 c1 += weight * ptr[(start + j + r->filter_length)*2 + 1];
848 ptr+(start + r->filter_length)*2,
854 out_tmp[2 * i + 0] = c0;
855 out_tmp[2 * i + 1] = c1;
866 conv_float_double(r->o_buf,out_tmp,2 * r->o_samples);
868 conv_float_double_sstr(r->o_buf,out_tmp,r->o_samples,2 * sizeof(double));
873 plugin_init (GstPlugin *plugin)
882 "Resampling routines for use in audio plugins",