Mercurial > hg > aim92
view 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 |
line wrap: on
line source
/*************************************************************************** pitch_strength.c Pitch strength measure from spiral sector-weights contour. ---------------- Michael Allerhand, 1992. Read m binary shorts (default m=SECTORS) for each specified frame. Compute the pitch-strength of the sector-weights by projecting onto the direction in the sector-weights space (given by vector `vec') which best explains the variation between weak and strong pitch, as exemplified by training data generated from iterated rippled noise. The sector weights are normalized with respect to angle (pitch) and magnitude (loudness), and also by extracting features using the method of Fourier descriptors. ****************************************************************************/ #include <stdio.h> #include <math.h> #include "options.h" #include "units.h" #include "strmatch.h" char applic[] = "Pitch-strength measure from spiral sector-weights contour.\n (Input and output in binary shorts)." ; static char *helpstr, *debugstr, *fstr, *vstr, *mstr, *shiftstr, *scalestr ; static Options option[] = { { "help" , "off" , &helpstr , "help" , DEBUG }, { "debug" , "off" , &debugstr , "debugging switch" , DEBUG }, { "frames" , "1-max" , &fstr , "select frames inclusively" , VAL }, { "nsectors" , "64" , &mstr , "number of sectors" , SVAL }, { "vector" , "off" , &vstr , "file for alternative projection vector", SVAL }, { "shift" , "212.0" , &shiftstr , "scale shifting by addition" , SVAL }, { "scale" , "0.7686" , &scalestr , "scaling by multiplication" , SVAL }, ( char * ) 0 } ; /* projection vector for 64-sector cntour */ char *defvec[] = { "0.000", "0.150", "-0.260", "-0.190", "-0.252", "-0.372", "-0.121", "-0.374", "-0.150", "-0.236", "-0.157", "-0.109", "-0.246", "-0.088", "-0.045", "-0.179", "-0.164", "-0.280", "-0.028", "-0.116", "-0.013", "-0.065", "-0.252", "-0.005", "-0.216", "-0.086", "0.043", "-0.061", "-0.055", "0.084", "-0.045", "-0.203", "211.670" } ; float shift, scale ; main (argc, argv) int argc; char ** argv; { FILE *fp, *fp1 ; int m, n; /* Number of sectors around spiral. */ short *sector; /* Sector-weights contour. */ float *vec; int i, a, b; char *val1, *val2 ; fp = openopts( option,argc,argv ) ; if ( !isoff( helpstr ) ) helpopts( helpstr, argv[0], applic, option ) ; shift = atof( shiftstr ) ; scale = atof( scalestr ) ; m = atoi( mstr ) ; n = m>>1 ; /* parse bounds on number of frames */ if ( getvals( fstr, &val1, &val2, "-" ) == BADVAL ) { fprintf(stderr,"loudness: bad frame selector [%s]\n", fstr ) ; exit( 1 ) ; } a = atoi( val1 ) ; if ( isempty( val2 ) ) b = a ; else if ( ismax( val2 ) ) b = 0 ; else b = atoi( val2 ) ; if (b<a && b>0) fprintf(stderr,"pitch_strength: warning, bad frame specifiers\n"); if ( ison( debugstr ) ) { printf("a=%d b=%d m=%d vector=%s\n", a, b, m, vstr ); exit(0); } /* Allocate space for sector-weights contour and discriminant vector */ if (( sector = (short *)malloc( m*sizeof(short) )) == NULL) fprintf(stderr,"pitch_strength: malloc out of space\n"); if (( vec = (float *)malloc( (n+1)*sizeof(float) )) == NULL) fprintf(stderr,"pitch_strength: malloc out of space\n"); /* Assign discriminant vector */ if ( isoff( vstr) ) /* copy internal (default) vector */ for (i=0 ; i<=n ; i++) vec[i] = atof( defvec[i] ) ; else { /* read alternative vector from file */ if ((fp1 = fopen( vstr, "r" )) == NULL) { fprintf(stderr,"pitch_strength: can't open %s\n", vstr ); exit(1); } if ( fread(vec, sizeof(float), n+1, fp1) == NULL ) { fprintf(stderr,"pitch_strength: empty discriminant vector\n"); exit(1); } fclose(fp1); } /* Seek past a-1 frames, then read the next b-a+1 frames, or all */ /* remaining frames if b==0. */ if (a>0) { for (i=1 ; i<a && fread(sector,sizeof(short),m,fp) ; i++) ; if (b > 0) for ( ; i<=b && fread(sector,sizeof(short),m,fp) ; i++) pitch_strength( sector, m, n, vec ); else while ( fread(sector,sizeof(short),m,fp) ) pitch_strength( sector, m, n, vec ); } fclose(fp); } pitch_strength( sector, m, n, vec ) short *sector; /* Sector-weights contour. */ int m, n; /* Number of sectors around spiral. */ float *vec; { float inner_product(); short w0; normalize_scale(sector,m); normalize_angle(sector,m); Fd(sector,m,n); sector[0] = 0; /* normalize for translation */ sector[n] = 1; /* Augment each data vector with 1 */ w0 = (short)( ( shift - inner_product( vec, sector, n+1 ) ) * scale ) ; fwrite (&w0, sizeof(short), 1, stdout); } /**************************************************************************** Inner product (for projection). ****************************************************************************/ float inner_product(W,V,m) float *W; short *V; int m; { int i; float w0=0; for (i=0 ; i<m ; i++) w0 += W[i] * V[i]; return w0; } /**************************************************************************** Normalize Scale. ****************************************************************************/ /* Normalize for unit variance and zero mean, and then scale for MEAN and STDDEV. In general the stddev is scaled down to STDDEV, but if the stddev is already less than the target STDDEV, than it is left alone. */ #define MEAN 100 #define STDDEV 32 /* Resulting variance will be this squared */ normalize_scale(V,m) short *V; int m; { int i; float mean, var; float sum, sumsq, stddev, norm; sum=0; sumsq=0; for (i=0 ; i<m ; i++) { sum += V[i]; sumsq += V[i] * V[i]; } mean = sum/m; var = sumsq/m - mean*mean; if ((stddev = sqrt(var)) >= STDDEV) for (i=0 ; i<m ; i++) { norm = ( (float)V[i] - mean ) / stddev; V[i] = norm * STDDEV + MEAN; } else for (i=0 ; i<m ; i++) { norm = (float)V[i]-mean; V[i] = norm + MEAN; } return (int)mean; } /**************************************************************************** Normalize Angle (orientation). ****************************************************************************/ /* For a given spoke number k (where the primary spoke is number 1, and the subsequent spokes are numbered 2,3,...,m), return the angle as a number of sectors from the primary spoke. In general, the angle between the primary spoke and the k'th spoke is given by the fractional part of log2(2k-1). This angle is a fraction of unity (the complete cycle), so in terms of m sectors, we simply multiply up by m. */ #define log2(x) (log((double)x)/log(2.0)) angle(k,m) short k, m; { double theta, fptr, iptr; if (k==0) return 0; theta = log2(2*k-1); fptr = modf(theta,&iptr); /* find fractional part of log time */ /* scale up to given resolution, and round */ return ((int)(0.5+(fptr*m))); } /* Normalize orientation. Find the orientation by rotating a template of four sectors set at relative angles appropriate to the first four spokes, (as the angle between spokes is known). The angle at which the weighted sum of these sectors is a maximum, as it is rotated, gives the orientation of the sector-weights contour. This angle of orientation, phi, is returned. The sector-weights contour is normalized by rotating, (ie sorting), so that the principal spoke, (the first of the four), is in the datum position, (at sector[0]). */ int normalize_angle(sector,m) short *sector; int m; /* number of sectors */ { int i, k, phi; float q, max; short *tmp; /* temporary array for sorting */ /* Find angle of orientation phi */ phi = 0; max = 0; for (k=0 ; k<m ; k++) { q = (float)sector[k] + 0.8*(float)sector[(k+angle(2,m))%m] + 0.6*(float)sector[(k+angle(3,m))%m] + 0.4*(float)sector[(k+angle(4,m))%m] ; if (q > max) { max = q; phi = k; } } /* Sort sector array to rotate contour into normalized orientation */ if (( tmp = (short *)malloc(m*sizeof(short))) == NULL) fprintf(stderr,"pitch_strength: malloc out of space\n"); for (i=0, k=phi ; k<m ; i++, k++) tmp[i] = sector[k]; for (k=0 ; k<phi ; i++, k++) tmp[i] = sector[k]; for (k=0 ; k<m ; k++) sector[k] = tmp[k]; /* Return orientation, (angle increases clockwise from 0 to m-1) */ if (phi == 0) return 0; else return ( m-phi ); } /**************************************************************************** Map m sector-weights onto m/2 Fourier descriptors. ****************************************************************************/ typedef struct { float real; float imag; } complex; #define PI 3.14159265 #define TWOPI 6.2831853 #define sq(x) ((x)*(x)) #define Re(C) ( (C)->real ) /* cartesian form */ #define Im(C) ( (C)->imag ) #define Mod(C) ( (C)->real ) /* polar form */ #define Arg(C) ( (C)->imag ) #define cscalar_mod(C) ( sqrt(sq(Re(C))+sq(Im(C))) ) #define FFT_real(V,n) ( realft((float *)(V)-1, n>>1 ,1) ) Fd(sector,m,n) short *sector; int m, n; { static float *V; static char first=1; int i, j; if (first) { /* Allocate space first time only */ if (( V = (float *) malloc( m*sizeof(float) )) == NULL) { fprintf(stderr,"pitch_strength: malloc out of space\n"); exit(1); } first=0; } for (i=0 ; i<m ; i++) V[i] = sector[i] ; FFT_real(V,m); cvector_mod( sector, (complex *)V, n ) ; /* magnitude spectrum */ } cvector_mod(V,C,m) short *V; complex *C; int m; { int i; for (i=0; i<m ; i++) V[i] = (short)( cscalar_mod(&C[i]) ) ; } realft(data,n,isign) float data[]; int n,isign; { int i,i1,i2,i3,i4,n2p3; float c1=0.5,c2,h1r,h1i,h2r,h2i; double wr,wi,wpr,wpi,wtemp,theta; theta=3.141592653589793/(double) n; if (isign == 1) { c2 = -0.5; four1(data,n,1); } else { c2=0.5; theta = -theta; } wtemp=sin(0.5*theta); wpr = -2.0*wtemp*wtemp; wpi=sin(theta); wr=1.0+wpr; wi=wpi; n2p3=2*n+3; for (i=2;i<=n/2;i++) { i4=1+(i3=n2p3-(i2=1+(i1=i+i-1))); h1r=c1*(data[i1]+data[i3]); h1i=c1*(data[i2]-data[i4]); h2r = -c2*(data[i2]+data[i4]); h2i=c2*(data[i1]-data[i3]); data[i1]=h1r+wr*h2r-wi*h2i; data[i2]=h1i+wr*h2i+wi*h2r; data[i3]=h1r-wr*h2r+wi*h2i; data[i4] = -h1i+wr*h2i+wi*h2r; wr=(wtemp=wr)*wpr-wi*wpi+wr; wi=wi*wpr+wtemp*wpi+wi; } if (isign == 1) { data[1] = (h1r=data[1])+data[2]; data[2] = h1r-data[2]; } else { data[1]=c1*((h1r=data[1])+data[2]); data[2]=c1*(h1r-data[2]); four1(data,n,-1); } } #define SWAP(a,b) tempr=(a);(a)=(b);(b)=tempr four1(data,nn,isign) float data[]; int nn,isign; { int n,mmax,m,j,istep,i; double wtemp,wr,wpr,wpi,wi,theta; float tempr,tempi; n=nn << 1; j=1; for (i=1;i<n;i+=2) { if (j > i) { SWAP(data[j],data[i]); SWAP(data[j+1],data[i+1]); } m=n >> 1; while (m >= 2 && j > m) { j -= m; m >>= 1; } j += m; } mmax=2; while (n > mmax) { istep=2*mmax; theta=6.28318530717959/(isign*mmax); wtemp=sin(0.5*theta); wpr = -2.0*wtemp*wtemp; wpi=sin(theta); wr=1.0; wi=0.0; for (m=1;m<mmax;m+=2) { for (i=m;i<=n;i+=istep) { j=i+mmax; tempr=wr*data[j]-wi*data[j+1]; tempi=wr*data[j+1]+wi*data[j]; data[j]=data[i]-tempr; data[j+1]=data[i+1]-tempi; data[i] += tempr; data[i+1] += tempi; } wr=(wtemp=wr)*wpr-wi*wpi+wr; wi=wi*wpr+wtemp*wpi+wi; } mmax=istep; } }