Coverage Report

Created: 2025-11-16 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gstreamer/subprojects/gst-plugins-base/gst-libs/gst/audio/audio-resampler.c
Line
Count
Source
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
0
#define MEM_ALIGN(m,a) ((gint8 *)((guintptr)((gint8 *)(m) + ((a)-1)) & ~((a)-1)))
37
0
#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
0
#define DEFAULT_RESAMPLER_METHOD GST_AUDIO_RESAMPLER_METHOD_KAISER
100
0
#define DEFAULT_QUALITY GST_AUDIO_RESAMPLER_QUALITY_DEFAULT
101
0
#define DEFAULT_OPT_CUBIC_B 1.0
102
0
#define DEFAULT_OPT_CUBIC_C 0.0
103
0
#define DEFAULT_OPT_FILTER_MODE GST_AUDIO_RESAMPLER_FILTER_MODE_AUTO
104
0
#define DEFAULT_OPT_FILTER_MODE_THRESHOLD 1048576
105
0
#define DEFAULT_OPT_FILTER_INTERPOLATION GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_CUBIC
106
0
#define DEFAULT_OPT_FILTER_OVERSAMPLE 8
107
0
#define DEFAULT_OPT_MAX_PHASE_ERROR 0.1
108
109
static gdouble
110
get_opt_double (GstStructure * options, const gchar * name, gdouble def)
111
0
{
112
0
  gdouble res;
113
0
  if (!options || !gst_structure_get_double (options, name, &res))
114
0
    res = def;
115
0
  return res;
116
0
}
117
118
static gint
119
get_opt_int (GstStructure * options, const gchar * name, gint def)
120
0
{
121
0
  gint res;
122
0
  if (!options || !gst_structure_get_int (options, name, &res))
123
0
    res = def;
124
0
  return res;
125
0
}
126
127
static gint
128
get_opt_enum (GstStructure * options, const gchar * name, GType type, gint def)
129
0
{
130
0
  gint res;
131
0
  if (!options || !gst_structure_get_enum (options, name, type, &res))
132
0
    res = def;
133
0
  return res;
134
0
}
135
136
137
0
#define GET_OPT_CUTOFF(options,def) get_opt_double(options, \
138
0
    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
0
#define GET_OPT_STOP_ATTENUATION(options,def) get_opt_double(options, \
142
0
    GST_AUDIO_RESAMPLER_OPT_STOP_ATTENUATION, def)
143
0
#define GET_OPT_TRANSITION_BANDWIDTH(options,def) get_opt_double(options, \
144
0
    GST_AUDIO_RESAMPLER_OPT_TRANSITION_BANDWIDTH, def)
145
0
#define GET_OPT_CUBIC_B(options) get_opt_double(options, \
146
0
    GST_AUDIO_RESAMPLER_OPT_CUBIC_B, DEFAULT_OPT_CUBIC_B)
147
0
#define GET_OPT_CUBIC_C(options) get_opt_double(options, \
148
0
    GST_AUDIO_RESAMPLER_OPT_CUBIC_C, DEFAULT_OPT_CUBIC_C)
149
0
#define GET_OPT_N_TAPS(options,def) get_opt_int(options, \
150
0
    GST_AUDIO_RESAMPLER_OPT_N_TAPS, def)
151
0
#define GET_OPT_FILTER_MODE(options) get_opt_enum(options, \
152
0
    GST_AUDIO_RESAMPLER_OPT_FILTER_MODE, GST_TYPE_AUDIO_RESAMPLER_FILTER_MODE, \
153
0
    DEFAULT_OPT_FILTER_MODE)
154
0
#define GET_OPT_FILTER_MODE_THRESHOLD(options) get_opt_int(options, \
155
0
    GST_AUDIO_RESAMPLER_OPT_FILTER_MODE_THRESHOLD, DEFAULT_OPT_FILTER_MODE_THRESHOLD)
156
0
#define GET_OPT_FILTER_INTERPOLATION(options) get_opt_enum(options, \
157
0
    GST_AUDIO_RESAMPLER_OPT_FILTER_INTERPOLATION, GST_TYPE_AUDIO_RESAMPLER_FILTER_INTERPOLATION, \
158
0
    DEFAULT_OPT_FILTER_INTERPOLATION)
159
0
#define GET_OPT_FILTER_OVERSAMPLE(options) get_opt_int(options, \
160
0
    GST_AUDIO_RESAMPLER_OPT_FILTER_OVERSAMPLE, DEFAULT_OPT_FILTER_OVERSAMPLE)
161
0
#define GET_OPT_MAX_PHASE_ERROR(options) get_opt_double(options, \
162
0
    GST_AUDIO_RESAMPLER_OPT_MAX_PHASE_ERROR, DEFAULT_OPT_MAX_PHASE_ERROR)
163
164
#include "dbesi0.c"
165
0
#define bessel dbesi0
166
167
static inline gdouble
168
get_linear_tap (gdouble x, gint n_taps)
169
0
{
170
0
  gdouble res = GST_ROUND_UP_2 (n_taps) / 2 - fabs (x);
171
0
  return res;
172
0
}
173
174
static inline gdouble
175
get_cubic_tap (gdouble x, gint n_taps, gdouble b, gdouble c)
176
0
{
177
0
  gdouble res, a, a2, a3;
178
179
0
  a = fabs (x * 4.0) / n_taps;
180
0
  a2 = a * a;
181
0
  a3 = a2 * a;
182
183
0
  if (a <= 1.0)
184
0
    res = ((12.0 - 9.0 * b - 6.0 * c) * a3 +
185
0
        (-18.0 + 12.0 * b + 6.0 * c) * a2 + (6.0 - 2.0 * b)) / 6.0;
186
0
  else if (a <= 2.0)
187
0
    res = ((-b - 6.0 * c) * a3 +
188
0
        (6.0 * b + 30.0 * c) * a2 +
189
0
        (-12.0 * b - 48.0 * c) * a + (8.0 * b + 24.0 * c)) / 6.0;
190
0
  else
191
0
    res = 0.0;
192
193
0
  return res;
194
0
}
195
196
static inline gdouble
197
get_blackman_nuttall_tap (gdouble x, gint n_taps, gdouble Fc)
198
0
{
199
0
  gdouble s, y, w;
200
201
0
  y = G_PI * x;
202
0
  s = (y == 0.0 ? Fc : sin (y * Fc) / y);
203
204
0
  w = 2.0 * y / n_taps + G_PI;
205
0
  return s * (0.3635819 - 0.4891775 * cos (w) + 0.1365995 * cos (2 * w) -
206
0
      0.0106411 * cos (3 * w));
207
0
}
208
209
static inline gdouble
210
get_kaiser_tap (gdouble x, gint n_taps, gdouble Fc, gdouble beta)
211
0
{
212
0
  gdouble s, y, w;
213
214
0
  y = G_PI * x;
215
0
  s = (y == 0.0 ? Fc : sin (y * Fc) / y);
216
217
0
  w = 2.0 * x / n_taps;
218
0
  return s * bessel (beta * sqrt (MAX (1 - w * w, 0)));
219
0
}
220
221
#define MAKE_CONVERT_TAPS_INT_FUNC(type, precision)                     \
222
static void                                                             \
223
convert_taps_##type##_c (gdouble *tmp_taps, gpointer taps,              \
224
0
    gdouble weight, gint n_taps)                                        \
225
0
{                                                                       \
226
0
  gint64 one = (1LL << precision) - 1;                                  \
227
0
  type *t = taps;                                                       \
228
0
  gdouble multiplier = one;                                             \
229
0
  gint i, j;                                                            \
230
0
  gdouble offset, l_offset, h_offset;                                   \
231
0
  gboolean exact = FALSE;                                               \
232
0
  /* Round to integer, but with an adjustable bias that we use to */    \
233
0
  /* eliminate the DC error. */                                         \
234
0
  l_offset = 0.0;                                                       \
235
0
  h_offset = 1.0;                                                       \
236
0
  offset = 0.5;                                                         \
237
0
  for (i = 0; i < 32; i++) {                                            \
238
0
    gint64 sum = 0;                                                     \
239
0
    for (j = 0; j < n_taps; j++)                                        \
240
0
      sum += floor (offset + tmp_taps[j] * multiplier / weight);        \
241
0
    if (sum == one) {                                                   \
242
0
      exact = TRUE;                                                     \
243
0
      break;                                                            \
244
0
    }                                                                   \
245
0
    if (l_offset == h_offset)                                           \
246
0
      break;                                                            \
247
0
    if (sum < one) {                                                    \
248
0
      if (offset > l_offset)                                            \
249
0
        l_offset = offset;                                              \
250
0
      offset += (h_offset - l_offset) / 2;                              \
251
0
    } else {                                                            \
252
0
      if (offset < h_offset)                                            \
253
0
        h_offset = offset;                                              \
254
0
      offset -= (h_offset - l_offset) / 2;                              \
255
0
    }                                                                   \
256
0
  }                                                                     \
257
0
  for (j = 0; j < n_taps; j++)                                          \
258
0
    t[j] = floor (offset + tmp_taps[j] * multiplier / weight);          \
259
0
  if (!exact)                                                           \
260
0
    GST_DEBUG ("can't find exact taps");                                \
261
0
}
Unexecuted instantiation: audio-resampler.c:convert_taps_gint16_c
Unexecuted instantiation: audio-resampler.c:convert_taps_gint32_c
262
263
#define MAKE_CONVERT_TAPS_FLOAT_FUNC(type)                              \
264
static void                                                             \
265
convert_taps_##type##_c (gdouble *tmp_taps, gpointer taps,              \
266
0
    gdouble weight, gint n_taps)                                        \
