audioconvert: Avoid int division in quantization

Since range size is always 2^n, we can simply use modulo (implemented
with a bitmask).

The previous implementation used 64-bit integer division, which is
done in software on ARMv7. Although the divisor was constant, the
division could not be transformed into "multiplication by magic number"
since the dividend was 64-bit.

The now-unused and not-so-fast gst_fast_random_(u)int32_range functions
were removed.

Also, implementing bug fixes:

1) ADD_DITHER_TPDF_HF_I no longer discards bias.

2) We change TPDF's noise range to be the same as RPDF's. Previously,
RPDF's noise ranged:
  { bias - dither, bias + dither }
while TPDF's noise ranged:
  { bias/2 - dither/2, bias/2 + dither/2 - 1 } +
  { bias/2 - dither/2, bias/2 + dither/2 - 1 } =
  { bias - dither, bias + dither - 2 }
Now, both range:
  { bias - dither, bias + dither - 1 }

https://bugzilla.gnome.org/show_bug.cgi?id=746661
This commit is contained in:
Ilya Konstantinov 2015-03-24 03:01:22 +02:00 committed by Sebastian Dröge
parent bf3e35a598
commit 7b398701cf
2 changed files with 14 additions and 34 deletions

View file

@ -136,7 +136,7 @@ MAKE_QUANTIZE_FUNC_NAME (name) (AudioConvertCtx *ctx, gdouble *src, \
/* Dithering definitions /* Dithering definitions
* See http://en.wikipedia.org/wiki/Dithering or * See http://en.wikipedia.org/wiki/Dithering or
* http://www.cadenzarecording.com/Dither.html for explainations. * http://www.users.qwest.net/~volt42/cadenzarecording/DitherExplained.pdf for explainations.
* *
* We already add the rounding offset to the dither noise here * We already add the rounding offset to the dither noise here
* to have only one overflow check instead of two. */ * to have only one overflow check instead of two. */
@ -145,9 +145,14 @@ MAKE_QUANTIZE_FUNC_NAME (name) (AudioConvertCtx *ctx, gdouble *src, \
gint32 rand; \ gint32 rand; \
gint32 dither = (1<<(scale)); gint32 dither = (1<<(scale));
/* Assuming dither == 2^n,
* returns one of 2^(n+1) possible random values:
* -dither <= retval < dither */
#define RANDOM_INT_DITHER(dither) \
(- dither + (gst_fast_random_int32 () & ((dither << 1) - 1)))
#define ADD_DITHER_RPDF_I() \ #define ADD_DITHER_RPDF_I() \
rand = gst_fast_random_int32_range (bias - dither, \ rand = bias + RANDOM_INT_DITHER(dither); \
bias + dither); \
if (rand > 0 && tmp > 0 && G_MAXINT32 - tmp <= rand) \ if (rand > 0 && tmp > 0 && G_MAXINT32 - tmp <= rand) \
tmp = G_MAXINT32; \ tmp = G_MAXINT32; \
else if (rand < 0 && tmp < 0 && G_MININT32 - tmp >= rand) \ else if (rand < 0 && tmp < 0 && G_MININT32 - tmp >= rand) \
@ -163,14 +168,11 @@ MAKE_QUANTIZE_FUNC_NAME (name) (AudioConvertCtx *ctx, gdouble *src, \
#define INIT_DITHER_TPDF_I() \ #define INIT_DITHER_TPDF_I() \
gint32 rand; \ gint32 rand; \
gint32 dither = (1<<(scale - 1)); \ gint32 dither = (1<<(scale - 1));
bias = bias >> 1;
#define ADD_DITHER_TPDF_I() \ #define ADD_DITHER_TPDF_I() \
rand = gst_fast_random_int32_range (bias - dither, \ rand = bias + RANDOM_INT_DITHER(dither) \
bias + dither - 1) \ + RANDOM_INT_DITHER(dither); \
+ gst_fast_random_int32_range (bias - dither, \
bias + dither - 1); \
if (rand > 0 && tmp > 0 && G_MAXINT32 - tmp <= rand) \ if (rand > 0 && tmp > 0 && G_MAXINT32 - tmp <= rand) \
tmp = G_MAXINT32; \ tmp = G_MAXINT32; \
else if (rand < 0 && tmp < 0 && G_MININT32 - tmp >= rand) \ else if (rand < 0 && tmp < 0 && G_MININT32 - tmp >= rand) \
@ -188,13 +190,11 @@ MAKE_QUANTIZE_FUNC_NAME (name) (AudioConvertCtx *ctx, gdouble *src, \
#define INIT_DITHER_TPDF_HF_I() \ #define INIT_DITHER_TPDF_HF_I() \
gint32 rand; \ gint32 rand; \
gint32 dither = (1<<(scale-1)); \ gint32 dither = (1<<(scale-1)); \
gint32 *last_random = (gint32 *) ctx->last_random, tmp_rand; \ gint32 *last_random = (gint32 *) ctx->last_random, tmp_rand;
bias = bias >> 1;
#define ADD_DITHER_TPDF_HF_I() \ #define ADD_DITHER_TPDF_HF_I() \
tmp_rand = gst_fast_random_int32_range (bias - dither, \ tmp_rand = RANDOM_INT_DITHER(dither); \
bias + dither); \ rand = bias + tmp_rand - last_random[chan_pos]; \
rand = tmp_rand - last_random[chan_pos]; \
last_random[chan_pos] = tmp_rand; \ last_random[chan_pos] = tmp_rand; \
if (rand > 0 && tmp > 0 && G_MAXINT32 - tmp <= rand) \ if (rand > 0 && tmp > 0 && G_MAXINT32 - tmp <= rand) \
tmp = G_MAXINT32; \ tmp = G_MAXINT32; \

View file

@ -38,32 +38,12 @@ gst_fast_random_uint32 (void)
return (state = state * 1103515245 + 12345); return (state = state * 1103515245 + 12345);
} }
static inline guint32
gst_fast_random_uint32_range (gint32 start, gint32 end)
{
guint64 tmp = gst_fast_random_uint32 ();
tmp = (tmp * (end - start)) / G_MAXUINT32 + start;
return (guint32) tmp;
}
static inline gint32 static inline gint32
gst_fast_random_int32 (void) gst_fast_random_int32 (void)
{ {
return (gint32) gst_fast_random_uint32 (); return (gint32) gst_fast_random_uint32 ();
} }
static inline gint32
gst_fast_random_int32_range (gint32 start, gint32 end)
{
gint64 tmp = gst_fast_random_uint32 ();
tmp = (tmp * (end - start)) / G_MAXUINT32 + start;
return (gint32) tmp;
}
static inline gdouble static inline gdouble
gst_fast_random_double (void) gst_fast_random_double (void)
{ {