diff 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 diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/pitch_strength.c	Fri May 20 15:19:45 2011 +0100
@@ -0,0 +1,449 @@
+/***************************************************************************
+  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;
+	}
+}
+