1 /* GStreamer
2 * Copyright (C) <2015> Wim Taymans <wim.taymans@gmail.com>
3 *
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.
8 *
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.
13 *
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.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
23
24 #include <string.h>
25 #include <stdio.h>
26 #include <math.h>
27
28 #ifdef HAVE_ORC
29 #include <orc/orc.h>
30 #endif
31
32 #include "audio-resampler.h"
33 #include "audio-resampler-private.h"
34 #include "audio-resampler-macros.h"
35
36 #define MEM_ALIGN(m,a) ((gint8 *)((guintptr)((gint8 *)(m) + ((a)-1)) & ~((a)-1)))
37 #define ALIGN 16
38 #define TAPS_OVERREAD 16
39
40 GST_DEBUG_CATEGORY_STATIC (audio_resampler_debug);
41 #define GST_CAT_DEFAULT audio_resampler_debug
42
43 /**
44 * SECTION:gstaudioresampler
45 * @title: GstAudioResampler
46 * @short_description: Utility structure for resampler information
47 *
48 * #GstAudioResampler is a structure which holds the information
49 * required to perform various kinds of resampling filtering.
50 *
51 */
52
53 static const gint oversample_qualities[] = {
54 4, 4, 4, 8, 8, 16, 16, 16, 16, 32, 32
55 };
56
57 typedef struct
58 {
59 gdouble cutoff;
60 gdouble downsample_cutoff_factor;
61 gdouble stopband_attenuation;
62 gdouble transition_bandwidth;
63 } KaiserQualityMap;
64
65 static const KaiserQualityMap kaiser_qualities[] = {
66 {0.860, 0.96511, 60, 0.7}, /* 8 taps */
67 {0.880, 0.96591, 65, 0.29}, /* 16 taps */
68 {0.910, 0.96923, 70, 0.145}, /* 32 taps */
69 {0.920, 0.97600, 80, 0.105}, /* 48 taps */
70 {0.940, 0.97979, 85, 0.087}, /* 64 taps default quality */
71 {0.940, 0.98085, 95, 0.077}, /* 80 taps */
72 {0.945, 0.99471, 100, 0.068}, /* 96 taps */
73 {0.950, 1.0, 105, 0.055}, /* 128 taps */
74 {0.960, 1.0, 110, 0.045}, /* 160 taps */
75 {0.968, 1.0, 115, 0.039}, /* 192 taps */
76 {0.975, 1.0, 120, 0.0305} /* 256 taps */
77 };
78
79 typedef struct
80 {
81 gint n_taps;
82 gdouble cutoff;
83 } BlackmanQualityMap;
84
85 static const BlackmanQualityMap blackman_qualities[] = {
86 {8, 0.5,},
87 {16, 0.6,},
88 {24, 0.72,},
89 {32, 0.8,},
90 {48, 0.85,}, /* default */
91 {64, 0.90,},
92 {80, 0.92,},
93 {96, 0.933,},
94 {128, 0.950,},
95 {148, 0.955,},
96 {160, 0.960,}
97 };
98
99 #define DEFAULT_RESAMPLER_METHOD GST_AUDIO_RESAMPLER_METHOD_KAISER
100 #define DEFAULT_QUALITY GST_AUDIO_RESAMPLER_QUALITY_DEFAULT
101 #define DEFAULT_OPT_CUBIC_B 1.0
102 #define DEFAULT_OPT_CUBIC_C 0.0
103 #define DEFAULT_OPT_FILTER_MODE GST_AUDIO_RESAMPLER_FILTER_MODE_AUTO
104 #define DEFAULT_OPT_FILTER_MODE_THRESHOLD 1048576
105 #define DEFAULT_OPT_FILTER_INTERPOLATION GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_CUBIC
106 #define DEFAULT_OPT_FILTER_OVERSAMPLE 8
107 #define DEFAULT_OPT_MAX_PHASE_ERROR 0.1
108
109 static gdouble
get_opt_double(GstStructure * options,const gchar * name,gdouble def)110 get_opt_double (GstStructure * options, const gchar * name, gdouble def)
111 {
112 gdouble res;
113 if (!options || !gst_structure_get_double (options, name, &res))
114 res = def;
115 return res;
116 }
117
118 static gint
get_opt_int(GstStructure * options,const gchar * name,gint def)119 get_opt_int (GstStructure * options, const gchar * name, gint def)
120 {
121 gint res;
122 if (!options || !gst_structure_get_int (options, name, &res))
123 res = def;
124 return res;
125 }
126
127 static gint
get_opt_enum(GstStructure * options,const gchar * name,GType type,gint def)128 get_opt_enum (GstStructure * options, const gchar * name, GType type, gint def)
129 {
130 gint res;
131 if (!options || !gst_structure_get_enum (options, name, type, &res))
132 res = def;
133 return res;
134 }
135
136
137 #define GET_OPT_CUTOFF(options,def) get_opt_double(options, \
138 GST_AUDIO_RESAMPLER_OPT_CUTOFF,def)
139 #define GET_OPT_DOWN_CUTOFF_FACTOR(options,def) get_opt_double(options, \
140 GST_AUDIO_RESAMPLER_OPT_DOWN_CUTOFF_FACTOR, def)
141 #define GET_OPT_STOP_ATTENUATION(options,def) get_opt_double(options, \
142 GST_AUDIO_RESAMPLER_OPT_STOP_ATTENUATION, def)
143 #define GET_OPT_TRANSITION_BANDWIDTH(options,def) get_opt_double(options, \
144 GST_AUDIO_RESAMPLER_OPT_TRANSITION_BANDWIDTH, def)
145 #define GET_OPT_CUBIC_B(options) get_opt_double(options, \
146 GST_AUDIO_RESAMPLER_OPT_CUBIC_B, DEFAULT_OPT_CUBIC_B)
147 #define GET_OPT_CUBIC_C(options) get_opt_double(options, \
148 GST_AUDIO_RESAMPLER_OPT_CUBIC_C, DEFAULT_OPT_CUBIC_C)
149 #define GET_OPT_N_TAPS(options,def) get_opt_int(options, \
150 GST_AUDIO_RESAMPLER_OPT_N_TAPS, def)
151 #define GET_OPT_FILTER_MODE(options) get_opt_enum(options, \
152 GST_AUDIO_RESAMPLER_OPT_FILTER_MODE, GST_TYPE_AUDIO_RESAMPLER_FILTER_MODE, \
153 DEFAULT_OPT_FILTER_MODE)
154 #define GET_OPT_FILTER_MODE_THRESHOLD(options) get_opt_int(options, \
155 GST_AUDIO_RESAMPLER_OPT_FILTER_MODE_THRESHOLD, DEFAULT_OPT_FILTER_MODE_THRESHOLD)
156 #define GET_OPT_FILTER_INTERPOLATION(options) get_opt_enum(options, \
157 GST_AUDIO_RESAMPLER_OPT_FILTER_INTERPOLATION, GST_TYPE_AUDIO_RESAMPLER_FILTER_INTERPOLATION, \
158 DEFAULT_OPT_FILTER_INTERPOLATION)
159 #define GET_OPT_FILTER_OVERSAMPLE(options) get_opt_int(options, \
160 GST_AUDIO_RESAMPLER_OPT_FILTER_OVERSAMPLE, DEFAULT_OPT_FILTER_OVERSAMPLE)
161 #define GET_OPT_MAX_PHASE_ERROR(options) get_opt_double(options, \
162 GST_AUDIO_RESAMPLER_OPT_MAX_PHASE_ERROR, DEFAULT_OPT_MAX_PHASE_ERROR)
163
164 #include "dbesi0.c"
165 #define bessel dbesi0
166
167 static inline gdouble
get_linear_tap(gdouble x,gint n_taps)168 get_linear_tap (gdouble x, gint n_taps)
169 {
170 gdouble res = GST_ROUND_UP_2 (n_taps) / 2 - fabs (x);
171 return res;
172 }
173
174 static inline gdouble
get_cubic_tap(gdouble x,gint n_taps,gdouble b,gdouble c)175 get_cubic_tap (gdouble x, gint n_taps, gdouble b, gdouble c)
176 {
177 gdouble res, a, a2, a3;
178
179 a = fabs (x * 4.0) / n_taps;
180 a2 = a * a;
181 a3 = a2 * a;
182
183 if (a <= 1.0)
184 res = ((12.0 - 9.0 * b - 6.0 * c) * a3 +
185 (-18.0 + 12.0 * b + 6.0 * c) * a2 + (6.0 - 2.0 * b)) / 6.0;
186 else if (a <= 2.0)
187 res = ((-b - 6.0 * c) * a3 +
188 (6.0 * b + 30.0 * c) * a2 +
189 (-12.0 * b - 48.0 * c) * a + (8.0 * b + 24.0 * c)) / 6.0;
190 else
191 res = 0.0;
192
193 return res;
194 }
195
196 static inline gdouble
get_blackman_nuttall_tap(gdouble x,gint n_taps,gdouble Fc)197 get_blackman_nuttall_tap (gdouble x, gint n_taps, gdouble Fc)
198 {
199 gdouble s, y, w;
200
201 y = G_PI * x;
202 s = (y == 0.0 ? Fc : sin (y * Fc) / y);
203
204 w = 2.0 * y / n_taps + G_PI;
205 return s * (0.3635819 - 0.4891775 * cos (w) + 0.1365995 * cos (2 * w) -
206 0.0106411 * cos (3 * w));
207 }
208
209 static inline gdouble
get_kaiser_tap(gdouble x,gint n_taps,gdouble Fc,gdouble beta)210 get_kaiser_tap (gdouble x, gint n_taps, gdouble Fc, gdouble beta)
211 {
212 gdouble s, y, w;
213
214 y = G_PI * x;
215 s = (y == 0.0 ? Fc : sin (y * Fc) / y);
216
217 w = 2.0 * x / n_taps;
218 return s * bessel (beta * sqrt (MAX (1 - w * w, 0)));
219 }
220
221 #define MAKE_CONVERT_TAPS_INT_FUNC(type, precision) \
222 static void \
223 convert_taps_##type##_c (gdouble *tmp_taps, gpointer taps, \
224 gdouble weight, gint n_taps) \
225 { \
226 gint64 one = (1LL << precision) - 1; \
227 type *t = taps; \
228 gdouble multiplier = one; \
229 gint i, j; \
230 gdouble offset, l_offset, h_offset; \
231 gboolean exact = FALSE; \
232 /* Round to integer, but with an adjustable bias that we use to */ \
233 /* eliminate the DC error. */ \
234 l_offset = 0.0; \
235 h_offset = 1.0; \
236 offset = 0.5; \
237 for (i = 0; i < 32; i++) { \
238 gint64 sum = 0; \
239 for (j = 0; j < n_taps; j++) \
240 sum += floor (offset + tmp_taps[j] * multiplier / weight); \
241 if (sum == one) { \
242 exact = TRUE; \
243 break; \
244 } \
245 if (l_offset == h_offset) \
246 break; \
247 if (sum < one) { \
248 if (offset > l_offset) \
249 l_offset = offset; \
250 offset += (h_offset - l_offset) / 2; \
251 } else { \
252 if (offset < h_offset) \
253 h_offset = offset; \
254 offset -= (h_offset - l_offset) / 2; \
255 } \
256 } \
257 for (j = 0; j < n_taps; j++) \
258 t[j] = floor (offset + tmp_taps[j] * multiplier / weight); \
259 if (!exact) \
260 GST_DEBUG ("can't find exact taps"); \
261 }
262
263 #define MAKE_CONVERT_TAPS_FLOAT_FUNC(type) \
264 static void \
265 convert_taps_##type##_c (gdouble *tmp_taps, gpointer taps, \
266 gdouble weight, gint n_taps) \
267 { \
268 gint i; \
269 type *t = taps; \
270 for (i = 0; i < n_taps; i++) \
271 t[i] = tmp_taps[i] / weight; \
272 }
273
274 MAKE_CONVERT_TAPS_INT_FUNC (gint16, PRECISION_S16);
275 MAKE_CONVERT_TAPS_INT_FUNC (gint32, PRECISION_S32);
276 MAKE_CONVERT_TAPS_FLOAT_FUNC (gfloat);
277 MAKE_CONVERT_TAPS_FLOAT_FUNC (gdouble);
278
279 static ConvertTapsFunc convert_taps_funcs[] = {
280 convert_taps_gint16_c,
281 convert_taps_gint32_c,
282 convert_taps_gfloat_c,
283 convert_taps_gdouble_c
284 };
285
286 #define convert_taps_gint16 convert_taps_funcs[0]
287 #define convert_taps_gint32 convert_taps_funcs[1]
288 #define convert_taps_gfloat convert_taps_funcs[2]
289 #define convert_taps_gdouble convert_taps_funcs[3]
290
291 static void
make_taps(GstAudioResampler * resampler,gdouble * res,gdouble x,gint n_taps)292 make_taps (GstAudioResampler * resampler, gdouble * res, gdouble x, gint n_taps)
293 {
294 gdouble weight = 0.0, *tmp_taps = resampler->tmp_taps;
295 gint i;
296
297 switch (resampler->method) {
298 case GST_AUDIO_RESAMPLER_METHOD_NEAREST:
299 break;
300
301 case GST_AUDIO_RESAMPLER_METHOD_LINEAR:
302 for (i = 0; i < n_taps; i++)
303 weight += tmp_taps[i] = get_linear_tap (x + i, resampler->n_taps);
304 break;
305
306 case GST_AUDIO_RESAMPLER_METHOD_CUBIC:
307 for (i = 0; i < n_taps; i++)
308 weight += tmp_taps[i] = get_cubic_tap (x + i, resampler->n_taps,
309 resampler->b, resampler->c);
310 break;
311
312 case GST_AUDIO_RESAMPLER_METHOD_BLACKMAN_NUTTALL:
313 for (i = 0; i < n_taps; i++)
314 weight += tmp_taps[i] =
315 get_blackman_nuttall_tap (x + i,
316 resampler->n_taps, resampler->cutoff);
317 break;
318
319 case GST_AUDIO_RESAMPLER_METHOD_KAISER:
320 for (i = 0; i < n_taps; i++)
321 weight += tmp_taps[i] =
322 get_kaiser_tap (x + i, resampler->n_taps,
323 resampler->cutoff, resampler->kaiser_beta);
324 break;
325 }
326 resampler->convert_taps (tmp_taps, res, weight, n_taps);
327 }
328
329 #define MAKE_COEFF_LINEAR_INT_FUNC(type,type2,prec) \
330 static inline void \
331 make_coeff_##type##_linear (gint num, gint denom, type *icoeff) \
332 { \
333 type x = ((gint64)num << prec) / denom; \
334 icoeff[0] = icoeff[2] = x; \
335 icoeff[1] = icoeff[3] = (type)(((type2)1 << prec)-1) - x; \
336 }
337 #define MAKE_COEFF_LINEAR_FLOAT_FUNC(type) \
338 static inline void \
339 make_coeff_##type##_linear (gint num, gint denom, type *icoeff) \
340 { \
341 type x = (type)num / denom; \
342 icoeff[0] = icoeff[2] = x; \
343 icoeff[1] = icoeff[3] = (type)1.0 - x; \
344 }
345 MAKE_COEFF_LINEAR_INT_FUNC (gint16, gint32, PRECISION_S16);
346 MAKE_COEFF_LINEAR_INT_FUNC (gint32, gint64, PRECISION_S32);
347 MAKE_COEFF_LINEAR_FLOAT_FUNC (gfloat);
348 MAKE_COEFF_LINEAR_FLOAT_FUNC (gdouble);
349
350 #define MAKE_COEFF_CUBIC_INT_FUNC(type,type2,prec) \
351 static inline void \
352 make_coeff_##type##_cubic (gint num, gint denom, type *icoeff) \
353 { \
354 type2 one = ((type2)1 << prec) - 1; \
355 type2 x = ((gint64) num << prec) / denom; \
356 type2 x2 = (x * x) >> prec; \
357 type2 x3 = (x2 * x) >> prec; \
358 icoeff[0] = (((x3 - x) << prec) / 6) >> prec; \
359 icoeff[1] = x + ((x2 - x3) >> 1); \
360 icoeff[3] = -(((x << prec) / 3) >> prec) + \
361 (x2 >> 1) - (((x3 << prec) / 6) >> prec); \
362 icoeff[2] = one - icoeff[0] - icoeff[1] - icoeff[3]; \
363 }
364 #define MAKE_COEFF_CUBIC_FLOAT_FUNC(type) \
365 static inline void \
366 make_coeff_##type##_cubic (gint num, gint denom, type *icoeff) \
367 { \
368 type x = (type) num / denom, x2 = x * x, x3 = x2 * x; \
369 icoeff[0] = 0.16667f * (x3 - x); \
370 icoeff[1] = x + 0.5f * (x2 - x3); \
371 icoeff[3] = -0.33333f * x + 0.5f * x2 - 0.16667f * x3; \
372 icoeff[2] = (type)1.0 - icoeff[0] - icoeff[1] - icoeff[3]; \
373 }
374 MAKE_COEFF_CUBIC_INT_FUNC (gint16, gint32, PRECISION_S16);
375 MAKE_COEFF_CUBIC_INT_FUNC (gint32, gint64, PRECISION_S32);
376 MAKE_COEFF_CUBIC_FLOAT_FUNC (gfloat);
377 MAKE_COEFF_CUBIC_FLOAT_FUNC (gdouble);
378
379 #define INTERPOLATE_INT_LINEAR_FUNC(type,type2,prec,limit) \
380 static inline void \
381 interpolate_##type##_linear_c (gpointer op, const gpointer ap, \
382 gint len, const gpointer icp, gint astride) \
383 { \
384 gint i; \
385 type *o = op, *a = ap, *ic = icp; \
386 type2 tmp, c0 = ic[0]; \
387 const type *c[2] = {(type*)((gint8*)a + 0*astride), \
388 (type*)((gint8*)a + 1*astride)}; \
389 \
390 for (i = 0; i < len; i++) { \
391 tmp = ((type2)c[0][i] - (type2)c[1][i]) * c0 + \
392 (((type2)c[1][i]) << (prec)); \
393 o[i] = (tmp + ((type2)1 << ((prec) - 1))) >> (prec); \
394 } \
395 }
396 #define INTERPOLATE_FLOAT_LINEAR_FUNC(type) \
397 static inline void \
398 interpolate_##type##_linear_c (gpointer op, const gpointer ap, \
399 gint len, const gpointer icp, gint astride) \
400 { \
401 gint i; \
402 type *o = op, *a = ap, *ic = icp; \
403 type c0 = ic[0]; \
404 const type *c[2] = {(type*)((gint8*)a + 0*astride), \
405 (type*)((gint8*)a + 1*astride)}; \
406 \
407 for (i = 0; i < len; i++) { \
408 o[i] = (c[0][i] - c[1][i]) * c0 + c[1][i]; \
409 } \
410 }
411
412 INTERPOLATE_INT_LINEAR_FUNC (gint16, gint32, PRECISION_S16, (gint32) 1 << 15);
413 INTERPOLATE_INT_LINEAR_FUNC (gint32, gint64, PRECISION_S32, (gint64) 1 << 31);
414 INTERPOLATE_FLOAT_LINEAR_FUNC (gfloat);
415 INTERPOLATE_FLOAT_LINEAR_FUNC (gdouble);
416
417 #define INTERPOLATE_INT_CUBIC_FUNC(type,type2,prec,limit) \
418 static inline void \
419 interpolate_##type##_cubic_c (gpointer op, const gpointer ap, \
420 gint len, const gpointer icp, gint astride) \
421 { \
422 gint i; \
423 type *o = op, *a = ap, *ic = icp; \
424 type2 tmp, c0 = ic[0], c1 = ic[1], c2 = ic[2], c3 = ic[3]; \
425 const type *c[4] = {(type*)((gint8*)a + 0*astride), \
426 (type*)((gint8*)a + 1*astride), \
427 (type*)((gint8*)a + 2*astride), \
428 (type*)((gint8*)a + 3*astride)}; \
429 \
430 for (i = 0; i < len; i++) { \
431 tmp = (type2)c[0][i] * c0 + (type2)c[1][i] * c1 + \
432 (type2)c[2][i] * c2 + (type2)c[3][i] * c3; \
433 tmp = (tmp + ((type2)1 << ((prec) - 1))) >> (prec); \
434 o[i] = CLAMP (tmp, -(limit), (limit) - 1); \
435 } \
436 }
437 #define INTERPOLATE_FLOAT_CUBIC_FUNC(type) \
438 static inline void \
439 interpolate_##type##_cubic_c (gpointer op, const gpointer ap, \
440 gint len, const gpointer icp, gint astride) \
441 { \
442 gint i; \
443 type *o = op, *a = ap, *ic = icp; \
444 type c0 = ic[0], c1 = ic[1], c2 = ic[2], c3 = ic[3]; \
445 const type *c[4] = {(type*)((gint8*)a + 0*astride), \
446 (type*)((gint8*)a + 1*astride), \
447 (type*)((gint8*)a + 2*astride), \
448 (type*)((gint8*)a + 3*astride)}; \
449 \
450 for (i = 0; i < len; i++) { \
451 o[i] = c[0][i] * c0 + c[1][i] * c1 + \
452 c[2][i] * c2 + c[3][i] * c3; \
453 } \
454 }
455
456 INTERPOLATE_INT_CUBIC_FUNC (gint16, gint32, PRECISION_S16, (gint32) 1 << 15);
457 INTERPOLATE_INT_CUBIC_FUNC (gint32, gint64, PRECISION_S32, (gint64) 1 << 31);
458 INTERPOLATE_FLOAT_CUBIC_FUNC (gfloat);
459 INTERPOLATE_FLOAT_CUBIC_FUNC (gdouble);
460
461 static InterpolateFunc interpolate_funcs[] = {
462 interpolate_gint16_linear_c,
463 interpolate_gint32_linear_c,
464 interpolate_gfloat_linear_c,
465 interpolate_gdouble_linear_c,
466
467 interpolate_gint16_cubic_c,
468 interpolate_gint32_cubic_c,
469 interpolate_gfloat_cubic_c,
470 interpolate_gdouble_cubic_c,
471 };
472
473 #define interpolate_gint16_linear interpolate_funcs[0]
474 #define interpolate_gint32_linear interpolate_funcs[1]
475 #define interpolate_gfloat_linear interpolate_funcs[2]
476 #define interpolate_gdouble_linear interpolate_funcs[3]
477
478 #define interpolate_gint16_cubic interpolate_funcs[4]
479 #define interpolate_gint32_cubic interpolate_funcs[5]
480 #define interpolate_gfloat_cubic interpolate_funcs[6]
481 #define interpolate_gdouble_cubic interpolate_funcs[7]
482
483 #define GET_TAPS_NEAREST_FUNC(type) \
484 static inline gpointer \
485 get_taps_##type##_nearest (GstAudioResampler * resampler, \
486 gint *samp_index, gint *samp_phase, type icoeff[4]) \
487 { \
488 gint out_rate = resampler->out_rate; \
489 *samp_index += resampler->samp_inc; \
490 *samp_phase += resampler->samp_frac; \
491 if (*samp_phase >= out_rate) { \
492 *samp_phase -= out_rate; \
493 *samp_index += 1; \
494 } \
495 return NULL; \
496 }
497 GET_TAPS_NEAREST_FUNC (gint16);
498 GET_TAPS_NEAREST_FUNC (gint32);
499 GET_TAPS_NEAREST_FUNC (gfloat);
500 GET_TAPS_NEAREST_FUNC (gdouble);
501
502 #define get_taps_gint16_nearest get_taps_gint16_nearest
503 #define get_taps_gint32_nearest get_taps_gint32_nearest
504 #define get_taps_gfloat_nearest get_taps_gfloat_nearest
505 #define get_taps_gdouble_nearest get_taps_gdouble_nearest
506
507 #define GET_TAPS_FULL_FUNC(type) \
508 DECL_GET_TAPS_FULL_FUNC(type) \
509 { \
510 gpointer res; \
511 gint out_rate = resampler->out_rate; \
512 gint n_phases = resampler->n_phases; \
513 gint phase = (n_phases == out_rate ? *samp_phase : \
514 ((gint64)*samp_phase * n_phases) / out_rate); \
515 \
516 res = resampler->cached_phases[phase]; \
517 if (G_UNLIKELY (res == NULL)) { \
518 res = (gint8 *) resampler->cached_taps + \
519 phase * resampler->cached_taps_stride; \
520 switch (resampler->filter_interpolation) { \
521 case GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_NONE: \
522 { \
523 gdouble x; \
524 gint n_taps = resampler->n_taps; \
525 \
526 x = 1.0 - n_taps / 2 - (gdouble) phase / n_phases; \
527 make_taps (resampler, res, x, n_taps); \
528 break; \
529 } \
530 default: \
531 { \
532 gint offset, pos, frac; \
533 gint oversample = resampler->oversample; \
534 gint taps_stride = resampler->taps_stride; \
535 gint n_taps = resampler->n_taps; \
536 type ic[4], *taps; \
537 \
538 pos = phase * oversample; \
539 offset = (oversample - 1) - pos / n_phases; \
540 frac = pos % n_phases; \
541 \
542 taps = (type *) ((gint8 *) resampler->taps + offset * taps_stride); \
543 \
544 switch (resampler->filter_interpolation) { \
545 default: \
546 case GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_LINEAR: \
547 make_coeff_##type##_linear (frac, n_phases, ic); \
548 break; \
549 case GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_CUBIC: \
550 make_coeff_##type##_cubic (frac, n_phases, ic); \
551 break; \
552 } \
553 resampler->interpolate (res, taps, n_taps, ic, taps_stride); \
554 } \
555 } \
556 resampler->cached_phases[phase] = res; \
557 } \
558 *samp_index += resampler->samp_inc; \
559 *samp_phase += resampler->samp_frac; \
560 if (*samp_phase >= out_rate) { \
561 *samp_phase -= out_rate; \
562 *samp_index += 1; \
563 } \
564 return res; \
565 }
566 GET_TAPS_FULL_FUNC (gint16);
567 GET_TAPS_FULL_FUNC (gint32);
568 GET_TAPS_FULL_FUNC (gfloat);
569 GET_TAPS_FULL_FUNC (gdouble);
570
571 #define GET_TAPS_INTERPOLATE_FUNC(type,inter) \
572 DECL_GET_TAPS_INTERPOLATE_FUNC (type, inter) \
573 { \
574 gpointer res; \
575 gint out_rate = resampler->out_rate; \
576 gint offset, frac, pos; \
577 gint oversample = resampler->oversample; \
578 gint taps_stride = resampler->taps_stride; \
579 \
580 pos = *samp_phase * oversample; \
581 offset = (oversample - 1) - pos / out_rate; \
582 frac = pos % out_rate; \
583 \
584 res = (gint8 *) resampler->taps + offset * taps_stride; \
585 make_coeff_##type##_##inter (frac, out_rate, icoeff); \
586 \
587 *samp_index += resampler->samp_inc; \
588 *samp_phase += resampler->samp_frac; \
589 if (*samp_phase >= out_rate) { \
590 *samp_phase -= out_rate; \
591 *samp_index += 1; \
592 } \
593 return res; \
594 }
595
596 GET_TAPS_INTERPOLATE_FUNC (gint16, linear);
597 GET_TAPS_INTERPOLATE_FUNC (gint32, linear);
598 GET_TAPS_INTERPOLATE_FUNC (gfloat, linear);
599 GET_TAPS_INTERPOLATE_FUNC (gdouble, linear);
600
601 GET_TAPS_INTERPOLATE_FUNC (gint16, cubic);
602 GET_TAPS_INTERPOLATE_FUNC (gint32, cubic);
603 GET_TAPS_INTERPOLATE_FUNC (gfloat, cubic);
604 GET_TAPS_INTERPOLATE_FUNC (gdouble, cubic);
605
606 #define INNER_PRODUCT_NEAREST_FUNC(type) \
607 static inline void \
608 inner_product_##type##_nearest_1_c (type * o, const type * a, \
609 const type * b, gint len, const type *ic, gint bstride) \
610 { \
611 *o = *a; \
612 }
613 INNER_PRODUCT_NEAREST_FUNC (gint16);
614 INNER_PRODUCT_NEAREST_FUNC (gint32);
615 INNER_PRODUCT_NEAREST_FUNC (gfloat);
616 INNER_PRODUCT_NEAREST_FUNC (gdouble);
617
618 #define INNER_PRODUCT_INT_FULL_FUNC(type,type2,prec,limit) \
619 static inline void \
620 inner_product_##type##_full_1_c (type * o, const type * a, \
621 const type * b, gint len, const type *ic, gint bstride) \
622 { \
623 gint i; \
624 type2 res[4] = { 0, 0, 0, 0 }; \
625 \
626 for (i = 0; i < len; i += 4) { \
627 res[0] += (type2) a[i + 0] * (type2) b[i + 0]; \
628 res[1] += (type2) a[i + 1] * (type2) b[i + 1]; \
629 res[2] += (type2) a[i + 2] * (type2) b[i + 2]; \
630 res[3] += (type2) a[i + 3] * (type2) b[i + 3]; \
631 } \
632 res[0] = res[0] + res[1] + res[2] + res[3]; \
633 res[0] = (res[0] + ((type2)1 << ((prec) - 1))) >> (prec); \
634 *o = CLAMP (res[0], -(limit), (limit) - 1); \
635 }
636
637 INNER_PRODUCT_INT_FULL_FUNC (gint16, gint32, PRECISION_S16, (gint32) 1 << 15);
638 INNER_PRODUCT_INT_FULL_FUNC (gint32, gint64, PRECISION_S32, (gint64) 1 << 31);
639
640 #define INNER_PRODUCT_INT_LINEAR_FUNC(type,type2,prec,limit) \
641 static inline void \
642 inner_product_##type##_linear_1_c (type * o, const type * a, \
643 const type * b, gint len, const type *ic, gint bstride) \
644 { \
645 gint i; \
646 type2 res[4] = { 0, 0, 0, 0 }, c0 = ic[0]; \
647 const type *c[2] = {(type*)((gint8*)b + 0*bstride), \
648 (type*)((gint8*)b + 1*bstride)}; \
649 \
650 for (i = 0; i < len; i += 2) { \
651 res[0] += (type2) a[i + 0] * (type2) c[0][i + 0]; \
652 res[1] += (type2) a[i + 0] * (type2) c[1][i + 0]; \
653 res[2] += (type2) a[i + 1] * (type2) c[0][i + 1]; \
654 res[3] += (type2) a[i + 1] * (type2) c[1][i + 1]; \
655 } \
656 res[0] = (res[0] + res[2]) >> (prec); \
657 res[1] = (res[1] + res[3]) >> (prec); \
658 res[0] = ((type2)(type)res[0] - (type2)(type)res[1]) * c0 + \
659 ((type2)(type)res[1] << (prec)); \
660 res[0] = (res[0] + ((type2)1 << ((prec) - 1))) >> (prec); \
661 *o = CLAMP (res[0], -(limit), (limit) - 1); \
662 }
663
664 INNER_PRODUCT_INT_LINEAR_FUNC (gint16, gint32, PRECISION_S16, (gint32) 1 << 15);
665 INNER_PRODUCT_INT_LINEAR_FUNC (gint32, gint64, PRECISION_S32, (gint64) 1 << 31);
666
667 #define INNER_PRODUCT_INT_CUBIC_FUNC(type,type2,prec,limit) \
668 static inline void \
669 inner_product_##type##_cubic_1_c (type * o, const type * a, \
670 const type * b, gint len, const type *ic, gint bstride) \
671 { \
672 gint i; \
673 type2 res[4] = { 0, 0, 0, 0 }; \
674 const type *c[4] = {(type*)((gint8*)b + 0*bstride), \
675 (type*)((gint8*)b + 1*bstride), \
676 (type*)((gint8*)b + 2*bstride), \
677 (type*)((gint8*)b + 3*bstride)}; \
678 \
679 for (i = 0; i < len; i++) { \
680 res[0] += (type2) a[i] * (type2) c[0][i]; \
681 res[1] += (type2) a[i] * (type2) c[1][i]; \
682 res[2] += (type2) a[i] * (type2) c[2][i]; \
683 res[3] += (type2) a[i] * (type2) c[3][i]; \
684 } \
685 res[0] = (type2)(type)(res[0] >> (prec)) * (type2) ic[0] + \
686 (type2)(type)(res[1] >> (prec)) * (type2) ic[1] + \
687 (type2)(type)(res[2] >> (prec)) * (type2) ic[2] + \
688 (type2)(type)(res[3] >> (prec)) * (type2) ic[3]; \
689 res[0] = (res[0] + ((type2)1 << ((prec) - 1))) >> (prec); \
690 *o = CLAMP (res[0], -(limit), (limit) - 1); \
691 }
692
693 INNER_PRODUCT_INT_CUBIC_FUNC (gint16, gint32, PRECISION_S16, (gint32) 1 << 15);
694 INNER_PRODUCT_INT_CUBIC_FUNC (gint32, gint64, PRECISION_S32, (gint64) 1 << 31);
695
696 #define INNER_PRODUCT_FLOAT_FULL_FUNC(type) \
697 static inline void \
698 inner_product_##type##_full_1_c (type * o, const type * a, \
699 const type * b, gint len, const type *ic, gint bstride) \
700 { \
701 gint i; \
702 type res[4] = { 0.0, 0.0, 0.0, 0.0 }; \
703 \
704 for (i = 0; i < len; i += 4) { \
705 res[0] += a[i + 0] * b[i + 0]; \
706 res[1] += a[i + 1] * b[i + 1]; \
707 res[2] += a[i + 2] * b[i + 2]; \
708 res[3] += a[i + 3] * b[i + 3]; \
709 } \
710 *o = res[0] + res[1] + res[2] + res[3]; \
711 }
712
713 INNER_PRODUCT_FLOAT_FULL_FUNC (gfloat);
714 INNER_PRODUCT_FLOAT_FULL_FUNC (gdouble);
715
716 #define INNER_PRODUCT_FLOAT_LINEAR_FUNC(type) \
717 static inline void \
718 inner_product_##type##_linear_1_c (type * o, const type * a, \
719 const type * b, gint len, const type *ic, gint bstride) \
720 { \
721 gint i; \
722 type res[4] = { 0.0, 0.0, 0.0, 0.0 }; \
723 const type *c[2] = {(type*)((gint8*)b + 0*bstride), \
724 (type*)((gint8*)b + 1*bstride)}; \
725 \
726 for (i = 0; i < len; i += 2) { \
727 res[0] += a[i + 0] * c[0][i + 0]; \
728 res[1] += a[i + 0] * c[1][i + 0]; \
729 res[2] += a[i + 1] * c[0][i + 1]; \
730 res[3] += a[i + 1] * c[1][i + 1]; \
731 } \
732 res[0] += res[2]; \
733 res[1] += res[3]; \
734 *o = (res[0] - res[1]) * ic[0] + res[1]; \
735 }
736 INNER_PRODUCT_FLOAT_LINEAR_FUNC (gfloat);
737 INNER_PRODUCT_FLOAT_LINEAR_FUNC (gdouble);
738
739 #define INNER_PRODUCT_FLOAT_CUBIC_FUNC(type) \
740 static inline void \
741 inner_product_##type##_cubic_1_c (type * o, const type * a, \
742 const type * b, gint len, const type *ic, gint bstride) \
743 { \
744 gint i; \
745 type res[4] = { 0.0, 0.0, 0.0, 0.0 }; \
746 const type *c[4] = {(type*)((gint8*)b + 0*bstride), \
747 (type*)((gint8*)b + 1*bstride), \
748 (type*)((gint8*)b + 2*bstride), \
749 (type*)((gint8*)b + 3*bstride)}; \
750 \
751 for (i = 0; i < len; i++) { \
752 res[0] += a[i] * c[0][i]; \
753 res[1] += a[i] * c[1][i]; \
754 res[2] += a[i] * c[2][i]; \
755 res[3] += a[i] * c[3][i]; \
756 } \
757 *o = res[0] * ic[0] + res[1] * ic[1] + \
758 res[2] * ic[2] + res[3] * ic[3]; \
759 }
760 INNER_PRODUCT_FLOAT_CUBIC_FUNC (gfloat);
761 INNER_PRODUCT_FLOAT_CUBIC_FUNC (gdouble);
762
763 MAKE_RESAMPLE_FUNC_STATIC (gint16, nearest, 1, c);
764 MAKE_RESAMPLE_FUNC_STATIC (gint32, nearest, 1, c);
765 MAKE_RESAMPLE_FUNC_STATIC (gfloat, nearest, 1, c);
766 MAKE_RESAMPLE_FUNC_STATIC (gdouble, nearest, 1, c);
767
768 MAKE_RESAMPLE_FUNC_STATIC (gint16, full, 1, c);
769 MAKE_RESAMPLE_FUNC_STATIC (gint32, full, 1, c);
770 MAKE_RESAMPLE_FUNC_STATIC (gfloat, full, 1, c);
771 MAKE_RESAMPLE_FUNC_STATIC (gdouble, full, 1, c);
772
773 MAKE_RESAMPLE_FUNC_STATIC (gint16, linear, 1, c);
774 MAKE_RESAMPLE_FUNC_STATIC (gint32, linear, 1, c);
775 MAKE_RESAMPLE_FUNC_STATIC (gfloat, linear, 1, c);
776 MAKE_RESAMPLE_FUNC_STATIC (gdouble, linear, 1, c);
777
778 MAKE_RESAMPLE_FUNC_STATIC (gint16, cubic, 1, c);
779 MAKE_RESAMPLE_FUNC_STATIC (gint32, cubic, 1, c);
780 MAKE_RESAMPLE_FUNC_STATIC (gfloat, cubic, 1, c);
781 MAKE_RESAMPLE_FUNC_STATIC (gdouble, cubic, 1, c);
782
783 static ResampleFunc resample_funcs[] = {
784 resample_gint16_nearest_1_c,
785 resample_gint32_nearest_1_c,
786 resample_gfloat_nearest_1_c,
787 resample_gdouble_nearest_1_c,
788
789 resample_gint16_full_1_c,
790 resample_gint32_full_1_c,
791 resample_gfloat_full_1_c,
792 resample_gdouble_full_1_c,
793
794 resample_gint16_linear_1_c,
795 resample_gint32_linear_1_c,
796 resample_gfloat_linear_1_c,
797 resample_gdouble_linear_1_c,
798
799 resample_gint16_cubic_1_c,
800 resample_gint32_cubic_1_c,
801 resample_gfloat_cubic_1_c,
802 resample_gdouble_cubic_1_c,
803 };
804
805 #define resample_gint16_nearest_1 resample_funcs[0]
806 #define resample_gint32_nearest_1 resample_funcs[1]
807 #define resample_gfloat_nearest_1 resample_funcs[2]
808 #define resample_gdouble_nearest_1 resample_funcs[3]
809
810 #define resample_gint16_full_1 resample_funcs[4]
811 #define resample_gint32_full_1 resample_funcs[5]
812 #define resample_gfloat_full_1 resample_funcs[6]
813 #define resample_gdouble_full_1 resample_funcs[7]
814
815 #define resample_gint16_linear_1 resample_funcs[8]
816 #define resample_gint32_linear_1 resample_funcs[9]
817 #define resample_gfloat_linear_1 resample_funcs[10]
818 #define resample_gdouble_linear_1 resample_funcs[11]
819
820 #define resample_gint16_cubic_1 resample_funcs[12]
821 #define resample_gint32_cubic_1 resample_funcs[13]
822 #define resample_gfloat_cubic_1 resample_funcs[14]
823 #define resample_gdouble_cubic_1 resample_funcs[15]
824
825 #if defined HAVE_ORC && !defined DISABLE_ORC
826 # if defined (HAVE_ARM_NEON)
827 # define CHECK_NEON
828 # include "audio-resampler-neon.h"
829 # endif
830 # if defined (__i386__) || defined (__x86_64__)
831 # define CHECK_X86
832 # include "audio-resampler-x86.h"
833 # endif
834 #endif
835
836 static void
audio_resampler_init(void)837 audio_resampler_init (void)
838 {
839 static gsize init_gonce = 0;
840
841 if (g_once_init_enter (&init_gonce)) {
842
843 GST_DEBUG_CATEGORY_INIT (audio_resampler_debug, "audio-resampler", 0,
844 "audio-resampler object");
845
846 #if defined HAVE_ORC && !defined DISABLE_ORC
847 orc_init ();
848 {
849 OrcTarget *target = orc_target_get_default ();
850 gint i;
851
852 if (target) {
853 const gchar *name;
854 unsigned int flags = orc_target_get_default_flags (target);
855
856 for (i = -1; i < 32; ++i) {
857 if (i == -1) {
858 name = orc_target_get_name (target);
859 GST_DEBUG ("target %s, default flags %08x", name, flags);
860 } else if (flags & (1U << i)) {
861 name = orc_target_get_flag_name (target, i);
862 GST_DEBUG ("target flag %s", name);
863 } else
864 name = NULL;
865
866 if (name) {
867 #ifdef CHECK_X86
868 audio_resampler_check_x86 (name);
869 #endif
870 #ifdef CHECK_NEON
871 audio_resampler_check_neon (name);
872 #endif
873 }
874 }
875 }
876 }
877 #endif
878 g_once_init_leave (&init_gonce, 1);
879 }
880 }
881
882 #define MAKE_DEINTERLEAVE_FUNC(type) \
883 static void \
884 deinterleave_ ##type (GstAudioResampler * resampler, gpointer sbuf[], \
885 gpointer in[], gsize in_frames) \
886 { \
887 gint i, c, channels = resampler->channels; \
888 gsize samples_avail = resampler->samples_avail; \
889 for (c = 0; c < channels; c++) { \
890 type *s = (type *) sbuf[c] + samples_avail; \
891 if (G_UNLIKELY (in == NULL)) { \
892 for (i = 0; i < in_frames; i++) \
893 s[i] = 0; \
894 } else { \
895 type *ip = (type *) in[0] + c; \
896 for (i = 0; i < in_frames; i++, ip += channels) \
897 s[i] = *ip; \
898 } \
899 } \
900 }
901
902 MAKE_DEINTERLEAVE_FUNC (gint16);
903 MAKE_DEINTERLEAVE_FUNC (gint32);
904 MAKE_DEINTERLEAVE_FUNC (gfloat);
905 MAKE_DEINTERLEAVE_FUNC (gdouble);
906
907 static DeinterleaveFunc deinterleave_funcs[] = {
908 deinterleave_gint16,
909 deinterleave_gint32,
910 deinterleave_gfloat,
911 deinterleave_gdouble
912 };
913
914 static void
copy_func(GstAudioResampler * resampler,gpointer sbuf[],gpointer in[],gsize in_frames)915 copy_func (GstAudioResampler * resampler, gpointer sbuf[],
916 gpointer in[], gsize in_frames)
917 {
918 gint c, channels = resampler->channels;
919 gsize samples_avail = resampler->samples_avail;
920 for (c = 0; c < channels; c++) {
921 guint8 *s = ((guint8 *) sbuf[c]) + (samples_avail * resampler->bps);
922 if (G_UNLIKELY (in == NULL)) {
923 memset (s, 0, in_frames * resampler->bps);
924 } else {
925 memcpy (s, in[c], in_frames * resampler->bps);
926 }
927 }
928 }
929
930 static void
calculate_kaiser_params(GstAudioResampler * resampler)931 calculate_kaiser_params (GstAudioResampler * resampler)
932 {
933 gdouble A, B, dw, tr_bw, Fc;
934 gint n;
935 const KaiserQualityMap *q = &kaiser_qualities[DEFAULT_QUALITY];
936
937 /* default cutoff */
938 Fc = q->cutoff;
939 if (resampler->out_rate < resampler->in_rate)
940 Fc *= q->downsample_cutoff_factor;
941
942 Fc = GET_OPT_CUTOFF (resampler->options, Fc);
943 A = GET_OPT_STOP_ATTENUATION (resampler->options, q->stopband_attenuation);
944 tr_bw =
945 GET_OPT_TRANSITION_BANDWIDTH (resampler->options,
946 q->transition_bandwidth);
947
948 GST_LOG ("Fc %f, A %f, tr_bw %f", Fc, A, tr_bw);
949
950 /* calculate Beta */
951 if (A > 50)
952 B = 0.1102 * (A - 8.7);
953 else if (A >= 21)
954 B = 0.5842 * pow (A - 21, 0.4) + 0.07886 * (A - 21);
955 else
956 B = 0.0;
957 /* calculate transition width in radians */
958 dw = 2 * G_PI * (tr_bw);
959 /* order of the filter */
960 n = (A - 8.0) / (2.285 * dw);
961
962 resampler->kaiser_beta = B;
963 resampler->n_taps = n + 1;
964 resampler->cutoff = Fc;
965
966 GST_LOG ("using Beta %f n_taps %d cutoff %f", resampler->kaiser_beta,
967 resampler->n_taps, resampler->cutoff);
968 }
969
970 static void
alloc_taps_mem(GstAudioResampler * resampler,gint bps,gint n_taps,gint n_phases)971 alloc_taps_mem (GstAudioResampler * resampler, gint bps, gint n_taps,
972 gint n_phases)
973 {
974 if (resampler->alloc_taps >= n_taps && resampler->alloc_phases >= n_phases)
975 return;
976
977 GST_DEBUG ("allocate bps %d n_taps %d n_phases %d", bps, n_taps, n_phases);
978
979 resampler->tmp_taps =
980 g_realloc_n (resampler->tmp_taps, n_taps, sizeof (gdouble));
981
982 resampler->taps_stride = GST_ROUND_UP_32 (bps * (n_taps + TAPS_OVERREAD));
983
984 g_free (resampler->taps_mem);
985 resampler->taps_mem =
986 g_malloc0 (n_phases * resampler->taps_stride + ALIGN - 1);
987 resampler->taps = MEM_ALIGN ((gint8 *) resampler->taps_mem, ALIGN);
988 resampler->alloc_taps = n_taps;
989 resampler->alloc_phases = n_phases;
990 }
991
992 static void
alloc_cache_mem(GstAudioResampler * resampler,gint bps,gint n_taps,gint n_phases)993 alloc_cache_mem (GstAudioResampler * resampler, gint bps, gint n_taps,
994 gint n_phases)
995 {
996 gsize phases_size;
997
998 resampler->tmp_taps =
999 g_realloc_n (resampler->tmp_taps, n_taps, sizeof (gdouble));
1000
1001 resampler->cached_taps_stride =
1002 GST_ROUND_UP_32 (bps * (n_taps + TAPS_OVERREAD));
1003
1004 phases_size = sizeof (gpointer) * n_phases;
1005
1006 g_free (resampler->cached_taps_mem);
1007 resampler->cached_taps_mem =
1008 g_malloc0 (phases_size + n_phases * resampler->cached_taps_stride +
1009 ALIGN - 1);
1010 resampler->cached_taps =
1011 MEM_ALIGN ((gint8 *) resampler->cached_taps_mem + phases_size, ALIGN);
1012 resampler->cached_phases = resampler->cached_taps_mem;
1013 }
1014
1015 static void
setup_functions(GstAudioResampler * resampler)1016 setup_functions (GstAudioResampler * resampler)
1017 {
1018 gint index, fidx;
1019
1020 index = resampler->format_index;
1021
1022 if (resampler->in_rate == resampler->out_rate)
1023 resampler->resample = resample_funcs[index];
1024 else {
1025 switch (resampler->filter_interpolation) {
1026 default:
1027 case GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_NONE:
1028 fidx = 0;
1029 break;
1030 case GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_LINEAR:
1031 GST_DEBUG ("using linear interpolation for filter coefficients");
1032 fidx = 0;
1033 break;
1034 case GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_CUBIC:
1035 GST_DEBUG ("using cubic interpolation for filter coefficients");
1036 fidx = 4;
1037 break;
1038 }
1039 GST_DEBUG ("using filter interpolate function %d", index + fidx);
1040 resampler->interpolate = interpolate_funcs[index + fidx];
1041
1042 switch (resampler->method) {
1043 case GST_AUDIO_RESAMPLER_METHOD_NEAREST:
1044 GST_DEBUG ("using nearest filter function");
1045 break;
1046 default:
1047 index += 4;
1048 switch (resampler->filter_mode) {
1049 default:
1050 case GST_AUDIO_RESAMPLER_FILTER_MODE_FULL:
1051 GST_DEBUG ("using full filter function");
1052 break;
1053 case GST_AUDIO_RESAMPLER_FILTER_MODE_INTERPOLATED:
1054 index += 4 + fidx;
1055 GST_DEBUG ("using interpolated filter function");
1056 break;
1057 }
1058 break;
1059 }
1060 GST_DEBUG ("using resample function %d", index);
1061 resampler->resample = resample_funcs[index];
1062 }
1063 }
1064
1065 static void
resampler_calculate_taps(GstAudioResampler * resampler)1066 resampler_calculate_taps (GstAudioResampler * resampler)
1067 {
1068 gint bps;
1069 gint n_taps, oversample;
1070 gint in_rate, out_rate;
1071 gboolean scale = TRUE, sinc_table = FALSE;
1072 GstAudioResamplerFilterInterpolation filter_interpolation;
1073
1074 switch (resampler->method) {
1075 case GST_AUDIO_RESAMPLER_METHOD_NEAREST:
1076 resampler->n_taps = 2;
1077 scale = FALSE;
1078 break;
1079 case GST_AUDIO_RESAMPLER_METHOD_LINEAR:
1080 resampler->n_taps = GET_OPT_N_TAPS (resampler->options, 2);
1081 break;
1082 case GST_AUDIO_RESAMPLER_METHOD_CUBIC:
1083 resampler->n_taps = GET_OPT_N_TAPS (resampler->options, 4);
1084 resampler->b = GET_OPT_CUBIC_B (resampler->options);
1085 resampler->c = GET_OPT_CUBIC_C (resampler->options);;
1086 break;
1087 case GST_AUDIO_RESAMPLER_METHOD_BLACKMAN_NUTTALL:
1088 {
1089 const BlackmanQualityMap *q = &blackman_qualities[DEFAULT_QUALITY];
1090 resampler->n_taps = GET_OPT_N_TAPS (resampler->options, q->n_taps);
1091 resampler->cutoff = GET_OPT_CUTOFF (resampler->options, q->cutoff);
1092 sinc_table = TRUE;
1093 break;
1094 }
1095 case GST_AUDIO_RESAMPLER_METHOD_KAISER:
1096 calculate_kaiser_params (resampler);
1097 sinc_table = TRUE;
1098 break;
1099 }
1100
1101 in_rate = resampler->in_rate;
1102 out_rate = resampler->out_rate;
1103
1104 if (out_rate < in_rate && scale) {
1105 resampler->cutoff = resampler->cutoff * out_rate / in_rate;
1106 resampler->n_taps =
1107 gst_util_uint64_scale_int (resampler->n_taps, in_rate, out_rate);
1108 }
1109
1110 if (sinc_table) {
1111 resampler->n_taps = GST_ROUND_UP_8 (resampler->n_taps);
1112 resampler->filter_mode = GET_OPT_FILTER_MODE (resampler->options);
1113 resampler->filter_threshold =
1114 GET_OPT_FILTER_MODE_THRESHOLD (resampler->options);
1115 filter_interpolation = GET_OPT_FILTER_INTERPOLATION (resampler->options);
1116
1117 } else {
1118 resampler->filter_mode = GST_AUDIO_RESAMPLER_FILTER_MODE_FULL;
1119 filter_interpolation = GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_NONE;
1120 }
1121
1122 /* calculate oversampling for interpolated filter */
1123 if (filter_interpolation != GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_NONE) {
1124 gint mult = 2;
1125
1126 oversample = GET_OPT_FILTER_OVERSAMPLE (resampler->options);
1127 while (oversample > 1) {
1128 if (mult * out_rate >= in_rate)
1129 break;
1130
1131 mult *= 2;
1132 oversample >>= 1;
1133 }
1134
1135 switch (filter_interpolation) {
1136 case GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_LINEAR:
1137 oversample *= 11;
1138 break;
1139 default:
1140 break;
1141 }
1142 } else {
1143 oversample = 1;
1144 }
1145 resampler->oversample = oversample;
1146
1147 n_taps = resampler->n_taps;
1148 bps = resampler->bps;
1149
1150 GST_LOG ("using n_taps %d cutoff %f oversample %d", n_taps, resampler->cutoff,
1151 oversample);
1152
1153 if (resampler->filter_mode == GST_AUDIO_RESAMPLER_FILTER_MODE_AUTO) {
1154 if (out_rate <= oversample
1155 && !(resampler->flags & GST_AUDIO_RESAMPLER_FLAG_VARIABLE_RATE)) {
1156 /* don't interpolate if we need to calculate at least the same amount
1157 * of filter coefficients than the full table case */
1158 resampler->filter_mode = GST_AUDIO_RESAMPLER_FILTER_MODE_FULL;
1159 GST_DEBUG ("automatically selected full filter, %d <= %d", out_rate,
1160 oversample);
1161 } else if (bps * n_taps * out_rate < resampler->filter_threshold) {
1162 /* switch to full filter when memory is below threshold */
1163 resampler->filter_mode = GST_AUDIO_RESAMPLER_FILTER_MODE_FULL;
1164 GST_DEBUG ("automatically selected full filter, memory %d <= %d",
1165 bps * n_taps * out_rate, resampler->filter_threshold);
1166 } else {
1167 GST_DEBUG ("automatically selected interpolated filter");
1168 resampler->filter_mode = GST_AUDIO_RESAMPLER_FILTER_MODE_INTERPOLATED;
1169 }
1170 }
1171 /* interpolated table but no interpolation given, assume default */
1172 if (resampler->filter_mode != GST_AUDIO_RESAMPLER_FILTER_MODE_FULL &&
1173 filter_interpolation == GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_NONE)
1174 filter_interpolation = DEFAULT_OPT_FILTER_INTERPOLATION;
1175
1176 resampler->filter_interpolation = filter_interpolation;
1177
1178 if (resampler->filter_mode == GST_AUDIO_RESAMPLER_FILTER_MODE_FULL &&
1179 resampler->method != GST_AUDIO_RESAMPLER_METHOD_NEAREST) {
1180 GST_DEBUG ("setting up filter cache");
1181 resampler->n_phases = out_rate;
1182 alloc_cache_mem (resampler, bps, n_taps, out_rate);
1183 }
1184
1185 if (resampler->filter_interpolation !=
1186 GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_NONE) {
1187 gint i, isize;
1188 gdouble x;
1189 gpointer taps;
1190
1191 switch (resampler->filter_interpolation) {
1192 default:
1193 case GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_LINEAR:
1194 GST_DEBUG ("using linear interpolation to build filter");
1195 isize = 2;
1196 break;
1197 case GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_CUBIC:
1198 GST_DEBUG ("using cubic interpolation to build filter");
1199 isize = 4;
1200 break;
1201 }
1202
1203 alloc_taps_mem (resampler, bps, n_taps, oversample + isize);
1204
1205 for (i = 0; i < oversample + isize; i++) {
1206 x = -(n_taps / 2) + i / (gdouble) oversample;
1207 taps = (gint8 *) resampler->taps + i * resampler->taps_stride;
1208 make_taps (resampler, taps, x, n_taps);
1209 }
1210 }
1211 }
1212
1213 #define PRINT_TAPS(type,print) \
1214 G_STMT_START { \
1215 type sum = 0.0, *taps; \
1216 type icoeff[4]; \
1217 gint samp_index = 0, samp_phase = i; \
1218 \
1219 taps = get_taps_##type##_full (resampler, &samp_index,\
1220 &samp_phase, icoeff); \
1221 \
1222 for (j = 0; j < n_taps; j++) { \
1223 type tap = taps[j]; \
1224 fprintf (stderr, "\t%" print " ", tap); \
1225 sum += tap; \
1226 } \
1227 fprintf (stderr, "\t: sum %" print "\n", sum); \
1228 } G_STMT_END
1229
1230 static void
resampler_dump(GstAudioResampler * resampler)1231 resampler_dump (GstAudioResampler * resampler)
1232 {
1233 #if 0
1234 gint i, n_taps, out_rate;
1235 gint64 a;
1236
1237 out_rate = resampler->out_rate;
1238 n_taps = resampler->n_taps;
1239
1240 fprintf (stderr, "out size %d, max taps %d\n", out_rate, n_taps);
1241
1242 a = g_get_monotonic_time ();
1243
1244 for (i = 0; i < out_rate; i++) {
1245 gint j;
1246
1247 //fprintf (stderr, "%u: %d %d\t ", i, t->sample_inc, t->next_phase);
1248 switch (resampler->format) {
1249 case GST_AUDIO_FORMAT_F64:
1250 PRINT_TAPS (gdouble, "f");
1251 break;
1252 case GST_AUDIO_FORMAT_F32:
1253 PRINT_TAPS (gfloat, "f");
1254 break;
1255 case GST_AUDIO_FORMAT_S32:
1256 PRINT_TAPS (gint32, "d");
1257 break;
1258 case GST_AUDIO_FORMAT_S16:
1259 PRINT_TAPS (gint16, "d");
1260 break;
1261 default:
1262 break;
1263 }
1264 }
1265 fprintf (stderr, "time %" G_GUINT64_FORMAT "\n", g_get_monotonic_time () - a);
1266 #endif
1267 }
1268
1269 /**
1270 * gst_audio_resampler_options_set_quality:
1271 * @method: a #GstAudioResamplerMethod
1272 * @quality: the quality
1273 * @in_rate: the input rate
1274 * @out_rate: the output rate
1275 * @options: a #GstStructure
1276 *
1277 * Set the parameters for resampling from @in_rate to @out_rate using @method
1278 * for @quality in @options.
1279 */
1280 void
gst_audio_resampler_options_set_quality(GstAudioResamplerMethod method,guint quality,gint in_rate,gint out_rate,GstStructure * options)1281 gst_audio_resampler_options_set_quality (GstAudioResamplerMethod method,
1282 guint quality, gint in_rate, gint out_rate, GstStructure * options)
1283 {
1284 g_return_if_fail (options != NULL);
1285 g_return_if_fail (quality <= GST_AUDIO_RESAMPLER_QUALITY_MAX);
1286 g_return_if_fail (in_rate > 0 && out_rate > 0);
1287
1288 switch (method) {
1289 case GST_AUDIO_RESAMPLER_METHOD_NEAREST:
1290 break;
1291 case GST_AUDIO_RESAMPLER_METHOD_LINEAR:
1292 gst_structure_set (options,
1293 GST_AUDIO_RESAMPLER_OPT_N_TAPS, G_TYPE_INT, 2, NULL);
1294 break;
1295 case GST_AUDIO_RESAMPLER_METHOD_CUBIC:
1296 gst_structure_set (options,
1297 GST_AUDIO_RESAMPLER_OPT_N_TAPS, G_TYPE_INT, 4,
1298 GST_AUDIO_RESAMPLER_OPT_CUBIC_B, G_TYPE_DOUBLE, DEFAULT_OPT_CUBIC_B,
1299 GST_AUDIO_RESAMPLER_OPT_CUBIC_C, G_TYPE_DOUBLE, DEFAULT_OPT_CUBIC_C,
1300 NULL);
1301 break;
1302 case GST_AUDIO_RESAMPLER_METHOD_BLACKMAN_NUTTALL:
1303 {
1304 const BlackmanQualityMap *map = &blackman_qualities[quality];
1305 gst_structure_set (options,
1306 GST_AUDIO_RESAMPLER_OPT_N_TAPS, G_TYPE_INT, map->n_taps,
1307 GST_AUDIO_RESAMPLER_OPT_CUTOFF, G_TYPE_DOUBLE, map->cutoff, NULL);
1308 break;
1309 }
1310 case GST_AUDIO_RESAMPLER_METHOD_KAISER:
1311 {
1312 const KaiserQualityMap *map = &kaiser_qualities[quality];
1313 gdouble cutoff;
1314
1315 cutoff = map->cutoff;
1316 if (out_rate < in_rate)
1317 cutoff *= map->downsample_cutoff_factor;
1318
1319 gst_structure_set (options,
1320 GST_AUDIO_RESAMPLER_OPT_CUTOFF, G_TYPE_DOUBLE, cutoff,
1321 GST_AUDIO_RESAMPLER_OPT_STOP_ATTENUATION, G_TYPE_DOUBLE,
1322 map->stopband_attenuation,
1323 GST_AUDIO_RESAMPLER_OPT_TRANSITION_BANDWIDTH, G_TYPE_DOUBLE,
1324 map->transition_bandwidth, NULL);
1325 break;
1326 }
1327 }
1328 gst_structure_set (options,
1329 GST_AUDIO_RESAMPLER_OPT_FILTER_OVERSAMPLE, G_TYPE_INT,
1330 oversample_qualities[quality], NULL);
1331 }
1332
1333 /**
1334 * gst_audio_resampler_new:
1335 * @method: a #GstAudioResamplerMethod
1336 * @flags: #GstAudioResamplerFlags
1337 * @format: the #GstAudioFormat
1338 * @channels: the number of channels
1339 * @in_rate: input rate
1340 * @out_rate: output rate
1341 * @options: extra options
1342 *
1343 * Make a new resampler.
1344 *
1345 * Returns: (skip) (transfer full): The new #GstAudioResampler, or
1346 * %NULL on failure.
1347 */
1348 GstAudioResampler *
gst_audio_resampler_new(GstAudioResamplerMethod method,GstAudioResamplerFlags flags,GstAudioFormat format,gint channels,gint in_rate,gint out_rate,GstStructure * options)1349 gst_audio_resampler_new (GstAudioResamplerMethod method,
1350 GstAudioResamplerFlags flags,
1351 GstAudioFormat format, gint channels,
1352 gint in_rate, gint out_rate, GstStructure * options)
1353 {
1354 gboolean non_interleaved_in, non_interleaved_out;
1355 GstAudioResampler *resampler;
1356 const GstAudioFormatInfo *info;
1357 GstStructure *def_options = NULL;
1358
1359 g_return_val_if_fail (method >= GST_AUDIO_RESAMPLER_METHOD_NEAREST
1360 && method <= GST_AUDIO_RESAMPLER_METHOD_KAISER, NULL);
1361 g_return_val_if_fail (format == GST_AUDIO_FORMAT_S16 ||
1362 format == GST_AUDIO_FORMAT_S32 || format == GST_AUDIO_FORMAT_F32 ||
1363 format == GST_AUDIO_FORMAT_F64, NULL);
1364 g_return_val_if_fail (channels > 0, NULL);
1365 g_return_val_if_fail (in_rate > 0, NULL);
1366 g_return_val_if_fail (out_rate > 0, NULL);
1367
1368 audio_resampler_init ();
1369
1370 resampler = g_slice_new0 (GstAudioResampler);
1371 resampler->method = method;
1372 resampler->flags = flags;
1373 resampler->format = format;
1374 resampler->channels = channels;
1375
1376 switch (format) {
1377 case GST_AUDIO_FORMAT_S16:
1378 resampler->format_index = 0;
1379 break;
1380 case GST_AUDIO_FORMAT_S32:
1381 resampler->format_index = 1;
1382 break;
1383 case GST_AUDIO_FORMAT_F32:
1384 resampler->format_index = 2;
1385 break;
1386 case GST_AUDIO_FORMAT_F64:
1387 resampler->format_index = 3;
1388 break;
1389 default:
1390 g_assert_not_reached ();
1391 break;
1392 }
1393
1394 info = gst_audio_format_get_info (format);
1395 resampler->bps = GST_AUDIO_FORMAT_INFO_WIDTH (info) / 8;
1396 resampler->sbuf = g_malloc0 (sizeof (gpointer) * channels);
1397
1398 non_interleaved_in =
1399 (resampler->flags & GST_AUDIO_RESAMPLER_FLAG_NON_INTERLEAVED_IN);
1400 non_interleaved_out =
1401 (resampler->flags & GST_AUDIO_RESAMPLER_FLAG_NON_INTERLEAVED_OUT);
1402
1403 /* we resample each channel separately */
1404 resampler->blocks = resampler->channels;
1405 resampler->inc = 1;
1406 resampler->ostride = non_interleaved_out ? 1 : resampler->channels;
1407 resampler->deinterleave = non_interleaved_in ?
1408 copy_func : deinterleave_funcs[resampler->format_index];
1409 resampler->convert_taps = convert_taps_funcs[resampler->format_index];
1410
1411 GST_DEBUG ("method %d, bps %d, channels %d", method, resampler->bps,
1412 resampler->channels);
1413
1414 if (options == NULL) {
1415 options = def_options =
1416 gst_structure_new_empty ("GstAudioResampler.options");
1417 gst_audio_resampler_options_set_quality (DEFAULT_RESAMPLER_METHOD,
1418 GST_AUDIO_RESAMPLER_QUALITY_DEFAULT, in_rate, out_rate, options);
1419 }
1420
1421 gst_audio_resampler_update (resampler, in_rate, out_rate, options);
1422 gst_audio_resampler_reset (resampler);
1423
1424 if (def_options)
1425 gst_structure_free (def_options);
1426
1427 return resampler;
1428 }
1429
1430 /* make the buffers to hold the (deinterleaved) samples */
1431 static inline gpointer *
get_sample_bufs(GstAudioResampler * resampler,gsize need)1432 get_sample_bufs (GstAudioResampler * resampler, gsize need)
1433 {
1434 if (G_LIKELY (resampler->samples_len < need)) {
1435 gint c, blocks = resampler->blocks;
1436 gsize bytes, to_move = 0;
1437 gint8 *ptr, *samples;
1438
1439 GST_LOG ("realloc %d -> %d", (gint) resampler->samples_len, (gint) need);
1440
1441 bytes = GST_ROUND_UP_N (need * resampler->bps * resampler->inc, ALIGN);
1442
1443 samples = g_malloc0 (blocks * bytes + ALIGN - 1);
1444 ptr = MEM_ALIGN (samples, ALIGN);
1445
1446 /* if we had some data, move history */
1447 if (resampler->samples_len > 0)
1448 to_move = resampler->samples_avail * resampler->bps * resampler->inc;
1449
1450 /* set up new pointers */
1451 for (c = 0; c < blocks; c++) {
1452 memcpy (ptr + (c * bytes), resampler->sbuf[c], to_move);
1453 resampler->sbuf[c] = ptr + (c * bytes);
1454 }
1455 g_free (resampler->samples);
1456 resampler->samples = samples;
1457 resampler->samples_len = need;
1458 }
1459 return resampler->sbuf;
1460 }
1461
1462 /**
1463 * gst_audio_resampler_reset:
1464 * @resampler: a #GstAudioResampler
1465 *
1466 * Reset @resampler to the state it was when it was first created, discarding
1467 * all sample history.
1468 */
1469 void
gst_audio_resampler_reset(GstAudioResampler * resampler)1470 gst_audio_resampler_reset (GstAudioResampler * resampler)
1471 {
1472 g_return_if_fail (resampler != NULL);
1473
1474 if (resampler->samples) {
1475 gsize bytes;
1476 gint c, blocks, bpf;
1477
1478 bpf = resampler->bps * resampler->inc;
1479 bytes = (resampler->n_taps / 2) * bpf;
1480 blocks = resampler->blocks;
1481
1482 for (c = 0; c < blocks; c++)
1483 memset (resampler->sbuf[c], 0, bytes);
1484 }
1485 /* half of the filter is filled with 0 */
1486 resampler->samp_index = 0;
1487 resampler->samples_avail = resampler->n_taps / 2 - 1;
1488 }
1489
1490 /**
1491 * gst_audio_resampler_update:
1492 * @resampler: a #GstAudioResampler
1493 * @in_rate: new input rate
1494 * @out_rate: new output rate
1495 * @options: new options or %NULL
1496 *
1497 * Update the resampler parameters for @resampler. This function should
1498 * not be called concurrently with any other function on @resampler.
1499 *
1500 * When @in_rate or @out_rate is 0, its value is unchanged.
1501 *
1502 * When @options is %NULL, the previously configured options are reused.
1503 *
1504 * Returns: %TRUE if the new parameters could be set
1505 */
1506 gboolean
gst_audio_resampler_update(GstAudioResampler * resampler,gint in_rate,gint out_rate,GstStructure * options)1507 gst_audio_resampler_update (GstAudioResampler * resampler,
1508 gint in_rate, gint out_rate, GstStructure * options)
1509 {
1510 gint gcd, samp_phase, old_n_taps;
1511 gdouble max_error;
1512
1513 g_return_val_if_fail (resampler != NULL, FALSE);
1514
1515 if (in_rate <= 0)
1516 in_rate = resampler->in_rate;
1517 if (out_rate <= 0)
1518 out_rate = resampler->out_rate;
1519
1520 if (resampler->out_rate > 0) {
1521 GST_INFO ("old phase %d/%d", resampler->samp_phase, resampler->out_rate);
1522 samp_phase =
1523 gst_util_uint64_scale_int (resampler->samp_phase, out_rate,
1524 resampler->out_rate);
1525 } else
1526 samp_phase = 0;
1527
1528 gcd = gst_util_greatest_common_divisor (in_rate, out_rate);
1529
1530 max_error = GET_OPT_MAX_PHASE_ERROR (resampler->options);
1531
1532 if (max_error < 1.0e-8) {
1533 GST_INFO ("using exact phase divider");
1534 gcd = gst_util_greatest_common_divisor (gcd, samp_phase);
1535 } else {
1536 while (gcd > 1) {
1537 gdouble ph1 = (gdouble) samp_phase / out_rate;
1538 gint factor = 2;
1539
1540 /* reduce the factor until we have a phase error of less than 10% */
1541 gdouble ph2 = (gdouble) (samp_phase / gcd) / (out_rate / gcd);
1542
1543 if (fabs (ph1 - ph2) < max_error)
1544 break;
1545
1546 while (gcd % factor != 0)
1547 factor++;
1548 gcd /= factor;
1549
1550 GST_INFO ("divide by factor %d, gcd %d", factor, gcd);
1551 }
1552 }
1553
1554 GST_INFO ("phase %d out_rate %d, in_rate %d, gcd %d", samp_phase, out_rate,
1555 in_rate, gcd);
1556
1557 resampler->samp_phase = samp_phase /= gcd;
1558 resampler->in_rate = in_rate /= gcd;
1559 resampler->out_rate = out_rate /= gcd;
1560
1561 GST_INFO ("new phase %d/%d", resampler->samp_phase, resampler->out_rate);
1562
1563 resampler->samp_inc = in_rate / out_rate;
1564 resampler->samp_frac = in_rate % out_rate;
1565
1566 if (options) {
1567 GST_INFO ("have new options, reconfigure filter");
1568
1569 if (resampler->options)
1570 gst_structure_free (resampler->options);
1571 resampler->options = gst_structure_copy (options);
1572
1573 old_n_taps = resampler->n_taps;
1574
1575 resampler_calculate_taps (resampler);
1576 resampler_dump (resampler);
1577
1578 if (old_n_taps > 0 && old_n_taps != resampler->n_taps) {
1579 gpointer *sbuf;
1580 gint i, bpf, bytes, soff, doff, diff;
1581
1582 sbuf = get_sample_bufs (resampler, resampler->n_taps);
1583
1584 bpf = resampler->bps * resampler->inc;
1585 bytes = resampler->samples_avail * bpf;
1586 soff = doff = resampler->samp_index * bpf;
1587
1588 diff = ((gint) resampler->n_taps - old_n_taps) / 2;
1589
1590 GST_DEBUG ("taps %d->%d, %d", old_n_taps, resampler->n_taps, diff);
1591
1592 if (diff < 0) {
1593 /* diff < 0, decrease taps, adjust source */
1594 soff += -diff * bpf;
1595 bytes -= -diff * bpf;
1596 } else {
1597 /* diff > 0, increase taps, adjust dest */
1598 doff += diff * bpf;
1599 }
1600
1601 /* now shrink or enlarge the history buffer, when we enlarge we
1602 * just leave the old samples in there. FIXME, probably do something better
1603 * like mirror or fill with zeroes. */
1604 for (i = 0; i < resampler->blocks; i++)
1605 memmove ((gint8 *) sbuf[i] + doff, (gint8 *) sbuf[i] + soff, bytes);
1606
1607 resampler->samples_avail += diff;
1608 }
1609 } else if (resampler->filter_mode == GST_AUDIO_RESAMPLER_FILTER_MODE_FULL) {
1610 GST_DEBUG ("setting up filter cache");
1611 resampler->n_phases = resampler->out_rate;
1612 alloc_cache_mem (resampler, resampler->bps, resampler->n_taps,
1613 resampler->n_phases);
1614 }
1615 setup_functions (resampler);
1616
1617 return TRUE;
1618 }
1619
1620 /**
1621 * gst_audio_resampler_free:
1622 * @resampler: a #GstAudioResampler
1623 *
1624 * Free a previously allocated #GstAudioResampler @resampler.
1625 */
1626 void
gst_audio_resampler_free(GstAudioResampler * resampler)1627 gst_audio_resampler_free (GstAudioResampler * resampler)
1628 {
1629 g_return_if_fail (resampler != NULL);
1630
1631 g_free (resampler->cached_taps_mem);
1632 g_free (resampler->taps_mem);
1633 g_free (resampler->tmp_taps);
1634 g_free (resampler->samples);
1635 g_free (resampler->sbuf);
1636 if (resampler->options)
1637 gst_structure_free (resampler->options);
1638 g_slice_free (GstAudioResampler, resampler);
1639 }
1640
1641 /**
1642 * gst_audio_resampler_get_out_frames:
1643 * @resampler: a #GstAudioResampler
1644 * @in_frames: number of input frames
1645 *
1646 * Get the number of output frames that would be currently available when
1647 * @in_frames are given to @resampler.
1648 *
1649 * Returns: The number of frames that would be available after giving
1650 * @in_frames as input to @resampler.
1651 */
1652 gsize
gst_audio_resampler_get_out_frames(GstAudioResampler * resampler,gsize in_frames)1653 gst_audio_resampler_get_out_frames (GstAudioResampler * resampler,
1654 gsize in_frames)
1655 {
1656 gsize need, avail, out;
1657
1658 g_return_val_if_fail (resampler != NULL, 0);
1659
1660 need = resampler->n_taps + resampler->samp_index + resampler->skip;
1661 avail = resampler->samples_avail + in_frames;
1662 GST_LOG ("need %d = %d + %d + %d, avail %d = %d + %d", (gint) need,
1663 resampler->n_taps, resampler->samp_index, resampler->skip,
1664 (gint) avail, (gint) resampler->samples_avail, (gint) in_frames);
1665 if (avail < need) {
1666 GST_LOG ("avail %d < need %d", (int) avail, (int) need);
1667 return 0;
1668 }
1669
1670 out = (avail - need) * resampler->out_rate;
1671 if (out < resampler->samp_phase) {
1672 GST_LOG ("out %d < samp_phase %d", (int) out, (int) resampler->samp_phase);
1673 return 0;
1674 }
1675
1676 out = ((out - resampler->samp_phase) / resampler->in_rate) + 1;
1677 GST_LOG ("out %d = ((%d * %d - %d) / %d) + 1", (gint) out,
1678 (gint) (avail - need), resampler->out_rate, resampler->samp_phase,
1679 resampler->in_rate);
1680
1681 return out;
1682 }
1683
1684 /**
1685 * gst_audio_resampler_get_in_frames:
1686 * @resampler: a #GstAudioResampler
1687 * @out_frames: number of input frames
1688 *
1689 * Get the number of input frames that would currently be needed
1690 * to produce @out_frames from @resampler.
1691 *
1692 * Returns: The number of input frames needed for producing
1693 * @out_frames of data from @resampler.
1694 */
1695 gsize
gst_audio_resampler_get_in_frames(GstAudioResampler * resampler,gsize out_frames)1696 gst_audio_resampler_get_in_frames (GstAudioResampler * resampler,
1697 gsize out_frames)
1698 {
1699 gsize in_frames;
1700
1701 g_return_val_if_fail (resampler != NULL, 0);
1702
1703 in_frames =
1704 (resampler->samp_phase +
1705 out_frames * resampler->samp_frac) / resampler->out_rate;
1706 in_frames += out_frames * resampler->samp_inc;
1707
1708 return in_frames;
1709 }
1710
1711 /**
1712 * gst_audio_resampler_get_max_latency:
1713 * @resampler: a #GstAudioResampler
1714 *
1715 * Get the maximum number of input samples that the resampler would
1716 * need before producing output.
1717 *
1718 * Returns: the latency of @resampler as expressed in the number of
1719 * frames.
1720 */
1721 gsize
gst_audio_resampler_get_max_latency(GstAudioResampler * resampler)1722 gst_audio_resampler_get_max_latency (GstAudioResampler * resampler)
1723 {
1724 g_return_val_if_fail (resampler != NULL, 0);
1725
1726 return resampler->n_taps / 2;
1727 }
1728
1729 /**
1730 * gst_audio_resampler_resample:
1731 * @resampler: a #GstAudioResampler
1732 * @in: input samples
1733 * @in_frames: number of input frames
1734 * @out: output samples
1735 * @out_frames: number of output frames
1736 *
1737 * Perform resampling on @in_frames frames in @in and write @out_frames to @out.
1738 *
1739 * In case the samples are interleaved, @in and @out must point to an
1740 * array with a single element pointing to a block of interleaved samples.
1741 *
1742 * If non-interleaved samples are used, @in and @out must point to an
1743 * array with pointers to memory blocks, one for each channel.
1744 *
1745 * @in may be %NULL, in which case @in_frames of silence samples are pushed
1746 * into the resampler.
1747 *
1748 * This function always produces @out_frames of output and consumes @in_frames of
1749 * input. Use gst_audio_resampler_get_out_frames() and
1750 * gst_audio_resampler_get_in_frames() to make sure @in_frames and @out_frames
1751 * are matching and @in and @out point to enough memory.
1752 */
1753 void
gst_audio_resampler_resample(GstAudioResampler * resampler,gpointer in[],gsize in_frames,gpointer out[],gsize out_frames)1754 gst_audio_resampler_resample (GstAudioResampler * resampler,
1755 gpointer in[], gsize in_frames, gpointer out[], gsize out_frames)
1756 {
1757 gsize samples_avail;
1758 gsize need, consumed;
1759 gpointer *sbuf;
1760
1761 /* do sample skipping */
1762 if (G_UNLIKELY (resampler->skip >= in_frames)) {
1763 /* we need tp skip all input */
1764 resampler->skip -= in_frames;
1765 return;
1766 }
1767 /* skip the last samples by advancing the sample index */
1768 resampler->samp_index += resampler->skip;
1769
1770 samples_avail = resampler->samples_avail;
1771
1772 /* make sure we have enough space to copy our samples */
1773 sbuf = get_sample_bufs (resampler, in_frames + samples_avail);
1774
1775 /* copy/deinterleave the samples */
1776 resampler->deinterleave (resampler, sbuf, in, in_frames);
1777
1778 /* update new amount of samples in our buffer */
1779 resampler->samples_avail = samples_avail += in_frames;
1780
1781 need = resampler->n_taps + resampler->samp_index;
1782 if (G_UNLIKELY (samples_avail < need || out_frames == 0)) {
1783 GST_LOG ("not enough samples to start: need %" G_GSIZE_FORMAT ", avail %"
1784 G_GSIZE_FORMAT ", out %" G_GSIZE_FORMAT, need, samples_avail,
1785 out_frames);
1786 /* not enough samples to start */
1787 return;
1788 }
1789
1790 /* resample all channels */
1791 resampler->resample (resampler, sbuf, samples_avail, out, out_frames,
1792 &consumed);
1793
1794 GST_LOG ("in %" G_GSIZE_FORMAT ", avail %" G_GSIZE_FORMAT ", consumed %"
1795 G_GSIZE_FORMAT, in_frames, samples_avail, consumed);
1796
1797 /* update pointers */
1798 if (G_LIKELY (consumed > 0)) {
1799 gssize left = samples_avail - consumed;
1800 if (left > 0) {
1801 /* we consumed part of our samples */
1802 resampler->samples_avail = left;
1803 } else {
1804 /* we consumed all our samples, empty our buffers */
1805 resampler->samples_avail = 0;
1806 resampler->skip = -left;
1807 }
1808 }
1809 }
1810