tomwalters@0
|
1 /***************************************************************************
|
tomwalters@0
|
2 pitch_strength.c Pitch strength measure from spiral sector-weights contour.
|
tomwalters@0
|
3 ----------------
|
tomwalters@0
|
4 Michael Allerhand, 1992.
|
tomwalters@0
|
5
|
tomwalters@0
|
6 Read m binary shorts (default m=SECTORS) for each specified frame.
|
tomwalters@0
|
7 Compute the pitch-strength of the sector-weights by projecting onto
|
tomwalters@0
|
8 the direction in the sector-weights space (given by vector `vec')
|
tomwalters@0
|
9 which best explains the variation between weak and strong pitch,
|
tomwalters@0
|
10 as exemplified by training data generated from iterated rippled noise.
|
tomwalters@0
|
11
|
tomwalters@0
|
12 The sector weights are normalized with respect to angle (pitch) and
|
tomwalters@0
|
13 magnitude (loudness), and also by extracting features using the
|
tomwalters@0
|
14 method of Fourier descriptors.
|
tomwalters@0
|
15
|
tomwalters@0
|
16 ****************************************************************************/
|
tomwalters@0
|
17
|
tomwalters@0
|
18 #include <stdio.h>
|
tomwalters@0
|
19 #include <math.h>
|
tomwalters@0
|
20 #include "options.h"
|
tomwalters@0
|
21 #include "units.h"
|
tomwalters@0
|
22 #include "strmatch.h"
|
tomwalters@0
|
23
|
tomwalters@0
|
24 char applic[] = "Pitch-strength measure from spiral sector-weights contour.\n (Input and output in binary shorts)." ;
|
tomwalters@0
|
25
|
tomwalters@0
|
26 static char *helpstr, *debugstr, *fstr, *vstr, *mstr, *shiftstr, *scalestr ;
|
tomwalters@0
|
27
|
tomwalters@0
|
28 static Options option[] = {
|
tomwalters@0
|
29 { "help" , "off" , &helpstr , "help" , DEBUG },
|
tomwalters@0
|
30 { "debug" , "off" , &debugstr , "debugging switch" , DEBUG },
|
tomwalters@0
|
31 { "frames" , "1-max" , &fstr , "select frames inclusively" , VAL },
|
tomwalters@0
|
32 { "nsectors" , "64" , &mstr , "number of sectors" , SVAL },
|
tomwalters@0
|
33 { "vector" , "off" , &vstr , "file for alternative projection vector", SVAL },
|
tomwalters@0
|
34 { "shift" , "212.0" , &shiftstr , "scale shifting by addition" , SVAL },
|
tomwalters@0
|
35 { "scale" , "0.7686" , &scalestr , "scaling by multiplication" , SVAL },
|
tomwalters@0
|
36 ( char * ) 0 } ;
|
tomwalters@0
|
37
|
tomwalters@0
|
38
|
tomwalters@0
|
39 /* projection vector for 64-sector cntour */
|
tomwalters@0
|
40
|
tomwalters@0
|
41 char *defvec[] = { "0.000", "0.150", "-0.260", "-0.190", "-0.252", "-0.372", "-0.121",
|
tomwalters@0
|
42 "-0.374", "-0.150", "-0.236", "-0.157", "-0.109", "-0.246", "-0.088",
|
tomwalters@0
|
43 "-0.045", "-0.179", "-0.164", "-0.280", "-0.028", "-0.116", "-0.013",
|
tomwalters@0
|
44 "-0.065", "-0.252", "-0.005", "-0.216", "-0.086", "0.043", "-0.061",
|
tomwalters@0
|
45 "-0.055", "0.084", "-0.045", "-0.203", "211.670" } ;
|
tomwalters@0
|
46
|
tomwalters@0
|
47
|
tomwalters@0
|
48 float shift, scale ;
|
tomwalters@0
|
49
|
tomwalters@0
|
50
|
tomwalters@0
|
51 main (argc, argv)
|
tomwalters@0
|
52 int argc;
|
tomwalters@0
|
53 char ** argv;
|
tomwalters@0
|
54 {
|
tomwalters@0
|
55 FILE *fp, *fp1 ;
|
tomwalters@0
|
56 int m, n; /* Number of sectors around spiral. */
|
tomwalters@0
|
57 short *sector; /* Sector-weights contour. */
|
tomwalters@0
|
58 float *vec;
|
tomwalters@0
|
59 int i, a, b;
|
tomwalters@0
|
60 char *val1, *val2 ;
|
tomwalters@0
|
61
|
tomwalters@0
|
62 fp = openopts( option,argc,argv ) ;
|
tomwalters@0
|
63 if ( !isoff( helpstr ) )
|
tomwalters@0
|
64 helpopts( helpstr, argv[0], applic, option ) ;
|
tomwalters@0
|
65
|
tomwalters@0
|
66 shift = atof( shiftstr ) ;
|
tomwalters@0
|
67 scale = atof( scalestr ) ;
|
tomwalters@0
|
68
|
tomwalters@0
|
69 m = atoi( mstr ) ;
|
tomwalters@0
|
70 n = m>>1 ;
|
tomwalters@0
|
71
|
tomwalters@0
|
72 /* parse bounds on number of frames */
|
tomwalters@0
|
73
|
tomwalters@0
|
74 if ( getvals( fstr, &val1, &val2, "-" ) == BADVAL ) {
|
tomwalters@0
|
75 fprintf(stderr,"loudness: bad frame selector [%s]\n", fstr ) ;
|
tomwalters@0
|
76 exit( 1 ) ;
|
tomwalters@0
|
77 }
|
tomwalters@0
|
78 a = atoi( val1 ) ;
|
tomwalters@0
|
79 if ( isempty( val2 ) ) b = a ;
|
tomwalters@0
|
80 else if ( ismax( val2 ) ) b = 0 ;
|
tomwalters@0
|
81 else b = atoi( val2 ) ;
|
tomwalters@0
|
82
|
tomwalters@0
|
83 if (b<a && b>0) fprintf(stderr,"pitch_strength: warning, bad frame specifiers\n");
|
tomwalters@0
|
84
|
tomwalters@0
|
85 if ( ison( debugstr ) ) {
|
tomwalters@0
|
86 printf("a=%d b=%d m=%d vector=%s\n",
|
tomwalters@0
|
87 a, b, m, vstr );
|
tomwalters@0
|
88 exit(0);
|
tomwalters@0
|
89 }
|
tomwalters@0
|
90
|
tomwalters@0
|
91
|
tomwalters@0
|
92 /* Allocate space for sector-weights contour and discriminant vector */
|
tomwalters@0
|
93
|
tomwalters@0
|
94 if (( sector = (short *)malloc( m*sizeof(short) )) == NULL)
|
tomwalters@0
|
95 fprintf(stderr,"pitch_strength: malloc out of space\n");
|
tomwalters@0
|
96 if (( vec = (float *)malloc( (n+1)*sizeof(float) )) == NULL)
|
tomwalters@0
|
97 fprintf(stderr,"pitch_strength: malloc out of space\n");
|
tomwalters@0
|
98
|
tomwalters@0
|
99
|
tomwalters@0
|
100 /* Assign discriminant vector */
|
tomwalters@0
|
101
|
tomwalters@0
|
102 if ( isoff( vstr) ) /* copy internal (default) vector */
|
tomwalters@0
|
103 for (i=0 ; i<=n ; i++)
|
tomwalters@0
|
104 vec[i] = atof( defvec[i] ) ;
|
tomwalters@0
|
105 else { /* read alternative vector from file */
|
tomwalters@0
|
106 if ((fp1 = fopen( vstr, "r" )) == NULL) {
|
tomwalters@0
|
107 fprintf(stderr,"pitch_strength: can't open %s\n", vstr );
|
tomwalters@0
|
108 exit(1);
|
tomwalters@0
|
109 }
|
tomwalters@0
|
110 if ( fread(vec, sizeof(float), n+1, fp1) == NULL ) {
|
tomwalters@0
|
111 fprintf(stderr,"pitch_strength: empty discriminant vector\n");
|
tomwalters@0
|
112 exit(1);
|
tomwalters@0
|
113 }
|
tomwalters@0
|
114 fclose(fp1);
|
tomwalters@0
|
115 }
|
tomwalters@0
|
116
|
tomwalters@0
|
117
|
tomwalters@0
|
118 /* Seek past a-1 frames, then read the next b-a+1 frames, or all */
|
tomwalters@0
|
119 /* remaining frames if b==0. */
|
tomwalters@0
|
120
|
tomwalters@0
|
121 if (a>0) {
|
tomwalters@0
|
122
|
tomwalters@0
|
123 for (i=1 ; i<a && fread(sector,sizeof(short),m,fp) ; i++)
|
tomwalters@0
|
124 ;
|
tomwalters@0
|
125 if (b > 0)
|
tomwalters@0
|
126 for ( ; i<=b && fread(sector,sizeof(short),m,fp) ; i++)
|
tomwalters@0
|
127 pitch_strength( sector, m, n, vec );
|
tomwalters@0
|
128 else
|
tomwalters@0
|
129 while ( fread(sector,sizeof(short),m,fp) )
|
tomwalters@0
|
130 pitch_strength( sector, m, n, vec );
|
tomwalters@0
|
131 }
|
tomwalters@0
|
132
|
tomwalters@0
|
133 fclose(fp);
|
tomwalters@0
|
134 }
|
tomwalters@0
|
135
|
tomwalters@0
|
136
|
tomwalters@0
|
137 pitch_strength( sector, m, n, vec )
|
tomwalters@0
|
138 short *sector; /* Sector-weights contour. */
|
tomwalters@0
|
139 int m, n; /* Number of sectors around spiral. */
|
tomwalters@0
|
140 float *vec;
|
tomwalters@0
|
141 {
|
tomwalters@0
|
142 float inner_product();
|
tomwalters@0
|
143 short w0;
|
tomwalters@0
|
144
|
tomwalters@0
|
145 normalize_scale(sector,m);
|
tomwalters@0
|
146 normalize_angle(sector,m);
|
tomwalters@0
|
147 Fd(sector,m,n);
|
tomwalters@0
|
148 sector[0] = 0; /* normalize for translation */
|
tomwalters@0
|
149 sector[n] = 1; /* Augment each data vector with 1 */
|
tomwalters@0
|
150 w0 = (short)( ( shift - inner_product( vec, sector, n+1 ) ) * scale ) ;
|
tomwalters@0
|
151 fwrite (&w0, sizeof(short), 1, stdout);
|
tomwalters@0
|
152 }
|
tomwalters@0
|
153
|
tomwalters@0
|
154
|
tomwalters@0
|
155 /****************************************************************************
|
tomwalters@0
|
156 Inner product (for projection).
|
tomwalters@0
|
157 ****************************************************************************/
|
tomwalters@0
|
158
|
tomwalters@0
|
159 float inner_product(W,V,m)
|
tomwalters@0
|
160 float *W;
|
tomwalters@0
|
161 short *V;
|
tomwalters@0
|
162 int m;
|
tomwalters@0
|
163 {
|
tomwalters@0
|
164 int i;
|
tomwalters@0
|
165 float w0=0;
|
tomwalters@0
|
166
|
tomwalters@0
|
167 for (i=0 ; i<m ; i++)
|
tomwalters@0
|
168 w0 += W[i] * V[i];
|
tomwalters@0
|
169 return w0;
|
tomwalters@0
|
170 }
|
tomwalters@0
|
171
|
tomwalters@0
|
172
|
tomwalters@0
|
173 /****************************************************************************
|
tomwalters@0
|
174 Normalize Scale.
|
tomwalters@0
|
175 ****************************************************************************/
|
tomwalters@0
|
176
|
tomwalters@0
|
177 /*
|
tomwalters@0
|
178 Normalize for unit variance and zero mean, and then scale for MEAN and STDDEV.
|
tomwalters@0
|
179 In general the stddev is scaled down to STDDEV, but if the stddev is already
|
tomwalters@0
|
180 less than the target STDDEV, than it is left alone.
|
tomwalters@0
|
181 */
|
tomwalters@0
|
182
|
tomwalters@0
|
183 #define MEAN 100
|
tomwalters@0
|
184 #define STDDEV 32 /* Resulting variance will be this squared */
|
tomwalters@0
|
185
|
tomwalters@0
|
186 normalize_scale(V,m)
|
tomwalters@0
|
187 short *V;
|
tomwalters@0
|
188 int m;
|
tomwalters@0
|
189 {
|
tomwalters@0
|
190 int i;
|
tomwalters@0
|
191 float mean, var;
|
tomwalters@0
|
192 float sum, sumsq, stddev, norm;
|
tomwalters@0
|
193
|
tomwalters@0
|
194 sum=0; sumsq=0;
|
tomwalters@0
|
195 for (i=0 ; i<m ; i++) {
|
tomwalters@0
|
196 sum += V[i];
|
tomwalters@0
|
197 sumsq += V[i] * V[i];
|
tomwalters@0
|
198 }
|
tomwalters@0
|
199 mean = sum/m;
|
tomwalters@0
|
200 var = sumsq/m - mean*mean;
|
tomwalters@0
|
201
|
tomwalters@0
|
202 if ((stddev = sqrt(var)) >= STDDEV)
|
tomwalters@0
|
203 for (i=0 ; i<m ; i++) {
|
tomwalters@0
|
204 norm = ( (float)V[i] - mean ) / stddev;
|
tomwalters@0
|
205 V[i] = norm * STDDEV + MEAN;
|
tomwalters@0
|
206 }
|
tomwalters@0
|
207 else
|
tomwalters@0
|
208 for (i=0 ; i<m ; i++) {
|
tomwalters@0
|
209 norm = (float)V[i]-mean;
|
tomwalters@0
|
210 V[i] = norm + MEAN;
|
tomwalters@0
|
211 }
|
tomwalters@0
|
212
|
tomwalters@0
|
213 return (int)mean;
|
tomwalters@0
|
214 }
|
tomwalters@0
|
215
|
tomwalters@0
|
216
|
tomwalters@0
|
217 /****************************************************************************
|
tomwalters@0
|
218 Normalize Angle (orientation).
|
tomwalters@0
|
219 ****************************************************************************/
|
tomwalters@0
|
220
|
tomwalters@0
|
221 /*
|
tomwalters@0
|
222 For a given spoke number k (where the primary spoke is number 1, and the
|
tomwalters@0
|
223 subsequent spokes are numbered 2,3,...,m), return the angle as a number of
|
tomwalters@0
|
224 sectors from the primary spoke.
|
tomwalters@0
|
225 In general, the angle between the primary spoke and the k'th spoke is
|
tomwalters@0
|
226 given by the fractional part of log2(2k-1). This angle is a fraction of
|
tomwalters@0
|
227 unity (the complete cycle), so in terms of m sectors, we simply multiply up
|
tomwalters@0
|
228 by m.
|
tomwalters@0
|
229 */
|
tomwalters@0
|
230
|
tomwalters@0
|
231 #define log2(x) (log((double)x)/log(2.0))
|
tomwalters@0
|
232
|
tomwalters@0
|
233 angle(k,m)
|
tomwalters@0
|
234 short k, m;
|
tomwalters@0
|
235 {
|
tomwalters@0
|
236 double theta, fptr, iptr;
|
tomwalters@0
|
237
|
tomwalters@0
|
238 if (k==0) return 0;
|
tomwalters@0
|
239 theta = log2(2*k-1);
|
tomwalters@0
|
240 fptr = modf(theta,&iptr); /* find fractional part of log time */
|
tomwalters@0
|
241 /* scale up to given resolution, and round */
|
tomwalters@0
|
242 return ((int)(0.5+(fptr*m)));
|
tomwalters@0
|
243 }
|
tomwalters@0
|
244
|
tomwalters@0
|
245
|
tomwalters@0
|
246 /*
|
tomwalters@0
|
247 Normalize orientation.
|
tomwalters@0
|
248 Find the orientation by rotating a template of four sectors set at relative
|
tomwalters@0
|
249 angles appropriate to the first four spokes, (as the angle between spokes is
|
tomwalters@0
|
250 known). The angle at which the weighted sum of these sectors is a maximum,
|
tomwalters@0
|
251 as it is rotated, gives the orientation of the sector-weights contour.
|
tomwalters@0
|
252 This angle of orientation, phi, is returned.
|
tomwalters@0
|
253 The sector-weights contour is normalized by rotating, (ie sorting), so that
|
tomwalters@0
|
254 the principal spoke, (the first of the four), is in the datum position, (at
|
tomwalters@0
|
255 sector[0]).
|
tomwalters@0
|
256 */
|
tomwalters@0
|
257
|
tomwalters@0
|
258 int normalize_angle(sector,m)
|
tomwalters@0
|
259 short *sector;
|
tomwalters@0
|
260 int m; /* number of sectors */
|
tomwalters@0
|
261 {
|
tomwalters@0
|
262 int i, k, phi;
|
tomwalters@0
|
263 float q, max;
|
tomwalters@0
|
264 short *tmp; /* temporary array for sorting */
|
tomwalters@0
|
265
|
tomwalters@0
|
266 /* Find angle of orientation phi */
|
tomwalters@0
|
267
|
tomwalters@0
|
268 phi = 0; max = 0;
|
tomwalters@0
|
269 for (k=0 ; k<m ; k++) {
|
tomwalters@0
|
270 q = (float)sector[k] + 0.8*(float)sector[(k+angle(2,m))%m] +
|
tomwalters@0
|
271 0.6*(float)sector[(k+angle(3,m))%m] + 0.4*(float)sector[(k+angle(4,m))%m] ;
|
tomwalters@0
|
272
|
tomwalters@0
|
273 if (q > max) {
|
tomwalters@0
|
274 max = q;
|
tomwalters@0
|
275 phi = k;
|
tomwalters@0
|
276 }
|
tomwalters@0
|
277 }
|
tomwalters@0
|
278
|
tomwalters@0
|
279 /* Sort sector array to rotate contour into normalized orientation */
|
tomwalters@0
|
280
|
tomwalters@0
|
281 if (( tmp = (short *)malloc(m*sizeof(short))) == NULL)
|
tomwalters@0
|
282 fprintf(stderr,"pitch_strength: malloc out of space\n");
|
tomwalters@0
|
283
|
tomwalters@0
|
284 for (i=0, k=phi ; k<m ; i++, k++)
|
tomwalters@0
|
285 tmp[i] = sector[k];
|
tomwalters@0
|
286 for (k=0 ; k<phi ; i++, k++)
|
tomwalters@0
|
287 tmp[i] = sector[k];
|
tomwalters@0
|
288 for (k=0 ; k<m ; k++)
|
tomwalters@0
|
289 sector[k] = tmp[k];
|
tomwalters@0
|
290
|
tomwalters@0
|
291 /* Return orientation, (angle increases clockwise from 0 to m-1) */
|
tomwalters@0
|
292
|
tomwalters@0
|
293 if (phi == 0) return 0;
|
tomwalters@0
|
294 else return ( m-phi );
|
tomwalters@0
|
295
|
tomwalters@0
|
296 }
|
tomwalters@0
|
297
|
tomwalters@0
|
298
|
tomwalters@0
|
299 /****************************************************************************
|
tomwalters@0
|
300 Map m sector-weights onto m/2 Fourier descriptors.
|
tomwalters@0
|
301 ****************************************************************************/
|
tomwalters@0
|
302
|
tomwalters@0
|
303 typedef struct {
|
tomwalters@0
|
304 float real;
|
tomwalters@0
|
305 float imag;
|
tomwalters@0
|
306 } complex;
|
tomwalters@0
|
307
|
tomwalters@0
|
308 #define PI 3.14159265
|
tomwalters@0
|
309 #define TWOPI 6.2831853
|
tomwalters@0
|
310 #define sq(x) ((x)*(x))
|
tomwalters@0
|
311 #define Re(C) ( (C)->real ) /* cartesian form */
|
tomwalters@0
|
312 #define Im(C) ( (C)->imag )
|
tomwalters@0
|
313 #define Mod(C) ( (C)->real ) /* polar form */
|
tomwalters@0
|
314 #define Arg(C) ( (C)->imag )
|
tomwalters@0
|
315 #define cscalar_mod(C) ( sqrt(sq(Re(C))+sq(Im(C))) )
|
tomwalters@0
|
316 #define FFT_real(V,n) ( realft((float *)(V)-1, n>>1 ,1) )
|
tomwalters@0
|
317
|
tomwalters@0
|
318
|
tomwalters@0
|
319 Fd(sector,m,n)
|
tomwalters@0
|
320 short *sector;
|
tomwalters@0
|
321 int m, n;
|
tomwalters@0
|
322 {
|
tomwalters@0
|
323 static float *V;
|
tomwalters@0
|
324 static char first=1;
|
tomwalters@0
|
325 int i, j;
|
tomwalters@0
|
326
|
tomwalters@0
|
327 if (first) { /* Allocate space first time only */
|
tomwalters@0
|
328 if (( V = (float *) malloc( m*sizeof(float) )) == NULL) {
|
tomwalters@0
|
329 fprintf(stderr,"pitch_strength: malloc out of space\n");
|
tomwalters@0
|
330 exit(1);
|
tomwalters@0
|
331 }
|
tomwalters@0
|
332 first=0;
|
tomwalters@0
|
333 }
|
tomwalters@0
|
334
|
tomwalters@0
|
335 for (i=0 ; i<m ; i++)
|
tomwalters@0
|
336 V[i] = sector[i] ;
|
tomwalters@0
|
337 FFT_real(V,m);
|
tomwalters@0
|
338 cvector_mod( sector, (complex *)V, n ) ; /* magnitude spectrum */
|
tomwalters@0
|
339
|
tomwalters@0
|
340 }
|
tomwalters@0
|
341
|
tomwalters@0
|
342 cvector_mod(V,C,m)
|
tomwalters@0
|
343 short *V;
|
tomwalters@0
|
344 complex *C;
|
tomwalters@0
|
345 int m;
|
tomwalters@0
|
346 {
|
tomwalters@0
|
347 int i;
|
tomwalters@0
|
348
|
tomwalters@0
|
349 for (i=0; i<m ; i++)
|
tomwalters@0
|
350 V[i] = (short)( cscalar_mod(&C[i]) ) ;
|
tomwalters@0
|
351 }
|
tomwalters@0
|
352
|
tomwalters@0
|
353
|
tomwalters@0
|
354 realft(data,n,isign)
|
tomwalters@0
|
355 float data[];
|
tomwalters@0
|
356 int n,isign;
|
tomwalters@0
|
357 {
|
tomwalters@0
|
358 int i,i1,i2,i3,i4,n2p3;
|
tomwalters@0
|
359 float c1=0.5,c2,h1r,h1i,h2r,h2i;
|
tomwalters@0
|
360 double wr,wi,wpr,wpi,wtemp,theta;
|
tomwalters@0
|
361
|
tomwalters@0
|
362
|
tomwalters@0
|
363 theta=3.141592653589793/(double) n;
|
tomwalters@0
|
364 if (isign == 1) {
|
tomwalters@0
|
365 c2 = -0.5;
|
tomwalters@0
|
366 four1(data,n,1);
|
tomwalters@0
|
367 } else {
|
tomwalters@0
|
368 c2=0.5;
|
tomwalters@0
|
369 theta = -theta;
|
tomwalters@0
|
370 }
|
tomwalters@0
|
371 wtemp=sin(0.5*theta);
|
tomwalters@0
|
372 wpr = -2.0*wtemp*wtemp;
|
tomwalters@0
|
373 wpi=sin(theta);
|
tomwalters@0
|
374 wr=1.0+wpr;
|
tomwalters@0
|
375 wi=wpi;
|
tomwalters@0
|
376 n2p3=2*n+3;
|
tomwalters@0
|
377 for (i=2;i<=n/2;i++) {
|
tomwalters@0
|
378 i4=1+(i3=n2p3-(i2=1+(i1=i+i-1)));
|
tomwalters@0
|
379 h1r=c1*(data[i1]+data[i3]);
|
tomwalters@0
|
380 h1i=c1*(data[i2]-data[i4]);
|
tomwalters@0
|
381 h2r = -c2*(data[i2]+data[i4]);
|
tomwalters@0
|
382 h2i=c2*(data[i1]-data[i3]);
|
tomwalters@0
|
383 data[i1]=h1r+wr*h2r-wi*h2i;
|
tomwalters@0
|
384 data[i2]=h1i+wr*h2i+wi*h2r;
|
tomwalters@0
|
385 data[i3]=h1r-wr*h2r+wi*h2i;
|
tomwalters@0
|
386 data[i4] = -h1i+wr*h2i+wi*h2r;
|
tomwalters@0
|
387 wr=(wtemp=wr)*wpr-wi*wpi+wr;
|
tomwalters@0
|
388 wi=wi*wpr+wtemp*wpi+wi;
|
tomwalters@0
|
389 }
|
tomwalters@0
|
390 if (isign == 1) {
|
tomwalters@0
|
391 data[1] = (h1r=data[1])+data[2];
|
tomwalters@0
|
392 data[2] = h1r-data[2];
|
tomwalters@0
|
393 } else {
|
tomwalters@0
|
394 data[1]=c1*((h1r=data[1])+data[2]);
|
tomwalters@0
|
395 data[2]=c1*(h1r-data[2]);
|
tomwalters@0
|
396 four1(data,n,-1);
|
tomwalters@0
|
397 }
|
tomwalters@0
|
398 }
|
tomwalters@0
|
399
|
tomwalters@0
|
400 #define SWAP(a,b) tempr=(a);(a)=(b);(b)=tempr
|
tomwalters@0
|
401
|
tomwalters@0
|
402 four1(data,nn,isign)
|
tomwalters@0
|
403 float data[];
|
tomwalters@0
|
404 int nn,isign;
|
tomwalters@0
|
405 {
|
tomwalters@0
|
406 int n,mmax,m,j,istep,i;
|
tomwalters@0
|
407 double wtemp,wr,wpr,wpi,wi,theta;
|
tomwalters@0
|
408 float tempr,tempi;
|
tomwalters@0
|
409
|
tomwalters@0
|
410 n=nn << 1;
|
tomwalters@0
|
411 j=1;
|
tomwalters@0
|
412 for (i=1;i<n;i+=2) {
|
tomwalters@0
|
413 if (j > i) {
|
tomwalters@0
|
414 SWAP(data[j],data[i]);
|
tomwalters@0
|
415 SWAP(data[j+1],data[i+1]);
|
tomwalters@0
|
416 }
|
tomwalters@0
|
417 m=n >> 1;
|
tomwalters@0
|
418 while (m >= 2 && j > m) {
|
tomwalters@0
|
419 j -= m;
|
tomwalters@0
|
420 m >>= 1;
|
tomwalters@0
|
421 }
|
tomwalters@0
|
422 j += m;
|
tomwalters@0
|
423 }
|
tomwalters@0
|
424 mmax=2;
|
tomwalters@0
|
425 while (n > mmax) {
|
tomwalters@0
|
426 istep=2*mmax;
|
tomwalters@0
|
427 theta=6.28318530717959/(isign*mmax);
|
tomwalters@0
|
428 wtemp=sin(0.5*theta);
|
tomwalters@0
|
429 wpr = -2.0*wtemp*wtemp;
|
tomwalters@0
|
430 wpi=sin(theta);
|
tomwalters@0
|
431 wr=1.0;
|
tomwalters@0
|
432 wi=0.0;
|
tomwalters@0
|
433 for (m=1;m<mmax;m+=2) {
|
tomwalters@0
|
434 for (i=m;i<=n;i+=istep) {
|
tomwalters@0
|
435 j=i+mmax;
|
tomwalters@0
|
436 tempr=wr*data[j]-wi*data[j+1];
|
tomwalters@0
|
437 tempi=wr*data[j+1]+wi*data[j];
|
tomwalters@0
|
438 data[j]=data[i]-tempr;
|
tomwalters@0
|
439 data[j+1]=data[i+1]-tempi;
|
tomwalters@0
|
440 data[i] += tempr;
|
tomwalters@0
|
441 data[i+1] += tempi;
|
tomwalters@0
|
442 }
|
tomwalters@0
|
443 wr=(wtemp=wr)*wpr-wi*wpi+wr;
|
tomwalters@0
|
444 wi=wi*wpr+wtemp*wpi+wi;
|
tomwalters@0
|
445 }
|
tomwalters@0
|
446 mmax=istep;
|
tomwalters@0
|
447 }
|
tomwalters@0
|
448 }
|
tomwalters@0
|
449
|