267
0
{                                                                       \
268
0
  gint i;                                                               \
269
0
  type *t = taps;                                                       \
270
0
  for (i = 0; i < n_taps; i++)                                          \
271
0
    t[i] = tmp_taps[i] / weight;                                        \
272
0
}
Unexecuted instantiation: audio-resampler.c:convert_taps_gfloat_c
Unexecuted instantiation: audio-resampler.c:convert_taps_gdouble_c
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
292
make_taps (GstAudioResampler * resampler, gdouble * res, gdouble x, gint n_taps)
293
0
{
294
0
  gdouble weight = 0.0, *tmp_taps = resampler->tmp_taps;
295
0
  gint i;
296
297
0
  switch (resampler->method) {
298
0
    case GST_AUDIO_RESAMPLER_METHOD_NEAREST:
299
0
      break;
300
301
0
    case GST_AUDIO_RESAMPLER_METHOD_LINEAR:
302
0
      for (i = 0; i < n_taps; i++)
303
0
        weight += tmp_taps[i] = get_linear_tap (x + i, resampler->n_taps);
304
0
      break;
305
306
0
    case GST_AUDIO_RESAMPLER_METHOD_CUBIC:
307
0
      for (i = 0; i < n_taps; i++)
308
0
        weight += tmp_taps[i] = get_cubic_tap (x + i, resampler->n_taps,
309
0
            resampler->b, resampler->c);
310
0
      break;
311
312
0
    case GST_AUDIO_RESAMPLER_METHOD_BLACKMAN_NUTTALL:
313
0
      for (i = 0; i < n_taps; i++)
314
0
        weight += tmp_taps[i] =
315
0
            get_blackman_nuttall_tap (x + i,
316
0
            resampler->n_taps, resampler->cutoff);
317
0
      break;
318
319
0
    case GST_AUDIO_RESAMPLER_METHOD_KAISER:
320
0
      for (i = 0; i < n_taps; i++)
321
0
        weight += tmp_taps[i] =
322
0
            get_kaiser_tap (x + i, resampler->n_taps,
323
0
            resampler->cutoff, resampler->kaiser_beta);
324
0
      break;
325
0
  }
326
0
  resampler->convert_taps (tmp_taps, res, weight, n_taps);
327
0
}
328
329
#define MAKE_COEFF_LINEAR_INT_FUNC(type,type2,prec)                     \
330
static inline void                                                      \
331
0
make_coeff_##type##_linear (gint num, gint denom, type *icoeff)         \
332
0
{                                                                       \
333
0
  type x = ((gint64)num << prec) / denom;                               \
334
0
  icoeff[0] = icoeff[2] = x;                                            \
335
0
  icoeff[1] = icoeff[3] = (type)(((type2)1 << prec)-1)  - x;            \
336
0
}
Unexecuted instantiation: audio-resampler.c:make_coeff_gint16_linear
Unexecuted instantiation: audio-resampler.c:make_coeff_gint32_linear
337
#define MAKE_COEFF_LINEAR_FLOAT_FUNC(type)                              \
338
static inline void                                                      \
339
0
make_coeff_##type##_linear (gint num, gint denom, type *icoeff)         \
340
0
{                                                                       \
341
0
  type x = (type)num / denom;                                           \
342
0
  icoeff[0] = icoeff[2] = x;                                            \
343
0
  icoeff[1] = icoeff[3] = (type)1.0 - x;                                \
344
0
}
Unexecuted instantiation: audio-resampler.c:make_coeff_gfloat_linear
Unexecuted instantiation: audio-resampler.c:make_coeff_gdouble_linear
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
0
make_coeff_##type##_cubic (gint num, gint denom, type *icoeff)          \
353
0
{                                                                       \
354
0
  type2 one = ((type2)1 << prec) - 1;                                   \
355
0
  type2 x = ((gint64) num << prec) / denom;                             \
356
0
  type2 x2 = (x * x) >> prec;                                           \
357
0
  type2 x3 = (x2 * x) >> prec;                                          \
358
0
  icoeff[0] = (((x3 - x) << prec) / 6) >> prec;                         \
359
0
  icoeff[1] = x + ((x2 - x3) >> 1);                                     \
360
0
  icoeff[3] = -(((x << prec) / 3) >> prec) +                            \
361
0
            (x2 >> 1) - (((x3 << prec) / 6) >> prec);                   \
362
0
  icoeff[2] = one - icoeff[0] - icoeff[1] - icoeff[3];                  \
363
0
}
Unexecuted instantiation: audio-resampler.c:make_coeff_gint16_cubic
Unexecuted instantiation: audio-resampler.c:make_coeff_gint32_cubic
364
#define MAKE_COEFF_CUBIC_FLOAT_FUNC(type)                               \
365
static inline void                                                      \
366
0
make_coeff_##type##_cubic (gint num, gint denom, type *icoeff)          \
367
0
{                                                                       \
368
0
  type x = (type) num / denom, x2 = x * x, x3 = x2 * x;                 \
369
0
  icoeff[0] = 0.16667f * (x3 - x);                                      \
370
0
  icoeff[1] = x + 0.5f * (x2 - x3);                                     \
371
0
  icoeff[3] = -0.33333f * x + 0.5f * x2 - 0.16667f * x3;                \
372
0
  icoeff[2] = (type)1.0 - icoeff[0] - icoeff[1] - icoeff[3];            \
373
0
}
Unexecuted instantiation: audio-resampler.c:make_coeff_gfloat_cubic
Unexecuted instantiation: audio-resampler.c:make_coeff_gdouble_cubic
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
0
    gint len, const gpointer icp, gint astride)                 \
383
0
{                                                               \
384
0
  gint i;                                                       \
385
0
  type *o = op, *a = ap, *ic = icp;                             \
386
0
  type2 tmp, c0 = ic[0];                                        \
387
0
  const type *c[2] = {(type*)((gint8*)a + 0*astride),           \
388
0
                      (type*)((gint8*)a + 1*astride)};          \
389
0
                                                                \
390
0
  for (i = 0; i < len; i++) {                                   \
391
0
    tmp = ((type2)c[0][i] - (type2)c[1][i]) * c0 +              \
392
0
         (((type2)c[1][i]) << (prec));                          \
393
0
    o[i] = (tmp + ((type2)1 << ((prec) - 1))) >> (prec);        \
394
0
  }                                                             \
395
0
}
Unexecuted instantiation: audio-resampler.c:interpolate_gint16_linear_c
Unexecuted instantiation: audio-resampler.c:interpolate_gint32_linear_c
396
#define INTERPOLATE_FLOAT_LINEAR_FUNC(type)                     \
397
static inline void                                              \
398
interpolate_##type##_linear_c (gpointer op, const gpointer ap,  \
399
0
    gint len, const gpointer icp, gint astride)                 \
400
0
{                                                               \
401
0
  gint i;                                                       \
402
0
  type *o = op, *a = ap, *ic = icp;                             \
403
0
  type c0 = ic[0];                                              \
404
0
  const type *c[2] = {(type*)((gint8*)a + 0*astride),           \
405
0
                      (type*)((gint8*)a + 1*astride)};          \
406
0
                                                                \
407
0
  for (i = 0; i < len; i++) {                                   \
408
0
    o[i] = (c[0][i] - c[1][i]) * c0 + c[1][i];                  \
409
0
  }                                                             \
410
0
}
Unexecuted instantiation: audio-resampler.c:interpolate_gfloat_linear_c
Unexecuted instantiation: audio-resampler.c:interpolate_gdouble_linear_c
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
0
    gint len, const gpointer icp, gint astride)                 \
421
0
{                                                               \
422
0
  gint i;                                                       \
423
0
  type *o = op, *a = ap, *ic = icp;                             \
424
0
  type2 tmp, c0 = ic[0], c1 = ic[1], c2 = ic[2], c3 = ic[3];    \
425
0
  const type *c[4] = {(type*)((gint8*)a + 0*astride),           \
426
0
                      (type*)((gint8*)a + 1*astride),           \
427
0
                      (type*)((gint8*)a + 2*astride),           \
428
0
                      (type*)((gint8*)a + 3*astride)};          \
429
0
                                                                \
430
0
  for (i = 0; i < len; i++) {                                   \
431
0
    tmp = (type2)c[0][i] * c0 + (type2)c[1][i] * c1 +           \
432
0
          (type2)c[2][i] * c2 + (type2)c[3][i] * c3;            \
433
0
    tmp = (tmp + ((type2)1 << ((prec) - 1))) >> (prec);         \
434
0
    o[i] = CLAMP (tmp, -(limit), (limit) - 1);                  \
435
0
  }                                                             \
436
0
}
Unexecuted instantiation: audio-resampler.c:interpolate_gint16_cubic_c
Unexecuted instantiation: audio-resampler.c:interpolate_gint32_cubic_c
437
#define INTERPOLATE_FLOAT_CUBIC_FUNC(type)                      \
438
static inline void                                              \
439
interpolate_##type##_cubic_c (gpointer op, const gpointer ap,   \
440
0
    gint len, const gpointer icp, gint astride)                 \
