1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
|
#include "main.h"
#include "SABuffer.h"
#include <math.h>
#include "WinampAttributes.h"
#include "fft.h"
extern int _srate;
#ifdef _M_IX86
__inline static int lrint(float flt)
{
int intgr;
_asm
{
fld flt
fistp intgr
}
return intgr;
}
#else
__inline static int lrint(float flt)
{
return (int)flt;
}
#endif
// quantizes to 23 bits - use appropriately
inline static float fastmin(float x, const float b)
{
x = b - x;
x += (float)fabs(x);
x *= 0.5f;
x = b - x;
return x;
}
#define FASTMIN(x,b) { x = b - x; x += (float)fabs(x); x *= 0.5f; x = b - x; }
inline static float fastclip(float x, const float a, const float b)
{
float x1 = (float)fabs(x-a);
float x2 = (float)fabs(x-b);
x = x1 + (a+b);
x -= x2;
x *= 0.5f;
return (x);
}
void makeOscData(char *tempdata, char *data_buf, int little_block, int channels, int bits)
{
float dd = little_block/75.0f;
int x,c;
int stride=bits/8; // number of bytes between samples
// we're calculating using only the most significant byte,
// because we only end up with 6 bit data anyway
// if you want full resolution, check out CVS tag BETA_2005_1122_182830, file: vis.c
char *ptr, *sbuf = data_buf;
for (x = 0; x < 75; x ++)
{
float val=0;
int index =(int)((float)x * dd); // calculate the nearest sample for this point, interpolation is too expensive for this use
ptr=&sbuf[index*stride*channels+stride-1]; // find first sample, and offset for little endian
for (c=0;c<channels;c++)
{
val += (float)*ptr / 8.0f; // we want our final value to be -32 to 32
ptr+=stride; // jump to the next sample (channels are interleaved)
}
tempdata[x] = (char)lrint(val / (float)channels); // average the channels
}
}
inline double fast_exp2(const double val)
{
int e;
double ret;
if (val >= 0)
{
e = int (val);
ret = val - (e - 1);
((*(1 + (int *) &ret)) &= ~(2047 << 20)) += (e + 1023) << 20;
}
else
{
e = int (val + 1023);
ret = val - (e - 1024);
((*(1 + (int *) &ret)) &= ~(2047 << 20)) += e << 20;
}
return (ret);
}
// ~6 clocks on Pentium M vs. ~24 for single precision sqrtf
#if !defined(_WIN64)
static inline float squareroot_sse_11bits(float x)
{
float z;
_asm
{
rsqrtss xmm0, x
rcpss xmm0, xmm0
movss z, xmm0 // z ~= sqrt(x) to 0.038%
}
return z;
}
static inline int floor_int(double x)
{
int i;
static const float round_toward_m_i = -0.5f;
__asm
{
fld x
fadd st, st(0)
fadd round_toward_m_i
fistp i
sar i, 1
}
return (i);
}
#endif
/*
static inline float hermite(float x, float y0, float y1, float y2, float y3)
{
// 4-point, 3rd-order Hermite (x-form)
float c0 = y1;
float c1 = 0.5f * (y2 - y0);
float c2 = y0 - 2.5f * y1 + 2.f * y2 - 0.5f * y3;
float c3 = 1.5f * (y1 - y2) + 0.5f * (y3 - y0);
return ((c3 * x + c2) * x + c1) * x + c0;
}
*/
/*
static const float c_half = 0.5f;
__declspec(naked) static float hermite(float frac_pos, const float* pntr)
{
__asm
{
push ecx;
mov ecx, dword ptr[esp + 12]; //////////////////////////////////////////////////////////////////////////////////////////////////
add ecx, 0x04; // ST(0) ST(1) ST(2) ST(3) ST(4) ST(5) ST(6) ST(7)
fld dword ptr [ecx+4]; // x1
fsub dword ptr [ecx-4]; // x1-xm1
fld dword ptr [ecx]; // x0 x1-xm1
fsub dword ptr [ecx+4]; // v x1-xm1
fld dword ptr [ecx+8]; // x2 v x1-xm1
fsub dword ptr [ecx]; // x2-x0 v x1-xm1
fxch st(2); // x1-m1 v x2-x0
fmul c_half; // c v x2-x0
fxch st(2); // x2-x0 v c
fmul c_half; // 0.5*(x2-x0) v c
fxch st(2); // c v 0.5*(x2-x0)
fst st(3); // c v 0.5*(x2-x0) c
fadd st(0), st(1); // w v 0.5*(x2-x0) c
fxch st(2); // 0.5*(x2-x0) v w c
faddp st(1), st(0); // v+.5(x2-x0) w c
fadd st(0), st(1); // a w c
fadd st(1), st(0); // a b_neg c
fmul dword ptr [esp+8]; // a*frac b_neg c
fsubrp st(1), st(0); // a*f-b c
fmul dword ptr [esp+8]; // (a*f-b)*f c
faddp st(1), st(0); // res-x0/f
fmul dword ptr [esp+8]; // res-x0
fadd dword ptr [ecx]; // res
pop ecx;
ret;
}
}
*/
inline float hermite(float x, float y0, float y1, float y2, float y3)
{
// 4-point, 3rd-order Hermite (x-form)
float c0 = y1;
float c1 = 0.5f * (y2 - y0);
float c3 = 1.5f * (y1 - y2) + 0.5f * (y3 - y0);
float c2 = y0 - y1 + c1 - c3;
return ((c3 * x + c2) * x + c1) * x + c0;
}
static inline float fpow2(const float y)
{
union
{
float f;
int i;
} c;
int integer = lrint(floor(y));
/* cut: because we guarantee y>=0
if(y < 0)
integer = integer-1;
*/
float frac = y - (float)integer;
c.i = (integer+127) << 23;
c.f *= 0.33977f*frac*frac + (1.0f-0.33977f)*frac + 1.0f;
return c.f;
}
//#define SAPOW(x) (powf(2.f, (float)(x)/12.f))
#define SAPOW(x) (fpow2((float)(x)/12.f))
//#define WARP(x) ((powf(1.1f, (float)(x)/12.f) - 1.) * bla)
#define WARP(x) ((SAPOW(x) - 1.f) * bla)
void makeSpecData(unsigned char *tempdata, float *wavetrum)
{
//WARP(75);
float bla = (255.f/SAPOW(75.f));
fft_9(wavetrum);
float spec_scale=0.5;
if (config_replaygain)
{ // benski> i'm sure there's some math identity we can use to optimize this.
spec_scale/=pow(10.0f, config_replaygain_non_rg_gain.GetFloat() / 20.0f);
}
for (int i=0;i<256;i++)
{
//int lookup=2*i;
float sinT = wavetrum[2*i];
float cosT = wavetrum[2*i+1];
wavetrum[i] = sqrt(sinT*sinT+cosT*cosT)*spec_scale;
}
float next = WARP(0)+1 ;
for (int x = 0; x < 75; x ++)
{
//float prev = 1.+(pow(2.,(float)x/12.) -1.) * bla;
float binF = next;
next = WARP(x+1) +1;
float thisValue = 0;
int bin = lrint(floor(binF));
int end = lrint(floor(next));
end = min(end, 255);
float mult = ((float)(bin+1))-binF;
bool herm=true;
do
{
if (bin == end)
{
mult = (next-binF);
herm=true;
}
if (herm)
{
float C=0, D=0;
if (bin<255)
{
C=wavetrum[bin+1];
if (bin<254)
D=wavetrum[bin+2];
}
//float samples[4] = { wavetrum[lookupA], wavetrum[lookupB], wavetrum[lookupC], wavetrum[lookupD] };
//thisValue += hermite(binF-bin, samples) * mult;
thisValue += hermite(binF-bin, wavetrum[bin-1], wavetrum[bin], C, D) * mult;
}
else
{
thisValue += wavetrum[bin];
}
herm=false;
bin++;
binF=(float)bin;
}
while (bin <= end);
tempdata[x]=lrint(fastmin(thisValue, 255.f));
}
}
////////////////////////////////
SABuffer saBuffer;
void sa_addpcmdata(void *_data_buf, int numChannels, int numBits, int ts)
{
char *data_buf = reinterpret_cast<char *>(_data_buf);
char tempdata[75*2] = {0};
__declspec(align(16)) float wavetrum[512];
//extern int sa_curmode;
int vis_Csa=sa_override ? 3 : sa_curmode;
switch (vis_Csa)
{
case 4:
tempdata[0] = 0;
tempdata[1] = 0;
sa_add(tempdata,ts,4);
return;
case 2:
makeOscData(tempdata,data_buf,576,numChannels, numBits);
sa_add(tempdata,ts,2);
return ;
case 3:
makeOscData(tempdata+75,data_buf,576,numChannels, numBits);
// fall through!
case 1:
calcVuData((unsigned char*)tempdata, data_buf, numChannels, numBits);
vu_add(tempdata, ts);
break;
}
bool done=false;
size_t samples=576;
while (samples)
{
unsigned int copied = saBuffer.AddToBuffer(data_buf, numChannels, numBits, ts, (unsigned int) samples);
samples-=copied;
data_buf+=(copied*(numBits/8)*numChannels);
if (saBuffer.Full())
{
saBuffer.WindowToFFTBuffer(wavetrum);
if (!done)
{
if (vis_Csa == 3)
{
makeSpecData((unsigned char*)tempdata, wavetrum);
sa_add(tempdata, ts, 0x80000003);
}
else if (vis_Csa == 1)
{
makeSpecData((unsigned char*)tempdata, wavetrum);
sa_add(tempdata, ts, 1);
}
}
//done=true;
saBuffer.CopyHalf();
ts+=MulDiv(SABUFFER_WINDOW_INCREMENT,1000,_srate);
}
}
}
|