annotate 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
rev   line source
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