441
0
{                                                               \
442
0
  gint i;                                                       \
443
0
  type *o = op, *a = ap, *ic = icp;                             \
444
0
  type c0 = ic[0], c1 = ic[1], c2 = ic[2], c3 = ic[3];          \
445
0
  const type *c[4] = {(type*)((gint8*)a + 0*astride),           \
446
0
                      (type*)((gint8*)a + 1*astride),           \
447
0
                      (type*)((gint8*)a + 2*astride),           \
448
0
                      (type*)((gint8*)a + 3*astride)};          \
449
0
                                                                \
450
0
  for (i = 0; i < len; i++) {                                   \
451
0
    o[i] = c[0][i] * c0 + c[1][i] * c1 +                        \
452
0
           c[2][i] * c2 + c[3][i] * c3;                         \
453
0
  }                                                             \
454
0
}
Unexecuted instantiation: audio-resampler.c:interpolate_gfloat_cubic_c
Unexecuted instantiation: audio-resampler.c:interpolate_gdouble_cubic_c
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
0
    gint *samp_index, gint *samp_phase, type icoeff[4])                         \
487
0
{                                                                               \
488
0
  gint out_rate = resampler->out_rate;                                          \
489
0
  *samp_index += resampler->samp_inc;                                           \
490
0
  *samp_phase += resampler->samp_frac;                                          \
491
0
  if (*samp_phase >= out_rate) {                                                \
492
0
    *samp_phase -= out_rate;                                                    \
493
0
    *samp_index += 1;                                                           \
494
0
  }                                                                             \
495
0
  return NULL;                                                                  \
496
0
}
497
0
GET_TAPS_NEAREST_FUNC (gint16);
498
0
GET_TAPS_NEAREST_FUNC (gint32);
499
0
GET_TAPS_NEAREST_FUNC (gfloat);
500
0
GET_TAPS_NEAREST_FUNC (gdouble);
501
502
0
#define get_taps_gint16_nearest get_taps_gint16_nearest
503
0
#define get_taps_gint32_nearest get_taps_gint32_nearest
504
0
#define get_taps_gfloat_nearest get_taps_gfloat_nearest
505
0
#define get_taps_gdouble_nearest get_taps_gdouble_nearest
506
507
#define GET_TAPS_FULL_FUNC(type)                                                \
508
0
DECL_GET_TAPS_FULL_FUNC(type)                                                   \
509
0
{                                                                               \
510
0
  gpointer res;                                                                 \
511
0
  gint out_rate = resampler->out_rate;                                          \
512
0
  gint n_phases = resampler->n_phases;                                          \
513
0
  gint phase = (n_phases == out_rate ? *samp_phase :                            \
514
0
      ((gint64)*samp_phase * n_phases) / out_rate);                             \
515
0
                                                                                \
516
0
  res = resampler->cached_phases[phase];                                        \
517
0
  if (G_UNLIKELY (res == NULL)) {                                               \
518
0
    res = (gint8 *) resampler->cached_taps +                                    \
519
0
                        phase * resampler->cached_taps_stride;                  \
520
0
    switch (resampler->filter_interpolation) {                                  \
521
0
      case GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_NONE:                       \
522
0
      {                                                                         \
523
0
        gdouble x;                                                              \
524
0
        gint n_taps = resampler->n_taps;                                        \
525
0
                                                                                \
526
0
        x = 1.0 - n_taps / 2 - (gdouble) phase / n_phases;                      \
527
0
        make_taps (resampler, res, x, n_taps);                                  \
528
0
        break;                                                                  \
529
0
      }                                                                         \
530
0
      default:                                                                  \
531
0
      {                                                                         \
532
0
        gint offset, pos, frac;                                                 \
533
0
        gint oversample = resampler->oversample;                                \
534
0
        gint taps_stride = resampler->taps_stride;                              \
535
0
        gint n_taps = resampler->n_taps;                                        \
536
0
        type ic[4], *taps;                                                      \
537
0
                                                                                \
538
0
        pos = phase * oversample;                                               \
539
0
        offset = (oversample - 1) - pos / n_phases;                             \
540
0
        frac = pos % n_phases;                                                  \
541
0
                                                                                \
542
0
        taps = (type *) ((gint8 *) resampler->taps + offset * taps_stride);     \
543
0
                                                                                \
544
0
        switch (resampler->filter_interpolation) {                              \
545
0
          default:                                                              \
546
0
          case GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_LINEAR:                 \
547
0
            make_coeff_##type##_linear (frac, n_phases, ic);                    \
548
0
            break;                                                              \
549
0
          case GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_CUBIC:                  \
550
0
            make_coeff_##type##_cubic (frac, n_phases, ic);                     \
551
0
            break;                                                              \
552
0
        }                                                                       \
553
0
        resampler->interpolate (res, taps, n_taps, ic, taps_stride);            \
554
0
      }                                                                         \
555
0
    }                                                                           \
556
0
    resampler->cached_phases[phase] = res;                                      \
557
0
  }                                                                             \
558
0
  *samp_index += resampler->samp_inc;                                           \
559
0
  *samp_phase += resampler->samp_frac;                                          \
560
0
  if (*samp_phase >= out_rate) {                                                \
561
0
    *samp_phase -= out_rate;                                                    \
562
0
    *samp_index += 1;                                                           \
563
0
  }                                                                             \
564
0
  return res;                                                                   \
565
0
}
Unexecuted instantiation: get_taps_gint16_full
Unexecuted instantiation: get_taps_gint32_full
Unexecuted instantiation: get_taps_gfloat_full
Unexecuted instantiation: get_taps_gdouble_full
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
0
DECL_GET_TAPS_INTERPOLATE_FUNC (type, inter)                    \
573
0
{                                                               \
574
0
  gpointer res;                                                 \
575
0
  gint out_rate = resampler->out_rate;                          \
576
0
  gint offset, frac, pos;                                       \
577
0
  gint oversample = resampler->oversample;                      \
578
0
  gint taps_stride = resampler->taps_stride;                    \
579
0
                                                                \
580
0
  pos = *samp_phase * oversample;                               \
581
0
  offset = (oversample - 1) - pos / out_rate;                   \
582
0
  frac = pos % out_rate;                                        \
583
0
                                                                \
584
0
  res = (gint8 *) resampler->taps + offset * taps_stride;       \
585
0
  make_coeff_##type##_##inter (frac, out_rate, icoeff);         \
586
0
                                                                \
587
0
  *samp_index += resampler->samp_inc;                           \
588
0
  *samp_phase += resampler->samp_frac;                          \
589
0
  if (*samp_phase >= out_rate) {                                \
590
0
    *samp_phase -= out_rate;                                    \
591
0
    *samp_index += 1;                                           \
592
0
  }                                                             \
593
0
  return res;                                                   \
594
0
}
Unexecuted instantiation: get_taps_gint16_linear
Unexecuted instantiation: get_taps_gint32_linear
Unexecuted instantiation: get_taps_gfloat_linear
Unexecuted instantiation: get_taps_gdouble_linear
Unexecuted instantiation: get_taps_gint16_cubic
Unexecuted instantiation: get_taps_gint32_cubic
Unexecuted instantiation: get_taps_gfloat_cubic
Unexecuted instantiation: get_taps_gdouble_cubic
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
0
    const type * b, gint len, const type *ic, gint bstride)     \
610
0
{                                                               \
611
0
  *o = *a;                                                      \
612
0
}
Unexecuted instantiation: audio-resampler.c:inner_product_gint16_nearest_1_c
Unexecuted instantiation: audio-resampler.c:inner_product_gint32_nearest_1_c
Unexecuted instantiation: audio-resampler.c:inner_product_gfloat_nearest_1_c
Unexecuted instantiation: audio-resampler.c:inner_product_gdouble_nearest_1_c
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
0
    const type * b, gint len, const type *ic, gint bstride)     \
622
0
{                                                               \
623
0
  gint i;                                                       \
624
0
  type2 res[4] = { 0, 0, 0, 0 };                                \
625
0
                                                                \
626
0
  for (i = 0; i < len; i += 4) {                                \
627
0
    res[0] += (type2) a[i + 0] * (type2) b[i + 0];              \
628
0
    res[1] += (type2) a[i + 1] * (type2) b[i + 1];              \
629
0
    res[2] += (type2) a[i + 2] * (type2) b[i + 2];              \
630
0
    res[3] += (type2) a[i + 3] * (type2) b[i + 3];              \
631
0
  }                                                             \
632
0
  res[0] = res[0] + res[1] + res[2] + res[3];                   \
633
0
  res[0] = (res[0] + ((type2)1 << ((prec) - 1))) >> (prec);     \
634
0
  *o = CLAMP (res[0], -(limit), (limit) - 1);                   \
635
0
}
Unexecuted instantiation: audio-resampler.c:inner_product_gint16_full_1_c
Unexecuted instantiation: audio-resampler.c:inner_product_gint32_full_1_c
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
0
    const type * b, gint len, const type *ic, gint bstride)     \
