summaryrefslogtreecommitdiff
path: root/gst/audioconvert/gstaudioquantize.c
diff options
context:
space:
mode:
Diffstat (limited to 'gst/audioconvert/gstaudioquantize.c')
-rw-r--r--gst/audioconvert/gstaudioquantize.c503
1 files changed, 0 insertions, 503 deletions
diff --git a/gst/audioconvert/gstaudioquantize.c b/gst/audioconvert/gstaudioquantize.c
deleted file mode 100644
index 2155397c..00000000
--- a/gst/audioconvert/gstaudioquantize.c
+++ /dev/null
@@ -1,503 +0,0 @@
-/* GStreamer
- * Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
- *
- * gstaudioquantize.c: quantizes audio to the target format and optionally
- * applies dithering and noise shaping.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-/*
- * FIXME: When doing dithering with int as intermediate format
- * one gets audible harmonics while the noise floor is
- * constant for double as intermediate format!
- */
-
-/* TODO: - Maybe drop 5-pole noise shaping and use coefficients
- * generated by dmaker
- * http://shibatch.sf.net
- */
-
-#include <gst/gst.h>
-#include <string.h>
-#include <math.h>
-#include "audioconvert.h"
-#include "gstaudioquantize.h"
-
-#include "gstfastrandom.h"
-
-#define MAKE_QUANTIZE_FUNC_NAME(name) \
-gst_audio_quantize_quantize_##name
-
-/* Quantize functions for gint32 as intermediate format */
-
-#define MAKE_QUANTIZE_FUNC_I(name, DITHER_INIT_FUNC, ADD_DITHER_FUNC, \
- ROUND_FUNC) \
-static void \
-MAKE_QUANTIZE_FUNC_NAME (name) (AudioConvertCtx *ctx, gint32 *src, \
- gint32 *dst, gint count) \
-{ \
- gint scale = ctx->out_scale; \
- gint channels = ctx->out.channels; \
- gint chan_pos; \
- \
- if (scale > 0) { \
- gint32 tmp; \
- guint32 mask = 0xffffffff & (0xffffffff << scale); \
- guint32 bias = 1U << (scale - 1); \
- DITHER_INIT_FUNC() \
- \
- for (;count;count--) { \
- for (chan_pos = 0; chan_pos < channels; chan_pos++) { \
- tmp = *src++; \
- ADD_DITHER_FUNC() \
- ROUND_FUNC() \
- *dst = tmp & mask; \
- dst++; \
- } \
- } \
- } else { \
- for (;count;count--) { \
- for (chan_pos = 0; chan_pos < channels; chan_pos++) { \
- *dst = *src++; \
- dst++; \
- } \
- } \
- } \
-}
-
-
-/* Quantize functions for gdouble as intermediate format with
- * int as target */
-
-#define MAKE_QUANTIZE_FUNC_F(name, DITHER_INIT_FUNC, NS_INIT_FUNC, \
- ADD_NS_FUNC, ADD_DITHER_FUNC, \
- UPDATE_ERROR_FUNC) \
-static void \
-MAKE_QUANTIZE_FUNC_NAME (name) (AudioConvertCtx *ctx, gdouble *src, \
- gdouble *dst, gint count) \
-{ \
- gint scale = ctx->out_scale; \
- gint channels = ctx->out.channels; \
- gint chan_pos; \
- gdouble factor = (1U<<(32-scale-1)) - 1; \
- \
- if (scale > 0) { \
- gdouble tmp; \
- DITHER_INIT_FUNC() \
- NS_INIT_FUNC() \
- \
- for (;count;count--) { \
- for (chan_pos = 0; chan_pos < channels; chan_pos++) { \
- tmp = *src++; \
- ADD_NS_FUNC() \
- ADD_DITHER_FUNC() \
- tmp = floor(tmp * factor + 0.5); \
- *dst = CLAMP (tmp, -factor - 1, factor); \
- UPDATE_ERROR_FUNC() \
- dst++; \
- } \
- } \
- } else { \
- for (;count;count--) { \
- for (chan_pos = 0; chan_pos < channels; chan_pos++) { \
- *dst = *src++ * 2147483647.0; \
- dst++; \
- } \
- } \
- } \
-}
-
-/* Rounding functions for int as intermediate format, only used when
- * not using dithering. With dithering we include this offset in our
- * dither noise instead. */
-
-#define ROUND() \
- if (tmp > 0 && G_MAXINT32 - tmp <= bias) \
- tmp = G_MAXINT32; \
- else \
- tmp += bias;
-
-
-#define NONE_FUNC()
-
-/* Dithering definitions
- * See http://en.wikipedia.org/wiki/Dithering or
- * http://www.cadenzarecording.com/Dither.html for explainations.
- *
- * We already add the rounding offset to the dither noise here
- * to have only one overflow check instead of two. */
-
-#define INIT_DITHER_RPDF_I() \
- gint32 rand; \
- gint32 dither = (1<<(scale));
-
-#define ADD_DITHER_RPDF_I() \
- rand = gst_fast_random_int32_range (bias - dither, \
- bias + dither); \
- if (rand > 0 && tmp > 0 && G_MAXINT32 - tmp <= rand) \
- tmp = G_MAXINT32; \
- else if (rand < 0 && tmp < 0 && G_MININT32 - tmp >= rand) \
- tmp = G_MININT32; \
- else \
- tmp += rand;
-
-#define INIT_DITHER_RPDF_F() \
- gdouble dither = 1.0/(1U<<(32 - scale - 1));
-
-#define ADD_DITHER_RPDF_F() \
- tmp += gst_fast_random_double_range (- dither, dither);
-
-#define INIT_DITHER_TPDF_I() \
- gint32 rand; \
- gint32 dither = (1<<(scale - 1)); \
- bias = bias >> 1;
-
-#define ADD_DITHER_TPDF_I() \
- rand = gst_fast_random_int32_range (bias - dither, \
- bias + dither - 1) \
- + gst_fast_random_int32_range (bias - dither, \
- bias + dither - 1); \
- if (rand > 0 && tmp > 0 && G_MAXINT32 - tmp <= rand) \
- tmp = G_MAXINT32; \
- else if (rand < 0 && tmp < 0 && G_MININT32 - tmp >= rand) \
- tmp = G_MININT32; \
- else \
- tmp += rand;
-
-#define INIT_DITHER_TPDF_F() \
- gdouble dither = 1.0/(1U<<(32 - scale));
-
-#define ADD_DITHER_TPDF_F() \
- tmp += gst_fast_random_double_range (- dither, dither) \
- + gst_fast_random_double_range (- dither, dither);
-
-#define INIT_DITHER_TPDF_HF_I() \
- gint32 rand; \
- gint32 dither = (1<<(scale-1)); \
- gint32 *last_random = (gint32 *) ctx->last_random, tmp_rand; \
- bias = bias >> 1;
-
-#define ADD_DITHER_TPDF_HF_I() \
- tmp_rand = gst_fast_random_int32_range (bias - dither, \
- bias + dither); \
- rand = tmp_rand - last_random[chan_pos]; \
- last_random[chan_pos] = tmp_rand; \
- if (rand > 0 && tmp > 0 && G_MAXINT32 - tmp <= rand) \
- tmp = G_MAXINT32; \
- else if (rand < 0 && tmp < 0 && G_MININT32 - tmp >= rand) \
- tmp = G_MININT32; \
- else \
- tmp += rand;
-
-/* Like TPDF dither but the dither noise is oriented more to the
- * higher frequencies */
-
-#define INIT_DITHER_TPDF_HF_F() \
- gdouble rand; \
- gdouble dither = 1.0/(1U<<(32 - scale)); \
- gdouble *last_random = (gdouble *) ctx->last_random, tmp_rand;
-
-#define ADD_DITHER_TPDF_HF_F() \
- tmp_rand = gst_fast_random_double_range (- dither, dither); \
- rand = tmp_rand - last_random[chan_pos]; \
- last_random[chan_pos] = tmp_rand; \
- tmp += rand;
-
-/* Noise shaping definitions.
- * See http://en.wikipedia.org/wiki/Noise_shaping for explanations. */
-
-
-/* Simple error feedback: Just accumulate the dithering and quantization
- * error and remove it from each sample. */
-
-#define INIT_NS_ERROR_FEEDBACK() \
- gdouble orig; \
- gdouble *errors = ctx->error_buf;
-
-#define ADD_NS_ERROR_FEEDBACK() \
- orig = tmp; \
- tmp -= errors[chan_pos];
-
-#define UPDATE_ERROR_ERROR_FEEDBACK() \
- errors[chan_pos] += (*dst)/factor - orig;
-
-/* Same as error feedback but also add 1/2 of the previous error value.
- * This moves the noise a bit more into the higher frequencies. */
-
-#define INIT_NS_SIMPLE() \
- gdouble orig; \
- gdouble *errors = ctx->error_buf, cur_error;
-
-#define ADD_NS_SIMPLE() \
- cur_error = errors[chan_pos*2] - 0.5 * errors[chan_pos*2 + 1]; \
- tmp -= cur_error; \
- orig = tmp;
-
-#define UPDATE_ERROR_SIMPLE() \
- errors[chan_pos*2 + 1] = errors[chan_pos*2]; \
- errors[chan_pos*2] = (*dst)/factor - orig;
-
-
-/* Noise shaping coefficients from[1], moves most power of the
- * error noise into inaudible frequency ranges.
- *
- * [1]
- * "Minimally Audible Noise Shaping", Stanley P. Lipshitz,
- * John Vanderkooy, and Robert A. Wannamaker,
- * J. Audio Eng. Soc., Vol. 39, No. 11, November 1991. */
-
-static const gdouble ns_medium_coeffs[] = {
- 2.033, -2.165, 1.959, -1.590, 0.6149
-};
-
-#define INIT_NS_MEDIUM() \
- gdouble orig; \
- gdouble *errors = ctx->error_buf, cur_error; \
- int j;
-
-#define ADD_NS_MEDIUM() \
- cur_error = 0.0; \
- for (j = 0; j < 5; j++) \
- cur_error += errors[chan_pos*5 + j] * ns_medium_coeffs[j]; \
- tmp -= cur_error; \
- orig = tmp;
-
-#define UPDATE_ERROR_MEDIUM() \
- for (j = 4; j > 0; j--) \
- errors[chan_pos*5 + j] = errors[chan_pos*5 + j-1]; \
- errors[chan_pos*5] = (*dst)/factor - orig;
-
-/* Noise shaping coefficients by David Schleef, moves most power of the
- * error noise into inaudible frequency ranges */
-
-static const gdouble ns_high_coeffs[] = {
- 2.08484, -2.92975, 3.27918, -3.31399, 2.61339, -1.72008, 0.876066, -0.340122
-};
-
-#define INIT_NS_HIGH() \
- gdouble orig; \
- gdouble *errors = ctx->error_buf, cur_error; \
- int j;
-
-#define ADD_NS_HIGH() \
- cur_error = 0.0; \
- for (j = 0; j < 8; j++) \
- cur_error += errors[chan_pos + j] * ns_high_coeffs[j]; \
- tmp -= cur_error; \
- orig = tmp;
-
-#define UPDATE_ERROR_HIGH() \
- for (j = 7; j > 0; j--) \
- errors[chan_pos + j] = errors[chan_pos + j-1]; \
- errors[chan_pos] = (*dst)/factor - orig;
-
-
-MAKE_QUANTIZE_FUNC_I (signed_none_none, NONE_FUNC, NONE_FUNC, ROUND);
-MAKE_QUANTIZE_FUNC_I (signed_rpdf_none, INIT_DITHER_RPDF_I, ADD_DITHER_RPDF_I,
- NONE_FUNC);
-MAKE_QUANTIZE_FUNC_I (signed_tpdf_none, INIT_DITHER_TPDF_I, ADD_DITHER_TPDF_I,
- NONE_FUNC);
-MAKE_QUANTIZE_FUNC_I (signed_tpdf_hf_none, INIT_DITHER_TPDF_HF_I,
- ADD_DITHER_TPDF_HF_I, NONE_FUNC);
-
-MAKE_QUANTIZE_FUNC_I (unsigned_none_none, NONE_FUNC, NONE_FUNC, ROUND);
-MAKE_QUANTIZE_FUNC_I (unsigned_rpdf_none, INIT_DITHER_RPDF_I, ADD_DITHER_RPDF_I,
- NONE_FUNC);
-MAKE_QUANTIZE_FUNC_I (unsigned_tpdf_none, INIT_DITHER_TPDF_I, ADD_DITHER_TPDF_I,
- NONE_FUNC);
-MAKE_QUANTIZE_FUNC_I (unsigned_tpdf_hf_none, INIT_DITHER_TPDF_HF_I,
- ADD_DITHER_TPDF_HF_I, NONE_FUNC);
-
-MAKE_QUANTIZE_FUNC_F (float_none_error_feedback, NONE_FUNC,
- INIT_NS_ERROR_FEEDBACK, ADD_NS_ERROR_FEEDBACK, NONE_FUNC,
- UPDATE_ERROR_ERROR_FEEDBACK);
-MAKE_QUANTIZE_FUNC_F (float_none_simple, NONE_FUNC, INIT_NS_SIMPLE,
- ADD_NS_SIMPLE, NONE_FUNC, UPDATE_ERROR_SIMPLE);
-MAKE_QUANTIZE_FUNC_F (float_none_medium, NONE_FUNC, INIT_NS_MEDIUM,
- ADD_NS_MEDIUM, NONE_FUNC, UPDATE_ERROR_MEDIUM);
-MAKE_QUANTIZE_FUNC_F (float_none_high, NONE_FUNC, INIT_NS_HIGH, ADD_NS_HIGH,
- NONE_FUNC, UPDATE_ERROR_HIGH);
-
-MAKE_QUANTIZE_FUNC_F (float_rpdf_error_feedback, INIT_DITHER_RPDF_F,
- INIT_NS_ERROR_FEEDBACK, ADD_NS_ERROR_FEEDBACK, ADD_DITHER_RPDF_F,
- UPDATE_ERROR_ERROR_FEEDBACK);
-MAKE_QUANTIZE_FUNC_F (float_rpdf_simple, INIT_DITHER_RPDF_F, INIT_NS_SIMPLE,
- ADD_NS_SIMPLE, ADD_DITHER_RPDF_F, UPDATE_ERROR_SIMPLE);
-MAKE_QUANTIZE_FUNC_F (float_rpdf_medium, INIT_DITHER_RPDF_F, INIT_NS_MEDIUM,
- ADD_NS_MEDIUM, ADD_DITHER_RPDF_F, UPDATE_ERROR_MEDIUM);
-MAKE_QUANTIZE_FUNC_F (float_rpdf_high, INIT_DITHER_RPDF_F, INIT_NS_HIGH,
- ADD_NS_HIGH, ADD_DITHER_RPDF_F, UPDATE_ERROR_HIGH);
-
-MAKE_QUANTIZE_FUNC_F (float_tpdf_error_feedback, INIT_DITHER_TPDF_F,
- INIT_NS_ERROR_FEEDBACK, ADD_NS_ERROR_FEEDBACK, ADD_DITHER_TPDF_F,
- UPDATE_ERROR_ERROR_FEEDBACK);
-MAKE_QUANTIZE_FUNC_F (float_tpdf_simple, INIT_DITHER_TPDF_F, INIT_NS_SIMPLE,
- ADD_NS_SIMPLE, ADD_DITHER_TPDF_F, UPDATE_ERROR_SIMPLE);
-MAKE_QUANTIZE_FUNC_F (float_tpdf_medium, INIT_DITHER_TPDF_F, INIT_NS_MEDIUM,
- ADD_NS_MEDIUM, ADD_DITHER_TPDF_F, UPDATE_ERROR_MEDIUM);
-MAKE_QUANTIZE_FUNC_F (float_tpdf_high, INIT_DITHER_TPDF_F, INIT_NS_HIGH,
- ADD_NS_HIGH, ADD_DITHER_TPDF_F, UPDATE_ERROR_HIGH);
-
-MAKE_QUANTIZE_FUNC_F (float_tpdf_hf_error_feedback, INIT_DITHER_TPDF_HF_F,
- INIT_NS_ERROR_FEEDBACK, ADD_NS_ERROR_FEEDBACK, ADD_DITHER_TPDF_HF_F,
- UPDATE_ERROR_ERROR_FEEDBACK);
-MAKE_QUANTIZE_FUNC_F (float_tpdf_hf_simple, INIT_DITHER_TPDF_HF_F,
- INIT_NS_SIMPLE, ADD_NS_SIMPLE, ADD_DITHER_TPDF_HF_F, UPDATE_ERROR_SIMPLE);
-MAKE_QUANTIZE_FUNC_F (float_tpdf_hf_medium, INIT_DITHER_TPDF_HF_F,
- INIT_NS_MEDIUM, ADD_NS_MEDIUM, ADD_DITHER_TPDF_HF_F, UPDATE_ERROR_MEDIUM);
-MAKE_QUANTIZE_FUNC_F (float_tpdf_hf_high, INIT_DITHER_TPDF_HF_F, INIT_NS_HIGH,
- ADD_NS_HIGH, ADD_DITHER_TPDF_HF_F, UPDATE_ERROR_HIGH);
-
-static AudioConvertQuantize quantize_funcs[] = {
- (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (signed_none_none),
- (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (signed_rpdf_none),
- (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (signed_tpdf_none),
- (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (signed_tpdf_hf_none),
- (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (unsigned_none_none),
- (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (unsigned_rpdf_none),
- (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (unsigned_tpdf_none),
- (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (unsigned_tpdf_hf_none),
- (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_none_error_feedback),
- (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_none_simple),
- (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_none_medium),
- (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_none_high),
- (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_rpdf_error_feedback),
- (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_rpdf_simple),
- (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_rpdf_medium),
- (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_rpdf_high),
- (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_error_feedback),
- (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_simple),
- (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_medium),
- (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_high),
- (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_hf_error_feedback),
- (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_hf_simple),
- (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_hf_medium),
- (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_hf_high)
-};
-
-static void
-gst_audio_quantize_setup_noise_shaping (AudioConvertCtx * ctx)
-{
- switch (ctx->ns) {
- case NOISE_SHAPING_HIGH:{
- ctx->error_buf = g_new0 (gdouble, ctx->out.channels * 8);
- break;
- }
- case NOISE_SHAPING_MEDIUM:{
- ctx->error_buf = g_new0 (gdouble, ctx->out.channels * 5);
- break;
- }
- case NOISE_SHAPING_SIMPLE:{
- ctx->error_buf = g_new0 (gdouble, ctx->out.channels * 2);
- break;
- }
- case NOISE_SHAPING_ERROR_FEEDBACK:
- ctx->error_buf = g_new0 (gdouble, ctx->out.channels);
- break;
- case NOISE_SHAPING_NONE:
- default:
- ctx->error_buf = NULL;
- break;
- }
- return;
-}
-
-static void
-gst_audio_quantize_free_noise_shaping (AudioConvertCtx * ctx)
-{
- switch (ctx->ns) {
- case NOISE_SHAPING_HIGH:
- case NOISE_SHAPING_MEDIUM:
- case NOISE_SHAPING_SIMPLE:
- case NOISE_SHAPING_ERROR_FEEDBACK:
- case NOISE_SHAPING_NONE:
- default:
- break;
- }
-
- g_free (ctx->error_buf);
- ctx->error_buf = NULL;
- return;
-}
-
-static void
-gst_audio_quantize_setup_dither (AudioConvertCtx * ctx)
-{
- switch (ctx->dither) {
- case DITHER_TPDF_HF:
- if (ctx->out.is_int)
- ctx->last_random = g_new0 (gint32, ctx->out.channels);
- else
- ctx->last_random = g_new0 (gdouble, ctx->out.channels);
- break;
- case DITHER_RPDF:
- case DITHER_TPDF:
- ctx->last_random = NULL;
- break;
- case DITHER_NONE:
- default:
- ctx->last_random = NULL;
- break;
- }
- return;
-}
-
-static void
-gst_audio_quantize_free_dither (AudioConvertCtx * ctx)
-{
- g_free (ctx->last_random);
-
- return;
-}
-
-static void
-gst_audio_quantize_setup_quantize_func (AudioConvertCtx * ctx)
-{
- gint index = 0;
-
- if (!ctx->out.is_int) {
- ctx->quantize = NULL;
- return;
- }
-
- if (ctx->ns == NOISE_SHAPING_NONE) {
- index += ctx->dither;
- index += (ctx->out.sign) ? 0 : 4;
- } else {
- index += 8 + (4 * ctx->dither);
- index += ctx->ns - 1;
- }
-
- ctx->quantize = quantize_funcs[index];
-}
-
-gboolean
-gst_audio_quantize_setup (AudioConvertCtx * ctx)
-{
- gst_audio_quantize_setup_dither (ctx);
- gst_audio_quantize_setup_noise_shaping (ctx);
- gst_audio_quantize_setup_quantize_func (ctx);
-
- return TRUE;
-}
-
-void
-gst_audio_quantize_free (AudioConvertCtx * ctx)
-{
- gst_audio_quantize_free_dither (ctx);
- gst_audio_quantize_free_noise_shaping (ctx);
-}