2 * Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
3 * (C) 2015 Wim Taymans <wim.taymans@gmail.com>
5 * gstaudioquantize.c: quantizes audio to the target format and optionally
6 * applies dithering and noise shaping.
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.
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.
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.
24 /* TODO: - Maybe drop 5-pole noise shaping and use coefficients
26 * http://shibatch.sf.net
33 #include "gstaudiopack.h"
34 #include "audio-quantize.h"
36 typedef void (*QuantizeFunc) (GstAudioQuantize * quant, const gpointer src,
37 gpointer dst, gint count);
39 struct _GstAudioQuantize
41 GstAudioDitherMethod dither;
42 GstAudioNoiseShapingMethod ns;
43 GstAudioQuantizeFlags flags;
44 GstAudioFormat format;
52 /* last random number generated per channel for hifreq TPDF dither */
54 /* contains the past quantization errors, error[channels][count] */
57 /* buffer with dither values */
60 /* noise shaping coefficients */
64 QuantizeFunc quantize;
67 #define ADDSS(res,val) \
68 if (val > 0 && res > 0 && G_MAXINT32 - res <= val){ \
70 } else if (val < 0 && res < 0 && G_MININT32 - res >= val){ \
76 gst_audio_quantize_quantize_memcpy (GstAudioQuantize * quant,
77 const gpointer src, gpointer dst, gint samples)
80 memcpy (dst, src, samples * sizeof (gint32) * quant->stride);
83 /* Quantize functions for gint32 as intermediate format */
85 gst_audio_quantize_quantize_int_none_none (GstAudioQuantize * quant,
86 const gpointer src, gpointer dst, gint samples)
88 audio_orc_int_bias (dst, src, quant->bias, ~quant->mask,
89 samples * quant->stride);
92 /* This is the base function, implementing a linear congruential generator
93 * and returning a pseudo random number between 0 and 2^32 - 1.
96 gst_fast_random_uint32 (void)
98 static guint32 state = 0xdeadbeef;
99 return (state = state * 1103515245 + 12345);
103 gst_fast_random_int32 (void)
105 return (gint32) gst_fast_random_uint32 ();
108 /* Assuming dither == 2^n,
109 * returns one of 2^(n+1) possible random values:
110 * -dither <= retval < dither */
111 #define RANDOM_INT_DITHER(dither) \
112 (- dither + (gst_fast_random_int32 () & ((dither << 1) - 1)))
115 setup_dither_buf (GstAudioQuantize * quant, gint samples)
117 gboolean need_init = FALSE;
118 gint stride = quant->stride;
119 gint i, len = samples * stride;
120 guint shift = quant->shift;
124 if (quant->dither_size < len) {
125 quant->dither_size = len;
126 quant->dither_buf = g_realloc (quant->dither_buf, len * sizeof (gint32));
131 d = quant->dither_buf;
133 switch (quant->dither) {
134 case GST_AUDIO_DITHER_NONE:
136 for (i = 0; i < len; i++)
141 case GST_AUDIO_DITHER_RPDF:
142 dither = 1 << (shift);
143 for (i = 0; i < len; i++)
144 d[i] = bias + RANDOM_INT_DITHER (dither);
147 case GST_AUDIO_DITHER_TPDF:
148 dither = 1 << (shift - 1);
149 for (i = 0; i < len; i++)
150 d[i] = bias + RANDOM_INT_DITHER (dither) + RANDOM_INT_DITHER (dither);
153 case GST_AUDIO_DITHER_TPDF_HF:
155 gint32 tmp, *last_random = quant->last_random;
157 dither = 1 << (shift - 1);
158 for (i = 0; i < len; i++) {
159 tmp = RANDOM_INT_DITHER (dither);
160 d[i] = bias + tmp - last_random[i % stride];
161 last_random[i % stride] = tmp;
169 gst_audio_quantize_quantize_int_dither_none (GstAudioQuantize * quant,
170 const gpointer src, gpointer dst, gint samples)
172 setup_dither_buf (quant, samples);
174 audio_orc_int_dither (dst, src, quant->dither_buf, ~quant->mask,
175 samples * quant->stride);
179 setup_error_buf (GstAudioQuantize * quant, gint samples, gint extra)
181 gint stride = quant->stride;
182 gint len = (samples + extra) * stride;
184 if (quant->error_size < len) {
185 quant->error_buf = g_realloc (quant->error_buf, len * sizeof (gint32));
186 if (quant->error_size == 0)
187 memset ((gint32 *) quant->error_buf, 0, stride * extra * sizeof (gint32));
188 quant->error_size = len;
193 gst_audio_quantize_quantize_int_dither_feedback (GstAudioQuantize * quant,
194 const gpointer src, gpointer dst, gint samples)
198 const gint32 *s = src;
199 gint32 *dith, *d = dst, v, o, *e, err;
201 setup_dither_buf (quant, samples);
202 setup_error_buf (quant, samples, 1);
204 stride = quant->stride;
205 len = samples * stride;
206 dith = quant->dither_buf;
207 e = quant->error_buf;
210 for (i = 0; i < len; i++) {
218 /* store new error */
219 e[i + stride] = e[i] + (v - o);
223 memmove (e, &e[len], sizeof (gint32) * stride);
228 #define RROUND (1<<(REDUCE-1))
230 #define SROUND (1<<(SREDUCE-1))
233 gst_audio_quantize_quantize_int_dither_noise_shape (GstAudioQuantize * quant,
234 const gpointer src, gpointer dst, gint samples)
237 gint i, j, k, len, stride, nc;
238 const gint32 *s = src;
239 gint32 *c, *dith, *d = dst, v, o, *e, err;
241 nc = quant->n_coeffs;
243 setup_dither_buf (quant, samples);
244 setup_error_buf (quant, samples, nc);
246 stride = quant->stride;
247 len = samples * stride;
248 dith = quant->dither_buf;
249 e = quant->error_buf;
253 for (i = 0; i < len; i++) {
255 /* combine and remove error */
257 for (j = 0, k = i; j < nc; j++, k += stride)
259 err = (err + SROUND) >> (SREDUCE);
267 /* store new error with reduced precision */
268 e[k] = (v - o + RROUND) >> REDUCE;
272 memmove (e, &e[len], sizeof (gint32) * stride * nc);
275 #define MAKE_QUANTIZE_FUNC_NAME(name) \
276 gst_audio_quantize_quantize_##name
278 static const QuantizeFunc quantize_funcs[] = {
279 (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_none_none),
280 (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_feedback),
281 (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape),
282 (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape),
283 (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape),
284 (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_none),
285 (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_feedback),
286 (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape),
287 (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape),
288 (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape),
289 (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_none),
290 (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_feedback),
291 (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape),
292 (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape),
293 (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape),
294 (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_none),
295 (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_feedback),
296 (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape),
297 (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape),
298 (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape),
301 /* Same as error feedback but also add 1/2 of the previous error value.
302 * This moves the noise a bit more into the higher frequencies. */
303 static const gdouble ns_simple_coeffs[] = {
307 /* Noise shaping coefficients from[1], moves most power of the
308 * error noise into inaudible frequency ranges.
311 * "Minimally Audible Noise Shaping", Stanley P. Lipshitz,
312 * John Vanderkooy, and Robert A. Wannamaker,
313 * J. Audio Eng. Soc., Vol. 39, No. 11, November 1991. */
315 static const gdouble ns_medium_coeffs[] = {
316 0.6149, -1.590, 1.959, -2.165, 2.033
319 /* Noise shaping coefficients by David Schleef, moves most power of the
320 * error noise into inaudible frequency ranges */
321 static const gdouble ns_high_coeffs[] = {
322 -0.340122, 0.876066, -1.72008, 2.61339, -3.31399, 3.27918, -2.92975, 2.08484,
327 gst_audio_quantize_setup_noise_shaping (GstAudioQuantize * quant)
329 gint i, n_coeffs = 0;
331 const gdouble *coeffs;
334 case GST_AUDIO_NOISE_SHAPING_HIGH:
336 coeffs = ns_high_coeffs;
339 case GST_AUDIO_NOISE_SHAPING_MEDIUM:
341 coeffs = ns_medium_coeffs;
344 case GST_AUDIO_NOISE_SHAPING_SIMPLE:
346 coeffs = ns_simple_coeffs;
349 case GST_AUDIO_NOISE_SHAPING_ERROR_FEEDBACK:
352 case GST_AUDIO_NOISE_SHAPING_NONE:
358 quant->n_coeffs = n_coeffs;
359 q = quant->coeffs = g_new0 (gint32, n_coeffs);
360 for (i = 0; i < n_coeffs; i++)
361 q[i] = floor (coeffs[i] * (1 << SHIFT) + 0.5);
367 gst_audio_quantize_setup_dither (GstAudioQuantize * quant)
369 switch (quant->dither) {
370 case GST_AUDIO_DITHER_TPDF_HF:
371 quant->last_random = g_new0 (gint32, quant->stride);
373 case GST_AUDIO_DITHER_RPDF:
374 case GST_AUDIO_DITHER_TPDF:
375 quant->last_random = NULL;
377 case GST_AUDIO_DITHER_NONE:
379 quant->last_random = NULL;
386 gst_audio_quantize_setup_quantize_func (GstAudioQuantize * quant)
390 if (quant->shift == 0) {
391 quant->quantize = (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (memcpy);
395 index = 5 * quant->dither + quant->ns;
396 quant->quantize = quantize_funcs[index];
400 count_power (guint v)
411 * gst_audio_quantize_new: (skip):
412 * @dither: a #GstAudioDitherMethod
413 * @ns: a #GstAudioNoiseShapingMethod
414 * @flags: #GstAudioQuantizeFlags
415 * @format: the #GstAudioFormat of the samples
416 * @channels: the amount of channels in the samples
417 * @quantizer: the quantizer to use
419 * Create a new quantizer object with the given parameters.
421 * Output samples will be quantized to a multiple of @quantizer. Better
422 * performance is achieved when @quantizer is a power of 2.
424 * Dithering and noise-shaping can be performed during quantization with
425 * the @dither and @ns parameters.
427 * Returns: a new #GstAudioQuantize. Free with gst_audio_quantize_free().
430 gst_audio_quantize_new (GstAudioDitherMethod dither,
431 GstAudioNoiseShapingMethod ns, GstAudioQuantizeFlags flags,
432 GstAudioFormat format, guint channels, guint quantizer)
434 GstAudioQuantize *quant;
436 g_return_val_if_fail (format == GST_AUDIO_FORMAT_S32, NULL);
437 g_return_val_if_fail (channels > 0, NULL);
439 quant = g_slice_new0 (GstAudioQuantize);
440 quant->dither = dither;
442 quant->flags = flags;
443 quant->format = format;
444 if (flags & GST_AUDIO_QUANTIZE_FLAG_NON_INTERLEAVED) {
446 quant->blocks = channels;
448 quant->stride = channels;
451 quant->quantizer = quantizer;
453 quant->shift = count_power (quantizer);
454 if (quant->shift > 0)
455 quant->bias = (1U << (quant->shift - 1));
458 quant->mask = (1U << quant->shift) - 1;
460 gst_audio_quantize_setup_dither (quant);
461 gst_audio_quantize_setup_noise_shaping (quant);
462 gst_audio_quantize_setup_quantize_func (quant);
468 * gst_audio_quantize_free:
469 * @quant: a #GstAudioQuantize
471 * Free a #GstAudioQuantize.
474 gst_audio_quantize_free (GstAudioQuantize * quant)
476 g_return_if_fail (quant != NULL);
478 g_free (quant->error_buf);
479 g_free (quant->coeffs);
480 g_free (quant->last_random);
481 g_free (quant->dither_buf);
483 g_slice_free (GstAudioQuantize, quant);
487 * gst_audio_quantize_reset:
488 * @quant: a #GstAudioQuantize
490 * Reset @quant to the state is was when created, clearing any
491 * history it might have.
494 gst_audio_quantize_reset (GstAudioQuantize * quant)
496 g_free (quant->error_buf);
497 quant->error_buf = NULL;
498 quant->error_size = 0;
502 * gst_audio_quantize_samples:
503 * @quant: a #GstAudioQuantize
505 * @out: output samples
506 * @samples: number of samples
508 * Perform quantization on @samples in @in and write the result to @out.
510 * In case the samples are interleaved, @in and @out must point to an
511 * array with a single element pointing to a block of interleaved samples.
513 * If non-interleaved samples are used, @in and @out must point to an
514 * array with pointers to memory blocks, one for each channel.
516 * @in and @out may point to the same memory location, in which case samples will be
520 gst_audio_quantize_samples (GstAudioQuantize * quant,
521 const gpointer in[], gpointer out[], guint samples)
525 g_return_if_fail (quant != NULL);
526 g_return_if_fail (out != NULL || samples == 0);
527 g_return_if_fail (in != NULL || samples == 0);
529 for (i = 0; i < quant->blocks; i++)
530 quant->quantize (quant, in[i], out[i], samples);