comparison tools/pitch_strength.c @ 0:5242703e91d3 tip

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