644
0
{                                                               \
645
0
  gint i;                                                       \
646
0
  type2 res[4] = { 0, 0, 0, 0 }, c0 = ic[0];                    \
647
0
  const type *c[2] = {(type*)((gint8*)b + 0*bstride),           \
648
0
                      (type*)((gint8*)b + 1*bstride)};          \
649
0
                                                                \
650
0
  for (i = 0; i < len; i += 2) {                                \
651
0
    res[0] += (type2) a[i + 0] * (type2) c[0][i + 0];           \
652
0
    res[1] += (type2) a[i + 0] * (type2) c[1][i + 0];           \
653
0
    res[2] += (type2) a[i + 1] * (type2) c[0][i + 1];           \
654
0
    res[3] += (type2) a[i + 1] * (type2) c[1][i + 1];           \
655
0
  }                                                             \
656
0
  res[0] = (res[0] + res[2]) >> (prec);                         \
657
0
  res[1] = (res[1] + res[3]) >> (prec);                         \
658
0
  res[0] = ((type2)(type)res[0] - (type2)(type)res[1]) * c0 +   \
659
0
           ((type2)(type)res[1] << (prec));                     \
660
0
  res[0] = (res[0] + ((type2)1 << ((prec) - 1))) >> (prec);     \
661
0
  *o = CLAMP (res[0], -(limit), (limit) - 1);                   \
662
0
}
Unexecuted instantiation: audio-resampler.c:inner_product_gint16_linear_1_c
Unexecuted instantiation: audio-resampler.c:inner_product_gint32_linear_1_c
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
0
    const type * b, gint len, const type *ic, gint bstride)     \
671
0
{                                                               \
672
0
  gint i;                                                       \
673
0
  type2 res[4] = { 0, 0, 0, 0 };                                \
674
0
  const type *c[4] = {(type*)((gint8*)b + 0*bstride),           \
675
0
                      (type*)((gint8*)b + 1*bstride),           \
676
0
                      (type*)((gint8*)b + 2*bstride),           \
677
0
                      (type*)((gint8*)b + 3*bstride)};          \
678
0
                                                                \
679
0
  for (i = 0; i < len; i++) {                                   \
680
0
    res[0] += (type2) a[i] * (type2) c[0][i];                   \
681
0
    res[1] += (type2) a[i] * (type2) c[1][i];                   \
682
0
    res[2] += (type2) a[i] * (type2) c[2][i];                   \
683
0
    res[3] += (type2) a[i] * (type2) c[3][i];                   \
684
0
  }                                                             \
685
0
  res[0] = (type2)(type)(res[0] >> (prec)) * (type2) ic[0] +    \
686
0
           (type2)(type)(res[1] >> (prec)) * (type2) ic[1] +    \
687
0
           (type2)(type)(res[2] >> (prec)) * (type2) ic[2] +    \
688
0
           (type2)(type)(res[3] >> (prec)) * (type2) ic[3];     \
689
0
  res[0] = (res[0] + ((type2)1 << ((prec) - 1))) >> (prec);     \
690
0
  *o = CLAMP (res[0], -(limit), (limit) - 1);                   \
691
0
}
Unexecuted instantiation: audio-resampler.c:inner_product_gint16_cubic_1_c
Unexecuted instantiation: audio-resampler.c:inner_product_gint32_cubic_1_c
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
0
    const type * b, gint len, const type *ic, gint bstride)     \
700
0
{                                                               \
701
0
  gint i;                                                       \
702
0
  type res[4] = { 0.0, 0.0, 0.0, 0.0 };                         \
703
0
                                                                \
704
0
  for (i = 0; i < len; i += 4) {                                \
705
0
    res[0] += a[i + 0] * b[i + 0];                              \
706
0
    res[1] += a[i + 1] * b[i + 1];                              \
707
0
    res[2] += a[i + 2] * b[i + 2];                              \
708
0
    res[3] += a[i + 3] * b[i + 3];                              \
709
0
  }                                                             \
710
0
  *o = res[0] + res[1] + res[2] + res[3];                       \
711
0
}
Unexecuted instantiation: audio-resampler.c:inner_product_gfloat_full_1_c
Unexecuted instantiation: audio-resampler.c:inner_product_gdouble_full_1_c
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
0
    const type * b, gint len, const type *ic, gint bstride)     \
720
0
{                                                               \
721
0
  gint i;                                                       \
722
0
  type res[4] = { 0.0, 0.0, 0.0, 0.0 };                         \
723
0
  const type *c[2] = {(type*)((gint8*)b + 0*bstride),           \
724
0
                      (type*)((gint8*)b + 1*bstride)};          \
725
0
                                                                \
726
0
  for (i = 0; i < len; i += 2) {                                \
727
0
    res[0] += a[i + 0] * c[0][i + 0];                           \
728
0
    res[1] += a[i + 0] * c[1][i + 0];                           \
729
0
    res[2] += a[i + 1] * c[0][i + 1];                           \
730
0
    res[3] += a[i + 1] * c[1][i + 1];                           \
731
0
  }                                                             \
732
0
  res[0] += res[2];                                             \
733
0
  res[1] += res[3];                                             \
734
0
  *o = (res[0] - res[1]) * ic[0] + res[1];                      \
735
0
}
Unexecuted instantiation: audio-resampler.c:inner_product_gfloat_linear_1_c
Unexecuted instantiation: audio-resampler.c:inner_product_gdouble_linear_1_c
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
0
    const type * b, gint len, const type *ic, gint bstride)     \
743
0
{                                                               \
744
0
  gint i;                                                       \
745
0
  type res[4] = { 0.0, 0.0, 0.0, 0.0 };                         \
746
0
  const type *c[4] = {(type*)((gint8*)b + 0*bstride),           \
747
0
                      (type*)((gint8*)b + 1*bstride),           \
748
0
                      (type*)((gint8*)b + 2*bstride),           \
749
0
                      (type*)((gint8*)b + 3*bstride)};          \
750
0
                                                                \
751
0
  for (i = 0; i < len; i++) {                                   \
752
0
    res[0] += a[i] * c[0][i];                                   \
753
0
    res[1] += a[i] * c[1][i];                                   \
754
0
    res[2] += a[i] * c[2][i];                                   \
755
0
    res[3] += a[i] * c[3][i];                                   \
756
0
  }                                                             \
757
0
  *o = res[0] * ic[0] + res[1] * ic[1] +                        \
758
0
       res[2] * ic[2] + res[3] * ic[3];                         \
759
0
}
Unexecuted instantiation: audio-resampler.c:inner_product_gfloat_cubic_1_c
Unexecuted instantiation: audio-resampler.c:inner_product_gdouble_cubic_1_c
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
837
audio_resampler_init (void)
838
0
{
839
0
  static gsize init_gonce = 0;
840
841
0
  if (g_once_init_enter (&init_gonce)) {
842
843
0
    GST_DEBUG_CATEGORY_INIT (audio_resampler_debug, "audio-resampler", 0,
844
0
        "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
0
    g_once_init_leave (&init_gonce, 1);
879
0
  }
880
0
}
881
882
#define MAKE_DEINTERLEAVE_FUNC(type)                                    \
883
static void                                                             \
884
deinterleave_ ##type (GstAudioResampler * resampler, gpointer sbuf[],   \
885
0
    gpointer in[], gsize in_frames)                                     \
886
0
{                                                                       \
887
0
  gint i, c, channels = resampler->channels;                            \
888
0
  gsize samples_avail = resampler->samples_avail;                       \
889
0
  for (c = 0; c < channels; c++) {                                      \
890
0
    type *s = (type *) sbuf[c] + samples_avail;                         \
891
0
    if (G_UNLIKELY (in == NULL)) {                                      \
892
0
      for (i = 0; i < in_frames; i++)                                   \
893
0
        s[i] = 0;                                                       \
894
0
    } else {                                                            \
895
0
      type *ip = (type *) in[0] + c;                                    \
896
0
      for (i = 0; i < in_frames; i++, ip += channels)                   \
897
0
        s[i] = *ip;                                                     \
898
0
    }                                                                   \
899
0
  }                                                                     \
900
0
}
Unexecuted instantiation: audio-resampler.c:deinterleave_gint16
Unexecuted instantiation: audio-resampler.c:deinterleave_gint32
Unexecuted instantiation: audio-resampler.c:deinterleave_gfloat
Unexecuted instantiation: audio-resampler.c:deinterleave_gdouble
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
915
copy_func (GstAudioResampler * resampler, gpointer sbuf[],
916
    gpointer in[], gsize in_frames)
