mirror of
https://github.com/outbackdingo/UltraGrid.git
synced 2026-03-21 12:40:19 +00:00
audio dithering: Fix some problems
* Replace bit shift with integer division - Shifting doesn't behave nicely for negative numbers, for example -2 >> 8 equals -1. This introduces distortion * Use rounding from 0.5 up - Truncating introduces distortion, because the interval of numbers that round to 0 is disproportionaly big (-1, 1). * Replace random number generation with a faster algorithm With all theese changes, the code is also a bit faster.
This commit is contained in:
@@ -206,15 +206,14 @@ void audio_frame_write_desc(struct audio_frame *f, struct audio_desc desc)
|
||||
}
|
||||
|
||||
int32_t downshift_with_dither(int32_t val, int shift){
|
||||
static thread_local std::uint_fast32_t last_rand = 1;
|
||||
static thread_local uint32_t last_rand = 0;
|
||||
|
||||
const int mask = (1 << shift) - 1;
|
||||
|
||||
//Pseudorandom number generation, same parameters as std::minstd_rand
|
||||
last_rand = (last_rand * 48271) % 2147483647;
|
||||
int triangle_dither = last_rand & mask;
|
||||
last_rand = (last_rand * 48271) % 2147483647;
|
||||
triangle_dither -= last_rand & mask; //triangle probability distribution
|
||||
//Quick and dirty random number generation (ranqd1)
|
||||
//Numerical Recipes in C, page 284
|
||||
last_rand = (last_rand * 1664525) + 1013904223L;
|
||||
int triangle_dither = last_rand >> (32 - shift);
|
||||
last_rand = (last_rand * 1664525) + 1013904223L;
|
||||
triangle_dither -= last_rand >> (32 - shift); //triangle probability distribution
|
||||
|
||||
/* Prevent over/underflow when val is big.
|
||||
*
|
||||
@@ -222,15 +221,20 @@ int32_t downshift_with_dither(int32_t val, int shift){
|
||||
* 32-bit pcm is rare and should not contain the value INT32_MIN
|
||||
* anyway because of symmetry, as specified by AES17 and IEC 61606-3
|
||||
*/
|
||||
if(INT32_MAX - abs(val) < mask)
|
||||
return val >> shift;
|
||||
if(INT32_MAX - abs(val) < (1 << shift) - 1 + (1 << (shift - 1)))
|
||||
return val / (1 << shift);
|
||||
|
||||
return (val + triangle_dither) >> shift;
|
||||
if(val > 0)
|
||||
val += 1 << (shift - 1);
|
||||
else
|
||||
val -= 1 << (shift - 1);
|
||||
|
||||
return (val + triangle_dither) / (1 << shift);
|
||||
}
|
||||
|
||||
#define NO_DITHER_PARAM "no-dither"
|
||||
ADD_TO_PARAM(NO_DITHER_PARAM, "* " NO_DITHER_PARAM "\n"
|
||||
" Disable audio dithering when resampling\n");
|
||||
" Disable audio dithering when reducing bit depth\n");
|
||||
|
||||
void change_bps(char *out, int out_bps, const char *in, int in_bps, int in_len /* bytes */) {
|
||||
static const bool dither = commandline_params.find(NO_DITHER_PARAM) == commandline_params.end();
|
||||
|
||||
Reference in New Issue
Block a user