Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
3960 | Serge | 1 | /* |
2 | dither: Generate shaped noise for dithering |
||
3 | |||
4 | copyright 2009 by the mpg123 project - free software under the terms of the LGPL 2.1 |
||
5 | see COPYING and AUTHORS files in distribution or http://mpg123.org |
||
6 | initially written by Taihei Monma |
||
7 | */ |
||
8 | |||
9 | #include "config.h" |
||
10 | #include "compat.h" |
||
11 | #include "dither.h" |
||
12 | |||
13 | static const uint32_t init_seed = 2463534242UL; |
||
14 | |||
15 | #define LAP 100 |
||
16 | |||
17 | /* |
||
18 | xorshift random number generator, with output scaling to [-0.5, 0.5] |
||
19 | This is the white noise... |
||
20 | See http://www.jstatsoft.org/v08/i14/paper on XOR shift random number generators. |
||
21 | */ |
||
22 | static float rand_xorshift32(uint32_t *seed) |
||
23 | { |
||
24 | union |
||
25 | { |
||
26 | uint32_t i; |
||
27 | float f; |
||
28 | } fi; |
||
29 | |||
30 | fi.i = *seed; |
||
31 | fi.i ^= (fi.i<<13); |
||
32 | fi.i ^= (fi.i>>17); |
||
33 | fi.i ^= (fi.i<<5); |
||
34 | *seed = fi.i; |
||
35 | |||
36 | /* scale the number to [-0.5, 0.5] */ |
||
37 | #ifdef IEEE_FLOAT |
||
38 | fi.i = (fi.i>>9)|0x3f800000; |
||
39 | fi.f -= 1.5f; |
||
40 | #else |
||
41 | fi.f = (double)fi.i / 4294967295.0; |
||
42 | fi.f -= 0.5f; |
||
43 | #endif |
||
44 | return fi.f; |
||
45 | } |
||
46 | |||
47 | static void white_noise(float *table, size_t count) |
||
48 | { |
||
49 | size_t i; |
||
50 | uint32_t seed = init_seed; |
||
51 | |||
52 | for(i=0; i |
||
53 | table[i] = rand_xorshift32(&seed); |
||
54 | } |
||
55 | |||
56 | static void tpdf_noise(float *table, size_t count) |
||
57 | { |
||
58 | size_t i; |
||
59 | uint32_t seed = init_seed; |
||
60 | |||
61 | for(i=0; i |
||
62 | table[i] = rand_xorshift32(&seed) + rand_xorshift32(&seed); |
||
63 | } |
||
64 | |||
65 | static void highpass_tpdf_noise(float *table, size_t count) |
||
66 | { |
||
67 | size_t i; |
||
68 | uint32_t seed = init_seed; |
||
69 | /* Ensure some minimum lap for keeping the high-pass filter circular. */ |
||
70 | size_t lap = count > 2*LAP ? LAP : count/2; |
||
71 | |||
72 | float input_noise; |
||
73 | float xv[9], yv[9]; |
||
74 | |||
75 | for(i=0;i<9;i++) |
||
76 | { |
||
77 | xv[i] = yv[i] = 0.0f; |
||
78 | } |
||
79 | |||
80 | for(i=0;i |
||
81 | { |
||
82 | if(i==count) seed=init_seed; |
||
83 | |||
84 | /* generate and add 2 random numbers, to make a TPDF noise distribution */ |
||
85 | input_noise = rand_xorshift32(&seed) + rand_xorshift32(&seed); |
||
86 | |||
87 | /* apply 8th order Chebyshev high-pass IIR filter */ |
||
88 | /* Coefficients are from http://www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html |
||
89 | Given parameters are: Chebyshev, Highpass, ripple=-1, order=8, samplerate=44100, corner1=19000 */ |
||
90 | 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]; |
||
91 | xv[8] = input_noise / 1.382814179e+07; |
||
92 | 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]; |
||
93 | yv[8] = (xv[0] + xv[8]) - 8 * (xv[1] + xv[7]) + 28 * (xv[2] + xv[6]) |
||
94 | - 56 * (xv[3] + xv[5]) + 70 * xv[4] |
||
95 | + ( -0.6706204984 * yv[0]) + ( -5.3720827038 * yv[1]) |
||
96 | + (-19.0865382480 * yv[2]) + (-39.2831607860 * yv[3]) |
||
97 | + (-51.2308985070 * yv[4]) + (-43.3590135780 * yv[5]) |
||
98 | + (-23.2632305320 * yv[6]) + ( -7.2370122050 * yv[7]); |
||
99 | if(i>=lap) table[i-lap] = yv[8] * 3.0f; |
||
100 | } |
||
101 | } |
||
102 | |||
103 | void mpg123_noise(float* table, size_t count, enum mpg123_noise_type noisetype) |
||
104 | { |
||
105 | switch(noisetype) |
||
106 | { |
||
107 | case mpg123_white_noise: white_noise(table, count); break; |
||
108 | case mpg123_tpdf_noise: tpdf_noise(table, count); break; |
||
109 | case mpg123_highpass_tpdf_noise: |
||
110 | highpass_tpdf_noise(table, count); |
||
111 | break; |
||
112 | } |
||
113 | } |
||
114 | |||
115 | /* Generate white noise and shape it with a high pass filter. */ |
||
116 | void dither_table_init(float *dithertable) |
||
117 | { |
||
118 | highpass_tpdf_noise(dithertable, DITHERSIZE); |
||
119 | } |