917
0
{
918
0
  gint c, channels = resampler->channels;
919
0
  gsize samples_avail = resampler->samples_avail;
920
0
  for (c = 0; c < channels; c++) {
921
0
    guint8 *s = ((guint8 *) sbuf[c]) + (samples_avail * resampler->bps);
922
0
    if (G_UNLIKELY (in == NULL)) {
923
0
      memset (s, 0, in_frames * resampler->bps);
924
0
    } else {
925
0
      memcpy (s, in[c], in_frames * resampler->bps);
926
0
    }
927
0
  }
928
0
}
929
930
static void
931
calculate_kaiser_params (GstAudioResampler * resampler)
932
0
{
933
0
  gdouble A, B, dw, tr_bw, Fc;
934
0
  gint n;
935
0
  const KaiserQualityMap *q = &kaiser_qualities[DEFAULT_QUALITY];
936
937
  /* default cutoff */
938
0
  Fc = q->cutoff;
939
0
  if (resampler->out_rate < resampler->in_rate)
940
0
    Fc *= q->downsample_cutoff_factor;
941
942
0
  Fc = GET_OPT_CUTOFF (resampler->options, Fc);
943
0
  A = GET_OPT_STOP_ATTENUATION (resampler->options, q->stopband_attenuation);
944
0
  tr_bw =
945
0
      GET_OPT_TRANSITION_BANDWIDTH (resampler->options,
946
0
      q->transition_bandwidth);
947
948
0
  GST_LOG ("Fc %f, A %f, tr_bw %f", Fc, A, tr_bw);
949
950
  /* calculate Beta */
951
0
  if (A > 50)
952
0
    B = 0.1102 * (A - 8.7);
953
0
  else if (A >= 21)
954
0
    B = 0.5842 * pow (A - 21, 0.4) + 0.07886 * (A - 21);
955
0
  else
956
0
    B = 0.0;
957
  /* calculate transition width in radians */
958
0
  dw = 2 * G_PI * (tr_bw);
959
  /* order of the filter */
960
0
  n = (A - 8.0) / (2.285 * dw);
961
962
0
  resampler->kaiser_beta = B;
963
0
  resampler->n_taps = n + 1;
964
0
  resampler->cutoff = Fc;
965
966
0
  GST_LOG ("using Beta %f n_taps %d cutoff %f", resampler->kaiser_beta,
967
0
      resampler->n_taps, resampler->cutoff);
968
0
}
969
970
static void
971
alloc_taps_mem (GstAudioResampler * resampler, gint bps, gint n_taps,
972
    gint n_phases)
973
0
{
974
0
  if (resampler->alloc_taps >= n_taps && resampler->alloc_phases >= n_phases)
975
0
    return;
976
977
0
  GST_DEBUG ("allocate bps %d n_taps %d n_phases %d", bps, n_taps, n_phases);
978
979
0
  resampler->tmp_taps =
980
0
      g_realloc_n (resampler->tmp_taps, n_taps, sizeof (gdouble));
981
982
0
  resampler->taps_stride = GST_ROUND_UP_32 (bps * (n_taps + TAPS_OVERREAD));
983
984
0
  g_free (resampler->taps_mem);
985
0
  resampler->taps_mem =
986
0
      g_malloc0 (n_phases * resampler->taps_stride + ALIGN - 1);
987
0
  resampler->taps = MEM_ALIGN ((gint8 *) resampler->taps_mem, ALIGN);
988
0
  resampler->alloc_taps = n_taps;
989
0
  resampler->alloc_phases = n_phases;
990
0
}
991
992
static void
993
alloc_cache_mem (GstAudioResampler * resampler, gint bps, gint n_taps,
994
    gint n_phases)
