|
Packit |
0652a1 |
/* GStreamer
|
|
Packit |
0652a1 |
* Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
|
|
Packit |
0652a1 |
* (C) 2015 Wim Taymans <wim.taymans@gmail.com>
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* gstaudioquantize.c: quantizes audio to the target format and optionally
|
|
Packit |
0652a1 |
* applies dithering and noise shaping.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* This library is free software; you can redistribute it and/or
|
|
Packit |
0652a1 |
* modify it under the terms of the GNU Library General Public
|
|
Packit |
0652a1 |
* License as published by the Free Software Foundation; either
|
|
Packit |
0652a1 |
* version 2 of the License, or (at your option) any later version.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* This library is distributed in the hope that it will be useful,
|
|
Packit |
0652a1 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
0652a1 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
0652a1 |
* Library General Public License for more details.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* You should have received a copy of the GNU Library General Public
|
|
Packit |
0652a1 |
* License along with this library; if not, write to the
|
|
Packit |
0652a1 |
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
Packit |
0652a1 |
* Boston, MA 02110-1301, USA.
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* TODO: - Maybe drop 5-pole noise shaping and use coefficients
|
|
Packit |
0652a1 |
* generated by dmaker
|
|
Packit |
0652a1 |
* http://shibatch.sf.net
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
#ifdef HAVE_CONFIG_H
|
|
Packit |
0652a1 |
#include "config.h"
|
|
Packit |
0652a1 |
#endif
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
#include <gst/gst.h>
|
|
Packit |
0652a1 |
#include <string.h>
|
|
Packit |
0652a1 |
#include <math.h>
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
#include "gstaudiopack.h"
|
|
Packit |
0652a1 |
#include "audio-quantize.h"
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
typedef void (*QuantizeFunc) (GstAudioQuantize * quant, const gpointer src,
|
|
Packit |
0652a1 |
gpointer dst, gint count);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
struct _GstAudioQuantize
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
GstAudioDitherMethod dither;
|
|
Packit |
0652a1 |
GstAudioNoiseShapingMethod ns;
|
|
Packit |
0652a1 |
GstAudioQuantizeFlags flags;
|
|
Packit |
0652a1 |
GstAudioFormat format;
|
|
Packit |
0652a1 |
guint quantizer;
|
|
Packit |
0652a1 |
guint stride;
|
|
Packit |
0652a1 |
guint blocks;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
guint shift;
|
|
Packit |
0652a1 |
guint32 mask, bias;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* last random number generated per channel for hifreq TPDF dither */
|
|
Packit |
0652a1 |
gpointer last_random;
|
|
Packit |
0652a1 |
/* contains the past quantization errors, error[channels][count] */
|
|
Packit |
0652a1 |
guint error_size;
|
|
Packit |
0652a1 |
gpointer error_buf;
|
|
Packit |
0652a1 |
/* buffer with dither values */
|
|
Packit |
0652a1 |
guint dither_size;
|
|
Packit |
0652a1 |
gpointer dither_buf;
|
|
Packit |
0652a1 |
/* noise shaping coefficients */
|
|
Packit |
0652a1 |
gpointer coeffs;
|
|
Packit |
0652a1 |
gint n_coeffs;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
QuantizeFunc quantize;
|
|
Packit |
0652a1 |
};
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
#define ADDSS(res,val) \
|
|
Packit |
0652a1 |
if (val > 0 && res > 0 && G_MAXINT32 - res <= val){ \
|
|
Packit |
0652a1 |
res = G_MAXINT32; \
|
|
Packit |
0652a1 |
} else if (val < 0 && res < 0 && G_MININT32 - res >= val){ \
|
|
Packit |
0652a1 |
res = G_MININT32; \
|
|
Packit |
0652a1 |
} else \
|
|
Packit |
0652a1 |
res += val;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
static void
|
|
Packit |
0652a1 |
gst_audio_quantize_quantize_memcpy (GstAudioQuantize * quant,
|
|
Packit |
0652a1 |
const gpointer src, gpointer dst, gint samples)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
if (src != dst)
|
|
Packit |
0652a1 |
memcpy (dst, src, samples * sizeof (gint32) * quant->stride);
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* Quantize functions for gint32 as intermediate format */
|
|
Packit |
0652a1 |
static void
|
|
Packit |
0652a1 |
gst_audio_quantize_quantize_int_none_none (GstAudioQuantize * quant,
|
|
Packit |
0652a1 |
const gpointer src, gpointer dst, gint samples)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
audio_orc_int_bias (dst, src, quant->bias, ~quant->mask,
|
|
Packit |
0652a1 |
samples * quant->stride);
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* This is the base function, implementing a linear congruential generator
|
|
Packit |
0652a1 |
* and returning a pseudo random number between 0 and 2^32 - 1.
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
static inline guint32
|
|
Packit |
0652a1 |
gst_fast_random_uint32 (void)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
static guint32 state = 0xdeadbeef;
|
|
Packit |
0652a1 |
return (state = state * 1103515245 + 12345);
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
static inline gint32
|
|
Packit |
0652a1 |
gst_fast_random_int32 (void)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
return (gint32) gst_fast_random_uint32 ();
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* Assuming dither == 2^n,
|
|
Packit |
0652a1 |
* returns one of 2^(n+1) possible random values:
|
|
Packit |
0652a1 |
* -dither <= retval < dither */
|
|
Packit |
0652a1 |
#define RANDOM_INT_DITHER(dither) \
|
|
Packit |
0652a1 |
(- dither + (gst_fast_random_int32 () & ((dither << 1) - 1)))
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
static void
|
|
Packit |
0652a1 |
setup_dither_buf (GstAudioQuantize * quant, gint samples)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
gboolean need_init = FALSE;
|
|
Packit |
0652a1 |
gint stride = quant->stride;
|
|
Packit |
0652a1 |
gint i, len = samples * stride;
|
|
Packit |
0652a1 |
guint shift = quant->shift;
|
|
Packit |
0652a1 |
guint32 bias;
|
|
Packit |
0652a1 |
gint32 dither, *d;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (quant->dither_size < len) {
|
|
Packit |
0652a1 |
quant->dither_size = len;
|
|
Packit |
0652a1 |
quant->dither_buf = g_realloc (quant->dither_buf, len * sizeof (gint32));
|
|
Packit |
0652a1 |
need_init = TRUE;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
bias = quant->bias;
|
|
Packit |
0652a1 |
d = quant->dither_buf;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
switch (quant->dither) {
|
|
Packit |
0652a1 |
case GST_AUDIO_DITHER_NONE:
|
|
Packit |
0652a1 |
if (need_init) {
|
|
Packit |
0652a1 |
for (i = 0; i < len; i++)
|
|
Packit |
0652a1 |
d[i] = 0;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
break;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
case GST_AUDIO_DITHER_RPDF:
|
|
Packit |
0652a1 |
dither = 1 << (shift);
|
|
Packit |
0652a1 |
for (i = 0; i < len; i++)
|
|
Packit |
0652a1 |
d[i] = bias + RANDOM_INT_DITHER (dither);
|
|
Packit |
0652a1 |
break;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
case GST_AUDIO_DITHER_TPDF:
|
|
Packit |
0652a1 |
dither = 1 << (shift - 1);
|
|
Packit |
0652a1 |
for (i = 0; i < len; i++)
|
|
Packit |
0652a1 |
d[i] = bias + RANDOM_INT_DITHER (dither) + RANDOM_INT_DITHER (dither);
|
|
Packit |
0652a1 |
break;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
case GST_AUDIO_DITHER_TPDF_HF:
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
gint32 tmp, *last_random = quant->last_random;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
dither = 1 << (shift - 1);
|
|
Packit |
0652a1 |
for (i = 0; i < len; i++) {
|
|
Packit |
0652a1 |
tmp = RANDOM_INT_DITHER (dither);
|
|
Packit |
0652a1 |
d[i] = bias + tmp - last_random[i % stride];
|
|
Packit |
0652a1 |
last_random[i % stride] = tmp;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
break;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
static void
|
|
Packit |
0652a1 |
gst_audio_quantize_quantize_int_dither_none (GstAudioQuantize * quant,
|
|
Packit |
0652a1 |
const gpointer src, gpointer dst, gint samples)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
setup_dither_buf (quant, samples);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
audio_orc_int_dither (dst, src, quant->dither_buf, ~quant->mask,
|
|
Packit |
0652a1 |
samples * quant->stride);
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
static void
|
|
Packit |
0652a1 |
setup_error_buf (GstAudioQuantize * quant, gint samples, gint extra)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
gint stride = quant->stride;
|
|
Packit |
0652a1 |
gint len = (samples + extra) * stride;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (quant->error_size < len) {
|
|
Packit |
0652a1 |
quant->error_buf = g_realloc (quant->error_buf, len * sizeof (gint32));
|
|
Packit |
0652a1 |
if (quant->error_size == 0)
|
|
Packit |
0652a1 |
memset ((gint32 *) quant->error_buf, 0, stride * extra * sizeof (gint32));
|
|
Packit |
0652a1 |
quant->error_size = len;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
static void
|
|
Packit |
0652a1 |
gst_audio_quantize_quantize_int_dither_feedback (GstAudioQuantize * quant,
|
|
Packit |
0652a1 |
const gpointer src, gpointer dst, gint samples)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
guint32 mask;
|
|
Packit |
0652a1 |
gint i, len, stride;
|
|
Packit |
0652a1 |
const gint32 *s = src;
|
|
Packit |
0652a1 |
gint32 *dith, *d = dst, v, o, *e, err;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
setup_dither_buf (quant, samples);
|
|
Packit |
0652a1 |
setup_error_buf (quant, samples, 1);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
stride = quant->stride;
|
|
Packit |
0652a1 |
len = samples * stride;
|
|
Packit |
0652a1 |
dith = quant->dither_buf;
|
|
Packit |
0652a1 |
e = quant->error_buf;
|
|
Packit |
0652a1 |
mask = ~quant->mask;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
for (i = 0; i < len; i++) {
|
|
Packit |
0652a1 |
o = v = s[i];
|
|
Packit |
0652a1 |
/* add dither */
|
|
Packit |
0652a1 |
err = dith[i];
|
|
Packit |
0652a1 |
/* remove error */
|
|
Packit |
0652a1 |
err -= e[i];
|
|
Packit |
0652a1 |
ADDSS (v, err);
|
|
Packit |
0652a1 |
v &= mask;
|
|
Packit |
0652a1 |
/* store new error */
|
|
Packit |
0652a1 |
e[i + stride] = e[i] + (v - o);
|
|
Packit |
0652a1 |
/* store result */
|
|
Packit |
0652a1 |
d[i] = v;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
memmove (e, &e[len], sizeof (gint32) * stride);
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
#define SHIFT 10
|
|
Packit |
0652a1 |
#define REDUCE 8
|
|
Packit |
0652a1 |
#define RROUND (1<<(REDUCE-1))
|
|
Packit |
0652a1 |
#define SREDUCE 2
|
|
Packit |
0652a1 |
#define SROUND (1<<(SREDUCE-1))
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
static void
|
|
Packit |
0652a1 |
gst_audio_quantize_quantize_int_dither_noise_shape (GstAudioQuantize * quant,
|
|
Packit |
0652a1 |
const gpointer src, gpointer dst, gint samples)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
guint32 mask;
|
|
Packit |
0652a1 |
gint i, j, k, len, stride, nc;
|
|
Packit |
0652a1 |
const gint32 *s = src;
|
|
Packit |
0652a1 |
gint32 *c, *dith, *d = dst, v, o, *e, err;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
nc = quant->n_coeffs;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
setup_dither_buf (quant, samples);
|
|
Packit |
0652a1 |
setup_error_buf (quant, samples, nc);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
stride = quant->stride;
|
|
Packit |
0652a1 |
len = samples * stride;
|
|
Packit |
0652a1 |
dith = quant->dither_buf;
|
|
Packit |
0652a1 |
e = quant->error_buf;
|
|
Packit |
0652a1 |
c = quant->coeffs;
|
|
Packit |
0652a1 |
mask = ~quant->mask;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
for (i = 0; i < len; i++) {
|
|
Packit |
0652a1 |
v = s[i];
|
|
Packit |
0652a1 |
/* combine and remove error */
|
|
Packit |
0652a1 |
err = 0;
|
|
Packit |
0652a1 |
for (j = 0, k = i; j < nc; j++, k += stride)
|
|
Packit |
0652a1 |
err -= e[k] * c[j];
|
|
Packit |
0652a1 |
err = (err + SROUND) >> (SREDUCE);
|
|
Packit |
0652a1 |
ADDSS (v, err);
|
|
Packit |
0652a1 |
o = v;
|
|
Packit |
0652a1 |
/* add dither */
|
|
Packit |
0652a1 |
err = dith[i];
|
|
Packit |
0652a1 |
ADDSS (v, err);
|
|
Packit |
0652a1 |
/* quantize */
|
|
Packit |
0652a1 |
v &= mask;
|
|
Packit |
0652a1 |
/* store new error with reduced precision */
|
|
Packit |
0652a1 |
e[k] = (v - o + RROUND) >> REDUCE;
|
|
Packit |
0652a1 |
/* store result */
|
|
Packit |
0652a1 |
d[i] = v;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
memmove (e, &e[len], sizeof (gint32) * stride * nc);
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
#define MAKE_QUANTIZE_FUNC_NAME(name) \
|
|
Packit |
0652a1 |
gst_audio_quantize_quantize_##name
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
static const QuantizeFunc quantize_funcs[] = {
|
|
Packit |
0652a1 |
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_none_none),
|
|
Packit |
0652a1 |
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_feedback),
|
|
Packit |
0652a1 |
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape),
|
|
Packit |
0652a1 |
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape),
|
|
Packit |
0652a1 |
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape),
|
|
Packit |
0652a1 |
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_none),
|
|
Packit |
0652a1 |
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_feedback),
|
|
Packit |
0652a1 |
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape),
|
|
Packit |
0652a1 |
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape),
|
|
Packit |
0652a1 |
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape),
|
|
Packit |
0652a1 |
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_none),
|
|
Packit |
0652a1 |
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_feedback),
|
|
Packit |
0652a1 |
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape),
|
|
Packit |
0652a1 |
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape),
|
|
Packit |
0652a1 |
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape),
|
|
Packit |
0652a1 |
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_none),
|
|
Packit |
0652a1 |
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_feedback),
|
|
Packit |
0652a1 |
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape),
|
|
Packit |
0652a1 |
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape),
|
|
Packit |
0652a1 |
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_dither_noise_shape),
|
|
Packit |
0652a1 |
};
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* Same as error feedback but also add 1/2 of the previous error value.
|
|
Packit |
0652a1 |
* This moves the noise a bit more into the higher frequencies. */
|
|
Packit |
0652a1 |
static const gdouble ns_simple_coeffs[] = {
|
|
Packit |
0652a1 |
-0.5, 1.0
|
|
Packit |
0652a1 |
};
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* Noise shaping coefficients from[1], moves most power of the
|
|
Packit |
0652a1 |
* error noise into inaudible frequency ranges.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* [1]
|
|
Packit |
0652a1 |
* "Minimally Audible Noise Shaping", Stanley P. Lipshitz,
|
|
Packit |
0652a1 |
* John Vanderkooy, and Robert A. Wannamaker,
|
|
Packit |
0652a1 |
* J. Audio Eng. Soc., Vol. 39, No. 11, November 1991. */
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
static const gdouble ns_medium_coeffs[] = {
|
|
Packit |
0652a1 |
0.6149, -1.590, 1.959, -2.165, 2.033
|
|
Packit |
0652a1 |
};
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* Noise shaping coefficients by David Schleef, moves most power of the
|
|
Packit |
0652a1 |
* error noise into inaudible frequency ranges */
|
|
Packit |
0652a1 |
static const gdouble ns_high_coeffs[] = {
|
|
Packit |
0652a1 |
-0.340122, 0.876066, -1.72008, 2.61339, -3.31399, 3.27918, -2.92975, 2.08484,
|
|
Packit |
0652a1 |
};
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
static void
|
|
Packit |
0652a1 |
gst_audio_quantize_setup_noise_shaping (GstAudioQuantize * quant)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
gint i, n_coeffs = 0;
|
|
Packit |
0652a1 |
gint32 *q;
|
|
Packit |
0652a1 |
const gdouble *coeffs;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
switch (quant->ns) {
|
|
Packit |
0652a1 |
case GST_AUDIO_NOISE_SHAPING_HIGH:
|
|
Packit |
0652a1 |
n_coeffs = 8;
|
|
Packit |
0652a1 |
coeffs = ns_high_coeffs;
|
|
Packit |
0652a1 |
break;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
case GST_AUDIO_NOISE_SHAPING_MEDIUM:
|
|
Packit |
0652a1 |
n_coeffs = 5;
|
|
Packit |
0652a1 |
coeffs = ns_medium_coeffs;
|
|
Packit |
0652a1 |
break;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
case GST_AUDIO_NOISE_SHAPING_SIMPLE:
|
|
Packit |
0652a1 |
n_coeffs = 2;
|
|
Packit |
0652a1 |
coeffs = ns_simple_coeffs;
|
|
Packit |
0652a1 |
break;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
case GST_AUDIO_NOISE_SHAPING_ERROR_FEEDBACK:
|
|
Packit |
0652a1 |
break;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
case GST_AUDIO_NOISE_SHAPING_NONE:
|
|
Packit |
0652a1 |
default:
|
|
Packit |
0652a1 |
break;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (n_coeffs) {
|
|
Packit |
0652a1 |
quant->n_coeffs = n_coeffs;
|
|
Packit |
0652a1 |
q = quant->coeffs = g_new0 (gint32, n_coeffs);
|
|
Packit |
0652a1 |
for (i = 0; i < n_coeffs; i++)
|
|
Packit |
0652a1 |
q[i] = floor (coeffs[i] * (1 << SHIFT) + 0.5);
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
return;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
static void
|
|
Packit |
0652a1 |
gst_audio_quantize_setup_dither (GstAudioQuantize * quant)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
switch (quant->dither) {
|
|
Packit |
0652a1 |
case GST_AUDIO_DITHER_TPDF_HF:
|
|
Packit |
0652a1 |
quant->last_random = g_new0 (gint32, quant->stride);
|
|
Packit |
0652a1 |
break;
|
|
Packit |
0652a1 |
case GST_AUDIO_DITHER_RPDF:
|
|
Packit |
0652a1 |
case GST_AUDIO_DITHER_TPDF:
|
|
Packit |
0652a1 |
quant->last_random = NULL;
|
|
Packit |
0652a1 |
break;
|
|
Packit |
0652a1 |
case GST_AUDIO_DITHER_NONE:
|
|
Packit |
0652a1 |
default:
|
|
Packit |
0652a1 |
quant->last_random = NULL;
|
|
Packit |
0652a1 |
break;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
return;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
static void
|
|
Packit |
0652a1 |
gst_audio_quantize_setup_quantize_func (GstAudioQuantize * quant)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
gint index;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (quant->shift == 0) {
|
|
Packit |
0652a1 |
quant->quantize = (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (memcpy);
|
|
Packit |
0652a1 |
return;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
index = 5 * quant->dither + quant->ns;
|
|
Packit |
0652a1 |
quant->quantize = quantize_funcs[index];
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
static gint
|
|
Packit |
0652a1 |
count_power (guint v)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
gint res = 0;
|
|
Packit |
0652a1 |
while (v > 1) {
|
|
Packit |
0652a1 |
res++;
|
|
Packit |
0652a1 |
v >>= 1;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
return res;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/**
|
|
Packit |
0652a1 |
* gst_audio_quantize_new: (skip):
|
|
Packit |
0652a1 |
* @dither: a #GstAudioDitherMethod
|
|
Packit |
0652a1 |
* @ns: a #GstAudioNoiseShapingMethod
|
|
Packit |
0652a1 |
* @flags: #GstAudioQuantizeFlags
|
|
Packit |
0652a1 |
* @format: the #GstAudioFormat of the samples
|
|
Packit |
0652a1 |
* @channels: the amount of channels in the samples
|
|
Packit |
0652a1 |
* @quantizer: the quantizer to use
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Create a new quantizer object with the given parameters.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Output samples will be quantized to a multiple of @quantizer. Better
|
|
Packit |
0652a1 |
* performance is achieved when @quantizer is a power of 2.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Dithering and noise-shaping can be performed during quantization with
|
|
Packit |
0652a1 |
* the @dither and @ns parameters.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Returns: a new #GstAudioQuantize. Free with gst_audio_quantize_free().
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
GstAudioQuantize *
|
|
Packit |
0652a1 |
gst_audio_quantize_new (GstAudioDitherMethod dither,
|
|
Packit |
0652a1 |
GstAudioNoiseShapingMethod ns, GstAudioQuantizeFlags flags,
|
|
Packit |
0652a1 |
GstAudioFormat format, guint channels, guint quantizer)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
GstAudioQuantize *quant;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
g_return_val_if_fail (format == GST_AUDIO_FORMAT_S32, NULL);
|
|
Packit |
0652a1 |
g_return_val_if_fail (channels > 0, NULL);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
quant = g_slice_new0 (GstAudioQuantize);
|
|
Packit |
0652a1 |
quant->dither = dither;
|
|
Packit |
0652a1 |
quant->ns = ns;
|
|
Packit |
0652a1 |
quant->flags = flags;
|
|
Packit |
0652a1 |
quant->format = format;
|
|
Packit |
0652a1 |
if (flags & GST_AUDIO_QUANTIZE_FLAG_NON_INTERLEAVED) {
|
|
Packit |
0652a1 |
quant->stride = 1;
|
|
Packit |
0652a1 |
quant->blocks = channels;
|
|
Packit |
0652a1 |
} else {
|
|
Packit |
0652a1 |
quant->stride = channels;
|
|
Packit |
0652a1 |
quant->blocks = 1;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
quant->quantizer = quantizer;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
quant->shift = count_power (quantizer);
|
|
Packit |
0652a1 |
if (quant->shift > 0)
|
|
Packit |
0652a1 |
quant->bias = (1U << (quant->shift - 1));
|
|
Packit |
0652a1 |
else
|
|
Packit |
0652a1 |
quant->bias = 0;
|
|
Packit |
0652a1 |
quant->mask = (1U << quant->shift) - 1;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
gst_audio_quantize_setup_dither (quant);
|
|
Packit |
0652a1 |
gst_audio_quantize_setup_noise_shaping (quant);
|
|
Packit |
0652a1 |
gst_audio_quantize_setup_quantize_func (quant);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
return quant;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/**
|
|
Packit |
0652a1 |
* gst_audio_quantize_free:
|
|
Packit |
0652a1 |
* @quant: a #GstAudioQuantize
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Free a #GstAudioQuantize.
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
void
|
|
Packit |
0652a1 |
gst_audio_quantize_free (GstAudioQuantize * quant)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
g_return_if_fail (quant != NULL);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
g_free (quant->error_buf);
|
|
Packit |
0652a1 |
g_free (quant->coeffs);
|
|
Packit |
0652a1 |
g_free (quant->last_random);
|
|
Packit |
0652a1 |
g_free (quant->dither_buf);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
g_slice_free (GstAudioQuantize, quant);
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/**
|
|
Packit |
0652a1 |
* gst_audio_quantize_reset:
|
|
Packit |
0652a1 |
* @quant: a #GstAudioQuantize
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Reset @quant to the state is was when created, clearing any
|
|
Packit |
0652a1 |
* history it might have.
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
void
|
|
Packit |
0652a1 |
gst_audio_quantize_reset (GstAudioQuantize * quant)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
g_free (quant->error_buf);
|
|
Packit |
0652a1 |
quant->error_buf = NULL;
|
|
Packit |
0652a1 |
quant->error_size = 0;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/**
|
|
Packit |
0652a1 |
* gst_audio_quantize_samples:
|
|
Packit |
0652a1 |
* @quant: a #GstAudioQuantize
|
|
Packit |
0652a1 |
* @in: input samples
|
|
Packit |
0652a1 |
* @out: output samples
|
|
Packit |
0652a1 |
* @samples: number of samples
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Perform quantization on @samples in @in and write the result to @out.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* In case the samples are interleaved, @in and @out must point to an
|
|
Packit |
0652a1 |
* array with a single element pointing to a block of interleaved samples.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* If non-interleaved samples are used, @in and @out must point to an
|
|
Packit |
0652a1 |
* array with pointers to memory blocks, one for each channel.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* @in and @out may point to the same memory location, in which case samples will be
|
|
Packit |
0652a1 |
* modified in-place.
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
void
|
|
Packit |
0652a1 |
gst_audio_quantize_samples (GstAudioQuantize * quant,
|
|
Packit |
0652a1 |
const gpointer in[], gpointer out[], guint samples)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
guint i;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
g_return_if_fail (quant != NULL);
|
|
Packit |
0652a1 |
g_return_if_fail (out != NULL || samples == 0);
|
|
Packit |
0652a1 |
g_return_if_fail (in != NULL || samples == 0);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
for (i = 0; i < quant->blocks; i++)
|
|
Packit |
0652a1 |
quant->quantize (quant, in[i], out[i], samples);
|
|
Packit |
0652a1 |
}
|