xue@11
|
1 /*
|
xue@11
|
2 Harmonic sinusoidal modelling and tools
|
xue@11
|
3
|
xue@11
|
4 C++ code package for harmonic sinusoidal modelling and relevant signal processing.
|
xue@11
|
5 Centre for Digital Music, Queen Mary, University of London.
|
xue@11
|
6 This file copyright 2011 Wen Xue.
|
xue@11
|
7
|
xue@11
|
8 This program is free software; you can redistribute it and/or
|
xue@11
|
9 modify it under the terms of the GNU General Public License as
|
xue@11
|
10 published by the Free Software Foundation; either version 2 of the
|
xue@11
|
11 License, or (at your option) any later version.
|
xue@11
|
12 */
|
xue@1
|
13 //---------------------------------------------------------------------------
|
xue@1
|
14 #include <math.h>
|
Chris@2
|
15 #include <string.h>
|
Chris@2
|
16 #include "windowfunctions.h"
|
xue@1
|
17 #include "align8.h"
|
xue@1
|
18 //---------------------------------------------------------------------------
|
xue@1
|
19
|
Chris@5
|
20 /**
|
xue@1
|
21 function I0: Bessel function of order zero
|
xue@1
|
22
|
xue@1
|
23 Returns the Bessel function of x.
|
xue@1
|
24 */
|
xue@1
|
25 double I0(double x)
|
xue@1
|
26 {
|
xue@1
|
27 const double eps=1e-9;
|
xue@1
|
28
|
xue@1
|
29 int n=1;
|
xue@1
|
30 double S=1, D=1, T;
|
xue@1
|
31
|
xue@1
|
32 while (D>eps*S)
|
xue@1
|
33 {
|
xue@1
|
34 T=x/(2*n++);
|
xue@1
|
35 D*=T*T;
|
xue@1
|
36 S+=D;
|
xue@1
|
37 }
|
xue@1
|
38 return S;
|
xue@1
|
39 }//I0
|
xue@1
|
40
|
Chris@5
|
41 /**
|
xue@1
|
42 function FillWindow: fills a buffer $Result with a window function.
|
xue@1
|
43
|
xue@1
|
44 In: wt:window type
|
xue@1
|
45 Count: window size
|
xue@1
|
46 ips & ups: extra window specificatin parameters
|
xue@1
|
47 Out: newwindow[Count+1]: the window function.
|
xue@1
|
48
|
xue@1
|
49 No return value. This function is designed assuming Count being even, and Count/2 is the symmetry
|
xue@1
|
50 centre of newwindow. newwindow has physical size Count+1 for compatibility purpose. For all vanishing
|
xue@1
|
51 windows (e.g. Hann) newwindow[0]=newwindow[Count]=0.
|
xue@1
|
52 */
|
xue@1
|
53 void FillWindow(double* Result, WindowType wt, int Count, int* ips, double* dps)
|
xue@1
|
54 {
|
xue@1
|
55 switch(wt)
|
xue@1
|
56 {
|
xue@1
|
57 case wtRectangle:
|
xue@1
|
58 for (int i=0; i<=Count; i++)
|
xue@1
|
59 Result[i]=1;
|
xue@1
|
60 break;
|
xue@1
|
61 case wtTriangular:
|
xue@1
|
62 for (int i=0; i<=Count; i++)
|
xue@1
|
63 Result[i]=1-2*fabs(i-Count/2.0)/Count;
|
xue@1
|
64 break;
|
xue@1
|
65 case wtHamming:
|
xue@1
|
66 for (int i=0; i<=Count; i++)
|
xue@1
|
67 Result[i]=(0.54-0.46*cos(2*M_PI*i/Count));
|
xue@1
|
68 break;
|
xue@1
|
69 case wtBlackman:
|
xue@1
|
70 for (int i=0; i<=Count; i++)
|
xue@1
|
71 Result[i]=0.42-0.5*cos(2*M_PI*i/Count)+0.08*cos(4*M_PI*i/Count);
|
xue@1
|
72 break;
|
xue@1
|
73 case wtGaussian:
|
xue@1
|
74 {
|
xue@1
|
75 double num=*dps*M_PI*M_PI/2/Count/Count;
|
xue@1
|
76 for (int i=0; i<=Count; i++)
|
xue@1
|
77 Result[i]=exp(-(i-Count/2.0)*(i-Count/2.0)*num);
|
xue@1
|
78 break;
|
xue@1
|
79 }
|
xue@1
|
80 case wtKaiser:
|
xue@1
|
81 {
|
xue@1
|
82 double ldps=*dps*M_PI*M_PI/2/Count;
|
xue@1
|
83 double den=I0(0.5*Count*ldps);
|
xue@1
|
84 for (int i=0; i<=Count; i++)
|
xue@1
|
85 Result[i]=I0(ldps*sqrt(0.25*Count*Count-(i-Count*0.5)*(i-Count*0.5)))/den;
|
xue@1
|
86 break;
|
xue@1
|
87 }
|
xue@1
|
88 case wtHalfCosine:
|
xue@1
|
89 {
|
xue@1
|
90 for (int i=0; i<=Count; i++)
|
xue@1
|
91 Result[i]=sin(M_PI*i/Count);
|
xue@1
|
92 break;
|
xue@1
|
93 }
|
xue@1
|
94 case wtHann:
|
xue@1
|
95 {
|
xue@1
|
96 for (int i=0; i<=Count; i++)
|
xue@1
|
97 Result[i]=(0.5-cos(M_PI*2*i/Count)/2);
|
xue@1
|
98 break;
|
xue@1
|
99 }
|
xue@1
|
100 case wtHannSqr:
|
xue@1
|
101 {
|
xue@1
|
102 for (int i=0; i<=Count; i++)
|
xue@1
|
103 Result[i]=(3-4*cos(M_PI*2*i/Count)+cos(M_PI*4*i/Count))/8;
|
xue@1
|
104 break;
|
xue@1
|
105 }
|
xue@1
|
106 case wtHann3sqrt:
|
xue@1
|
107 {
|
xue@1
|
108 for (int i=0; i<=Count; i++)
|
xue@1
|
109 {
|
xue@1
|
110 double tmp=sin(M_PI*i/Count);
|
xue@1
|
111 Result[i]=tmp*tmp*tmp;
|
xue@1
|
112 }
|
xue@1
|
113 break;
|
xue@1
|
114 }
|
xue@1
|
115 }
|
xue@1
|
116 }//FillWindow
|
xue@1
|
117
|
Chris@5
|
118 /**
|
xue@1
|
119 function NewWindow: creates a window function.
|
xue@1
|
120
|
xue@1
|
121 In: wt: window type
|
xue@1
|
122 Count: window size
|
xue@1
|
123 ips & ups: extra window specificatin parameters
|
xue@1
|
124 Out: newwindow[Count+1]: the window function.
|
xue@1
|
125
|
xue@1
|
126 Returns pointer to newwindow. newwindow is created anew if newwindow=0 is specified on start.
|
xue@1
|
127 */
|
xue@1
|
128 double* NewWindow(WindowType wt, int Count, int* ips, double* dps, double* newwindow)
|
xue@1
|
129 {
|
xue@1
|
130 double* Result=newwindow; if (!Result) Result=new double[Count+1];
|
xue@1
|
131 FillWindow(Result, wt, Count, ips, dps);
|
xue@1
|
132 return Result;
|
xue@1
|
133 }//NewWindow
|
xue@1
|
134
|
Chris@5
|
135 /**
|
xue@1
|
136 function NewWindow8: 8-byte aligned version of NewWindow.
|
xue@1
|
137
|
xue@1
|
138 In: wt: window type
|
xue@1
|
139 Count: window size
|
xue@1
|
140 ips & ups: extra window specificatin parameters
|
xue@1
|
141 Out: newwindow[Count+1]: the window function.
|
xue@1
|
142
|
xue@1
|
143 Returns pointer to newwindow. newwindow is created anew and 8-byte aligned if newwindow=0 is
|
xue@1
|
144 specified on start. However, if newwindow is not 8-byte aligned on start, the unaligned buffer is
|
xue@1
|
145 returned.
|
xue@1
|
146 */
|
xue@1
|
147 double* NewWindow8(WindowType wt, int Count, int* ips, double* dps, double* newwindow)
|
xue@1
|
148 {
|
xue@1
|
149 double* Result=newwindow; if (!Result) Result=(double*)malloc8(sizeof(double)*(Count+1));
|
xue@1
|
150 FillWindow(Result, wt, Count, ips, dps);
|
xue@1
|
151 return Result;
|
xue@1
|
152 }//NewWindow8
|
xue@1
|
153
|
Chris@5
|
154 /**
|
xue@1
|
155 function NewdWindow: computes the derivative of a window function.
|
xue@1
|
156
|
xue@1
|
157 In: wt: window type
|
xue@1
|
158 Count: window size
|
xue@1
|
159 ips & ups: extra window specificatin parameters
|
xue@1
|
160 Out: newdwindow[Count+1]: the derivative window function.
|
xue@1
|
161
|
xue@1
|
162 Returns pointer to newdwindow. newdwindow is created anew if newdwindow=0 is specified on start.
|
xue@1
|
163 */
|
xue@1
|
164 double* NewdWindow(WindowType wt, int Count, int* ips, double* dps, double* newdwindow)
|
xue@1
|
165 {
|
xue@1
|
166 double* Result=newdwindow; if (!Result) Result=new double[Count+1];
|
xue@1
|
167 double piiCount=M_PI/Count;
|
xue@1
|
168 switch(wt)
|
xue@1
|
169 {
|
xue@1
|
170 case wtRectangle:
|
xue@1
|
171 memset(Result, 0, sizeof(double)*(Count+1));
|
xue@1
|
172 break;
|
xue@1
|
173 case wtTriangular:
|
xue@1
|
174 throw("Trying to differentiate triangular window.");
|
xue@1
|
175 break;
|
xue@1
|
176 case wtHamming:
|
xue@1
|
177 for (int i=0; i<=Count; i++)
|
xue@1
|
178 Result[i]=0.92*piiCount*sin(2*piiCount*i);
|
xue@1
|
179 break;
|
xue@1
|
180 case wtBlackman:
|
xue@1
|
181 for (int i=0; i<=Count; i++)
|
xue@1
|
182 Result[i]=piiCount*sin(2*piiCount*i)-0.32*piiCount*sin(4*piiCount*i);
|
xue@1
|
183 break;
|
xue@1
|
184 case wtGaussian:
|
xue@1
|
185 throw("Trying to differentiate Gaussian window.");
|
xue@1
|
186 break;
|
xue@1
|
187 case wtKaiser:
|
xue@1
|
188 throw("Trying to differentiate Kaiser window.");
|
xue@1
|
189 break;
|
xue@1
|
190 case wtHalfCosine:
|
xue@1
|
191 {
|
xue@1
|
192 for (int i=0; i<=Count; i++)
|
xue@1
|
193 Result[i]=piiCount*cos(piiCount*i);
|
xue@1
|
194 break;
|
xue@1
|
195 }
|
xue@1
|
196 case wtHann:
|
xue@1
|
197 {
|
xue@1
|
198 for (int i=0; i<=Count; i++)
|
xue@1
|
199 Result[i]=piiCount*sin(2*piiCount*i);
|
xue@1
|
200 break;
|
xue@1
|
201 }
|
xue@1
|
202 case wtHannSqr:
|
xue@1
|
203 {
|
xue@1
|
204 for (int i=0; i<=Count; i++)
|
xue@1
|
205 Result[i]=piiCount*sin(2*piiCount*i)-0.5*piiCount*sin(4*piiCount*i);
|
xue@1
|
206 break;
|
xue@1
|
207 }
|
xue@1
|
208 case wtHann3sqrt:
|
xue@1
|
209 {
|
xue@1
|
210 for (int i=0; i<=Count; i++)
|
xue@1
|
211 {
|
xue@1
|
212 double s=sin(M_PI*i/Count), c=cos(M_PI*i/Count);
|
xue@1
|
213 Result[i]=3*piiCount*s*s*c;
|
xue@1
|
214 }
|
xue@1
|
215 }
|
xue@1
|
216 }
|
xue@1
|
217 return Result;
|
xue@1
|
218 }//NewdWindow
|
xue@1
|
219
|
Chris@5
|
220 /**
|
xue@1
|
221 function NewddWindow: computes the 2nd-order derivative of a window function.
|
xue@1
|
222
|
xue@1
|
223 In: wt: window type
|
xue@1
|
224 Count: window size
|
xue@1
|
225 ips & ups: extra window specificatin parameters
|
xue@1
|
226 Out: newddwindow[Count+1]: the 2nd-order derivative window function.
|
xue@1
|
227
|
xue@1
|
228 Returns pointer to newddwindow. newddwindow is created anew if newddwindow=0 is specified on start.
|
xue@1
|
229 */
|
xue@1
|
230 double* NewddWindow(WindowType wt, int Count, int* ips, double* dps, double* newddwindow)
|
xue@1
|
231 {
|
xue@1
|
232 double* Result=newddwindow; if (!Result) Result=new double[Count+1];
|
xue@1
|
233 double piiCount=M_PI/Count;
|
xue@1
|
234 double piC2=piiCount*piiCount;
|
xue@1
|
235 switch(wt)
|
xue@1
|
236 {
|
xue@1
|
237 case wtRectangle:
|
xue@1
|
238 memset(Result, 0, sizeof(double)*(Count+1));
|
xue@1
|
239 break;
|
xue@1
|
240 case wtTriangular:
|
xue@1
|
241 throw("Trying to double-differentiate triangular window.");
|
xue@1
|
242 break;
|
xue@1
|
243 case wtHamming:
|
xue@1
|
244 for (int i=0; i<=Count; i++)
|
xue@1
|
245 Result[i]=1.84*piC2*cos(2*piiCount*i);
|
xue@1
|
246 break;
|
xue@1
|
247 case wtBlackman:
|
xue@1
|
248 for (int i=0; i<=Count; i++)
|
xue@1
|
249 Result[i]=2*piC2*cos(2*piiCount*i)-1.28*piC2*cos(4*piiCount*i);
|
xue@1
|
250 break;
|
xue@1
|
251 case wtGaussian:
|
xue@1
|
252 throw("Trying to double-differentiate Gaussian window.");
|
xue@1
|
253 break;
|
xue@1
|
254 case wtKaiser:
|
xue@1
|
255 throw("Trying to double-differentiate Kaiser window.");
|
xue@1
|
256 break;
|
xue@1
|
257 case wtHalfCosine:
|
xue@1
|
258 {
|
xue@1
|
259 for (int i=0; i<=Count; i++)
|
xue@1
|
260 Result[i]=-piC2*sin(piiCount*i);
|
xue@1
|
261 break;
|
xue@1
|
262 }
|
xue@1
|
263 case wtHann:
|
xue@1
|
264 {
|
xue@1
|
265 for (int i=0; i<=Count; i++)
|
xue@1
|
266 Result[i]=2*piC2*cos(2*piiCount*i);
|
xue@1
|
267 break;
|
xue@1
|
268 }
|
xue@1
|
269 case wtHannSqr:
|
xue@1
|
270 {
|
xue@1
|
271 for (int i=0; i<=Count; i++)
|
xue@1
|
272 Result[i]=2*piC2*cos(2*piiCount*i)-2*piC2*cos(4*piiCount*i);
|
xue@1
|
273 break;
|
xue@1
|
274 }
|
xue@1
|
275 case wtHann3sqrt:
|
xue@1
|
276 {
|
xue@1
|
277 for (int i=0; i<=Count; i++)
|
xue@1
|
278 {
|
xue@1
|
279 double s=sin(M_PI*i/Count), c=cos(M_PI*i/Count);
|
xue@1
|
280 Result[i]=3*piC2*(2*c*c-s*s)*s;
|
xue@1
|
281 }
|
xue@1
|
282 break;
|
xue@1
|
283 }
|
xue@1
|
284 }
|
xue@1
|
285 return Result;
|
xue@1
|
286 }//NewddWindow
|
xue@1
|
287
|
Chris@5
|
288 /**
|
xue@1
|
289 function NewdddWindow: computes the 3rd-order derivative of a window function.
|
xue@1
|
290 In: wt: window type
|
xue@1
|
291 Count: window size
|
xue@1
|
292 ips & ups: extra window specificatin parameters
|
xue@1
|
293 Out: newdddwindow[Count+1]: the 3rd-order derivative window function.
|
xue@1
|
294
|
xue@1
|
295 Returns pointer to newdddwindow. newdddwindow is created anew if newdddwindow=0 is specified on start.
|
xue@1
|
296 */
|
xue@1
|
297 double* NewdddWindow(WindowType wt, int Count, int* ips, double* dps, double* newdddwindow)
|
xue@1
|
298 {
|
xue@1
|
299 double* Result=newdddwindow; if (!Result) Result=new double[Count+1];
|
xue@1
|
300 double piiCount=M_PI/Count;
|
xue@1
|
301 double piC2=piiCount*piiCount;
|
xue@1
|
302 double piC3=piiCount*piC2;
|
xue@1
|
303 switch(wt)
|
xue@1
|
304 {
|
xue@1
|
305 case wtRectangle:
|
xue@1
|
306 memset(Result, 0, sizeof(double)*(Count+1));
|
xue@1
|
307 break;
|
xue@1
|
308 case wtTriangular:
|
xue@1
|
309 throw("Trying to triple-differentiate triangular window.");
|
xue@1
|
310 break;
|
xue@1
|
311 case wtHamming:
|
xue@1
|
312 for (int i=0; i<=Count; i++)
|
xue@1
|
313 Result[i]=-3.68*piC3*sin(2*piiCount*i);
|
xue@1
|
314 break;
|
xue@1
|
315 case wtBlackman:
|
xue@1
|
316 for (int i=0; i<=Count; i++)
|
xue@1
|
317 Result[i]=-4*piC3*sin(2*piiCount*i)+5.12*piC3*sin(4*piiCount*i);
|
xue@1
|
318 break;
|
xue@1
|
319 case wtGaussian:
|
xue@1
|
320 throw("Trying to triple-differentiate Gaussian window.");
|
xue@1
|
321 break;
|
xue@1
|
322 case wtKaiser:
|
xue@1
|
323 throw("Trying to triple-differentiate Kaiser window.");
|
xue@1
|
324 break;
|
xue@1
|
325 case wtHalfCosine:
|
xue@1
|
326 {
|
xue@1
|
327 for (int i=0; i<=Count; i++)
|
xue@1
|
328 Result[i]=-piC3*cos(piiCount*i);
|
xue@1
|
329 break;
|
xue@1
|
330 }
|
xue@1
|
331 case wtHann:
|
xue@1
|
332 {
|
xue@1
|
333 for (int i=0; i<=Count; i++)
|
xue@1
|
334 Result[i]=-4*piC3*sin(2*piiCount*i);
|
xue@1
|
335 break;
|
xue@1
|
336 }
|
xue@1
|
337 case wtHannSqr:
|
xue@1
|
338 {
|
xue@1
|
339 for (int i=0; i<=Count; i++)
|
xue@1
|
340 Result[i]=-4*piC3*sin(2*piiCount*i)+8*piC3*sin(4*piiCount*i);
|
xue@1
|
341 break;
|
xue@1
|
342 }
|
xue@1
|
343 case wtHann3sqrt:
|
xue@1
|
344 throw("Trying to triple-differentiate Hann^1.5 window.");
|
xue@1
|
345 break;
|
xue@1
|
346 }
|
xue@1
|
347 return Result;
|
xue@1
|
348 }//NewdddWindow
|
xue@1
|
349
|
xue@1
|
350 //---------------------------------------------------------------------------
|
Chris@5
|
351 /**
|
xue@1
|
352 function windowspec: computes a few descriptors of a cosine family window. A window function in the
|
xue@1
|
353 cosine window family is the linear combination of a few cosine functions, therefore has a cosine
|
xue@1
|
354 decomposition.
|
xue@1
|
355
|
xue@1
|
356 In: wt: window type
|
xue@1
|
357 N: window size
|
xue@1
|
358 Out: c[M+1], coefficients of cosine decomposition
|
xue@1
|
359 iH2: reciprocal of square of L2 norm,
|
xue@1
|
360 d[2M+1]: self-convolution of c[], optional
|
xue@1
|
361
|
xue@1
|
362 No return value.
|
xue@1
|
363 */
|
xue@1
|
364 void windowspec(WindowType wt, int N, int* M, double* c, double* iH2, double* d)
|
xue@1
|
365 {
|
xue@1
|
366 switch(wt)
|
xue@1
|
367 {
|
xue@1
|
368 case wtRectangle:
|
xue@1
|
369 M[0]=0, c[0]=1, iH2[0]=1.0/N/N;
|
xue@1
|
370 if (d) d[0]=1;
|
xue@1
|
371 break;
|
xue@1
|
372 case wtHamming:
|
xue@1
|
373 M[0]=1, c[0]=0.54, c[1]=0.23, iH2[0]=1.0/(0.3974*N*N);
|
xue@1
|
374 if (d) d[0]=0.3974, d[1]=0.2484, d[2]=0.0529;
|
xue@1
|
375 break;
|
xue@1
|
376 case wtBlackman:
|
xue@1
|
377 M[0]=2, c[0]=0.42, c[1]=0.25, c[2]=0.04, iH2[0]=1.0/(0.3046*N*N);
|
xue@1
|
378 if (d) d[0]=0.3046, d[1]=0.23, d[2]=0.0961, d[4]=0.02, d[5]=0.0016;
|
xue@1
|
379 break;
|
xue@1
|
380 case wtHann:
|
xue@1
|
381 M[0]=1, c[0]=0.5, c[1]=0.25, iH2[0]=1.0/(0.375*N*N);
|
xue@1
|
382 if (d) d[0]=0.375, d[1]=0.25, d[2]=0.0625;
|
xue@1
|
383 break;
|
xue@1
|
384 default:
|
xue@1
|
385 M[0]=1, c[0]=0.5, c[1]=0.25, iH2[0]=1.0/(0.375*N*N);
|
xue@1
|
386 if (d) d[0]=0.375, d[1]=0.25, d[2]=0.0625;
|
xue@1
|
387 break;
|
xue@1
|
388 }
|
xue@1
|
389 }//windowspec
|