995
0
{
996
0
  gsize phases_size;
997
998
0
  resampler->tmp_taps =
999
0
      g_realloc_n (resampler->tmp_taps, n_taps, sizeof (gdouble));
1000
1001
0
  resampler->cached_taps_stride =
1002
0
      GST_ROUND_UP_32 (bps * (n_taps + TAPS_OVERREAD));
1003
1004
0
  phases_size = sizeof (gpointer) * n_phases;
1005
1006
0
  g_free (resampler->cached_taps_mem);
1007
0
  resampler->cached_taps_mem =
1008
0
      g_malloc0 (phases_size + n_phases * resampler->cached_taps_stride +
1009
0
      ALIGN - 1);
1010
0
  resampler->cached_taps =
1011
0
      MEM_ALIGN ((gint8 *) resampler->cached_taps_mem + phases_size, ALIGN);
1012
0
  resampler->cached_phases = resampler->cached_taps_mem;
1013
0
}
1014
1015
static void
1016
setup_functions (GstAudioResampler * resampler)
1017
0
{
1018
0
  gint index, fidx;
1019
1020
0
  index = resampler->format_index;
1021
1022
0
  if (resampler->in_rate == resampler->out_rate)
1023
0
    resampler->resample = resample_funcs[index];
1024
0
  else {
1025
0
    switch (resampler->filter_interpolation) {
1026
0
      default:
1027
0
      case GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_NONE:
1028
0
        fidx = 0;
1029
0
        break;
1030
0
      case GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_LINEAR:
1031
0
        GST_DEBUG ("using linear interpolation for filter coefficients");
1032
0
        fidx = 0;
1033
0
        break;
1034
0
      case GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_CUBIC:
1035
0
        GST_DEBUG ("using cubic interpolation for filter coefficients");
1036
0
        fidx = 4;
1037
0
        break;
1038
0
    }
1039
0
    GST_DEBUG ("using filter interpolate function %d", index + fidx);
1040
0
    resampler->interpolate = interpolate_funcs[index + fidx];
1041
1042
0
    switch (resampler->method) {
1043
0
      case GST_AUDIO_RESAMPLER_METHOD_NEAREST:
1044
0
        GST_DEBUG ("using nearest filter function");
1045
0
        break;
1046
0
      default:
1047
0
        index += 4;
1048
0
        switch (resampler->filter_mode) {
1049
0
          default:
1050
0
          case GST_AUDIO_RESAMPLER_FILTER_MODE_FULL:
1051
0
            GST_DEBUG ("using full filter function");
1052
0
            break;
1053
0
          case GST_AUDIO_RESAMPLER_FILTER_MODE_INTERPOLATED:
1054
0
            index += 4 + fidx;
1055
0
            GST_DEBUG ("using interpolated filter function");
1056
0
            break;
1057
0
        }
1058
0
        break;
1059
0
    }
1060
0
    GST_DEBUG ("using resample function %d", index);
1061
0
    resampler->resample = resample_funcs[index];
1062
0
  }
1063
0
}
1064
1065
static void
1066
resampler_calculate_taps (GstAudioResampler * resampler)
1067
0
{
1068
0
  gint bps;
1069
0
  gint n_taps, oversample;
1070
0
  gint in_rate, out_rate;
1071
0
  gboolean scale = TRUE, sinc_table = FALSE;
1072
0
  GstAudioResamplerFilterInterpolation filter_interpolation;
1073
1074
0
  switch (resampler->method) {
1075
0
    case GST_AUDIO_RESAMPLER_METHOD_NEAREST:
1076
0
      resampler->n_taps = 2;
1077
0
      scale = FALSE;
1078
0
      break;
1079
0
    case GST_AUDIO_RESAMPLER_METHOD_LINEAR:
1080
0
      resampler->n_taps = GET_OPT_N_TAPS (resampler->options, 2);
1081
0
      break;
1082
0
    case GST_AUDIO_RESAMPLER_METHOD_CUBIC:
1083
0
      resampler->n_taps = GET_OPT_N_TAPS (resampler->options, 4);
1084
0
      resampler->b = GET_OPT_CUBIC_B (resampler->options);
1085
0
      resampler->c = GET_OPT_CUBIC_C (resampler->options);;
1086
0
      break;
1087
0
    case GST_AUDIO_RESAMPLER_METHOD_BLACKMAN_NUTTALL:
1088
0
    {
1089
0
      const BlackmanQualityMap *q = &blackman_qualities[DEFAULT_QUALITY];
1090
0
      resampler->n_taps = GET_OPT_N_TAPS (resampler->options, q->n_taps);
1091
0
      resampler->cutoff = GET_OPT_CUTOFF (resampler->options, q->cutoff);
1092
0
      sinc_table = TRUE;
1093
0
      break;
1094
0
    }
1095
0
    case GST_AUDIO_RESAMPLER_METHOD_KAISER:
1096
0
      calculate_kaiser_params (resampler);
1097
0
      sinc_table = TRUE;
1098
0
      break;
1099
0
  }
1100
1101
0
  in_rate = resampler->in_rate;
1102
0
  out_rate = resampler->out_rate;
1103
1104
0
  if (out_rate < in_rate && scale) {
1105
0
    resampler->cutoff = resampler->cutoff * out_rate / in_rate;
1106
0
    resampler->n_taps =
1107
0
        gst_util_uint64_scale_int (resampler->n_taps, in_rate, out_rate);
1108
0
  }
1109
1110
0
  if (sinc_table) {
1111
0
    resampler->n_taps = GST_ROUND_UP_8 (resampler->n_taps);
1112
0
    resampler->filter_mode = GET_OPT_FILTER_MODE (resampler->options);
1113
0
    resampler->filter_threshold =
1114
0
        GET_OPT_FILTER_MODE_THRESHOLD (resampler->options);
1115
0
    filter_interpolation = GET_OPT_FILTER_INTERPOLATION (resampler->options);
1116
1117
0
  } else {
1118
0
    resampler->filter_mode = GST_AUDIO_RESAMPLER_FILTER_MODE_FULL;
1119
0
    filter_interpolation = GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_NONE;
1120
0
  }
1121
1122
  /* calculate oversampling for interpolated filter */
1123
0
  if (filter_interpolation != GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_NONE) {
1124
0
    gint mult = 2;
1125
1126
0
    oversample = GET_OPT_FILTER_OVERSAMPLE (resampler->options);
1127
0
    while (oversample > 1) {
1128
0
      if (mult * out_rate >= in_rate)
1129
0
        break;
1130
1131
0
      mult *= 2;
1132
0
      oversample >>= 1;
1133
0
    }
1134
1135
0
    switch (filter_interpolation) {
1136
0
      case GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_LINEAR:
1137
0
        oversample *= 11;
1138
0
        break;
1139
0
      default:
1140
0
        break;
1141
0
    }
1142
0
  } else {
1143
0
    oversample = 1;
1144
0
  }
1145
0
  resampler->oversample = oversample;
1146
1147
0
  n_taps = resampler->n_taps;
1148
0
  bps = resampler->bps;
1149
1150
0
  GST_LOG ("using n_taps %d cutoff %f oversample %d", n_taps, resampler->cutoff,
1151
0
      oversample);
1152
1153
0
  if (resampler->filter_mode == GST_AUDIO_RESAMPLER_FILTER_MODE_AUTO) {
1154
0
    if (out_rate <= oversample
1155
0
        && !(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
0
      resampler->filter_mode = GST_AUDIO_RESAMPLER_FILTER_MODE_FULL;
1159
0
      GST_DEBUG ("automatically selected full filter, %d <= %d", out_rate,
1160
0
          oversample);
1161
0
    } else if (bps * n_taps * out_rate < resampler->filter_threshold) {
1162
      /* switch to full filter when memory is below threshold */
1163
0
      resampler->filter_mode = GST_AUDIO_RESAMPLER_FILTER_MODE_FULL;
1164
0
      GST_DEBUG ("automatically selected full filter, memory %d <= %d",
1165
0
          bps * n_taps * out_rate, resampler->filter_threshold);
1166
0
    } else {
1167
0
      GST_DEBUG ("automatically selected interpolated filter");
1168
0
      resampler->filter_mode = GST_AUDIO_RESAMPLER_FILTER_MODE_INTERPOLATED;
1169
0
    }
1170
0
  }
1171
  /* interpolated table but no interpolation given, assume default */
1172
0
  if (resampler->filter_mode != GST_AUDIO_RESAMPLER_FILTER_MODE_FULL &&
1173
0
      filter_interpolation == GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_NONE)
1174
0
    filter_interpolation = DEFAULT_OPT_FILTER_INTERPOLATION;
1175
1176
0
  resampler->filter_interpolation = filter_interpolation;
1177
1178
0
  if (resampler->filter_mode == GST_AUDIO_RESAMPLER_FILTER_MODE_FULL &&
1179
0
      resampler->method != GST_AUDIO_RESAMPLER_METHOD_NEAREST) {
1180
0
    GST_DEBUG ("setting up filter cache");
1181
0
    resampler->n_phases = out_rate;
1182
0
    alloc_cache_mem (resampler, bps, n_taps, out_rate);
1183
0
  }
1184
1185
0
  if (resampler->filter_interpolation !=
1186
0
      GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_NONE) {
1187
0
    gint i, isize;
1188
0
    gdouble x;
1189
0
    gpointer taps;
1190
1191
0
    switch (resampler->filter_interpolation) {
1192
0
      default:
1193
0
      case GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_LINEAR:
1194
0
        GST_DEBUG ("using linear interpolation to build filter");
1195
0
        isize = 2;
1196
0
        break;
1197
0
      case GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_CUBIC:
1198
0
        GST_DEBUG ("using cubic interpolation to build filter");
1199
0
        isize = 4;
1200
0
        break;
1201
0
    }
1202
1203
0
    alloc_taps_mem (resampler, bps, n_taps, oversample + isize);
1204
1205
0
    for (i = 0; i < oversample + isize; i++) {
1206
0
      x = -(n_taps / 2) + i / (gdouble) oversample;
1207
0
      taps = (gint8 *) resampler->taps + i * resampler->taps_stride;
1208
0
      make_taps (resampler, taps, x, n_taps);
1209
0
    }
1210
0
  }
1211
0
}
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
1231
resampler_dump (GstAudioResampler * resampler)
1232
0
{
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
0
}
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
1281
gst_audio_resampler_options_set_quality (GstAudioResamplerMethod method,
1282
    guint quality, gint in_rate, gint out_rate, GstStructure * options)
1283
0
{
1284
0
  g_return_if_fail (options != NULL);
1285
0
  g_return_if_fail (quality <= GST_AUDIO_RESAMPLER_QUALITY_MAX);
1286
0
  g_return_if_fail (in_rate > 0 && out_rate > 0);
1287
1288
0
  switch (method) {
1289
0
    case GST_AUDIO_RESAMPLER_METHOD_NEAREST:
1290
0
      break;
1291
0
    case GST_AUDIO_RESAMPLER_METHOD_LINEAR:
1292
0
      gst_structure_set (options,
1293
0
          GST_AUDIO_RESAMPLER_OPT_N_TAPS, G_TYPE_INT, 2, NULL);
1294
0
      break;
1295
0
    case GST_AUDIO_RESAMPLER_METHOD_CUBIC:
1296
0
      gst_structure_set (options,
1297
0
          GST_AUDIO_RESAMPLER_OPT_N_TAPS, G_TYPE_INT, 4,
1298
0
          GST_AUDIO_RESAMPLER_OPT_CUBIC_B, G_TYPE_DOUBLE, DEFAULT_OPT_CUBIC_B,
1299
0
          GST_AUDIO_RESAMPLER_OPT_CUBIC_C, G_TYPE_DOUBLE, DEFAULT_OPT_CUBIC_C,
1300
0
          NULL);
1301
0
      break;
1302
0
    case GST_AUDIO_RESAMPLER_METHOD_BLACKMAN_NUTTALL:
1303
0
    {
1304
0
      const BlackmanQualityMap *map = &blackman_qualities[quality];
1305
0
      gst_structure_set (options,
1306
0
          GST_AUDIO_RESAMPLER_OPT_N_TAPS, G_TYPE_INT, map->n_taps,
1307
0
          GST_AUDIO_RESAMPLER_OPT_CUTOFF, G_TYPE_DOUBLE, map->cutoff, NULL);
1308
0
      break;
1309
0
    }
1310
0
    case GST_AUDIO_RESAMPLER_METHOD_KAISER:
1311
0
    {
1312
0
      const KaiserQualityMap *map = &kaiser_qualities[quality];
1313
0
      gdouble cutoff;
1314
1315
0
      cutoff = map->cutoff;
1316
0
      if (out_rate < in_rate)
1317
0
        cutoff *= map->downsample_cutoff_factor;
1318
1319
0
      gst_structure_set (options,
1320
0
          GST_AUDIO_RESAMPLER_OPT_CUTOFF, G_TYPE_DOUBLE, cutoff,
1321
0
          GST_AUDIO_RESAMPLER_OPT_STOP_ATTENUATION, G_TYPE_DOUBLE,
1322
0
          map->stopband_attenuation,
1323
0
          GST_AUDIO_RESAMPLER_OPT_TRANSITION_BANDWIDTH, G_TYPE_DOUBLE,
1324
0
          map->transition_bandwidth, NULL);
1325
0
      break;
1326
0
    }
1327
0
  }
1328
0
  gst_structure_set (options,
1329
0
      GST_AUDIO_RESAMPLER_OPT_FILTER_OVERSAMPLE, G_TYPE_INT,
1330
0
      oversample_qualities[quality], NULL);
1331
0
}
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.
1346
 */
1347
GstAudioResampler *
1348
gst_audio_resampler_new (GstAudioResamplerMethod method,
1349
    GstAudioResamplerFlags flags,
1350
    GstAudioFormat format, gint channels,
1351
    gint in_rate, gint out_rate, GstStructure * options)
1352
0
{
1353
0
  gboolean non_interleaved_in, non_interleaved_out;
1354
0
  GstAudioResampler *resampler;
1355
0
  const GstAudioFormatInfo *info;
1356
0
  GstStructure *def_options = NULL;
1357
1358
0
  g_return_val_if_fail (method >= GST_AUDIO_RESAMPLER_METHOD_NEAREST
1359
0
      && method <= GST_AUDIO_RESAMPLER_METHOD_KAISER, NULL);
1360
0
  g_return_val_if_fail (format == GST_AUDIO_FORMAT_S16 ||
1361
0
      format == GST_AUDIO_FORMAT_S32 || format == GST_AUDIO_FORMAT_F32 ||
1362
0
      format == GST_AUDIO_FORMAT_F64, NULL);
1363
0
  g_return_val_if_fail (channels > 0, NULL);
1364
0
  g_return_val_if_fail (in_rate > 0, NULL);
1365
0
  g_return_val_if_fail (out_rate > 0, NULL);
1366
1367
0
  audio_resampler_init ();
1368
1369
0
  resampler = g_new0 (GstAudioResampler, 1);
1370
0
  resampler->method = method;
1371
0
  resampler->flags = flags;
1372
0
  resampler->format = format;
1373
0
  resampler->channels = channels;
1374
1375
0
  switch (format) {
1376
0
    case GST_AUDIO_FORMAT_S16:
1377
0
      resampler->format_index = 0;
1378
0
      break;
1379
0
    case GST_AUDIO_FORMAT_S32:
1380
0
      resampler->format_index = 1;
1381
0
      break;
1382
0
    case GST_AUDIO_FORMAT_F32:
1383
0
      resampler->format_index = 2;
1384
0
      break;
1385
0
    case GST_AUDIO_FORMAT_F64:
1386
0
      resampler->format_index = 3;
1387
0
      break;
1388
0
    default:
1389
0
      g_assert_not_reached ();
1390
0
      break;
1391
0
  }
1392
1393
0
  info = gst_audio_format_get_info (format);
1394
0
  resampler->bps = GST_AUDIO_FORMAT_INFO_WIDTH (info) / 8;
1395
0
  resampler->sbuf = g_malloc0 (sizeof (gpointer) * channels);
1396
1397
0
  non_interleaved_in =
1398
0
      (resampler->flags & GST_AUDIO_RESAMPLER_FLAG_NON_INTERLEAVED_IN);
1399
0
  non_interleaved_out =
1400
0
      (resampler->flags & GST_AUDIO_RESAMPLER_FLAG_NON_INTERLEAVED_OUT);
1401
1402
  /* we resample each channel separately */
1403
0
  resampler->blocks = resampler->channels;
1404
0
  resampler->inc = 1;
1405
0
  resampler->ostride = non_interleaved_out ? 1 : resampler->channels;
1406
0
  resampler->deinterleave = non_interleaved_in ?
1407
0
      copy_func : deinterleave_funcs[resampler->format_index];
1408
0
  resampler->convert_taps = convert_taps_funcs[resampler->format_index];
1409
1410
0
  GST_DEBUG ("method %d, bps %d, channels %d", method, resampler->bps,
1411
0
      resampler->channels);
1412
1413
0
  if (options == NULL) {
1414
0
    options = def_options =
1415
0
        gst_structure_new_empty ("GstAudioResampler.options");
1416
0
    gst_audio_resampler_options_set_quality (DEFAULT_RESAMPLER_METHOD,
1417
0
        GST_AUDIO_RESAMPLER_QUALITY_DEFAULT, in_rate, out_rate, options);
1418
0
  }
1419
1420
0
  gst_audio_resampler_update (resampler, in_rate, out_rate, options);
1421
0
  gst_audio_resampler_reset (resampler);
1422
1423
0
  if (def_options)
1424
0
    gst_structure_free (def_options);
1425
1426
0
  return resampler;
1427
0
}
1428
1429
/* make the buffers to hold the (deinterleaved) samples */
1430
static inline gpointer *
1431
get_sample_bufs (GstAudioResampler * resampler, gsize need)
1432
0
{
1433
0
  if (G_LIKELY (resampler->samples_len < need)) {
1434
0
    gint c, blocks = resampler->blocks;
1435
0
    gsize bytes, to_move = 0;
1436
0
    gint8 *ptr, *samples;
1437
1438
0
    GST_LOG ("realloc %d -> %d", (gint) resampler->samples_len, (gint) need);
1439
1440
0
    bytes = GST_ROUND_UP_N (need * resampler->bps * resampler->inc, ALIGN);
1441
1442
0
    samples = g_malloc0 (blocks * bytes + ALIGN - 1);
1443
0
    ptr = MEM_ALIGN (samples, ALIGN);
1444
1445
    /* if we had some data, move history */
1446
0
    if (resampler->samples_len > 0)
1447
0
      to_move = resampler->samples_avail * resampler->bps * resampler->inc;
1448
1449
    /* set up new pointers */
1450
0
    for (c = 0; c < blocks; c++) {
1451
0
      memcpy (ptr + (c * bytes), resampler->sbuf[c], to_move);
1452
0
      resampler->sbuf[c] = ptr + (c * bytes);
1453
0
    }
1454
0
    g_free (resampler->samples);
1455
0
    resampler->samples = samples;
1456
0
    resampler->samples_len = need;
1457
0
  }
1458
0
  return resampler->sbuf;
1459
0
}
1460
1461
/**
1462
 * gst_audio_resampler_reset:
1463
 * @resampler: a #GstAudioResampler
1464
 *
1465
 * Reset @resampler to the state it was when it was first created, discarding
1466
 * all sample history.
1467
 */
1468
void
1469
gst_audio_resampler_reset (GstAudioResampler * resampler)
1470
0
{
1471
0
  g_return_if_fail (resampler != NULL);
1472
1473
0
  if (resampler->samples) {
1474
0
    gsize bytes;
1475
0
    gint c, blocks, bpf;
1476
1477
0
    bpf = resampler->bps * resampler->inc;
1478
0
    bytes = (resampler->n_taps / 2) * bpf;
1479
0
    blocks = resampler->blocks;
1480
1481
0
    for (c = 0; c < blocks; c++)
1482
0
      memset (resampler->sbuf[c], 0, bytes);
1483
0
  }
1484
  /* half of the filter is filled with 0 */
1485
0
  resampler->samp_index = 0;
1486
0
  resampler->samples_avail = resampler->n_taps / 2 - 1;
1487
0
}
1488
1489
/**
1490
 * gst_audio_resampler_update:
1491
 * @resampler: a #GstAudioResampler
1492
 * @in_rate: new input rate
1493
 * @out_rate: new output rate
1494
 * @options: new options or %NULL
1495
 *
1496
 * Update the resampler parameters for @resampler. This function should
1497
 * not be called concurrently with any other function on @resampler.
1498
 *
1499
 * When @in_rate or @out_rate is 0, its value is unchanged.
1500
 *
1501
 * When @options is %NULL, the previously configured options are reused.
1502
 *
1503
 * Returns: %TRUE if the new parameters could be set
1504
 */
1505
gboolean
1506
gst_audio_resampler_update (GstAudioResampler * resampler,
1507
    gint in_rate, gint out_rate, GstStructure * options)
1508
0
{
1509
0
  gint gcd, samp_phase, old_n_taps;
1510
0
  gdouble max_error;
1511
1512
0
  g_return_val_if_fail (resampler != NULL, FALSE);
1513
1514
0
  if (in_rate <= 0)
1515
0
    in_rate = resampler->in_rate;
1516
0
  if (out_rate <= 0)
1517
0
    out_rate = resampler->out_rate;
1518
1519
0
  if (resampler->out_rate > 0) {
1520
0
    GST_INFO ("old phase %d/%d", resampler->samp_phase, resampler->out_rate);
1521
0
    samp_phase =
1522
0
        gst_util_uint64_scale_int (resampler->samp_phase, out_rate,
1523
0
        resampler->out_rate);
1524
0
  } else
1525
0
    samp_phase = 0;
1526
1527
0
  gcd = gst_util_greatest_common_divisor (in_rate, out_rate);
1528
1529
0
  max_error = GET_OPT_MAX_PHASE_ERROR (resampler->options);
1530
1531
0
  if (max_error < 1.0e-8) {
1532
0
    GST_INFO ("using exact phase divider");
1533
0
    gcd = gst_util_greatest_common_divisor (gcd, samp_phase);
1534
0
  } else {
1535
0
    while (gcd > 1) {
1536
0
      gdouble ph1 = (gdouble) samp_phase / out_rate;
1537
0
      gint factor = 2;
1538
1539
      /* reduce the factor until we have a phase error of less than 10% */
1540
0
      gdouble ph2 = (gdouble) (samp_phase / gcd) / (out_rate / gcd);
1541
1542
0
      if (fabs (ph1 - ph2) < max_error)
1543
0
        break;
1544
1545
0
      while (gcd % factor != 0)
1546
0
        factor++;
1547
0
      gcd /= factor;
1548
1549
0
      GST_INFO ("divide by factor %d, gcd %d", factor, gcd);
1550
0
    }
1551
0
  }
1552
1553
0
  GST_INFO ("phase %d out_rate %d, in_rate %d, gcd %d", samp_phase, out_rate,
1554
0
      in_rate, gcd);
1555
1556
0
  resampler->samp_phase = samp_phase /= gcd;
1557
0
  resampler->in_rate = in_rate /= gcd;
1558
0
  resampler->out_rate = out_rate /= gcd;
1559
1560
0
  GST_INFO ("new phase %d/%d", resampler->samp_phase, resampler->out_rate);
1561
1562
0
  resampler->samp_inc = in_rate / out_rate;
1563
0
  resampler->samp_frac = in_rate % out_rate;
1564
1565
0
  if (options) {
1566
0
    GST_INFO ("have new options, reconfigure filter");
1567
1568
0
    if (resampler->options)
1569
0
      gst_structure_free (resampler->options);
1570
0
    resampler->options = gst_structure_copy (options);
1571
1572
0
    old_n_taps = resampler->n_taps;
1573
1574
0
    resampler_calculate_taps (resampler);
1575
0
    resampler_dump (resampler);
1576
1577
0
    if (old_n_taps > 0 && old_n_taps != resampler->n_taps) {
1578
0
      gpointer *sbuf;
1579
0
      gint i, bpf, bytes, soff, doff, diff;
1580
1581
0
      sbuf = get_sample_bufs (resampler, resampler->n_taps);
1582
1583
0
      bpf = resampler->bps * resampler->inc;
1584
0
      bytes = resampler->samples_avail * bpf;
1585
0
      soff = doff = resampler->samp_index * bpf;
1586
1587
0
      diff = ((gint) resampler->n_taps - old_n_taps) / 2;
1588
1589
0
      GST_DEBUG ("taps %d->%d, %d", old_n_taps, resampler->n_taps, diff);
1590
1591
0
      if (diff < 0) {
1592
        /* diff < 0, decrease taps, adjust source */
1593
0
        soff += -diff * bpf;
1594
0
        bytes -= -diff * bpf;
1595
0
      } else {
1596
        /* diff > 0, increase taps, adjust dest */
1597
0
        doff += diff * bpf;
1598
0
      }
1599
1600
      /* now shrink or enlarge the history buffer, when we enlarge we
1601
       * just leave the old samples in there. FIXME, probably do something better
1602
       * like mirror or fill with zeroes. */
1603
0
      for (i = 0; i < resampler->blocks; i++)
1604
0
        memmove ((gint8 *) sbuf[i] + doff, (gint8 *) sbuf[i] + soff, bytes);
1605
1606
0
      resampler->samples_avail += diff;
1607
0
    }
1608
0
  } else if (resampler->filter_mode == GST_AUDIO_RESAMPLER_FILTER_MODE_FULL) {
1609
0
    GST_DEBUG ("setting up filter cache");
1610
0
    resampler->n_phases = resampler->out_rate;
1611
0
    alloc_cache_mem (resampler, resampler->bps, resampler->n_taps,
1612
0
        resampler->n_phases);
1613
0
  }
1614
0
  setup_functions (resampler);
1615
1616
0
  return TRUE;
1617
0
}
1618
1619
/**
1620
 * gst_audio_resampler_free:
1621
 * @resampler: a #GstAudioResampler
1622
 *
1623
 * Free a previously allocated #GstAudioResampler @resampler.
1624
 */
1625
void
1626
gst_audio_resampler_free (GstAudioResampler * resampler)
1627
0
{
1628
0
  g_return_if_fail (resampler != NULL);
1629
1630
0
  g_free (resampler->cached_taps_mem);
1631
0
  g_free (resampler->taps_mem);
1632
0
  g_free (resampler->tmp_taps);
1633
0
  g_free (resampler->samples);
1634
0
  g_free (resampler->sbuf);
1635
0
  if (resampler->options)
1636
0
    gst_structure_free (resampler->options);
1637
0
  g_free (resampler);
1638
0
}
1639
1640
/**
1641
 * gst_audio_resampler_get_out_frames:
1642
 * @resampler: a #GstAudioResampler
1643
 * @in_frames: number of input frames
1644
 *
1645
 * Get the number of output frames that would be currently available when
1646
 * @in_frames are given to @resampler.
1647
 *
1648
 * Returns: The number of frames that would be available after giving
1649
 * @in_frames as input to @resampler.
1650
 */
1651
gsize
1652
gst_audio_resampler_get_out_frames (GstAudioResampler * resampler,
1653
    gsize in_frames)
1654
0
{
1655
0
  gsize need, avail, out;
1656
1657
0
  g_return_val_if_fail (resampler != NULL, 0);
1658
1659
0
  need = resampler->n_taps + resampler->samp_index + resampler->skip;
1660
0
  avail = resampler->samples_avail + in_frames;
1661
0
  GST_LOG ("need %d = %d + %d + %d, avail %d = %d + %d", (gint) need,
1662
0
      resampler->n_taps, resampler->samp_index, resampler->skip,
1663
0
      (gint) avail, (gint) resampler->samples_avail, (gint) in_frames);
1664
0
  if (avail < need) {
1665
0
    GST_LOG ("avail %d < need %d", (int) avail, (int) need);
1666
0
    return 0;
1667
0
  }
1668
1669
0
  out = (avail - need) * resampler->out_rate;
1670
0
  if (out < resampler->samp_phase) {
1671
0
    GST_LOG ("out %d < samp_phase %d", (int) out, (int) resampler->samp_phase);
1672
0
    return 0;
1673
0
  }
1674
1675
0
  out = ((out - resampler->samp_phase) / resampler->in_rate) + 1;
1676
0
  GST_LOG ("out %d = ((%d * %d - %d) / %d) + 1", (gint) out,
1677
0
      (gint) (avail - need), resampler->out_rate, resampler->samp_phase,
1678
0
      resampler->in_rate);
1679
1680
0
  return out;
1681
0
}
1682
1683
/**
1684
 * gst_audio_resampler_get_in_frames:
1685
 * @resampler: a #GstAudioResampler
1686
 * @out_frames: number of input frames
1687
 *
1688
 * Get the number of input frames that would currently be needed
1689
 * to produce @out_frames from @resampler.
1690
 *
1691
 * Returns: The number of input frames needed for producing
1692
 * @out_frames of data from @resampler.
1693
 */
1694
gsize
1695
gst_audio_resampler_get_in_frames (GstAudioResampler * resampler,
1696
    gsize out_frames)
1697
0
{
1698
0
  gsize in_frames;
1699
1700
0
  g_return_val_if_fail (resampler != NULL, 0);
1701
1702
0
  in_frames =
1703
0
      (resampler->samp_phase +
1704
0
      out_frames * resampler->samp_frac) / resampler->out_rate;
1705
0
  in_frames += out_frames * resampler->samp_inc;
1706
1707
0
  return in_frames;
1708
0
}
1709
1710
/**
1711
 * gst_audio_resampler_get_max_latency:
1712
 * @resampler: a #GstAudioResampler
1713
 *
1714
 * Get the maximum number of input samples that the resampler would
1715
 * need before producing output.
1716
 *
1717
 * Returns: the latency of @resampler as expressed in the number of
1718
 * frames.
1719
 */
1720
gsize
1721
gst_audio_resampler_get_max_latency (GstAudioResampler * resampler)
1722
0
{
1723
0
  g_return_val_if_fail (resampler != NULL, 0);
1724
1725
0
  return resampler->n_taps / 2;
1726
0
}
1727
1728
/**
1729
 * gst_audio_resampler_resample:
1730
 * @resampler: a #GstAudioResampler
1731
 * @in: input samples
1732
 * @in_frames: number of input frames
1733
 * @out: output samples
1734
 * @out_frames: number of output frames
1735
 *
1736
 * Perform resampling on @in_frames frames in @in and write @out_frames to @out.
1737
 *
1738
 * In case the samples are interleaved, @in and @out must point to an
1739
 * array with a single element pointing to a block of interleaved samples.
1740
 *
1741
 * If non-interleaved samples are used, @in and @out must point to an
1742
 * array with pointers to memory blocks, one for each channel.
1743
 *
1744
 * @in may be %NULL, in which case @in_frames of silence samples are pushed
1745
 * into the resampler.
1746
 *
1747
 * This function always produces @out_frames of output and consumes @in_frames of
1748
 * input. Use gst_audio_resampler_get_out_frames() and
1749
 * gst_audio_resampler_get_in_frames() to make sure @in_frames and @out_frames
1750
 * are matching and @in and @out point to enough memory.
1751
 */
1752
void
1753
gst_audio_resampler_resample (GstAudioResampler * resampler,
1754
    gpointer in[], gsize in_frames, gpointer out[], gsize out_frames)
1755
0
{
1756
0
  gsize samples_avail;
1757
0
  gsize need, consumed;
1758
0
  gpointer *sbuf;
1759
1760
  /* do sample skipping */
1761
0
  if (G_UNLIKELY (resampler->skip >= in_frames)) {
1762
    /* we need tp skip all input */
1763
0
    resampler->skip -= in_frames;
1764
0
    return;
1765
0
  }
1766
  /* skip the last samples by advancing the sample index */
1767
0
  resampler->samp_index += resampler->skip;
1768
1769
0
  samples_avail = resampler->samples_avail;
1770
1771
  /* make sure we have enough space to copy our samples */
1772
0
  sbuf = get_sample_bufs (resampler, in_frames + samples_avail);
1773
1774
  /* copy/deinterleave the samples */
1775
0
  resampler->deinterleave (resampler, sbuf, in, in_frames);
1776
1777
  /* update new amount of samples in our buffer */
1778
0
  resampler->samples_avail = samples_avail += in_frames;
1779
1780
0
  need = resampler->n_taps + resampler->samp_index;
1781
0
  if (G_UNLIKELY (samples_avail < need || out_frames == 0)) {
1782
0
    GST_LOG ("not enough samples to start: need %" G_GSIZE_FORMAT ", avail %"
1783
0
        G_GSIZE_FORMAT ", out %" G_GSIZE_FORMAT, need, samples_avail,
1784
0
        out_frames);
1785
    /* not enough samples to start */
1786
0
    return;
1787
0
  }
1788
1789
  /* resample all channels */
1790
0
  resampler->resample (resampler, sbuf, samples_avail, out, out_frames,
1791
0
      &consumed);
1792
1793
0
  GST_LOG ("in %" G_GSIZE_FORMAT ", avail %" G_GSIZE_FORMAT ", consumed %"
1794
0
      G_GSIZE_FORMAT, in_frames, samples_avail, consumed);
1795
1796
  /* update pointers */
1797
0
  if (G_LIKELY (consumed > 0)) {
1798
0
    gssize left = samples_avail - consumed;
1799
0
    if (left > 0) {
1800
      /* we consumed part of our samples */
1801
0
      resampler->samples_avail = left;
1802
0
    } else {
1803
      /* we consumed all our samples, empty our buffers */
1804
0
      resampler->samples_avail = 0;
1805
0
      resampler->skip = -left;
1806
0
    }
1807
0
  }
1808
0
}