• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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