/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 | } |