Mercurial > hg > aim92
view tools/audim.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
/* audim.c auditory images --------- This program provides methods of constructing time-varying auditory images from the output of the cochlear model which are alternatives to the gensai (stabilized auditory image) program. Correlograms (ie. row- wise autocorrelation) and row-wise Fourier transform are provided. The program reads an AIM header and the output from the genbmm (basilar mem- brane motion) or gennap (neural activity pattern) programs. This is divided into contiguous time frames and written on the stdout with an appropriate header as if output from the gensai program. This enables genbmm or gennap output to be divided into time frames and replayed as a cartoon by gensai using the "useprevious" option. Additional processing to each frame is optionally available to compute alternative forms of auditory image according to the "image" option. The options "start" and "length" specify the size of the input. The options "width" and "frstep" specify the frames which are output. The input is divided into frames according to the width option and the frstep option. Special option values are: length=max Read all the input from the given start to its end. width=max Output framewidth is set equal to the given input length, and if this is also "max", then the framewidth is the remainder of the input. frames=1-max Select the 1st to the last frame inclusively. frame=4 Select the 4th frame only. image=off Divide the input into frames for replay as a cartoon. image=acgram Compute correlogram of each frame. image=ftgram Compute power spectrum of each channel of each frame. image=phgram Compute phase spectrum of each channel of each frame. Most options in the input header are copied to the output header. This enables options which are needed for the eventual display to pass straight through. Some options are set so that they can override the input header. For example, the display option is set on to enable display even when input has display=off. The animate option can be set on even when the input has animate=off. Parts of the header are changed for the new sai format: (frames, frameshift, framewidth, frameheight, framebytes). Padding: The input nap is divided into frames according to the width option (called framewidth internally) and the frstep option (called frameshift internally). The framewidth is used as the basis for output image frame width: the output width is actually the next power-of-2 above twice the framewidth. This is because: a. fft and acf output is always half the given frame size, due to symmetry, so the input must be padded to twice its width. b. To use fft, the input must also be a power of two. So, each input row is padded out to the next power of two above twice its width. Certain display parameters have different default values for different applications. The gensai display parameters should be set to the appropriate values, in order to plot the cartoon on the same scale. For example: when the source application is gennap, set gensai top=1000, when the source application is genbmm, set gensai bottom=-100. Examples: 1. An animated normalized autocorrelogram from a nap: gennap len=64ms output=stdout display=off file | audim norm=on anim=on > file.sai gensai useprev=on top=1000 cegc -(for landscape plot) genspl useprev=on top=1000 pensize=2 cegc -(for spiral plot) 2. To convert a nap to multiple animated frames: gennap len=16ms display=off output=stdout file | audim image=off width=8ms frstep=0.2ms anim=on > file.sai gensai useprev=on top=1000 cegc -(for landscape plot) genspl useprev=on top=1000 pensize=2 cegc -(for spiral plot) (Note: spirals look better in a square box, so you might use options: dencf=1 width=500 height=500 ) 3. To view the basilar membrane from a cross section, animating the waves on it. genbmm mincf=220 maxcf=660 len=8ms output=stdout display=off file | audim image=off width=1p frstep=1p display=on anim=on | edframe Tran=on > foo.sai gensai bott=-100 useprev=on mag=.2 foo or: genbmm mincf=220 maxcf=660 len=32ms output=stdout display=off file | \ audim image=off width=1p frstep=1p display=on anim=on | \ edframe Tran=on Header=off > foo x11play -n75 -a500 foo */ #include <stdio.h> #include <math.h> #include "header.h" #include "options.h" #include "units.h" #include "strmatch.h" #include "sigproc.h" #include "freqs.c" char applic[] = "Auditory images of neural activity patterns (NAP). " ; static char *helpstr, *debugstr, *dispstr, *anistr, *startstr, *imstr ; static char *lengthstr, *widthstr, *shiftstr, *headerstr, *cfstr, *framestr ; static char *normstr, *wstr, *sacfstr, *smagstr, *sphstr ; static char *blstr, *erbstr ; static Options option[] = { { "help" , "off" , &helpstr , "help" , DEBUG }, { "debug" , "off" , &debugstr , "debugging switch" , DEBUG }, { "display" , "on" , &dispstr , "Display output image." , SETFLAG }, { "animate" , "off" , &anistr , "Animate cartoon." , SETFLAG }, { "frames" , "1-max" , &framestr , "Select frames inclusively" , VAL }, { "image" , "acgram" , &imstr , "Form of auditory image." , VAL }, { "header" , "on" , &headerstr , "Header (for gensai useprevious=on)." , VAL }, { "start" , "0" , &startstr , "Start point in i/p NAP" , VAL }, { "length" , "max" , &lengthstr , "Length of i/p NAP to process." , VAL }, { "frstep" , "16ms" , &shiftstr , "Step between frames of the auditory image." , VAL }, { "width" , "32ms" , &widthstr , "Width of auditory image." , VAL }, { "normalize" , "off" , &normstr , "Normalization" , SETFLAG }, { "window" , "off" , &wstr , "Hamming window" , SETFLAG }, { "bandlimit" , "off" , &blstr , "Zero outside bandwidth." , SETFLAG }, { "erbs" , "2" , &erbstr , "Width (in ERBS) of band either side of cf." , SVAL }, { "align_cf" , "off" , &cfstr , "Align on centre frequency." , SETFLAG }, { "scale_acf" , "0.025" , &sacfstr , "Scale factor for acf output" , SVAL }, { "scale_fft" , "0.08" , &smagstr , "Scale factor for fft magnitude output" , SVAL }, { "scale_phs" , "100" , &sphstr , "Scale factor for fft phase output" , SVAL }, ( char * ) 0 } ; int frameheight ; /* Nap parameters read from header */ int frames, samplerate ; int framewidth ; /* width option */ int start, length ; int Newframeheight, Newframewidth ; /* Sai parameters to write */ int Newframes ; int Newframeshift ; int Newframebytes ; char *limitstr ; /* Sai parameters used to get centre-frequencies */ char *qualstr ; char *minstr ; char *maxstr ; char *denstr ; char *chansstr ; double *frequencies ; int nerbs ; /* bandwidth defined as number of erbs either side of cf */ int bandlimit ; /* flag for zeroing outside bandwidth around centre-freqs */ int align ; /* flag for aligning centre-freqs */ #define NONE 0 /* forms of auditory image */ #define ACGRAM 1 #define FTGRAM 2 #define PHGRAM 3 int image ; float *buf ; /* fft working space */ int zeroes ; /* padding */ float *W ; /* Hamming window for fft */ short window ; /* flag for window */ short debug ; /* flag for debug printf's */ main(argc, argv) int argc ; char *argv[] ; { FILE *fp ; int i, framebytes, startbytes, frameshift, framebyteshift; char *header, *SaiHeader(); short *nap, *frame, *endframe; int a, b ; char *val1, *val2 ; fp = openopts( option,argc,argv ) ; if ( !isoff( helpstr ) ) helpopts( helpstr, argv[0], applic, option ) ; window = ison( wstr ) ; nerbs = atoi( erbstr ) ; debug = ison( debugstr ) ; /**** Form of image ****/ if ( iststr( imstr, "acgram" ) ) { image = ACGRAM ; } else if ( iststr( imstr, "ftgram" ) ) { image = FTGRAM ; } else if ( iststr( imstr, "phgram" ) ) { image = PHGRAM ; } else if ( isoff( imstr ) ) { image = NONE ; } else { fprintf(stderr, "audim: unknown form of auditory image [%s]\n", imstr ) ; exit( 1 ) ; } align = ison( cfstr ) ; bandlimit = ison( blstr ) ; /**** parse bounds on number of frames ****/ if ( getvals( framestr, &val1, &val2, "-" ) == BADVAL ) { fprintf(stderr,"audim: bad frame selector [%s]\n", framestr ) ; 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,"audim warning: bad frame specifiers\n"); /**** Read header and options to find dimensions of auditory image ****/ if ( (header = ReadHeader(fp)) == (char *) 0 ) { fprintf(stderr,"audim: header not found\n"); exit(1); } frameheight = HeaderInt( header, "frameheight" ); frames = HeaderInt( header, "frames" ); samplerate = HeaderSamplerate( header ); start = to_p( startstr, samplerate ); frameshift = to_p( shiftstr, samplerate ) ; if ( ismax( lengthstr ) ) /* Special case for remainder of input */ length = frames - start ; else length = to_p( lengthstr, samplerate ); if ( start + length > frames ) { fprintf(stderr,"audim: nap too small (%d ms) for requested start and length \n", to_ms( frames, samplerate ) ); exit(1); } framebytes = frameheight * length * sizeof(short) ; startbytes = frameheight * start * sizeof(short) ; if ( ismax( widthstr ) ) /* Special case for single frame of max width */ framewidth = length ; else framewidth = to_p( widthstr, samplerate ) ; frames = ( length - framewidth ) / frameshift ; zeroes = getpower( framewidth << 1 ) - framewidth ; /**** Get centre-frequencies information using info given in header ****/ limitstr = HeaderStringOnly( header, "bwmin_afb" ); qualstr = HeaderStringOnly( header, "quality_afb" ); minstr = HeaderStringOnly( header, "mincf_afb" ); maxstr = HeaderStringOnly( header, "maxcf_afb" ); denstr = HeaderStringOnly( header, "dencf_afb" ); chansstr = HeaderStringOnly( header, "channels_afb" ); SetErbParameters( to_Hz( limitstr ), atof( qualstr ) ) ; if( OptionInt( chansstr ) == 0 ) frequencies = GenerateCenterFrequencies( to_Hz( minstr ), to_Hz( maxstr ), atof( denstr ) ) ; else frequencies = NumberedCenterFrequencies( to_Hz( minstr ), to_Hz( maxstr ), OptionInt( chansstr ) ) ; /**** Output frame dimensions (to write into new header) ****/ Newframeheight = frameheight ; if ( !align ) { if ( image == NONE ) Newframewidth = framewidth ; else Newframewidth = ( framewidth + zeroes ) >> 1 ; /* spectral bins */ } else { /* number of bins corresponding to the filter bandwidth */ switch ( image ) { case NONE : Newframewidth = framewidth ; break ; case ACGRAM : Newframewidth = maxlagwidth( to_Hz( minstr ), nerbs ) ; break ; case FTGRAM : Newframewidth = maxbandwidth( to_Hz( maxstr ), nerbs, (framewidth+zeroes)>>1 ) ; break ; } } Newframeshift = frameshift ; Newframebytes = Newframeheight * Newframewidth * sizeof(short) ; if ( frameshift > 0 ) { if ( b == 0 ) Newframes = frames - (a-1) ; else Newframes = b - (a-1) ; } else { fprintf(stderr,"audim: non-positive frstep [%d]\n", frameshift); exit(1); } /**** Check limits etc.. ****/ if ( b > frames ) { fprintf(stderr,"audim: can't select frame %d out of %d frames\n", b, frames ) ; exit(1); } if ( length < framewidth ) { fprintf(stderr,"audim: nap too small (%d ms) for requested width\n", to_ms( length, samplerate ) ); exit(1); } if (frames<=0) { if (frames==0) fprintf(stderr,"audim: zero frames input\n"); if (frames<0) fprintf(stderr,"audim: garbled number of frames, (start set too big?)\n"); exit(1); } if (a>frames || b>frames) fprintf(stderr,"audim warning: bad frame selectors\n"); if ( debug ) { fprintf(stderr, "Header: frames=%d frameheight=%d\n", frames, frameheight ) ; fprintf(stderr, "Options: a=%d b=%d start=%d length=%d frameshift=%d framewidth=%d\n", a, b, start, length, frameshift, framewidth ) ; fprintf(stderr, "Output: zeroes=%d Newframewidth=%d Newframes=%d \n", zeroes, Newframewidth, Newframes ) ; } /**** Write new sai header ****/ if ( ison( headerstr ) ) WriteHeader( SaiHeader(header), stdout ); /**** Allocate space for framebytes of nap data ****/ if ( (nap = (short *)malloc( framebytes )) == NULL ) { fprintf(stderr,"audim: malloc out of space\n"); exit(1); } /**** Allocate and assign window coeffs ****/ if ( window ) W = hamming( framewidth ) ; /**** Allocate fft working space ****/ buf = (float *)malloc( ( framewidth + zeroes ) * sizeof(float) ); /**** Seek to start in blocks of framebytes ****/ for (i=framebytes ; i < startbytes ; i += framebytes) if ( fread( nap, framebytes, 1, fp ) == NULL ) { fprintf(stderr,"audim: missing data after header\n"); exit(1); } if ( (startbytes -= (i - framebytes)) > 0 ) if ( fread( nap, startbytes, 1, fp ) == NULL ) { fprintf(stderr,"audim: missing data after header\n"); exit(1); } /**** Read framebytes of i/p nap data ****/ if ( fread( nap, framebytes, 1, fp ) == NULL ) { fprintf(stderr,"audim: missing data after header\n"); exit(1); } framebyteshift = frameshift * frameheight ; nap = nap + (a-1) * framebyteshift ; endframe = nap + Newframes * framebyteshift ; switch ( image ) { case NONE : fprintf(stderr,"Output framewidth = %dp \n", Newframewidth ) ; break ; case ACGRAM : fprintf(stderr,"Output framewidth = %dp Lag range = 0-%dms\n", Newframewidth, (Newframewidth*1000)/samplerate ) ; break ; case FTGRAM : fprintf(stderr,"Output framewidth = %dp Frequency range = 0-%dkHz\n", Newframewidth, samplerate/2000 ) ; break ; case PHGRAM : break ; } for ( frame = nap ; frame < endframe ; frame += framebyteshift ) { fprintf(stderr,"audim: %d / %d\n", a++, frames ); switch ( image ) { case NONE : writeframe( frame ) ; break ; case ACGRAM : acgram( frame ) ; break ; case FTGRAM : ftgram( frame ) ; break ; case PHGRAM : phgram( frame ) ; break ; } } fprintf(stderr,"audim: done\n" ); } int OptionInt( str ) char *str ; { if( strcmp( str, "on" ) == 0 ) return( 1 ) ; else if( strcmp( str, "Not_used" ) == 0 ) return( 0 ) ; else return( atoi( str ) ) ; } /*********************** Read header and build new header *****************/ /* Copy the original nap header to a new sai header, changing in order: frames frameshift framewidth frameheight framebytes animate display Finally, update the new header_bytes, and return the new header. */ char *SaiHeader( napheader ) char *napheader ; { char *saiheader; char *p0, *p1, *p2, *s, str[64]; saiheader = (char *)malloc( strlen(napheader) + 256 ) ; p0 = saiheader ; p1 = napheader ; /* copy to first item after the header_bytes */ p2 = HeaderString( napheader , "header_bytes" ) ; while( p1 < p2 ) *p0++ = *p1++ ; while (*p1 != '\n') *p0++ = *p1++ ; *p0++ = *p1++; /* insert frstep_aid at top of new header */ sprintf( str,"frstep_aid=%s\n", shiftstr ) ; for (s = str ; *s != '\n' ; ) *p0++ = *s++; *p0++ = *s; /** copy up to frames **/ p2 = HeaderString( napheader , "frames" ) ; while( p1 < p2 ) *p0++ = *p1++ ; sprintf(str,"%d\n", Newframes); for (s = str ; *s != '\n' ; ) *p0++ = *s++; *p0++ = *s; while (*p1 != '\n') *p1++; *p1++; /** copy up to frameshift **/ p2 = HeaderString( napheader , "frameshift" ) ; while ( p1 < p2 ) *p0++ = *p1++ ; sprintf(str,"%d\n", Newframeshift); for (s = str ; *s != '\n' ; ) *p0++ = *s++; *p0++ = *s; while (*p1 != '\n') *p1++; *p1++; /** copy up to framewidth **/ p2 = HeaderString( napheader , "framewidth" ) ; while ( p1 < p2 ) *p0++ = *p1++ ; sprintf(str,"%d\n", Newframewidth); for (s = str ; *s != '\n' ; ) *p0++ = *s++; *p0++ = *s; while (*p1 != '\n') *p1++; *p1++; /** copy up to frameheight **/ p2 = HeaderString( napheader , "frameheight" ) ; while ( p1 < p2 ) *p0++ = *p1++ ; sprintf(str,"%d\n", Newframeheight); for (s = str ; *s != '\n' ; ) *p0++ = *s++; *p0++ = *s; while (*p1 != '\n') *p1++; *p1++; /** copy up to framebytes **/ p2 = HeaderString( napheader , "framebytes" ) ; while ( p1 < p2 ) *p0++ = *p1++ ; sprintf(str,"%d\n", Newframebytes); for (s = str ; *s != '\n' ; ) *p0++ = *s++; *p0++ = *s; while (*p1 != '\n') *p1++; *p1++; /** copy up to animate_ctn **/ p2 = HeaderString( napheader , "animate_ctn" ) ; while ( p1 < p2 ) *p0++ = *p1++ ; sprintf(str,"%s\n", anistr ); for (s = str ; *s != '\n' ; ) *p0++ = *s++; *p0++ = *s; while (*p1 != '\n') *p1++; *p1++; /** copy up to display **/ p2 = HeaderString( napheader , "display" ) ; while ( p1 < p2 ) *p0++ = *p1++ ; sprintf(str,"%s\n", dispstr ); for (s = str ; *s != '\n' ; ) *p0++ = *s++; *p0++ = *s; while (*p1 != '\n') *p1++; *p1++; /** copy rest of header **/ p2 = HeaderString( napheader , "Version" ) ; while ( p1 < p2 ) *p0++ = *p1++ ; if ( ( p2 = ApplicString( napheader ) ) == (char *)0 ) { fprintf(stderr,"audim: application name not found in header\n"); exit( 1 ) ; } while ( p1 < p2 ) *p0++ = *p1++ ; *p0++ = 's' ; *p0++ = 'a' ; *p0++ = 'i' ; /* copy sai into applic name */ p1 += 3 ; while (*p1 != '\n') *p0++ = *p1++ ; *p0++ = *p1++ ; /** update header_bytes **/ sprintf(str, "%0*d", 7, p0-saiheader); p0 = HeaderString( saiheader , "header_bytes" ) ; s = str; while(*p0 != '\n') *p0++ = *s++ ; return saiheader; } /************************** Autocorrelation function ***********************/ /* Call acf for each row in auditory image */ acgram( frame ) short *frame ; { static float scale ; static int normalize ; static int first = 1 ; register int i, j, row, col ; short p ; if (first) { normalize = ison( normstr ) ; scale = 1./(double)( framewidth + zeroes ) * atof( sacfstr ) ; first=0; } for ( row=0 ; row < frameheight ; row++ ) { for ( col=0 , i=row ; col < framewidth ; col++, i+=frameheight ) buf[col] = frame[i] ; for ( j=0 ; j<zeroes ; j++ ) /* padding */ buf[col++] = 0 ; acf( buf, framewidth+zeroes ) ; if ( align || bandlimit ) writelags( buf, row, (framewidth+zeroes)>>1, Newframewidth, scale ) ; else { if ( normalize == 0 ) writebuf( buf, Newframewidth, scale ) ; else writebuf( buf, Newframewidth, 5000./buf[0] ) ; } } } /********************************** FFT ************************************/ /* Call fft and magnitude spectrum for each row in auditory image */ ftgram( frame ) short *frame ; { static float scale ; static int first = 1 ; register int i, j, row, col ; if (first) { scale = atof( smagstr ) ; first=0; } for ( row=0 ; row < frameheight ; row++ ) { if ( window ) for ( col=0 , i=row ; col < framewidth ; col++, i+=frameheight ) buf[col] = frame[i] * W[col] ; else for ( col=0 , i=row ; col < framewidth ; col++, i+=frameheight ) buf[col] = frame[i] ; for ( j=0 ; j<zeroes ; j++ ) /* padding */ buf[col++] = 0 ; fft( buf, framewidth+zeroes, 1 ) ; mag( buf, framewidth+zeroes ) ; if ( align || bandlimit ) writebins( buf, row, (framewidth+zeroes)>>1, Newframewidth, scale ) ; else writebuf( buf, Newframewidth, scale ) ; } } /********************************** Phase **********************************/ /* Call fft and phase spectrum for each row in auditory image */ phgram( frame ) short *frame ; { static float scale ; static int first = 1 ; register int i, j, row, col ; if (first) { scale = atof( sphstr ) ; first=0; } for ( row=0 ; row < frameheight ; row++ ) { for ( col=0 , i=row ; col < framewidth ; col++, i+=frameheight ) buf[col] = frame[i] ; for ( j=0 ; j<zeroes ; j++ ) /* padding */ buf[col++] = 0 ; fft( buf, framewidth+zeroes, 1 ) ; phase( buf, framewidth+zeroes ) ; writebuf( buf, Newframewidth, scale ) ; } } /**** Write o/p routines ****/ writebuf( buf, n, scale ) /* write buffer as scaled shorts */ float *buf ; int n ; float scale ; { register int i ; short p ; for (i=0 ; i < n ; i++) { p = (short)( buf[i] * scale ) ; fwrite( &p, sizeof(short), 1, stdout ) ; } } writeframe( frame ) /* Write a nap frame in sai format */ short *frame ; { int i, row, col; for (row=0 ; row < frameheight ; row++) for (col=0 , i=row ; col < framewidth ; col++, i+=frameheight) fwrite( &frame[i], sizeof(short), 1, stdout ); } /* Write a band of spectral bins around the centre-freq of the given channel. The o/p spectrum is 0 to samplerate/2 Hz, resolved into spectral bins: bins = (framewidth + zeroes) / 2 For the i'th channel, the centre-frequency cf = frequencies[i]. Filters are symmetrical bandpass, so considering a bandwidth of 4 ERB the side-frequencies at the band limits are: side1 = cf - 2*ERB [Hz] side2 = cf + 2*ERB [Hz] Note: side1 < side2 Convert frequency to bin number as follows: Let centre-frequency cf have bin number j, so that ratios: cf/(samplerate/2) = j/bins and so: j = ( cf*bins ) / ( samplerate/2 ) (Similarly for each of the side-frequencies at the 2-ERB band limits). */ writebins( buf, chan, bins, maxwidth, scale ) float *buf ; int chan ; int bins ; /* number of spectral bins */ int maxwidth ; float scale ; { double ERB, cf, side1, side2, max ; register int i, j, s1, s2 ; short p ; ERB = frequencies[chan]/9.26449 + 24.7 ; cf = frequencies[chan] ; side1 = frequencies[chan] - nerbs*ERB ; side2 = frequencies[chan] + nerbs*ERB ; j = (int)( ( cf * bins ) / ( samplerate >> 1 ) + 0.5 ) ; /* rounding */ s1 = (int)( ( side1 * bins ) / ( samplerate >> 1 ) + 0.5 ) ; s2 = (int)( ( side2 * bins ) / ( samplerate >> 1 ) + 0.5 ) ; if ( debug ) fprintf(stderr,"chan=%d bins=%d maxwidth=%d j=%d side1=%d side2=%d\n",chan,bins,maxwidth,j,s1,s2); /* Plot the given bandwidth, zeroing elsewhere: */ if ( bandlimit && !align ) { for ( i=0, p=0 ; i < s1 ; i++ ) fwrite( &p, sizeof(short), 1, stdout ) ; for ( ; i < s2 && i < bins ; i++ ) { p = (short)( buf[i] * scale ) ; fwrite( &p, sizeof(short), 1, stdout ) ; } for ( p=0 ; i < bins ; i++ ) fwrite( &p, sizeof(short), 1, stdout ) ; } /* Plot the given bandwidth, shifting it to the centre */ if ( align ) { /* align on max bin in band max = 0 ; for ( i=s1 ; i<s2 ; i++ ) if ( buf[i] >= max ) { max = buf[i] ; j = i ; } for ( i=0, p=0 ; i < s1+(maxwidth/2-j) ; i++ ) fwrite( &p, sizeof(short), 1, stdout ) ; for ( j = s1 ; j < s2 && i < maxwidth ; i++, j++ ) { p = (short)( buf[j] * scale ) ; fwrite( &p, sizeof(short), 1, stdout ) ; } for ( p=0 ; i < maxwidth ; i++ ) fwrite( &p, sizeof(short), 1, stdout ) ; */ j = (maxwidth+s1-s2)/2 ; for ( i=0, p=0 ; i < j ; i++ ) fwrite( &p, sizeof(short), 1, stdout ) ; for ( j = s1 ; j < s2 ; i++, j++ ) { p = (short)( buf[j] * scale ) ; fwrite( &p, sizeof(short), 1, stdout ) ; } for ( p=0 ; i < maxwidth ; i++ ) fwrite( &p, sizeof(short), 1, stdout ) ; } } /* Write a band of acf lags around the centre-period of the given channel. For the i'th channel, the centre-frequency Centre-frequency cf = frequencies[i] [Hz] Bandwidth ERB = cf/9.26449 + 24.7 [Hz] Centre-period cp = samplerate / cf [samples] Filters are symmetrical bandpass, so considering a bandwidth of 4 ERB side1 = samplerate / ( cf - 2*ERB ) [samples] side2 = samplerate / ( cf + 2*ERB ) [samples] Note: side2 < side1 since periods Also, successive bins ARE successive lags (in samples). */ writelags( buf, chan, lags, maxwidth, scale ) float *buf ; int chan ; int lags ; /* number of acf lags */ int maxwidth ; float scale ; { double ERB, cp, side1, side2 ; register int i, j, s1, s2 ; short p ; ERB = frequencies[chan]/9.26449 + 24.7 ; cp = (double)samplerate / frequencies[chan] ; side1 = (double)samplerate / ( frequencies[chan] - nerbs*ERB ) ; side2 = (double)samplerate / ( frequencies[chan] + nerbs*ERB ) ; j = (int)( cp + 0.5 ) ; /* rounding */ s1 = (int)( side1 + 0.5 ) ; s2 = (int)( side2 + 0.5 ) ; if ( debug ) fprintf(stderr,"chan=%d lags=%d side1=%d side2=%d\n",chan,lags,s1,s2); /* Plot the given bandwidth, zeroing elsewhere: */ if ( bandlimit && !align ) { for ( i=0, p=0 ; i < s2 ; i++ ) fwrite( &p, sizeof(short), 1, stdout ) ; for ( ; i < s1 && i < lags ; i++ ) { p = (short)( buf[i] * scale ) ; fwrite( &p, sizeof(short), 1, stdout ) ; } for ( p=0 ; i < lags ; i++ ) fwrite( &p, sizeof(short), 1, stdout ) ; } /* Plot the given bandwidth, shifting it to the centre */ if ( align ) { j = (maxwidth+s2-s1)/2 ; for ( i=0, p=0 ; i < j ; i++ ) fwrite( &p, sizeof(short), 1, stdout ) ; for ( j = s2 ; j < s1 ; i++, j++ ) { p = (short)( buf[j] * scale ) ; fwrite( &p, sizeof(short), 1, stdout ) ; } for ( p=0 ; i < maxwidth ; i++ ) fwrite( &p, sizeof(short), 1, stdout ) ; } } /* Return the number of lags corresponding to a bandwidth of nerbs ERBS either side of a given mincf. This will be the max required framewidth. */ maxlagwidth( mincf, nerbs ) double mincf ; int nerbs ; { double ERB, side1, side2 ; ERB = mincf/9.26449 + 24.7 ; side1 = (double)samplerate / ( mincf - nerbs*ERB ) ; side2 = (double)samplerate / ( mincf + nerbs*ERB ) ; return (int)( side1 - side2 ) ; } /* Return the number of bins corresponding to a bandwidth of nerbs ERBS either side of a given maxcf. This will be the max required framewidth. */ maxbandwidth( maxcf, nerbs, bins ) double maxcf ; int nerbs ; int bins ; { double ERB, side1, side2 ; int s1, s2 ; ERB = maxcf/9.26449 + 24.7 ; side1 = maxcf - nerbs*ERB ; side2 = maxcf + nerbs*ERB ; /* convert frequencies to bin numbers */ s1 = (int)( ( side1 * bins ) / ( samplerate >> 1 ) + 0.5 ) ; s2 = (int)( ( side2 * bins ) / ( samplerate >> 1 ) + 0.5 ) ; return (int)( s2 - s1 ) ; }