2 * Copyright (C) <2015> Wim Taymans <wim.taymans@gmail.com>
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 (at your option) 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., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
32 #include "audio-resampler.h"
39 typedef void (*MakeTapsFunc) (GstAudioResampler * resampler, Tap * t, gint j);
40 typedef void (*ResampleFunc) (GstAudioResampler * resampler, gpointer in[],
41 gsize in_len, gpointer out[], gsize out_len, gsize * consumed);
42 typedef void (*DeinterleaveFunc) (GstAudioResampler * resampler,
43 gpointer * sbuf, gpointer in[], gsize in_frames);
45 #define MEM_ALIGN(m,a) ((gint8 *)((guintptr)((gint8 *)(m) + ((a)-1)) & ~((a)-1)))
47 #define TAPS_OVERREAD 16
49 struct _GstAudioResampler
51 GstAudioResamplerMethod method;
52 GstAudioResamplerFlags flags;
53 GstAudioFormat format;
54 GstStructure *options;
66 GstAudioResamplerFilterMode filter_mode;
67 guint filter_threshold;
68 GstAudioResamplerFilterInterpolation filter_interpolation;
80 DeinterleaveFunc deinterleave;
81 ResampleFunc resample;
97 GST_DEBUG_CATEGORY_STATIC (audio_resampler_debug);
98 #define GST_CAT_DEFAULT audio_resampler_debug
101 * SECTION:gstaudioresampler
102 * @short_description: Utility structure for resampler information
104 * #GstAudioResampler is a structure which holds the information
105 * required to perform various kinds of resampling filtering.
109 static const gint oversample_qualities[] = {
110 4, 4, 4, 8, 8, 16, 16, 16, 16, 32, 32
116 gdouble downsample_cutoff_factor;
117 gdouble stopband_attenuation;
118 gdouble transition_bandwidth;
121 static const KaiserQualityMap kaiser_qualities[] = {
122 {0.860, 0.96511, 60, 0.7}, /* 8 taps */
123 {0.880, 0.96591, 65, 0.29}, /* 16 taps */
124 {0.910, 0.96923, 70, 0.145}, /* 32 taps */
125 {0.920, 0.97600, 80, 0.105}, /* 48 taps */
126 {0.940, 0.97979, 85, 0.087}, /* 64 taps default quality */
127 {0.940, 0.98085, 95, 0.077}, /* 80 taps */
128 {0.945, 0.99471, 100, 0.068}, /* 96 taps */
129 {0.950, 1.0, 105, 0.055}, /* 128 taps */
130 {0.960, 1.0, 110, 0.045}, /* 160 taps */
131 {0.968, 1.0, 115, 0.039}, /* 192 taps */
132 {0.975, 1.0, 120, 0.0305} /* 256 taps */
139 } BlackmanQualityMap;
141 static const BlackmanQualityMap blackman_qualities[] = {
146 {48, 0.85,}, /* default */
155 #define DEFAULT_QUALITY GST_AUDIO_RESAMPLER_QUALITY_DEFAULT
156 #define DEFAULT_OPT_CUBIC_B 1.0
157 #define DEFAULT_OPT_CUBIC_C 0.0
158 #define DEFAULT_OPT_FILTER_MODE GST_AUDIO_RESAMPLER_FILTER_MODE_AUTO
159 #define DEFAULT_OPT_FILTER_MODE_THRESHOLD 1048576
160 #define DEFAULT_OPT_FILTER_INTERPOLATION GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_LINEAR
161 #define DEFAULT_OPT_FILTER_OVERSAMPLE 8
162 #define DEFAULT_OPT_MAX_PHASE_ERROR 0.1
165 get_opt_double (GstStructure * options, const gchar * name, gdouble def)
168 if (!options || !gst_structure_get_double (options, name, &res))
174 get_opt_int (GstStructure * options, const gchar * name, gint def)
177 if (!options || !gst_structure_get_int (options, name, &res))
183 get_opt_enum (GstStructure * options, const gchar * name, GType type, gint def)
186 if (!options || !gst_structure_get_enum (options, name, type, &res))
192 #define GET_OPT_CUTOFF(options,def) get_opt_double(options, \
193 GST_AUDIO_RESAMPLER_OPT_CUTOFF,def)
194 #define GET_OPT_DOWN_CUTOFF_FACTOR(options,def) get_opt_double(options, \
195 GST_AUDIO_RESAMPLER_OPT_DOWN_CUTOFF_FACTOR, def)
196 #define GET_OPT_STOP_ATTENUATION(options,def) get_opt_double(options, \
197 GST_AUDIO_RESAMPLER_OPT_STOP_ATTENUATION, def)
198 #define GET_OPT_TRANSITION_BANDWIDTH(options,def) get_opt_double(options, \
199 GST_AUDIO_RESAMPLER_OPT_TRANSITION_BANDWIDTH, def)
200 #define GET_OPT_CUBIC_B(options) get_opt_double(options, \
201 GST_AUDIO_RESAMPLER_OPT_CUBIC_B, DEFAULT_OPT_CUBIC_B)
202 #define GET_OPT_CUBIC_C(options) get_opt_double(options, \
203 GST_AUDIO_RESAMPLER_OPT_CUBIC_C, DEFAULT_OPT_CUBIC_C)
204 #define GET_OPT_N_TAPS(options,def) get_opt_int(options, \
205 GST_AUDIO_RESAMPLER_OPT_N_TAPS, def)
206 #define GET_OPT_FILTER_MODE(options) get_opt_enum(options, \
207 GST_AUDIO_RESAMPLER_OPT_FILTER_MODE, GST_TYPE_AUDIO_RESAMPLER_FILTER_MODE, \
208 DEFAULT_OPT_FILTER_MODE)
209 #define GET_OPT_FILTER_MODE_THRESHOLD(options) get_opt_int(options, \
210 GST_AUDIO_RESAMPLER_OPT_FILTER_MODE_THRESHOLD, DEFAULT_OPT_FILTER_MODE_THRESHOLD)
211 #define GET_OPT_FILTER_INTERPOLATION(options) get_opt_enum(options, \
212 GST_AUDIO_RESAMPLER_OPT_FILTER_INTERPOLATION, GST_TYPE_AUDIO_RESAMPLER_FILTER_INTERPOLATION, \
213 DEFAULT_OPT_FILTER_INTERPOLATION)
214 #define GET_OPT_FILTER_OVERSAMPLE(options) get_opt_int(options, \
215 GST_AUDIO_RESAMPLER_OPT_FILTER_OVERSAMPLE, DEFAULT_OPT_FILTER_OVERSAMPLE)
216 #define GET_OPT_MAX_PHASE_ERROR(options) get_opt_double(options, \
217 GST_AUDIO_RESAMPLER_OPT_MAX_PHASE_ERROR, DEFAULT_OPT_MAX_PHASE_ERROR)
220 #define bessel dbesi0
222 static inline gdouble
223 get_nearest_tap (gdouble x)
225 gdouble a = fabs (x);
233 static inline gdouble
234 get_linear_tap (gdouble x, gint n_taps)
238 a = fabs (x) / n_taps;
246 static inline gdouble
247 get_cubic_tap (gdouble x, gint n_taps, gdouble b, gdouble c)
251 a = fabs (x * 4.0) / n_taps;
256 return ((12.0 - 9.0 * b - 6.0 * c) * a3 +
257 (-18.0 + 12.0 * b + 6.0 * c) * a2 + (6.0 - 2.0 * b)) / 6.0;
259 return ((-b - 6.0 * c) * a3 +
260 (6.0 * b + 30.0 * c) * a2 +
261 (-12.0 * b - 48.0 * c) * a + (8.0 * b + 24.0 * c)) / 6.0;
266 static inline gdouble
267 get_blackman_nuttall_tap (gdouble x, gint n_taps, gdouble Fc)
272 s = (y == 0.0 ? Fc : sin (y * Fc) / y);
274 w = 2.0 * y / n_taps + G_PI;
275 return s * (0.3635819 - 0.4891775 * cos (w) + 0.1365995 * cos (2 * w) -
276 0.0106411 * cos (3 * w));
279 static inline gdouble
280 get_kaiser_tap (gdouble x, gint n_taps, gdouble Fc, gdouble beta)
285 s = (y == 0.0 ? Fc : sin (y * Fc) / y);
287 w = 2.0 * x / n_taps;
288 return s * bessel (beta * sqrt (MAX (1 - w * w, 0)));
291 #define PRECISION_S16 14
292 #define PRECISION_S32 30
294 static inline gdouble
295 fill_taps (GstAudioResampler * resampler,
296 gdouble * tmpcoeff, gdouble x, gint n_taps, gint oversample)
298 gdouble weight = 0.0;
301 switch (resampler->method) {
302 case GST_AUDIO_RESAMPLER_METHOD_NEAREST:
303 for (i = 0; i < n_taps; i++)
304 weight += tmpcoeff[i] = get_nearest_tap (x + i / (double) oversample);
307 case GST_AUDIO_RESAMPLER_METHOD_LINEAR:
308 for (i = 0; i < n_taps; i++)
309 weight += tmpcoeff[i] =
310 get_linear_tap (x + i / (double) oversample, resampler->n_taps);
313 case GST_AUDIO_RESAMPLER_METHOD_CUBIC:
314 for (i = 0; i < n_taps; i++)
315 weight += tmpcoeff[i] =
316 get_cubic_tap (x + i / (double) oversample, resampler->n_taps,
317 resampler->b, resampler->c);
320 case GST_AUDIO_RESAMPLER_METHOD_BLACKMAN_NUTTALL:
321 for (i = 0; i < n_taps; i++)
322 weight += tmpcoeff[i] =
323 get_blackman_nuttall_tap (x + i / (double) oversample,
324 resampler->n_taps, resampler->cutoff);
327 case GST_AUDIO_RESAMPLER_METHOD_KAISER:
328 for (i = 0; i < n_taps; i++)
329 weight += tmpcoeff[i] =
330 get_kaiser_tap (x + i / (double) oversample, resampler->n_taps,
331 resampler->cutoff, resampler->kaiser_beta);
340 #define MAKE_CONVERT_TAPS_INT_FUNC(type, precision) \
342 convert_taps_##type (gdouble *tmpcoeff, type *taps, \
343 gdouble weight, gint n_taps) \
345 gdouble multiplier = (1 << precision); \
347 gdouble offset, l_offset, h_offset; \
348 gboolean exact = FALSE; \
349 /* Round to integer, but with an adjustable bias that we use to */ \
350 /* eliminate the DC error. */ \
354 for (i = 0; i < 32; i++) { \
356 for (j = 0; j < n_taps; j++) \
357 sum += taps[j] = floor (offset + tmpcoeff[j] * multiplier / weight); \
358 if (sum == (1 << precision)) { \
362 if (l_offset == h_offset) \
364 if (sum < (1 << precision)) { \
365 if (offset > l_offset) \
367 offset += (h_offset - l_offset) / 2; \
369 if (offset < h_offset) \
371 offset -= (h_offset - l_offset) / 2; \
375 GST_WARNING ("can't find exact taps"); \
378 #define MAKE_CONVERT_TAPS_FLOAT_FUNC(type) \
380 convert_taps_##type (gdouble *tmpcoeff, type *taps, \
381 gdouble weight, gint n_taps) \
384 for (i = 0; i < n_taps; i++) \
385 taps[i] = tmpcoeff[i] / weight; \
388 MAKE_CONVERT_TAPS_INT_FUNC (gint16, PRECISION_S16);
389 MAKE_CONVERT_TAPS_INT_FUNC (gint32, PRECISION_S32);
390 MAKE_CONVERT_TAPS_FLOAT_FUNC (gfloat);
391 MAKE_CONVERT_TAPS_FLOAT_FUNC (gdouble);
393 #define GET_TAPS_NONE_FUNC(type) \
394 static inline gpointer \
395 get_taps_##type##_none (GstAudioResampler * resampler, \
396 gint *samp_index, gint *samp_phase, type icoeff[4]) \
398 Tap *t = &resampler->taps[*samp_phase]; \
401 gint out_rate = resampler->out_rate; \
402 gdouble *tmpcoeff = resampler->tmpcoeff; \
403 gint n_taps = resampler->n_taps; \
405 if (G_LIKELY (t->taps)) { \
408 res = (gint8 *) resampler->coeff + *samp_phase * resampler->cstride; \
410 x = 1.0 - n_taps / 2 - (double) *samp_phase / out_rate; \
411 weight = fill_taps (resampler, tmpcoeff, x, n_taps, 1); \
412 convert_taps_##type (tmpcoeff, res, weight, n_taps); \
416 *samp_index += resampler->samp_inc; \
417 *samp_phase += resampler->samp_frac; \
418 if (*samp_phase >= out_rate) { \
419 *samp_phase -= out_rate; \
425 GET_TAPS_NONE_FUNC (gint16);
426 GET_TAPS_NONE_FUNC (gint32);
427 GET_TAPS_NONE_FUNC (gfloat);
428 GET_TAPS_NONE_FUNC (gdouble);
430 #define MAKE_COEFF_LINEAR_FLOAT_FUNC(type) \
432 make_coeff_##type##_linear (gint frac, gint out_rate, type *icoeff) \
434 type x = (type)frac / out_rate; \
435 icoeff[0] = icoeff[2] = 1.0 - x; \
436 icoeff[1] = icoeff[3] = x; \
438 #define MAKE_COEFF_LINEAR_INT_FUNC(type,type2,prec) \
440 make_coeff_##type##_linear (gint frac, gint out_rate, type *icoeff) \
442 type x = ((type2)frac << prec) / out_rate; \
443 icoeff[0] = icoeff[2] = (1 << prec) - x; \
444 icoeff[1] = icoeff[3] = x; \
447 MAKE_COEFF_LINEAR_INT_FUNC (gint16, gint32, PRECISION_S16);
448 MAKE_COEFF_LINEAR_INT_FUNC (gint32, gint64, PRECISION_S32);
449 MAKE_COEFF_LINEAR_FLOAT_FUNC (gfloat);
450 MAKE_COEFF_LINEAR_FLOAT_FUNC (gdouble);
452 #define GET_TAPS_LINEAR_FUNC(type) \
453 static inline gpointer \
454 get_taps_##type##_linear (GstAudioResampler * resampler, \
455 gint *samp_index, gint *samp_phase, type icoeff[4]) \
458 gint out_rate = resampler->out_rate; \
459 gint offset, frac, pos; \
461 pos = ((out_rate - 1) - *samp_phase) * resampler->oversample; \
462 offset = pos / out_rate; \
463 frac = pos % out_rate; \
465 res = (type *)resampler->coeff + offset; \
466 make_coeff_##type##_linear (frac, out_rate, icoeff); \
468 *samp_index += resampler->samp_inc; \
469 *samp_phase += resampler->samp_frac; \
470 if (*samp_phase >= out_rate) { \
471 *samp_phase -= out_rate; \
477 GET_TAPS_LINEAR_FUNC (gint16);
478 GET_TAPS_LINEAR_FUNC (gint32);
479 GET_TAPS_LINEAR_FUNC (gfloat);
480 GET_TAPS_LINEAR_FUNC (gdouble);
482 #define INNER_PRODUCT_INT_NONE_FUNC(type,type2,prec,limit) \
484 inner_product_##type##_none_1_c (type * o, const type * a, \
485 const type * b, gint len, const type *ic, gint oversample) \
490 for (i = 0; i < len; i++) \
491 res += (type2) a[i] * (type2) b[i]; \
493 res = (res + (1 << ((prec) - 1))) >> (prec); \
494 *o = CLAMP (res, -(limit), (limit) - 1); \
497 INNER_PRODUCT_INT_NONE_FUNC (gint16, gint32, PRECISION_S16, 1L << 15);
498 INNER_PRODUCT_INT_NONE_FUNC (gint32, gint64, PRECISION_S32, 1L << 31);
500 #define INNER_PRODUCT_INT_LINEAR_FUNC(type,type2,prec,limit) \
502 inner_product_##type##_linear_1_c (type * o, const type * a, \
503 const type * b, gint len, const type *ic, gint oversample) \
506 type2 res, res1 = 0, res2 = 0; \
508 for (i = 0; i < len; i++) { \
509 res1 += (type2) a[i] * (type2) b[i * oversample]; \
510 res2 += (type2) a[i] * (type2) b[i * oversample + 1]; \
512 res = (res1 >> (prec)) * ic[0] + (res2 >> (prec)) * ic[1]; \
513 res = (res + (1 << ((prec) - 1))) >> (prec); \
514 *o = CLAMP (res, -(limit), (limit) - 1); \
517 INNER_PRODUCT_INT_LINEAR_FUNC (gint16, gint32, PRECISION_S16, 1L << 15);
518 INNER_PRODUCT_INT_LINEAR_FUNC (gint32, gint64, PRECISION_S32, 1L << 31);
520 #define INNER_PRODUCT_FLOAT_NONE_FUNC(type) \
522 inner_product_##type##_none_1_c (type * o, const type * a, \
523 const type * b, gint len, const type *ic, gint oversample) \
528 for (i = 0; i < len; i++) \
529 res += a[i] * b[i]; \
534 INNER_PRODUCT_FLOAT_NONE_FUNC (gfloat);
535 INNER_PRODUCT_FLOAT_NONE_FUNC (gdouble);
537 #define INNER_PRODUCT_FLOAT_LINEAR_FUNC(type) \
539 inner_product_##type##_linear_1_c (type * o, const type * a, \
540 const type * b, gint len, const type *ic, gint oversample) \
543 type res1 = 0.0, res2 = 0.0; \
545 for (i = 0; i < len; i++) { \
546 res1 += a[i] * b[i * oversample]; \
547 res2 += a[i] * b[i * oversample + 1]; \
549 *o = res1 * ic[0] + res2 * ic[1]; \
551 INNER_PRODUCT_FLOAT_LINEAR_FUNC (gfloat);
552 INNER_PRODUCT_FLOAT_LINEAR_FUNC (gdouble);
554 #define MAKE_RESAMPLE_FUNC(type,inter,channels,arch) \
556 resample_ ##type## _ ##inter## _ ##channels## _ ##arch (GstAudioResampler * resampler, \
557 gpointer in[], gsize in_len, gpointer out[], gsize out_len, \
561 gint n_taps = resampler->n_taps; \
562 gint blocks = resampler->blocks; \
563 gint ostride = resampler->ostride; \
564 gint oversample = resampler->oversample; \
565 gint samp_index = 0; \
566 gint samp_phase = 0; \
568 for (c = 0; c < blocks; c++) { \
570 type *op = ostride == 1 ? out[c] : (type *)out[0] + c; \
572 samp_index = resampler->samp_index; \
573 samp_phase = resampler->samp_phase; \
575 for (di = 0; di < out_len; di++) { \
576 type *ipp, icoeff[4], *taps; \
578 ipp = &ip[samp_index * channels]; \
580 taps = get_taps_ ##type##_##inter (resampler, &samp_index, &samp_phase, icoeff); \
582 inner_product_ ##type##_##inter##_##channels##_##arch (op, ipp, taps, n_taps, icoeff, oversample); \
585 memmove (ip, &ip[samp_index * channels], \
586 (in_len - samp_index) * sizeof(type) * channels); \
588 *consumed = samp_index - resampler->samp_index; \
590 resampler->samp_index = 0; \
591 resampler->samp_phase = samp_phase; \
594 MAKE_RESAMPLE_FUNC (gint16, none, 1, c);
595 MAKE_RESAMPLE_FUNC (gint32, none, 1, c);
596 MAKE_RESAMPLE_FUNC (gfloat, none, 1, c);
597 MAKE_RESAMPLE_FUNC (gdouble, none, 1, c);
599 MAKE_RESAMPLE_FUNC (gint16, linear, 1, c);
600 MAKE_RESAMPLE_FUNC (gint32, linear, 1, c);
601 MAKE_RESAMPLE_FUNC (gfloat, linear, 1, c);
602 MAKE_RESAMPLE_FUNC (gdouble, linear, 1, c);
604 static ResampleFunc resample_funcs[] = {
605 resample_gint16_none_1_c,
606 resample_gint32_none_1_c,
607 resample_gfloat_none_1_c,
608 resample_gdouble_none_1_c,
614 resample_gint16_linear_1_c,
615 resample_gint32_linear_1_c,
616 resample_gfloat_linear_1_c,
617 resample_gdouble_linear_1_c,
624 #define resample_gint16_none_1 resample_funcs[0]
625 #define resample_gint32_none_1 resample_funcs[1]
626 #define resample_gfloat_none_1 resample_funcs[2]
627 #define resample_gdouble_none_1 resample_funcs[3]
628 #define resample_gint16_none_2 resample_funcs[4]
629 #define resample_gint32_none_2 resample_funcs[5]
630 #define resample_gfloat_none_2 resample_funcs[6]
631 #define resample_gdouble_none_2 resample_funcs[7]
633 #define resample_gint16_linear_1 resample_funcs[8]
634 #define resample_gint32_linear_1 resample_funcs[9]
635 #define resample_gfloat_linear_1 resample_funcs[10]
636 #define resample_gdouble_linear_1 resample_funcs[11]
638 #if defined HAVE_ORC && !defined DISABLE_ORC
639 # if defined (__i386__) || defined (__x86_64__)
641 # include "audio-resampler-x86.h"
646 audio_resampler_init (void)
648 static gsize init_gonce = 0;
650 if (g_once_init_enter (&init_gonce)) {
652 GST_DEBUG_CATEGORY_INIT (audio_resampler_debug, "audio-resampler", 0,
653 "audio-resampler object");
655 #if defined HAVE_ORC && !defined DISABLE_ORC
658 OrcTarget *target = orc_target_get_default ();
662 unsigned int flags = orc_target_get_default_flags (target);
665 name = orc_target_get_name (target);
666 GST_DEBUG ("target %s, default flags %08x", name, flags);
668 for (i = 0; i < 32; ++i) {
669 if (flags & (1U << i)) {
670 name = orc_target_get_flag_name (target, i);
671 GST_DEBUG ("target flag %s", name);
673 audio_resampler_check_x86 (name);
680 g_once_init_leave (&init_gonce, 1);
684 #define MAKE_DEINTERLEAVE_FUNC(type) \
686 deinterleave_ ##type (GstAudioResampler * resampler, gpointer sbuf[], \
687 gpointer in[], gsize in_frames) \
689 guint i, c, channels = resampler->channels; \
690 gsize samples_avail = resampler->samples_avail; \
691 for (c = 0; c < channels; c++) { \
692 type *s = (type *) sbuf[c] + samples_avail; \
693 if (G_UNLIKELY (in == NULL)) { \
694 for (i = 0; i < in_frames; i++) \
697 type *ip = (type *) in[0] + c; \
698 for (i = 0; i < in_frames; i++, ip += channels) \
704 MAKE_DEINTERLEAVE_FUNC (gdouble);
705 MAKE_DEINTERLEAVE_FUNC (gfloat);
706 MAKE_DEINTERLEAVE_FUNC (gint32);
707 MAKE_DEINTERLEAVE_FUNC (gint16);
709 static DeinterleaveFunc deinterleave_funcs[] = {
717 deinterleave_copy (GstAudioResampler * resampler, gpointer sbuf[],
718 gpointer in[], gsize in_frames)
720 guint c, blocks = resampler->blocks;
721 gsize bytes_avail, in_bytes, bpf;
723 bpf = resampler->bps * resampler->inc;
724 bytes_avail = resampler->samples_avail * bpf;
725 in_bytes = in_frames * bpf;
727 for (c = 0; c < blocks; c++) {
728 if (G_UNLIKELY (in == NULL))
729 memset ((guint8 *) sbuf[c] + bytes_avail, 0, in_bytes);
731 memcpy ((guint8 *) sbuf[c] + bytes_avail, in[c], in_bytes);
736 calculate_kaiser_params (GstAudioResampler * resampler)
738 gdouble A, B, dw, tr_bw, Fc;
740 const KaiserQualityMap *q = &kaiser_qualities[DEFAULT_QUALITY];
744 if (resampler->out_rate < resampler->in_rate)
745 Fc *= q->downsample_cutoff_factor;
747 Fc = GET_OPT_CUTOFF (resampler->options, Fc);
748 A = GET_OPT_STOP_ATTENUATION (resampler->options, q->stopband_attenuation);
750 GET_OPT_TRANSITION_BANDWIDTH (resampler->options,
751 q->transition_bandwidth);
753 GST_LOG ("Fc %f, A %f, tr_bw %f", Fc, A, tr_bw);
757 B = 0.1102 * (A - 8.7);
759 B = 0.5842 * pow (A - 21, 0.4) + 0.07886 * (A - 21);
762 /* calculate transition width in radians */
763 dw = 2 * G_PI * (tr_bw);
764 /* order of the filter */
765 n = (A - 8.0) / (2.285 * dw);
767 resampler->kaiser_beta = B;
768 resampler->n_taps = n + 1;
769 resampler->cutoff = Fc;
771 GST_LOG ("using Beta %f n_taps %d cutoff %f", resampler->kaiser_beta,
772 resampler->n_taps, resampler->cutoff);
776 alloc_coeff_mem (GstAudioResampler * resampler, gint bps, gint n_taps,
779 if (resampler->alloc_taps >= n_taps && resampler->alloc_phases >= n_phases)
782 resampler->tmpcoeff =
783 g_realloc_n (resampler->tmpcoeff, n_taps, sizeof (gdouble));
785 resampler->cstride = GST_ROUND_UP_32 (bps * (n_taps + TAPS_OVERREAD));
786 g_free (resampler->coeffmem);
787 resampler->coeffmem = g_malloc0 (n_phases * resampler->cstride + ALIGN - 1);
788 resampler->coeff = MEM_ALIGN (resampler->coeffmem, ALIGN);
789 resampler->alloc_taps = n_taps;
790 resampler->alloc_phases = n_phases;
796 resampler_calculate_taps (GstAudioResampler * resampler)
801 gint in_rate, index, oversample;
802 gboolean non_interleaved, interpolate;
803 DeinterleaveFunc deinterleave;
804 ResampleFunc resample, resample_2;
806 switch (resampler->method) {
807 case GST_AUDIO_RESAMPLER_METHOD_NEAREST:
808 resampler->n_taps = 2;
810 case GST_AUDIO_RESAMPLER_METHOD_LINEAR:
811 resampler->n_taps = GET_OPT_N_TAPS (resampler->options, 2);
813 case GST_AUDIO_RESAMPLER_METHOD_CUBIC:
814 resampler->n_taps = GET_OPT_N_TAPS (resampler->options, 4);
815 resampler->b = GET_OPT_CUBIC_B (resampler->options);
816 resampler->c = GET_OPT_CUBIC_C (resampler->options);;
818 case GST_AUDIO_RESAMPLER_METHOD_BLACKMAN_NUTTALL:
820 const BlackmanQualityMap *q = &blackman_qualities[DEFAULT_QUALITY];
821 resampler->n_taps = GET_OPT_N_TAPS (resampler->options, q->n_taps);
822 resampler->cutoff = GET_OPT_CUTOFF (resampler->options, q->cutoff);
825 case GST_AUDIO_RESAMPLER_METHOD_KAISER:
826 calculate_kaiser_params (resampler);
830 in_rate = resampler->in_rate;
831 out_rate = resampler->out_rate;
833 oversample = GET_OPT_FILTER_OVERSAMPLE (resampler->options);
835 if (out_rate < in_rate) {
838 resampler->cutoff = resampler->cutoff * out_rate / in_rate;
840 gst_util_uint64_scale_int (resampler->n_taps, in_rate, out_rate);
842 while (oversample > 1) {
843 if (mult * out_rate >= in_rate)
850 resampler->oversample = oversample;
852 /* only round up for bigger taps, the small taps are used for nearest,
853 * linear and cubic and we want to use less taps for those. */
854 if (resampler->n_taps > 4)
855 resampler->n_taps = GST_ROUND_UP_8 (resampler->n_taps);
857 n_taps = resampler->n_taps;
858 bps = resampler->bps;
860 GST_LOG ("using n_taps %d cutoff %f, oversample %d", n_taps,
861 resampler->cutoff, oversample);
863 resampler->filter_mode = GET_OPT_FILTER_MODE (resampler->options);
864 resampler->filter_threshold =
865 GET_OPT_FILTER_MODE_THRESHOLD (resampler->options);
867 switch (resampler->filter_mode) {
868 case GST_AUDIO_RESAMPLER_FILTER_MODE_INTERPOLATED:
871 case GST_AUDIO_RESAMPLER_FILTER_MODE_FULL:
875 case GST_AUDIO_RESAMPLER_FILTER_MODE_AUTO:
876 if (out_rate <= oversample) {
877 /* don't interpolate if we need to calculate at least the same amount
878 * of filter coefficients than the full table case */
887 gint otaps = oversample * n_taps + 1;
888 GstAudioResamplerFilterInterpolation filter_interpolation =
889 GET_OPT_FILTER_INTERPOLATION (resampler->options);
891 /* if we're asked to intepolate but no interpolation was given, */
892 if (filter_interpolation == GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_NONE)
893 resampler->filter_interpolation = DEFAULT_OPT_FILTER_INTERPOLATION;
895 resampler->filter_interpolation = filter_interpolation;
897 if (alloc_coeff_mem (resampler, bps, otaps, 1)) {
898 gpointer coeff = (gint8 *) resampler->coeff;
899 gdouble *tmpcoeff = resampler->tmpcoeff;
902 x = 1.0 - n_taps / 2;
903 weight = fill_taps (resampler, tmpcoeff, x, otaps, oversample);
905 switch (resampler->format) {
906 case GST_AUDIO_FORMAT_S16:
907 convert_taps_gint16 (tmpcoeff, coeff, weight / oversample, otaps);
909 case GST_AUDIO_FORMAT_S32:
910 convert_taps_gint32 (tmpcoeff, coeff, weight / oversample, otaps);
912 case GST_AUDIO_FORMAT_F32:
913 convert_taps_gfloat (tmpcoeff, coeff, weight / oversample, otaps);
916 case GST_AUDIO_FORMAT_F64:
917 convert_taps_gdouble (tmpcoeff, coeff, weight / oversample, otaps);
922 resampler->filter_interpolation =
923 GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_NONE;
924 resampler->taps = g_realloc_n (resampler->taps, out_rate, sizeof (Tap));
925 memset (resampler->taps, 0, sizeof (Tap) * out_rate);
926 alloc_coeff_mem (resampler, bps, n_taps, out_rate);
929 resampler->samp_inc = in_rate / out_rate;
930 resampler->samp_frac = in_rate % out_rate;
933 (resampler->flags & GST_AUDIO_RESAMPLER_FLAG_NON_INTERLEAVED);
935 resampler->ostride = non_interleaved ? 1 : resampler->channels;
937 switch (resampler->format) {
938 case GST_AUDIO_FORMAT_S16:
941 case GST_AUDIO_FORMAT_S32:
944 case GST_AUDIO_FORMAT_F32:
947 case GST_AUDIO_FORMAT_F64:
951 g_assert_not_reached ();
954 deinterleave = deinterleave_funcs[index];
956 switch (resampler->filter_interpolation) {
958 case GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_NONE:
960 case GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_LINEAR:
963 case GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_CUBIC:
967 resample = resample_funcs[index];
968 resample_2 = resample_funcs[index + 4];
970 if (!non_interleaved && resampler->channels == 2 && n_taps >= 4 && resample_2) {
971 /* we resample 2 channels in parallel */
972 resampler->resample = resample_2;
973 resampler->deinterleave = deinterleave_copy;
974 resampler->blocks = 1;
975 resampler->inc = resampler->channels;;
977 /* we resample each channel separately */
978 resampler->resample = resample;
979 resampler->deinterleave = deinterleave;
980 resampler->blocks = resampler->channels;
985 #define PRINT_TAPS(type,print) \
987 type sum = 0.0, *taps; \
989 gint samp_index = 0, samp_phase = i; \
991 taps = get_taps_##type##_none (resampler, &samp_index,\
992 &samp_phase, icoeff); \
994 for (j = 0; j < n_taps; j++) { \
995 type tap = taps[j]; \
996 fprintf (stderr, "\t%" print " ", tap); \
999 fprintf (stderr, "\t: sum %" print "\n", sum); \
1003 resampler_dump (GstAudioResampler * resampler)
1006 gint i, n_taps, out_rate;
1009 out_rate = resampler->out_rate;
1010 n_taps = resampler->n_taps;
1012 fprintf (stderr, "out size %d, max taps %d\n", out_rate, n_taps);
1014 a = g_get_monotonic_time ();
1016 for (i = 0; i < out_rate; i++) {
1019 //fprintf (stderr, "%u: %d %d\t ", i, t->sample_inc, t->next_phase);
1020 switch (resampler->format) {
1021 case GST_AUDIO_FORMAT_F64:
1022 PRINT_TAPS (gdouble, "f");
1024 case GST_AUDIO_FORMAT_F32:
1025 PRINT_TAPS (gfloat, "f");
1027 case GST_AUDIO_FORMAT_S32:
1028 PRINT_TAPS (gint32, "d");
1030 case GST_AUDIO_FORMAT_S16:
1031 PRINT_TAPS (gint16, "d");
1037 fprintf (stderr, "time %" G_GUINT64_FORMAT "\n", g_get_monotonic_time () - a);
1042 * gst_audio_resampler_options_set_quality:
1043 * @method: a #GstAudioResamplerMethod
1044 * @quality: the quality
1045 * @in_rate: the input rate
1046 * @out_rate: the output rate
1047 * @options: a #GstStructure
1049 * Set the parameters for resampling from @in_rate to @out_rate using @method
1050 * for @quality in @options.
1053 gst_audio_resampler_options_set_quality (GstAudioResamplerMethod method,
1054 guint quality, gint in_rate, gint out_rate, GstStructure * options)
1056 g_return_if_fail (options != NULL);
1057 g_return_if_fail (quality <= GST_AUDIO_RESAMPLER_QUALITY_MAX);
1058 g_return_if_fail (in_rate > 0 && out_rate > 0);
1061 case GST_AUDIO_RESAMPLER_METHOD_NEAREST:
1063 case GST_AUDIO_RESAMPLER_METHOD_LINEAR:
1064 gst_structure_set (options,
1065 GST_AUDIO_RESAMPLER_OPT_N_TAPS, G_TYPE_INT, 2, NULL);
1067 case GST_AUDIO_RESAMPLER_METHOD_CUBIC:
1068 gst_structure_set (options,
1069 GST_AUDIO_RESAMPLER_OPT_N_TAPS, G_TYPE_INT, 4,
1070 GST_AUDIO_RESAMPLER_OPT_CUBIC_B, G_TYPE_DOUBLE, DEFAULT_OPT_CUBIC_B,
1071 GST_AUDIO_RESAMPLER_OPT_CUBIC_C, G_TYPE_DOUBLE, DEFAULT_OPT_CUBIC_C,
1074 case GST_AUDIO_RESAMPLER_METHOD_BLACKMAN_NUTTALL:
1076 const BlackmanQualityMap *map = &blackman_qualities[quality];
1077 gst_structure_set (options,
1078 GST_AUDIO_RESAMPLER_OPT_N_TAPS, G_TYPE_INT, map->n_taps,
1079 GST_AUDIO_RESAMPLER_OPT_CUTOFF, G_TYPE_DOUBLE, map->cutoff, NULL);
1082 case GST_AUDIO_RESAMPLER_METHOD_KAISER:
1084 const KaiserQualityMap *map = &kaiser_qualities[quality];
1087 cutoff = map->cutoff;
1088 if (out_rate < in_rate)
1089 cutoff *= map->downsample_cutoff_factor;
1091 gst_structure_set (options,
1092 GST_AUDIO_RESAMPLER_OPT_CUTOFF, G_TYPE_DOUBLE, cutoff,
1093 GST_AUDIO_RESAMPLER_OPT_STOP_ATTENUATION, G_TYPE_DOUBLE,
1094 map->stopband_attenuation,
1095 GST_AUDIO_RESAMPLER_OPT_TRANSITION_BANDWIDTH, G_TYPE_DOUBLE,
1096 map->transition_bandwidth, NULL);
1100 gst_structure_set (options,
1101 GST_AUDIO_RESAMPLER_OPT_FILTER_OVERSAMPLE, G_TYPE_INT,
1102 oversample_qualities[quality], NULL);
1106 * gst_audio_resampler_new:
1107 * @resampler: a #GstAudioResampler
1108 * @method: a #GstAudioResamplerMethod
1109 * @flags: #GstAudioResamplerFlags
1110 * @in_rate: input rate
1111 * @out_rate: output rate
1112 * @options: extra options
1114 * Make a new resampler.
1116 * Returns: %TRUE on success
1119 gst_audio_resampler_new (GstAudioResamplerMethod method,
1120 GstAudioResamplerFlags flags,
1121 GstAudioFormat format, gint channels,
1122 gint in_rate, gint out_rate, GstStructure * options)
1124 GstAudioResampler *resampler;
1125 const GstAudioFormatInfo *info;
1127 g_return_val_if_fail (channels > 0, FALSE);
1128 g_return_val_if_fail (in_rate > 0, FALSE);
1129 g_return_val_if_fail (out_rate > 0, FALSE);
1131 audio_resampler_init ();
1133 resampler = g_slice_new0 (GstAudioResampler);
1134 resampler->method = method;
1135 resampler->flags = flags;
1136 resampler->format = format;
1137 resampler->channels = channels;
1139 info = gst_audio_format_get_info (format);
1140 resampler->bps = GST_AUDIO_FORMAT_INFO_WIDTH (info) / 8;
1141 resampler->sbuf = g_malloc0 (sizeof (gpointer) * channels);
1143 GST_DEBUG ("method %d, bps %d, channels %d", method, resampler->bps,
1144 resampler->channels);
1146 gst_audio_resampler_update (resampler, in_rate, out_rate, options);
1148 /* half of the filter is filled with 0 */
1149 resampler->samp_index = 0;
1150 resampler->samples_avail = resampler->n_taps / 2 - 1;
1155 /* make the buffers to hold the (deinterleaved) samples */
1156 static inline gpointer *
1157 get_sample_bufs (GstAudioResampler * resampler, gsize need)
1159 if (G_LIKELY (resampler->samples_len < need)) {
1160 guint c, blocks = resampler->blocks;
1161 gsize bytes, to_move = 0;
1162 gint8 *ptr, *samples;
1164 GST_LOG ("realloc %d -> %d", (gint) resampler->samples_len, (gint) need);
1166 bytes = GST_ROUND_UP_N (need * resampler->bps * resampler->inc, ALIGN);
1168 samples = g_malloc0 (blocks * bytes + ALIGN - 1);
1169 ptr = MEM_ALIGN (samples, ALIGN);
1171 /* if we had some data, move history */
1172 if (resampler->samples_len > 0)
1173 to_move = resampler->samples_avail * resampler->bps * resampler->inc;
1175 /* set up new pointers */
1176 for (c = 0; c < blocks; c++) {
1177 memcpy (ptr + (c * bytes), resampler->sbuf[c], to_move);
1178 resampler->sbuf[c] = ptr + (c * bytes);
1180 g_free (resampler->samples);
1181 resampler->samples = samples;
1182 resampler->samples_len = need;
1184 return resampler->sbuf;
1188 * gst_audio_resampler_reset:
1189 * @resampler: a #GstAudioResampler
1191 * Reset @resampler to the state it was when it was first created, discarding
1192 * all sample history.
1195 gst_audio_resampler_reset (GstAudioResampler * resampler)
1197 g_return_if_fail (resampler != NULL);
1199 if (resampler->samples) {
1201 gint c, blocks, bpf;
1203 bpf = resampler->bps * resampler->inc;
1204 bytes = (resampler->n_taps / 2) * bpf;
1205 blocks = resampler->blocks;
1207 for (c = 0; c < blocks; c++)
1208 memset (resampler->sbuf[c], 0, bytes);
1210 /* half of the filter is filled with 0 */
1211 resampler->samp_index = 0;
1212 resampler->samples_avail = resampler->n_taps / 2 - 1;
1216 * gst_audio_resampler_update:
1217 * @resampler: a #GstAudioResampler
1218 * @in_rate: new input rate
1219 * @out_rate: new output rate
1220 * @options: new options or %NULL
1222 * Update the resampler parameters for @resampler. This function should
1223 * not be called concurrently with any other function on @resampler.
1225 * When @in_rate or @out_rate is 0, its value is unchanged.
1227 * When @options is %NULL, the previously configured options are reused.
1229 * Returns: %TRUE if the new parameters could be set
1232 gst_audio_resampler_update (GstAudioResampler * resampler,
1233 gint in_rate, gint out_rate, GstStructure * options)
1235 gint gcd, samp_phase, old_n_taps;
1238 g_return_val_if_fail (resampler != NULL, FALSE);
1241 in_rate = resampler->in_rate;
1243 out_rate = resampler->out_rate;
1245 if (resampler->out_rate > 0)
1247 gst_util_uint64_scale_int (resampler->samp_phase, out_rate,
1248 resampler->out_rate);
1252 gcd = gst_util_greatest_common_divisor (in_rate, out_rate);
1254 max_error = GET_OPT_MAX_PHASE_ERROR (resampler->options);
1256 if (max_error < 1.0e-8) {
1257 gcd = gst_util_greatest_common_divisor (gcd, samp_phase);
1260 gdouble ph1 = (gdouble) samp_phase / out_rate;
1263 /* reduce the factor until we have a phase error of less than 10% */
1264 gdouble ph2 = (gdouble) (samp_phase / gcd) / (out_rate / gcd);
1266 if (fabs (ph1 - ph2) < max_error)
1269 while (gcd % factor != 0)
1273 GST_INFO ("divide by factor %d, gcd %d", factor, gcd);
1277 GST_INFO ("phase %d, out_rate %d, in_rate %d, gcd %d", samp_phase, out_rate,
1280 resampler->samp_phase = samp_phase / gcd;
1281 resampler->in_rate = in_rate / gcd;
1282 resampler->out_rate = out_rate / gcd;
1285 if (resampler->options)
1286 gst_structure_free (resampler->options);
1287 resampler->options = gst_structure_copy (options);
1290 old_n_taps = resampler->n_taps;
1292 resampler_calculate_taps (resampler);
1293 resampler_dump (resampler);
1295 GST_DEBUG ("rate %u->%u, taps %d->%d", resampler->in_rate,
1296 resampler->out_rate, old_n_taps, resampler->n_taps);
1298 if (old_n_taps > 0) {
1300 gint i, bpf, bytes, soff, doff, diff;
1302 sbuf = get_sample_bufs (resampler, resampler->n_taps);
1304 bpf = resampler->bps * resampler->inc;
1305 bytes = resampler->samples_avail * bpf;
1306 soff = doff = resampler->samp_index * bpf;
1308 diff = ((gint) resampler->n_taps - old_n_taps) / 2;
1311 /* diff < 0, decrease taps, adjust source */
1312 soff += -diff * bpf;
1313 bytes -= -diff * bpf;
1315 /* diff > 0, increase taps, adjust dest */
1319 /* now shrink or enlarge the history buffer, when we enlarge we
1320 * just leave the old samples in there. FIXME, probably do something better
1321 * like mirror or fill with zeroes. */
1322 for (i = 0; i < resampler->blocks; i++)
1323 memmove ((gint8 *) sbuf[i] + doff, (gint8 *) sbuf[i] + soff, bytes);
1325 resampler->samples_avail += diff;
1331 * gst_audio_resampler_free:
1332 * @resampler: a #GstAudioResampler
1334 * Free a previously allocated #GstAudioResampler @resampler.
1339 gst_audio_resampler_free (GstAudioResampler * resampler)
1341 g_return_if_fail (resampler != NULL);
1343 g_free (resampler->taps);
1344 g_free (resampler->coeffmem);
1345 g_free (resampler->tmpcoeff);
1346 g_free (resampler->samples);
1347 g_free (resampler->sbuf);
1348 if (resampler->options)
1349 gst_structure_free (resampler->options);
1350 g_slice_free (GstAudioResampler, resampler);
1354 calc_out (GstAudioResampler * resampler, gsize in)
1358 out = in * resampler->out_rate;
1359 if (out < resampler->samp_phase)
1362 out = ((out - resampler->samp_phase) / resampler->in_rate) + 1;
1363 GST_LOG ("out %d = ((%d * %d - %d) / %d) + 1", (gint) out,
1364 (gint) in, resampler->out_rate, resampler->samp_phase,
1365 resampler->in_rate);
1371 * gst_audio_resampler_get_out_frames:
1372 * @resampler: a #GstAudioResampler
1373 * @in_frames: number of input frames
1375 * Get the number of output frames that would be currently available when
1376 * @in_frames are given to @resampler.
1378 * Returns: The number of frames that would be availabe after giving
1379 * @in_frames as input to @resampler.
1382 gst_audio_resampler_get_out_frames (GstAudioResampler * resampler,
1387 g_return_val_if_fail (resampler != NULL, 0);
1389 need = resampler->n_taps + resampler->samp_index + resampler->skip;
1390 avail = resampler->samples_avail + in_frames;
1391 GST_LOG ("need %d = %d + %d + %d, avail %d = %d + %d", (gint) need,
1392 resampler->n_taps, resampler->samp_index, resampler->skip,
1393 (gint) avail, (gint) resampler->samples_avail, (gint) in_frames);
1397 return calc_out (resampler, avail - need);
1401 * gst_audio_resampler_get_in_frames:
1402 * @resampler: a #GstAudioResampler
1403 * @out_frames: number of input frames
1405 * Get the number of input frames that would currently be needed
1406 * to produce @out_frames from @resampler.
1408 * Returns: The number of input frames needed for producing
1409 * @out_frames of data from @resampler.
1412 gst_audio_resampler_get_in_frames (GstAudioResampler * resampler,
1417 g_return_val_if_fail (resampler != NULL, 0);
1420 (resampler->samp_phase +
1421 out_frames * resampler->samp_frac) / resampler->out_rate;
1422 in_frames += out_frames * resampler->samp_inc;
1428 * gst_audio_resampler_get_max_latency:
1429 * @resampler: a #GstAudioResampler
1431 * Get the maximum number of input samples that the resampler would
1432 * need before producing output.
1434 * Returns: the latency of @resampler as expressed in the number of
1438 gst_audio_resampler_get_max_latency (GstAudioResampler * resampler)
1440 g_return_val_if_fail (resampler != NULL, 0);
1442 return resampler->n_taps / 2;
1446 * gst_audio_resampler_resample:
1447 * @resampler: a #GstAudioResampler
1448 * @in: input samples
1449 * @in_frames: number of input frames
1450 * @out: output samples
1451 * @out_frames: number of output frames
1453 * Perform resampling on @in_frames frames in @in and write @out_frames to @out.
1455 * In case the samples are interleaved, @in and @out must point to an
1456 * array with a single element pointing to a block of interleaved samples.
1458 * If non-interleaved samples are used, @in and @out must point to an
1459 * array with pointers to memory blocks, one for each channel.
1461 * @in may be %NULL, in which case @in_frames of silence samples are pushed
1462 * into the resampler.
1464 * This function always produces @out_frames of output and consumes @in_frames of
1465 * input. Use gst_audio_resampler_get_out_frames() and
1466 * gst_audio_resampler_get_in_frames() to make sure @in_frames and @out_frames
1467 * are matching and @in and @out point to enough memory.
1470 gst_audio_resampler_resample (GstAudioResampler * resampler,
1471 gpointer in[], gsize in_frames, gpointer out[], gsize out_frames)
1473 gsize samples_avail;
1474 gsize need, consumed;
1477 /* do sample skipping */
1478 if (G_UNLIKELY (resampler->skip >= in_frames)) {
1479 /* we need tp skip all input */
1480 resampler->skip -= in_frames;
1483 /* skip the last samples by advancing the sample index */
1484 resampler->samp_index += resampler->skip;
1486 samples_avail = resampler->samples_avail;
1488 /* make sure we have enough space to copy our samples */
1489 sbuf = get_sample_bufs (resampler, in_frames + samples_avail);
1491 /* copy/deinterleave the samples */
1492 resampler->deinterleave (resampler, sbuf, in, in_frames);
1494 /* update new amount of samples in our buffer */
1495 resampler->samples_avail = samples_avail += in_frames;
1497 need = resampler->n_taps + resampler->samp_index;
1498 if (G_UNLIKELY (samples_avail < need)) {
1499 /* not enough samples to start */
1503 /* resample all channels */
1504 resampler->resample (resampler, sbuf, samples_avail, out, out_frames,
1507 GST_LOG ("in %" G_GSIZE_FORMAT ", avail %" G_GSIZE_FORMAT ", consumed %"
1508 G_GSIZE_FORMAT, in_frames, samples_avail, consumed);
1510 /* update pointers */
1511 if (G_LIKELY (consumed > 0)) {
1512 gssize left = samples_avail - consumed;
1514 /* we consumed part of our samples */
1515 resampler->samples_avail = left;
1517 /* we consumed all our samples, empty our buffers */
1518 resampler->samples_avail = 0;
1519 resampler->skip = -left;