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 /* contains the past quantization errors, error[channels][count] */
58 guint error_size;
59 gpointer error_buf;
60 /* buffer with dither values */
61 guint dither_size;
62 gpointer dither_buf;
63 /* noise shaping coefficients */
64 gpointer coeffs;
65 gint n_coeffs;
66
67 QuantizeFunc quantize;
68 };
69
70 #define ADDSS(res,val) \
71 if (val > 0 && res > 0 && G_MAXINT32 - res <= val){ \
72 res = G_MAXINT32; \
73 } else if (val < 0 && res < 0 && G_MININT32 - res >= val){ \
74 res = G_MININT32; \
75 } else \
76 res += val;
77
78 static void
gst_audio_quantize_quantize_memcpy(GstAudioQuantize * quant,const gpointer src,gpointer dst,gint samples)79 gst_audio_quantize_quantize_memcpy (GstAudioQuantize * quant,
80 const gpointer src, gpointer dst, gint samples)
81 {
82 if (src != dst)
83 memcpy (dst, src, samples * sizeof (gint32) * quant->stride);
84 }
85
86 /* Quantize functions for gint32 as intermediate format */
87 static void
gst_audio_quantize_quantize_int_none_none(GstAudioQuantize * quant,const gpointer src,gpointer dst,gint samples)88 gst_audio_quantize_quantize_int_none_none (GstAudioQuantize * quant,
89 const gpointer src, gpointer dst, gint samples)
90 {
91 audio_orc_int_bias (dst, src, quant->bias, ~quant->mask,
92 samples * quant->stride);
93 }
94
95 /* This is the base function, implementing a linear congruential generator
96 * and returning a pseudo random number between 0 and 2^32 - 1.
97 */
98 static inline guint32
gst_fast_random_uint32(void)99 gst_fast_random_uint32 (void)
100 {
101 static guint32 state = 0xdeadbeef;
102 return (state = state * 1103515245 + 12345);
103 }
104
105 static inline gint32
gst_fast_random_int32(void)106 gst_fast_random_int32 (void)
107 {
108 return (gint32) gst_fast_random_uint32 ();
109 }
110
111 /* Assuming dither == 2^n,
112 * returns one of 2^(n+1) possible random values:
113 * -dither <= retval < dither */
114 #define RANDOM_INT_DITHER(dither) \
115 (- dither + (gst_fast_random_int32 () & ((dither << 1) - 1)))
116
117 static void
setup_dither_buf(GstAudioQuantize * quant,gint samples)118 setup_dither_buf (GstAudioQuantize * quant, gint samples)
119 {
120 gboolean need_init = FALSE;
121 gint stride = quant->stride;
122 gint i, len = samples * stride;
123 guint shift = quant->shift;
124 guint32 bias;
125 gint32 dither, *d;
126
127 if (quant->dither_size < len) {
128 quant->dither_size = len;
129 quant->dither_buf = g_realloc (quant->dither_buf, len * sizeof (gint32));
130 need_init = TRUE;
131 }
132
133 bias = quant->bias;
134 d = quant->dither_buf;
135
136 switch (quant->dither) {
137 case GST_AUDIO_DITHER_NONE:
138 if (need_init) {
139 for (i = 0; i < len; i++)
140 d[i] = 0;
141 }
142 break;
143
144 case GST_AUDIO_DITHER_RPDF:
145 dither = 1 << (shift);
146 for (i = 0; i < len; i++)
147 d[i] = bias + RANDOM_INT_DITHER (dither);
148 break;
149
150 case GST_AUDIO_DITHER_TPDF:
151 dither = 1 << (shift - 1);
152 for (i = 0; i < len; i++)
153 d[i] = bias + RANDOM_INT_DITHER (dither) + RANDOM_INT_DITHER (dither);
154 break;
155
156 case GST_AUDIO_DITHER_TPDF_HF:
157 {
158 gint32 tmp, *last_random = quant->last_random;
159
160 dither = 1 << (shift - 1);
161 for (i = 0; i < len; i++) {
162 tmp = RANDOM_INT_DITHER (dither);
163 d[i] = bias + tmp - last_random[i % stride];
164 last_random[i % stride] = tmp;
165 }
166 break;
167 }
168 }
169 }
170
171 static void
gst_audio_quantize_quantize_int_dither_none(GstAudioQuantize * quant,const gpointer src,gpointer dst,gint samples)172 gst_audio_quantize_quantize_int_dither_none (GstAudioQuantize * quant,
173 const gpointer src, gpointer dst, gint samples)
174 {
175 setup_dither_buf (quant, samples);
176
177 audio_orc_int_dither (dst, src, quant->dither_buf, ~quant->mask,
178 samples * quant->stride);
179 }
180
181 static void
setup_error_buf(GstAudioQuantize * quant,gint samples,gint extra)182 setup_error_buf (GstAudioQuantize * quant, gint samples, gint extra)
183 {
184 gint stride = quant->stride;
185 gint len = (samples + extra) * stride;
186
187 if (quant->error_size < len) {
188 quant->error_buf = g_realloc (quant->error_buf, len * sizeof (gint32));
189 if (quant->error_size == 0)
190 memset ((gint32 *) quant->error_buf, 0, stride * extra * sizeof (gint32));
191 quant->error_size = len;
192 }
193 }
194
195 static void
gst_audio_quantize_quantize_int_dither_feedback(GstAudioQuantize * quant,const gpointer src,gpointer dst,gint samples)196 gst_audio_quantize_quantize_int_dither_feedback (GstAudioQuantize * quant,
197 const gpointer src, gpointer dst, gint samples)
198 {
199 guint32 mask;
200 gint i, len, stride;
201 const gint32 *s = src;
202 gint32 *dith, *d = dst, v, o, *e, err;
203
204 setup_dither_buf (quant, samples);
205 setup_error_buf (quant, samples, 1);
206
207 stride = quant->stride;
208 len = samples * stride;
209 dith = quant->dither_buf;
210 e = quant->error_buf;
211 mask = ~quant->mask;
212
213 for (i = 0; i < len; i++) {
214 o = v = s[i];
215 /* add dither */
216 err = dith[i];
217 /* remove error */
218 err -= e[i];
219 ADDSS (v, err);
220 v &= mask;
221 /* store new error */
222 e[i + stride] = e[i] + (v - o);
223 /* store result */
224 d[i] = v;
225 }
226 memmove (e, &e[len], sizeof (gint32) * stride);
227 }
228
229 #define SHIFT 10
230 #define REDUCE 8
231 #define RROUND (1<<(REDUCE-1))
232 #define SREDUCE 2
233 #define SROUND (1<<(SREDUCE-1))
234
235 static void
gst_audio_quantize_quantize_int_dither_noise_shape(GstAudioQuantize * quant,const gpointer src,gpointer dst,gint samples)236 gst_audio_quantize_quantize_int_dither_noise_shape (GstAudioQuantize * quant,
237 const gpointer src, gpointer dst, gint samples)
238 {
239 guint32 mask;
240 gint i, j, k, len, stride, nc;
241 const gint32 *s = src;
242 gint32 *c, *dith, *d = dst, v, o, *e, err;
243
244 nc = quant->n_coeffs;
245
246 setup_dither_buf (quant, samples);
247 setup_error_buf (quant, samples, nc);
248
249 stride = quant->stride;
250 len = samples * stride;
251 dith = quant->dither_buf;
252 e = quant->error_buf;
253 c = quant->coeffs;
254 mask = ~quant->mask;
255
256 for (i = 0; i < len; i++) {
257 v = s[i];
258 /* combine and remove error */
259 err = 0;
260 for (j = 0, k = i; j < nc; j++, k += stride)
261 err -= e[k] * c[j];
262 err = (err + SROUND) >> (SREDUCE);
263 ADDSS (v, err);
264 o = v;
265 /* add dither */
266 err = dith[i];
267 ADDSS (v, err);
268 /* quantize */
269 v &= mask;
270 /* store new error with reduced precision */
271 e[k] = (v - o + RROUND) >> REDUCE;
272 /* store result */
273 d[i] = v;
274 }
275 memmove (e, &e[len], sizeof (gint32) * stride * nc);
276 }
277
278 #define MAKE_QUANTIZE_FUNC_NAME(name) \
279 gst_audio_quantize_quantize_##name
280
281 static const QuantizeFunc quantize_funcs[] = {
282 (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_none_none),
283 (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_feedback),
284 (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape),
285 (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape),
286 (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape),
287 (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_none),
288 (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_feedback),
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_noise_shape),
292 (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_none),
293 (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_feedback),
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_noise_shape),
297 (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_none),
298 (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_feedback),
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_noise_shape),
302 };
303
304 /* Same as error feedback but also add 1/2 of the previous error value.
305 * This moves the noise a bit more into the higher frequencies. */
306 static const gdouble ns_simple_coeffs[] = {
307 -0.5, 1.0
308 };
309
310 /* Noise shaping coefficients from[1], moves most power of the
311 * error noise into inaudible frequency ranges.
312 *
313 * [1]
314 * "Minimally Audible Noise Shaping", Stanley P. Lipshitz,
315 * John Vanderkooy, and Robert A. Wannamaker,
316 * J. Audio Eng. Soc., Vol. 39, No. 11, November 1991. */
317
318 static const gdouble ns_medium_coeffs[] = {
319 0.6149, -1.590, 1.959, -2.165, 2.033
320 };
321
322 /* Noise shaping coefficients by David Schleef, moves most power of the
323 * error noise into inaudible frequency ranges */
324 static const gdouble ns_high_coeffs[] = {
325 -0.340122, 0.876066, -1.72008, 2.61339, -3.31399, 3.27918, -2.92975, 2.08484,
326 };
327
328
329 static void
gst_audio_quantize_setup_noise_shaping(GstAudioQuantize * quant)330 gst_audio_quantize_setup_noise_shaping (GstAudioQuantize * quant)
331 {
332 gint i, n_coeffs = 0;
333 gint32 *q;
334 const gdouble *coeffs;
335
336 switch (quant->ns) {
337 case GST_AUDIO_NOISE_SHAPING_HIGH:
338 n_coeffs = 8;
339 coeffs = ns_high_coeffs;
340 break;
341
342 case GST_AUDIO_NOISE_SHAPING_MEDIUM:
343 n_coeffs = 5;
344 coeffs = ns_medium_coeffs;
345 break;
346
347 case GST_AUDIO_NOISE_SHAPING_SIMPLE:
348 n_coeffs = 2;
349 coeffs = ns_simple_coeffs;
350 break;
351
352 case GST_AUDIO_NOISE_SHAPING_ERROR_FEEDBACK:
353 break;
354
355 case GST_AUDIO_NOISE_SHAPING_NONE:
356 default:
357 break;
358 }
359
360 if (n_coeffs) {
361 quant->n_coeffs = n_coeffs;
362 q = quant->coeffs = g_new0 (gint32, n_coeffs);
363 for (i = 0; i < n_coeffs; i++)
364 q[i] = floor (coeffs[i] * (1 << SHIFT) + 0.5);
365 }
366 return;
367 }
368
369 static void
gst_audio_quantize_setup_dither(GstAudioQuantize * quant)370 gst_audio_quantize_setup_dither (GstAudioQuantize * quant)
371 {
372 switch (quant->dither) {
373 case GST_AUDIO_DITHER_TPDF_HF:
374 quant->last_random = g_new0 (gint32, quant->stride);
375 break;
376 case GST_AUDIO_DITHER_RPDF:
377 case GST_AUDIO_DITHER_TPDF:
378 quant->last_random = NULL;
379 break;
380 case GST_AUDIO_DITHER_NONE:
381 default:
382 quant->last_random = NULL;
383 break;
384 }
385 return;
386 }
387
388 static void
gst_audio_quantize_setup_quantize_func(GstAudioQuantize * quant)389 gst_audio_quantize_setup_quantize_func (GstAudioQuantize * quant)
390 {
391 gint index;
392
393 if (quant->shift == 0) {
394 quant->quantize = (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (memcpy);
395 return;
396 }
397
398 index = 5 * quant->dither + quant->ns;
399 quant->quantize = quantize_funcs[index];
400 }
401
402 static gint
count_power(guint v)403 count_power (guint v)
404 {
405 gint res = 0;
406 while (v > 1) {
407 res++;
408 v >>= 1;
409 }
410 return res;
411 }
412
413 /**
414 * gst_audio_quantize_new: (skip):
415 * @dither: a #GstAudioDitherMethod
416 * @ns: a #GstAudioNoiseShapingMethod
417 * @flags: #GstAudioQuantizeFlags
418 * @format: the #GstAudioFormat of the samples
419 * @channels: the amount of channels in the samples
420 * @quantizer: the quantizer to use
421 *
422 * Create a new quantizer object with the given parameters.
423 *
424 * Output samples will be quantized to a multiple of @quantizer. Better
425 * performance is achieved when @quantizer is a power of 2.
426 *
427 * Dithering and noise-shaping can be performed during quantization with
428 * the @dither and @ns parameters.
429 *
430 * Returns: a new #GstAudioQuantize. Free with gst_audio_quantize_free().
431 */
432 GstAudioQuantize *
gst_audio_quantize_new(GstAudioDitherMethod dither,GstAudioNoiseShapingMethod ns,GstAudioQuantizeFlags flags,GstAudioFormat format,guint channels,guint quantizer)433 gst_audio_quantize_new (GstAudioDitherMethod dither,
434 GstAudioNoiseShapingMethod ns, GstAudioQuantizeFlags flags,
435 GstAudioFormat format, guint channels, guint quantizer)
436 {
437 GstAudioQuantize *quant;
438
439 g_return_val_if_fail (format == GST_AUDIO_FORMAT_S32, NULL);
440 g_return_val_if_fail (channels > 0, NULL);
441
442 quant = g_slice_new0 (GstAudioQuantize);
443 quant->dither = dither;
444 quant->ns = ns;
445 quant->flags = flags;
446 quant->format = format;
447 if (flags & GST_AUDIO_QUANTIZE_FLAG_NON_INTERLEAVED) {
448 quant->stride = 1;
449 quant->blocks = channels;
450 } else {
451 quant->stride = channels;
452 quant->blocks = 1;
453 }
454 quant->quantizer = quantizer;
455
456 quant->shift = count_power (quantizer);
457 if (quant->shift > 0)
458 quant->bias = (1U << (quant->shift - 1));
459 else
460 quant->bias = 0;
461 quant->mask = (1U << quant->shift) - 1;
462
463 gst_audio_quantize_setup_dither (quant);
464 gst_audio_quantize_setup_noise_shaping (quant);
465 gst_audio_quantize_setup_quantize_func (quant);
466
467 return quant;
468 }
469
470 /**
471 * gst_audio_quantize_free:
472 * @quant: a #GstAudioQuantize
473 *
474 * Free a #GstAudioQuantize.
475 */
476 void
gst_audio_quantize_free(GstAudioQuantize * quant)477 gst_audio_quantize_free (GstAudioQuantize * quant)
478 {
479 g_return_if_fail (quant != NULL);
480
481 g_free (quant->error_buf);
482 g_free (quant->coeffs);
483 g_free (quant->last_random);
484 g_free (quant->dither_buf);
485
486 g_slice_free (GstAudioQuantize, quant);
487 }
488
489 /**
490 * gst_audio_quantize_reset:
491 * @quant: a #GstAudioQuantize
492 *
493 * Reset @quant to the state is was when created, clearing any
494 * history it might have.
495 */
496 void
gst_audio_quantize_reset(GstAudioQuantize * quant)497 gst_audio_quantize_reset (GstAudioQuantize * quant)
498 {
499 g_free (quant->error_buf);
500 quant->error_buf = NULL;
501 quant->error_size = 0;
502 }
503
504 /**
505 * gst_audio_quantize_samples:
506 * @quant: a #GstAudioQuantize
507 * @in: input samples
508 * @out: output samples
509 * @samples: number of samples
510 *
511 * Perform quantization on @samples in @in and write the result to @out.
512 *
513 * In case the samples are interleaved, @in and @out must point to an
514 * array with a single element pointing to a block of interleaved samples.
515 *
516 * If non-interleaved samples are used, @in and @out must point to an
517 * array with pointers to memory blocks, one for each channel.
518 *
519 * @in and @out may point to the same memory location, in which case samples will be
520 * modified in-place.
521 */
522 void
gst_audio_quantize_samples(GstAudioQuantize * quant,const gpointer in[],gpointer out[],guint samples)523 gst_audio_quantize_samples (GstAudioQuantize * quant,
524 const gpointer in[], gpointer out[], guint samples)
525 {
526 guint i;
527
528 g_return_if_fail (quant != NULL);
529 g_return_if_fail (out != NULL || samples == 0);
530 g_return_if_fail (in != NULL || samples == 0);
531
532 for (i = 0; i < quant->blocks; i++)
533 quant->quantize (quant, in[i], out[i], samples);
534 }
535