2 * Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
4 * gstaudioquantize.c: quantizes audio to the target format and optionally
5 * applies dithering and noise shaping.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
24 * FIXME: When doing dithering with int as intermediate format
25 * one gets audible harmonics while the noise floor is
26 * constant for double as intermediate format!
29 /* TODO: - Maybe drop 5-pole noise shaping and use coefficients
31 * http://shibatch.sf.net
37 #include "audioconvert.h"
38 #include "gstaudioquantize.h"
40 #include "gstfastrandom.h"
42 #define MAKE_QUANTIZE_FUNC_NAME(name) \
43 gst_audio_quantize_quantize_##name
45 /* Quantize functions for gint32 as intermediate format */
47 #define MAKE_QUANTIZE_FUNC_I(name, DITHER_INIT_FUNC, ADD_DITHER_FUNC, \
50 MAKE_QUANTIZE_FUNC_NAME (name) (AudioConvertCtx *ctx, gint32 *src, \
51 gint32 *dst, gint count) \
53 gint scale = ctx->out_scale; \
54 gint channels = ctx->out.channels; \
59 guint32 mask = 0xffffffff & (0xffffffff << scale); \
60 guint32 bias = 1U << (scale - 1); \
63 for (;count;count--) { \
64 for (chan_pos = 0; chan_pos < channels; chan_pos++) { \
73 for (;count;count--) { \
74 for (chan_pos = 0; chan_pos < channels; chan_pos++) { \
83 /* Quantize functions for gdouble as intermediate format with
86 #define MAKE_QUANTIZE_FUNC_F(name, DITHER_INIT_FUNC, NS_INIT_FUNC, \
87 ADD_NS_FUNC, ADD_DITHER_FUNC, \
90 MAKE_QUANTIZE_FUNC_NAME (name) (AudioConvertCtx *ctx, gdouble *src, \
91 gdouble *dst, gint count) \
93 gint scale = ctx->out_scale; \
94 gint channels = ctx->out.channels; \
96 gdouble factor = (1U<<(32-scale-1)) - 1; \
103 for (;count;count--) { \
104 for (chan_pos = 0; chan_pos < channels; chan_pos++) { \
108 tmp = floor(tmp * factor + 0.5); \
109 *dst = CLAMP (tmp, -factor - 1, factor); \
110 UPDATE_ERROR_FUNC() \
115 for (;count;count--) { \
116 for (chan_pos = 0; chan_pos < channels; chan_pos++) { \
117 *dst = *src++ * 2147483647.0; \
124 /* Rounding functions for int as intermediate format, only used when
125 * not using dithering. With dithering we include this offset in our
126 * dither noise instead. */
129 if (tmp > 0 && G_MAXINT32 - tmp <= bias) \
137 /* Dithering definitions
138 * See http://en.wikipedia.org/wiki/Dithering or
139 * http://www.cadenzarecording.com/Dither.html for explainations.
141 * We already add the rounding offset to the dither noise here
142 * to have only one overflow check instead of two. */
144 #define INIT_DITHER_RPDF_I() \
146 gint32 dither = (1<<(scale));
148 #define ADD_DITHER_RPDF_I() \
149 rand = gst_fast_random_int32_range (bias - dither, \
151 if (rand > 0 && tmp > 0 && G_MAXINT32 - tmp <= rand) \
153 else if (rand < 0 && tmp < 0 && G_MININT32 - tmp >= rand) \
158 #define INIT_DITHER_RPDF_F() \
159 gdouble dither = 1.0/(1U<<(32 - scale - 1));
161 #define ADD_DITHER_RPDF_F() \
162 tmp += gst_fast_random_double_range (- dither, dither);
164 #define INIT_DITHER_TPDF_I() \
166 gint32 dither = (1<<(scale - 1)); \
169 #define ADD_DITHER_TPDF_I() \
170 rand = gst_fast_random_int32_range (bias - dither, \
172 + gst_fast_random_int32_range (bias - dither, \
173 bias + dither - 1); \
174 if (rand > 0 && tmp > 0 && G_MAXINT32 - tmp <= rand) \
176 else if (rand < 0 && tmp < 0 && G_MININT32 - tmp >= rand) \
181 #define INIT_DITHER_TPDF_F() \
182 gdouble dither = 1.0/(1U<<(32 - scale));
184 #define ADD_DITHER_TPDF_F() \
185 tmp += gst_fast_random_double_range (- dither, dither) \
186 + gst_fast_random_double_range (- dither, dither);
188 #define INIT_DITHER_TPDF_HF_I() \
190 gint32 dither = (1<<(scale-1)); \
191 gint32 *last_random = (gint32 *) ctx->last_random, tmp_rand; \
194 #define ADD_DITHER_TPDF_HF_I() \
195 tmp_rand = gst_fast_random_int32_range (bias - dither, \
197 rand = tmp_rand - last_random[chan_pos]; \
198 last_random[chan_pos] = tmp_rand; \
199 if (rand > 0 && tmp > 0 && G_MAXINT32 - tmp <= rand) \
201 else if (rand < 0 && tmp < 0 && G_MININT32 - tmp >= rand) \
206 /* Like TPDF dither but the dither noise is oriented more to the
207 * higher frequencies */
209 #define INIT_DITHER_TPDF_HF_F() \
211 gdouble dither = 1.0/(1U<<(32 - scale)); \
212 gdouble *last_random = (gdouble *) ctx->last_random, tmp_rand;
214 #define ADD_DITHER_TPDF_HF_F() \
215 tmp_rand = gst_fast_random_double_range (- dither, dither); \
216 rand = tmp_rand - last_random[chan_pos]; \
217 last_random[chan_pos] = tmp_rand; \
220 /* Noise shaping definitions.
221 * See http://en.wikipedia.org/wiki/Noise_shaping for explanations. */
224 /* Simple error feedback: Just accumulate the dithering and quantization
225 * error and remove it from each sample. */
227 #define INIT_NS_ERROR_FEEDBACK() \
229 gdouble *errors = ctx->error_buf;
231 #define ADD_NS_ERROR_FEEDBACK() \
233 tmp -= errors[chan_pos];
235 #define UPDATE_ERROR_ERROR_FEEDBACK() \
236 errors[chan_pos] += (*dst)/factor - orig;
238 /* Same as error feedback but also add 1/2 of the previous error value.
239 * This moves the noise a bit more into the higher frequencies. */
241 #define INIT_NS_SIMPLE() \
243 gdouble *errors = ctx->error_buf, cur_error;
245 #define ADD_NS_SIMPLE() \
246 cur_error = errors[chan_pos*2] - 0.5 * errors[chan_pos*2 + 1]; \
250 #define UPDATE_ERROR_SIMPLE() \
251 errors[chan_pos*2 + 1] = errors[chan_pos*2]; \
252 errors[chan_pos*2] = (*dst)/factor - orig;
255 /* Noise shaping coefficients from[1], moves most power of the
256 * error noise into inaudible frequency ranges.
259 * "Minimally Audible Noise Shaping", Stanley P. Lipshitz,
260 * John Vanderkooy, and Robert A. Wannamaker,
261 * J. Audio Eng. Soc., Vol. 39, No. 11, November 1991. */
263 static const gdouble ns_medium_coeffs[] = {
264 2.033, -2.165, 1.959, -1.590, 0.6149
267 #define INIT_NS_MEDIUM() \
269 gdouble *errors = ctx->error_buf, cur_error; \
272 #define ADD_NS_MEDIUM() \
274 for (j = 0; j < 5; j++) \
275 cur_error += errors[chan_pos*5 + j] * ns_medium_coeffs[j]; \
279 #define UPDATE_ERROR_MEDIUM() \
280 for (j = 4; j > 0; j--) \
281 errors[chan_pos*5 + j] = errors[chan_pos*5 + j-1]; \
282 errors[chan_pos*5] = (*dst)/factor - orig;
284 /* Noise shaping coefficients by David Schleef, moves most power of the
285 * error noise into inaudible frequency ranges */
287 static const gdouble ns_high_coeffs[] = {
288 2.08484, -2.92975, 3.27918, -3.31399, 2.61339, -1.72008, 0.876066, -0.340122
291 #define INIT_NS_HIGH() \
293 gdouble *errors = ctx->error_buf, cur_error; \
296 #define ADD_NS_HIGH() \
298 for (j = 0; j < 8; j++) \
299 cur_error += errors[chan_pos + j] * ns_high_coeffs[j]; \
303 #define UPDATE_ERROR_HIGH() \
304 for (j = 7; j > 0; j--) \
305 errors[chan_pos + j] = errors[chan_pos + j-1]; \
306 errors[chan_pos] = (*dst)/factor - orig;
309 MAKE_QUANTIZE_FUNC_I (signed_none_none, NONE_FUNC, NONE_FUNC, ROUND);
310 MAKE_QUANTIZE_FUNC_I (signed_rpdf_none, INIT_DITHER_RPDF_I, ADD_DITHER_RPDF_I,
312 MAKE_QUANTIZE_FUNC_I (signed_tpdf_none, INIT_DITHER_TPDF_I, ADD_DITHER_TPDF_I,
314 MAKE_QUANTIZE_FUNC_I (signed_tpdf_hf_none, INIT_DITHER_TPDF_HF_I,
315 ADD_DITHER_TPDF_HF_I, NONE_FUNC);
317 MAKE_QUANTIZE_FUNC_I (unsigned_none_none, NONE_FUNC, NONE_FUNC, ROUND);
318 MAKE_QUANTIZE_FUNC_I (unsigned_rpdf_none, INIT_DITHER_RPDF_I, ADD_DITHER_RPDF_I,
320 MAKE_QUANTIZE_FUNC_I (unsigned_tpdf_none, INIT_DITHER_TPDF_I, ADD_DITHER_TPDF_I,
322 MAKE_QUANTIZE_FUNC_I (unsigned_tpdf_hf_none, INIT_DITHER_TPDF_HF_I,
323 ADD_DITHER_TPDF_HF_I, NONE_FUNC);
325 MAKE_QUANTIZE_FUNC_F (float_none_error_feedback, NONE_FUNC,
326 INIT_NS_ERROR_FEEDBACK, ADD_NS_ERROR_FEEDBACK, NONE_FUNC,
327 UPDATE_ERROR_ERROR_FEEDBACK);
328 MAKE_QUANTIZE_FUNC_F (float_none_simple, NONE_FUNC, INIT_NS_SIMPLE,
329 ADD_NS_SIMPLE, NONE_FUNC, UPDATE_ERROR_SIMPLE);
330 MAKE_QUANTIZE_FUNC_F (float_none_medium, NONE_FUNC, INIT_NS_MEDIUM,
331 ADD_NS_MEDIUM, NONE_FUNC, UPDATE_ERROR_MEDIUM);
332 MAKE_QUANTIZE_FUNC_F (float_none_high, NONE_FUNC, INIT_NS_HIGH, ADD_NS_HIGH,
333 NONE_FUNC, UPDATE_ERROR_HIGH);
335 MAKE_QUANTIZE_FUNC_F (float_rpdf_error_feedback, INIT_DITHER_RPDF_F,
336 INIT_NS_ERROR_FEEDBACK, ADD_NS_ERROR_FEEDBACK, ADD_DITHER_RPDF_F,
337 UPDATE_ERROR_ERROR_FEEDBACK);
338 MAKE_QUANTIZE_FUNC_F (float_rpdf_simple, INIT_DITHER_RPDF_F, INIT_NS_SIMPLE,
339 ADD_NS_SIMPLE, ADD_DITHER_RPDF_F, UPDATE_ERROR_SIMPLE);
340 MAKE_QUANTIZE_FUNC_F (float_rpdf_medium, INIT_DITHER_RPDF_F, INIT_NS_MEDIUM,
341 ADD_NS_MEDIUM, ADD_DITHER_RPDF_F, UPDATE_ERROR_MEDIUM);
342 MAKE_QUANTIZE_FUNC_F (float_rpdf_high, INIT_DITHER_RPDF_F, INIT_NS_HIGH,
343 ADD_NS_HIGH, ADD_DITHER_RPDF_F, UPDATE_ERROR_HIGH);
345 MAKE_QUANTIZE_FUNC_F (float_tpdf_error_feedback, INIT_DITHER_TPDF_F,
346 INIT_NS_ERROR_FEEDBACK, ADD_NS_ERROR_FEEDBACK, ADD_DITHER_TPDF_F,
347 UPDATE_ERROR_ERROR_FEEDBACK);
348 MAKE_QUANTIZE_FUNC_F (float_tpdf_simple, INIT_DITHER_TPDF_F, INIT_NS_SIMPLE,
349 ADD_NS_SIMPLE, ADD_DITHER_TPDF_F, UPDATE_ERROR_SIMPLE);
350 MAKE_QUANTIZE_FUNC_F (float_tpdf_medium, INIT_DITHER_TPDF_F, INIT_NS_MEDIUM,
351 ADD_NS_MEDIUM, ADD_DITHER_TPDF_F, UPDATE_ERROR_MEDIUM);
352 MAKE_QUANTIZE_FUNC_F (float_tpdf_high, INIT_DITHER_TPDF_F, INIT_NS_HIGH,
353 ADD_NS_HIGH, ADD_DITHER_TPDF_F, UPDATE_ERROR_HIGH);
355 MAKE_QUANTIZE_FUNC_F (float_tpdf_hf_error_feedback, INIT_DITHER_TPDF_HF_F,
356 INIT_NS_ERROR_FEEDBACK, ADD_NS_ERROR_FEEDBACK, ADD_DITHER_TPDF_HF_F,
357 UPDATE_ERROR_ERROR_FEEDBACK);
358 MAKE_QUANTIZE_FUNC_F (float_tpdf_hf_simple, INIT_DITHER_TPDF_HF_F,
359 INIT_NS_SIMPLE, ADD_NS_SIMPLE, ADD_DITHER_TPDF_HF_F, UPDATE_ERROR_SIMPLE);
360 MAKE_QUANTIZE_FUNC_F (float_tpdf_hf_medium, INIT_DITHER_TPDF_HF_F,
361 INIT_NS_MEDIUM, ADD_NS_MEDIUM, ADD_DITHER_TPDF_HF_F, UPDATE_ERROR_MEDIUM);
362 MAKE_QUANTIZE_FUNC_F (float_tpdf_hf_high, INIT_DITHER_TPDF_HF_F, INIT_NS_HIGH,
363 ADD_NS_HIGH, ADD_DITHER_TPDF_HF_F, UPDATE_ERROR_HIGH);
365 static AudioConvertQuantize quantize_funcs[] = {
366 (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (signed_none_none),
367 (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (signed_rpdf_none),
368 (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (signed_tpdf_none),
369 (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (signed_tpdf_hf_none),
370 (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (unsigned_none_none),
371 (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (unsigned_rpdf_none),
372 (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (unsigned_tpdf_none),
373 (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (unsigned_tpdf_hf_none),
374 (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_none_error_feedback),
375 (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_none_simple),
376 (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_none_medium),
377 (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_none_high),
378 (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_rpdf_error_feedback),
379 (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_rpdf_simple),
380 (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_rpdf_medium),
381 (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_rpdf_high),
382 (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_error_feedback),
383 (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_simple),
384 (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_medium),
385 (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_high),
386 (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_hf_error_feedback),
387 (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_hf_simple),
388 (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_hf_medium),
389 (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_hf_high)
393 gst_audio_quantize_setup_noise_shaping (AudioConvertCtx * ctx)
396 case NOISE_SHAPING_HIGH:{
397 ctx->error_buf = g_new0 (gdouble, ctx->out.channels * 8);
400 case NOISE_SHAPING_MEDIUM:{
401 ctx->error_buf = g_new0 (gdouble, ctx->out.channels * 5);
404 case NOISE_SHAPING_SIMPLE:{
405 ctx->error_buf = g_new0 (gdouble, ctx->out.channels * 2);
408 case NOISE_SHAPING_ERROR_FEEDBACK:
409 ctx->error_buf = g_new0 (gdouble, ctx->out.channels);
411 case NOISE_SHAPING_NONE:
413 ctx->error_buf = NULL;
420 gst_audio_quantize_free_noise_shaping (AudioConvertCtx * ctx)
423 case NOISE_SHAPING_HIGH:
424 case NOISE_SHAPING_MEDIUM:
425 case NOISE_SHAPING_SIMPLE:
426 case NOISE_SHAPING_ERROR_FEEDBACK:
427 case NOISE_SHAPING_NONE:
432 g_free (ctx->error_buf);
433 ctx->error_buf = NULL;
438 gst_audio_quantize_setup_dither (AudioConvertCtx * ctx)
440 switch (ctx->dither) {
442 if (GST_AUDIO_FORMAT_INFO_IS_INTEGER (ctx->out.finfo))
443 ctx->last_random = g_new0 (gint32, ctx->out.channels);
445 ctx->last_random = g_new0 (gdouble, ctx->out.channels);
449 ctx->last_random = NULL;
453 ctx->last_random = NULL;
460 gst_audio_quantize_free_dither (AudioConvertCtx * ctx)
462 g_free (ctx->last_random);
468 gst_audio_quantize_setup_quantize_func (AudioConvertCtx * ctx)
472 if (!GST_AUDIO_FORMAT_INFO_IS_INTEGER (ctx->out.finfo)) {
473 ctx->quantize = NULL;
477 if (ctx->ns == NOISE_SHAPING_NONE) {
478 index += ctx->dither;
479 index += GST_AUDIO_FORMAT_INFO_IS_SIGNED (ctx->out.finfo) ? 0 : 4;
481 index += 8 + (4 * ctx->dither);
482 index += ctx->ns - 1;
485 ctx->quantize = quantize_funcs[index];
489 gst_audio_quantize_setup (AudioConvertCtx * ctx)
491 gst_audio_quantize_setup_dither (ctx);
492 gst_audio_quantize_setup_noise_shaping (ctx);
493 gst_audio_quantize_setup_quantize_func (ctx);
499 gst_audio_quantize_free (AudioConvertCtx * ctx)
501 gst_audio_quantize_free_dither (ctx);
502 gst_audio_quantize_free_noise_shaping (ctx);