|
Packit |
c32a2d |
/*
|
|
Packit |
c32a2d |
dither: Generate shaped noise for dithering
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
copyright 2009 by the mpg123 project - free software under the terms of the LGPL 2.1
|
|
Packit |
c32a2d |
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
|
Packit |
c32a2d |
initially written by Taihei Monma
|
|
Packit |
c32a2d |
*/
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
#include "config.h"
|
|
Packit |
c32a2d |
#include "compat.h"
|
|
Packit |
c32a2d |
#include "dither.h"
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static const uint32_t init_seed = 2463534242UL;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
#define LAP 100
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/*
|
|
Packit |
c32a2d |
xorshift random number generator, with output scaling to [-0.5, 0.5]
|
|
Packit |
c32a2d |
This is the white noise...
|
|
Packit |
c32a2d |
See http://www.jstatsoft.org/v08/i14/paper on XOR shift random number generators.
|
|
Packit |
c32a2d |
*/
|
|
Packit |
c32a2d |
static float rand_xorshift32(uint32_t *seed)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
union
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
uint32_t i;
|
|
Packit |
c32a2d |
float f;
|
|
Packit |
c32a2d |
} fi;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
fi.i = *seed;
|
|
Packit |
c32a2d |
fi.i ^= (fi.i<<13);
|
|
Packit |
c32a2d |
fi.i ^= (fi.i>>17);
|
|
Packit |
c32a2d |
fi.i ^= (fi.i<<5);
|
|
Packit |
c32a2d |
*seed = fi.i;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* scale the number to [-0.5, 0.5] */
|
|
Packit |
c32a2d |
#ifdef IEEE_FLOAT
|
|
Packit |
c32a2d |
fi.i = (fi.i>>9)|0x3f800000;
|
|
Packit |
c32a2d |
fi.f -= 1.5f;
|
|
Packit |
c32a2d |
#else
|
|
Packit |
c32a2d |
fi.f = (double)fi.i / 4294967295.0;
|
|
Packit |
c32a2d |
fi.f -= 0.5f;
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
return fi.f;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static void white_noise(float *table, size_t count)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
size_t i;
|
|
Packit |
c32a2d |
uint32_t seed = init_seed;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
for(i=0; i
|
|
Packit |
c32a2d |
table[i] = rand_xorshift32(&seed);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static void tpdf_noise(float *table, size_t count)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
size_t i;
|
|
Packit |
c32a2d |
uint32_t seed = init_seed;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
for(i=0; i
|
|
Packit |
c32a2d |
table[i] = rand_xorshift32(&seed) + rand_xorshift32(&seed);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static void highpass_tpdf_noise(float *table, size_t count)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
size_t i;
|
|
Packit |
c32a2d |
uint32_t seed = init_seed;
|
|
Packit |
c32a2d |
/* Ensure some minimum lap for keeping the high-pass filter circular. */
|
|
Packit |
c32a2d |
size_t lap = count > 2*LAP ? LAP : count/2;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
float input_noise;
|
|
Packit |
c32a2d |
float xv[9], yv[9];
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
for(i=0;i<9;i++)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
xv[i] = yv[i] = 0.0f;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
for(i=0;i
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
if(i==count) seed=init_seed;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* generate and add 2 random numbers, to make a TPDF noise distribution */
|
|
Packit |
c32a2d |
input_noise = rand_xorshift32(&seed) + rand_xorshift32(&seed);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* apply 8th order Chebyshev high-pass IIR filter */
|
|
Packit |
c32a2d |
/* Coefficients are from http://www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html
|
|
Packit |
c32a2d |
Given parameters are: Chebyshev, Highpass, ripple=-1, order=8, samplerate=44100, corner1=19000 */
|
|
Packit |
c32a2d |
xv[0] = xv[1]; xv[1] = xv[2]; xv[2] = xv[3]; xv[3] = xv[4]; xv[4] = xv[5]; xv[5] = xv[6]; xv[6] = xv[7]; xv[7] = xv[8];
|
|
Packit |
c32a2d |
xv[8] = input_noise / 1.382814179e+07;
|
|
Packit |
c32a2d |
yv[0] = yv[1]; yv[1] = yv[2]; yv[2] = yv[3]; yv[3] = yv[4]; yv[4] = yv[5]; yv[5] = yv[6]; yv[6] = yv[7]; yv[7] = yv[8];
|
|
Packit |
c32a2d |
yv[8] = (xv[0] + xv[8]) - 8 * (xv[1] + xv[7]) + 28 * (xv[2] + xv[6])
|
|
Packit |
c32a2d |
- 56 * (xv[3] + xv[5]) + 70 * xv[4]
|
|
Packit |
c32a2d |
+ ( -0.6706204984 * yv[0]) + ( -5.3720827038 * yv[1])
|
|
Packit |
c32a2d |
+ (-19.0865382480 * yv[2]) + (-39.2831607860 * yv[3])
|
|
Packit |
c32a2d |
+ (-51.2308985070 * yv[4]) + (-43.3590135780 * yv[5])
|
|
Packit |
c32a2d |
+ (-23.2632305320 * yv[6]) + ( -7.2370122050 * yv[7]);
|
|
Packit |
c32a2d |
if(i>=lap) table[i-lap] = yv[8] * 3.0f;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
void mpg123_noise(float* table, size_t count, enum mpg123_noise_type noisetype)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
switch(noisetype)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
case mpg123_white_noise: white_noise(table, count); break;
|
|
Packit |
c32a2d |
case mpg123_tpdf_noise: tpdf_noise(table, count); break;
|
|
Packit |
c32a2d |
case mpg123_highpass_tpdf_noise:
|
|
Packit |
c32a2d |
highpass_tpdf_noise(table, count);
|
|
Packit |
c32a2d |
break;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Generate white noise and shape it with a high pass filter. */
|
|
Packit |
c32a2d |
void dither_table_init(float *dithertable)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
highpass_tpdf_noise(dithertable, DITHERSIZE);
|
|
Packit |
c32a2d |
}
|