/src/gstreamer/subprojects/gst-plugins-base/gst-libs/gst/audio/audio-quantize.c
Line | Count | Source |
1 | | /* GStreamer |
2 | | * Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org> |
3 | | * (C) 2015 Wim Taymans <wim.taymans@gmail.com> |
4 | | * |
5 | | * gstaudioquantize.c: quantizes audio to the target format and optionally |
6 | | * applies dithering and noise shaping. |
7 | | * |
8 | | * This library is free software; you can redistribute it and/or |
9 | | * modify it under the terms of the GNU Library General Public |
10 | | * License as published by the Free Software Foundation; either |
11 | | * version 2 of the License, or (at your option) any later version. |
12 | | * |
13 | | * This library is distributed in the hope that it will be useful, |
14 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | | * Library General Public License for more details. |
17 | | * |
18 | | * You should have received a copy of the GNU Library General Public |
19 | | * License along with this library; if not, write to the |
20 | | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, |
21 | | * Boston, MA 02110-1301, USA. |
22 | | */ |
23 | | |
24 | | /* TODO: - Maybe drop 5-pole noise shaping and use coefficients |
25 | | * generated by dmaker |
26 | | * http://shibatch.sf.net |
27 | | */ |
28 | | #ifdef HAVE_CONFIG_H |
29 | | #include "config.h" |
30 | | #endif |
31 | | |
32 | | #include <gst/gst.h> |
33 | | #include <string.h> |
34 | | #include <math.h> |
35 | | |
36 | | #include "gstaudiopack.h" |
37 | | #include "audio-quantize.h" |
38 | | |
39 | | typedef void (*QuantizeFunc) (GstAudioQuantize * quant, const gpointer src, |
40 | | gpointer dst, gint count); |
41 | | |
42 | | struct _GstAudioQuantize |
43 | | { |
44 | | GstAudioDitherMethod dither; |
45 | | GstAudioNoiseShapingMethod ns; |
46 | | GstAudioQuantizeFlags flags; |
47 | | GstAudioFormat format; |
48 | | guint quantizer; |
49 | | guint stride; |
50 | | guint blocks; |
51 | | |
52 | | guint shift; |
53 | | guint32 mask, bias; |
54 | | |
55 | | /* last random number generated per channel for hifreq TPDF dither */ |
56 | | gpointer last_random; |
57 | | guint32 random_state; |
58 | | /* contains the past quantization errors, error[channels][count] */ |
59 | | guint error_size; |
60 | | gpointer error_buf; |
61 | | /* buffer with dither values */ |
62 | | guint dither_size; |
63 | | gpointer dither_buf; |
64 | | /* noise shaping coefficients */ |
65 | | gpointer coeffs; |
66 | | gint n_coeffs; |
67 | | |
68 | | QuantizeFunc quantize; |
69 | | }; |
70 | | |
71 | | #define ADDSS(res,val) \ |
72 | 0 | if (val > 0 && res > 0 && G_MAXINT32 - res <= val){ \ |
73 | 0 | res = G_MAXINT32; \ |
74 | 0 | } else if (val < 0 && res < 0 && G_MININT32 - res >= val){ \ |
75 | 0 | res = G_MININT32; \ |
76 | 0 | } else \ |
77 | 0 | res += val; |
78 | | |
79 | | static void |
80 | | gst_audio_quantize_quantize_memcpy (GstAudioQuantize * quant, |
81 | | const gpointer src, gpointer dst, gint samples) |
82 | 0 | { |
83 | 0 | if (src != dst) |
84 | 0 | memcpy (dst, src, samples * sizeof (gint32) * quant->stride); |
85 | 0 | } |
86 | | |
87 | | /* Quantize functions for gint32 as intermediate format */ |
88 | | static void |
89 | | gst_audio_quantize_quantize_int_none_none (GstAudioQuantize * quant, |
90 | | const gpointer src, gpointer dst, gint samples) |
91 | 0 | { |
92 | 0 | audio_orc_int_bias (dst, src, quant->bias, ~quant->mask, |
93 | 0 | samples * quant->stride); |
94 | 0 | } |
95 | | |
96 | | /* 32 bit xorshift PRNG, see https://en.wikipedia.org/wiki/Xorshift */ |
97 | | static inline guint32 |
98 | | gst_fast_random_uint32 (guint32 * state) |
99 | 0 | { |
100 | 0 | guint64 x = *state; |
101 | 0 | x ^= x << 13; |
102 | 0 | x ^= x >> 17; |
103 | 0 | x ^= x << 5; |
104 | 0 | return (*state = x); |
105 | 0 | } |
106 | | |
107 | | static inline gint32 |
108 | | gst_fast_random_int32 (guint32 * state) |
109 | 0 | { |
110 | 0 | return (gint32) gst_fast_random_uint32 (state); |
111 | 0 | } |
112 | | |
113 | | /* Assuming dither == 2^n, |
114 | | * returns one of 2^(n+1) possible random values: |
115 | | * -dither <= retval < dither */ |
116 | | #define RANDOM_INT_DITHER(state, dither) \ |
117 | 0 | (- dither + (gst_fast_random_int32 (state) & ((dither << 1) - 1))) |
118 | | |
119 | | static void |
120 | | setup_dither_buf (GstAudioQuantize * quant, gint samples) |
121 | 0 | { |
122 | 0 | gboolean need_init = FALSE; |
123 | 0 | gint stride = quant->stride; |
124 | 0 | gint i, len = samples * stride; |
125 | 0 | guint shift = quant->shift; |
126 | 0 | guint32 bias; |
127 | 0 | gint32 dither, *d; |
128 | |
|
129 | 0 | if (quant->dither_size < len) { |
130 | 0 | quant->dither_size = len; |
131 | 0 | quant->dither_buf = g_realloc (quant->dither_buf, len * sizeof (gint32)); |
132 | 0 | need_init = TRUE; |
133 | 0 | } |
134 | |
|
135 | 0 | bias = quant->bias; |
136 | 0 | d = quant->dither_buf; |
137 | |
|
138 | 0 | switch (quant->dither) { |
139 | 0 | case GST_AUDIO_DITHER_NONE: |
140 | 0 | if (need_init) { |
141 | 0 | for (i = 0; i < len; i++) |
142 | 0 | d[i] = 0; |
143 | 0 | } |
144 | 0 | break; |
145 | | |
146 | 0 | case GST_AUDIO_DITHER_RPDF: |
147 | 0 | dither = 1 << (shift); |
148 | 0 | for (i = 0; i < len; i++) |
149 | 0 | d[i] = bias + RANDOM_INT_DITHER (&quant->random_state, dither); |
150 | 0 | break; |
151 | | |
152 | 0 | case GST_AUDIO_DITHER_TPDF: |
153 | 0 | dither = 1 << (shift - 1); |
154 | 0 | for (i = 0; i < len; i++) |
155 | 0 | d[i] = |
156 | 0 | bias + RANDOM_INT_DITHER (&quant->random_state, |
157 | 0 | dither) + RANDOM_INT_DITHER (&quant->random_state, dither); |
158 | 0 | break; |
159 | | |
160 | 0 | case GST_AUDIO_DITHER_TPDF_HF: |
161 | 0 | { |
162 | 0 | gint32 tmp, *last_random = quant->last_random; |
163 | |
|
164 | 0 | dither = 1 << (shift - 1); |
165 | 0 | for (i = 0; i < len; i++) { |
166 | 0 | tmp = RANDOM_INT_DITHER (&quant->random_state, dither); |
167 | 0 | d[i] = bias + tmp - last_random[i % stride]; |
168 | 0 | last_random[i % stride] = tmp; |
169 | 0 | } |
170 | 0 | break; |
171 | 0 | } |
172 | 0 | } |
173 | 0 | } |
174 | | |
175 | | static void |
176 | | gst_audio_quantize_quantize_int_dither_none (GstAudioQuantize * quant, |
177 | | const gpointer src, gpointer dst, gint samples) |
178 | 0 | { |
179 | 0 | setup_dither_buf (quant, samples); |
180 | |
|
181 | 0 | audio_orc_int_dither (dst, src, quant->dither_buf, ~quant->mask, |
182 | 0 | samples * quant->stride); |
183 | 0 | } |
184 | | |
185 | | static void |
186 | | setup_error_buf (GstAudioQuantize * quant, gint samples, gint extra) |
187 | 0 | { |
188 | 0 | gint stride = quant->stride; |
189 | 0 | gint len = (samples + extra) * stride; |
190 | |
|
191 | 0 | if (quant->error_size < len) { |
192 | 0 | quant->error_buf = g_realloc (quant->error_buf, len * sizeof (gint32)); |
193 | 0 | if (quant->error_size == 0) |
194 | 0 | memset ((gint32 *) quant->error_buf, 0, stride * extra * sizeof (gint32)); |
195 | 0 | quant->error_size = len; |
196 | 0 | } |
197 | 0 | } |
198 | | |
199 | | static void |
200 | | gst_audio_quantize_quantize_int_dither_feedback (GstAudioQuantize * quant, |
201 | | const gpointer src, gpointer dst, gint samples) |
202 | 0 | { |
203 | 0 | guint32 mask; |
204 | 0 | gint i, len, stride; |
205 | 0 | const gint32 *s = src; |
206 | 0 | gint32 *dith, *d = dst, v, o, *e, err; |
207 | |
|
208 | 0 | setup_dither_buf (quant, samples); |
209 | 0 | setup_error_buf (quant, samples, 1); |
210 | |
|
211 | 0 | stride = quant->stride; |
212 | 0 | len = samples * stride; |
213 | 0 | dith = quant->dither_buf; |
214 | 0 | e = quant->error_buf; |
215 | 0 | mask = ~quant->mask; |
216 | |
|
217 | 0 | for (i = 0; i < len; i++) { |
218 | 0 | o = v = s[i]; |
219 | | /* add dither */ |
220 | 0 | err = dith[i]; |
221 | | /* remove error */ |
222 | 0 | err -= e[i]; |
223 | 0 | ADDSS (v, err); |
224 | 0 | v &= mask; |
225 | | /* store new error */ |
226 | 0 | e[i + stride] = e[i] + (v - o); |
227 | | /* store result */ |
228 | 0 | d[i] = v; |
229 | 0 | } |
230 | 0 | memmove (e, &e[len], sizeof (gint32) * stride); |
231 | 0 | } |
232 | | |
233 | 0 | #define SHIFT 10 |
234 | 0 | #define REDUCE 8 |
235 | 0 | #define RROUND (1<<(REDUCE-1)) |
236 | 0 | #define SREDUCE 2 |
237 | 0 | #define SROUND (1<<(SREDUCE-1)) |
238 | | |
239 | | static void |
240 | | gst_audio_quantize_quantize_int_dither_noise_shape (GstAudioQuantize * quant, |
241 | | const gpointer src, gpointer dst, gint samples) |
242 | 0 | { |
243 | 0 | guint32 mask; |
244 | 0 | gint i, j, k, len, stride, nc; |
245 | 0 | const gint32 *s = src; |
246 | 0 | gint32 *c, *dith, *d = dst, v, o, *e, err; |
247 | |
|
248 | 0 | nc = quant->n_coeffs; |
249 | |
|
250 | 0 | setup_dither_buf (quant, samples); |
251 | 0 | setup_error_buf (quant, samples, nc); |
252 | |
|
253 | 0 | stride = quant->stride; |
254 | 0 | len = samples * stride; |
255 | 0 | dith = quant->dither_buf; |
256 | 0 | e = quant->error_buf; |
257 | 0 | c = quant->coeffs; |
258 | 0 | mask = ~quant->mask; |
259 | |
|
260 | 0 | for (i = 0; i < len; i++) { |
261 | 0 | v = s[i]; |
262 | | /* combine and remove error */ |
263 | 0 | err = 0; |
264 | 0 | for (j = 0, k = i; j < nc; j++, k += stride) |
265 | 0 | err -= e[k] * c[j]; |
266 | 0 | err = (err + SROUND) >> (SREDUCE); |
267 | 0 | ADDSS (v, err); |
268 | 0 | o = v; |
269 | | /* add dither */ |
270 | 0 | err = dith[i]; |
271 | 0 | ADDSS (v, err); |
272 | | /* quantize */ |
273 | 0 | v &= mask; |
274 | | /* store new error with reduced precision */ |
275 | 0 | e[k] = (v - o + RROUND) >> REDUCE; |
276 | | /* store result */ |
277 | 0 | d[i] = v; |
278 | 0 | } |
279 | 0 | memmove (e, &e[len], sizeof (gint32) * stride * nc); |
280 | 0 | } |
281 | | |
282 | 0 | #define MAKE_QUANTIZE_FUNC_NAME(name) \ |
283 | 0 | gst_audio_quantize_quantize_##name |
284 | | |
285 | | static const QuantizeFunc quantize_funcs[] = { |
286 | | (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_none_none), |
287 | | (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_feedback), |
288 | | (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape), |
289 | | (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape), |
290 | | (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape), |
291 | | (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_none), |
292 | | (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_feedback), |
293 | | (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape), |
294 | | (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape), |
295 | | (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape), |
296 | | (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_none), |
297 | | (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_feedback), |
298 | | (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape), |
299 | | (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape), |
300 | | (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape), |
301 | | (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_none), |
302 | | (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_feedback), |
303 | | (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape), |
304 | | (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape), |
305 | | (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape), |
306 | | }; |
307 | | |
308 | | /* Same as error feedback but also add 1/2 of the previous error value. |
309 | | * This moves the noise a bit more into the higher frequencies. */ |
310 | | static const gdouble ns_simple_coeffs[] = { |
311 | | -0.5, 1.0 |
312 | | }; |
313 | | |
314 | | /* Noise shaping coefficients from[1], moves most power of the |
315 | | * error noise into inaudible frequency ranges. |
316 | | * |
317 | | * [1] |
318 | | * "Minimally Audible Noise Shaping", Stanley P. Lipshitz, |
319 | | * John Vanderkooy, and Robert A. Wannamaker, |
320 | | * J. Audio Eng. Soc., Vol. 39, No. 11, November 1991. */ |
321 | | |
322 | | static const gdouble ns_medium_coeffs[] = { |
323 | | 0.6149, -1.590, 1.959, -2.165, 2.033 |
324 | | }; |
325 | | |
326 | | /* Noise shaping coefficients by David Schleef, moves most power of the |
327 | | * error noise into inaudible frequency ranges */ |
328 | | static const gdouble ns_high_coeffs[] = { |
329 | | -0.340122, 0.876066, -1.72008, 2.61339, -3.31399, 3.27918, -2.92975, 2.08484, |
330 | | }; |
331 | | |
332 | | |
333 | | static void |
334 | | gst_audio_quantize_setup_noise_shaping (GstAudioQuantize * quant) |
335 | 0 | { |
336 | 0 | gint i, n_coeffs = 0; |
337 | 0 | gint32 *q; |
338 | 0 | const gdouble *coeffs; |
339 | |
|
340 | 0 | switch (quant->ns) { |
341 | 0 | case GST_AUDIO_NOISE_SHAPING_HIGH: |
342 | 0 | n_coeffs = 8; |
343 | 0 | coeffs = ns_high_coeffs; |
344 | 0 | break; |
345 | | |
346 | 0 | case GST_AUDIO_NOISE_SHAPING_MEDIUM: |
347 | 0 | n_coeffs = 5; |
348 | 0 | coeffs = ns_medium_coeffs; |
349 | 0 | break; |
350 | | |
351 | 0 | case GST_AUDIO_NOISE_SHAPING_SIMPLE: |
352 | 0 | n_coeffs = 2; |
353 | 0 | coeffs = ns_simple_coeffs; |
354 | 0 | break; |
355 | | |
356 | 0 | case GST_AUDIO_NOISE_SHAPING_ERROR_FEEDBACK: |
357 | 0 | break; |
358 | | |
359 | 0 | case GST_AUDIO_NOISE_SHAPING_NONE: |
360 | 0 | default: |
361 | 0 | break; |
362 | 0 | } |
363 | | |
364 | 0 | if (n_coeffs) { |
365 | 0 | quant->n_coeffs = n_coeffs; |
366 | 0 | q = quant->coeffs = g_new0 (gint32, n_coeffs); |
367 | 0 | for (i = 0; i < n_coeffs; i++) |
368 | 0 | q[i] = floor (coeffs[i] * (1 << SHIFT) + 0.5); |
369 | 0 | } |
370 | 0 | return; |
371 | 0 | } |
372 | | |
373 | | static void |
374 | | gst_audio_quantize_setup_dither (GstAudioQuantize * quant) |
375 | 0 | { |
376 | | /* Some non-zero number */ |
377 | 0 | quant->random_state = 0xc2d6038f; |
378 | |
|
379 | 0 | switch (quant->dither) { |
380 | 0 | case GST_AUDIO_DITHER_TPDF_HF: |
381 | 0 | quant->last_random = g_new0 (gint32, quant->stride); |
382 | 0 | break; |
383 | 0 | case GST_AUDIO_DITHER_RPDF: |
384 | 0 | case GST_AUDIO_DITHER_TPDF: |
385 | 0 | quant->last_random = NULL; |
386 | 0 | break; |
387 | 0 | case GST_AUDIO_DITHER_NONE: |
388 | 0 | default: |
389 | 0 | quant->last_random = NULL; |
390 | 0 | break; |
391 | 0 | } |
392 | 0 | return; |
393 | 0 | } |
394 | | |
395 | | static void |
396 | | gst_audio_quantize_setup_quantize_func (GstAudioQuantize * quant) |
397 | 0 | { |
398 | 0 | gint index; |
399 | |
|
400 | 0 | if (quant->shift == 0) { |
401 | 0 | quant->quantize = (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (memcpy); |
402 | 0 | return; |
403 | 0 | } |
404 | | |
405 | 0 | index = 5 * quant->dither + quant->ns; |
406 | 0 | quant->quantize = quantize_funcs[index]; |
407 | 0 | } |
408 | | |
409 | | static gint |
410 | | count_power (guint v) |
411 | 0 | { |
412 | 0 | gint res = 0; |
413 | 0 | while (v > 1) { |
414 | 0 | res++; |
415 | 0 | v >>= 1; |
416 | 0 | } |
417 | 0 | return res; |
418 | 0 | } |
419 | | |
420 | | /** |
421 | | * gst_audio_quantize_new: (constructor) (skip): |
422 | | * @dither: a #GstAudioDitherMethod |
423 | | * @ns: a #GstAudioNoiseShapingMethod |
424 | | * @flags: #GstAudioQuantizeFlags |
425 | | * @format: the #GstAudioFormat of the samples |
426 | | * @channels: the amount of channels in the samples |
427 | | * @quantizer: the quantizer to use |
428 | | * |
429 | | * Create a new quantizer object with the given parameters. |
430 | | * |
431 | | * Output samples will be quantized to a multiple of @quantizer. Better |
432 | | * performance is achieved when @quantizer is a power of 2. |
433 | | * |
434 | | * Dithering and noise-shaping can be performed during quantization with |
435 | | * the @dither and @ns parameters. |
436 | | * |
437 | | * Returns: a new #GstAudioQuantize. Free with gst_audio_quantize_free(). |
438 | | */ |
439 | | GstAudioQuantize * |
440 | | gst_audio_quantize_new (GstAudioDitherMethod dither, |
441 | | GstAudioNoiseShapingMethod ns, GstAudioQuantizeFlags flags, |
442 | | GstAudioFormat format, guint channels, guint quantizer) |
443 | 0 | { |
444 | 0 | GstAudioQuantize *quant; |
445 | |
|
446 | 0 | g_return_val_if_fail (format == GST_AUDIO_FORMAT_S32, NULL); |
447 | 0 | g_return_val_if_fail (channels > 0, NULL); |
448 | | |
449 | 0 | quant = g_new0 (GstAudioQuantize, 1); |
450 | 0 | quant->dither = dither; |
451 | 0 | quant->ns = ns; |
452 | 0 | quant->flags = flags; |
453 | 0 | quant->format = format; |
454 | 0 | if (flags & GST_AUDIO_QUANTIZE_FLAG_NON_INTERLEAVED) { |
455 | 0 | quant->stride = 1; |
456 | 0 | quant->blocks = channels; |
457 | 0 | } else { |
458 | 0 | quant->stride = channels; |
459 | 0 | quant->blocks = 1; |
460 | 0 | } |
461 | 0 | quant->quantizer = quantizer; |
462 | |
|
463 | 0 | quant->shift = count_power (quantizer); |
464 | 0 | if (quant->shift > 0) |
465 | 0 | quant->bias = (1U << (quant->shift - 1)); |
466 | 0 | else |
467 | 0 | quant->bias = 0; |
468 | 0 | quant->mask = (1U << quant->shift) - 1; |
469 | |
|
470 | 0 | gst_audio_quantize_setup_dither (quant); |
471 | 0 | gst_audio_quantize_setup_noise_shaping (quant); |
472 | 0 | gst_audio_quantize_setup_quantize_func (quant); |
473 | |
|
474 | 0 | return quant; |
475 | 0 | } |
476 | | |
477 | | /** |
478 | | * gst_audio_quantize_free: |
479 | | * @quant: a #GstAudioQuantize |
480 | | * |
481 | | * Free a #GstAudioQuantize. |
482 | | */ |
483 | | void |
484 | | gst_audio_quantize_free (GstAudioQuantize * quant) |
485 | 0 | { |
486 | 0 | g_return_if_fail (quant != NULL); |
487 | | |
488 | 0 | g_free (quant->error_buf); |
489 | 0 | g_free (quant->coeffs); |
490 | 0 | g_free (quant->last_random); |
491 | 0 | g_free (quant->dither_buf); |
492 | |
|
493 | 0 | g_free (quant); |
494 | 0 | } |
495 | | |
496 | | /** |
497 | | * gst_audio_quantize_reset: |
498 | | * @quant: a #GstAudioQuantize |
499 | | * |
500 | | * Reset @quant to the state is was when created, clearing any |
501 | | * history it might have. |
502 | | */ |
503 | | void |
504 | | gst_audio_quantize_reset (GstAudioQuantize * quant) |
505 | 0 | { |
506 | 0 | g_free (quant->error_buf); |
507 | 0 | quant->error_buf = NULL; |
508 | 0 | quant->error_size = 0; |
509 | 0 | } |
510 | | |
511 | | /** |
512 | | * gst_audio_quantize_samples: |
513 | | * @quant: a #GstAudioQuantize |
514 | | * @in: (array) (element-type gpointer): input samples |
515 | | * @out: (array) (element-type gpointer): output samples |
516 | | * @samples: number of samples |
517 | | * |
518 | | * Perform quantization on @samples in @in and write the result to @out. |
519 | | * |
520 | | * In case the samples are interleaved, @in and @out must point to an |
521 | | * array with a single element pointing to a block of interleaved samples. |
522 | | * |
523 | | * If non-interleaved samples are used, @in and @out must point to an |
524 | | * array with pointers to memory blocks, one for each channel. |
525 | | * |
526 | | * @in and @out may point to the same memory location, in which case samples will be |
527 | | * modified in-place. |
528 | | */ |
529 | | void |
530 | | gst_audio_quantize_samples (GstAudioQuantize * quant, |
531 | | const gpointer in[], gpointer out[], guint samples) |
532 | 0 | { |
533 | 0 | guint i; |
534 | |
|
535 | 0 | g_return_if_fail (quant != NULL); |
536 | 0 | g_return_if_fail (out != NULL || samples == 0); |
537 | 0 | g_return_if_fail (in != NULL || samples == 0); |
538 | | |
539 | 0 | for (i = 0; i < quant->blocks; i++) |
540 | 0 | quant->quantize (quant, in[i], out[i], samples); |
541 | 0 | } |