Mercurial > hg > aim92
view tools/edframe.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
/* edframe.c Edit (ie. partition) AIM output files. ---------- The input file must have a model header. Usage: edframe [[-]frame=a[-b]] [[-]time=a[-b]] [[-]freq=a[-b]] [file] Special arguments: -help Print help on stderr. -info Print frame size information on the stdout. info=fbank Print channel centre-frequency information for the selected range of frequencies on the stdout. (This information is based on the filterbank parameters given in the input header). Each input frame is a matrix with (0,0) in the bottom left. The partition, output for each frame, is a sub-matrix indexed by rows a-to-b and columns a-to-b inclusive. The partition is specified using args: freq=a-b (rows) and time=a-b (cols). A single row or col is specified using a single number: freq=a or time=a. Rows (channels) are numbered 0,1,...,frameheight-1 -(lowest freq first). Cols (samples) are numbered 0,1,...,framewidth-1. The strings "min" and "max" can be used as selectors, meaning eg: freq=a-max rows a to frameheight-1 freq=min-b rows 0 to b time=a-max cols a to framewidth-1 time=min-b cols 0 to b The default selector specifies the whole matrix: freq=min-max time=min-max Expressing time as cols (along the horizontal axis) and frequency as rows (up the vertical axis) applies to most gen programs with the exception of genwav (where the vertical axis contains just one wave), and the excitation patterns genasa, genepn, and gensep (where frequency is measured as cols along the horizontal axis). The horizontal dimension is controlled by the "freq" parameter for excitation patterns. The units of the freq selector are Hz or kHz, specifying a range of channels in terms of frequency, or if no units are appended, then the selector is interpreted as a channel number in the range 0 to frameheight-1. When the freq selector is given with frequency units, then the "closest" corresponding channel number is used. (This depends upon the parameters mincf_afb, maxcf_afb, and dencf_afb as given in the header). The units of the time selector are s or ms, specifying a range of samples in terms of time, (seconds and milliseconds respectively), or if no units are appended, then the selector is interpreted as a sample number in the range 0 to framewidth-1. When the input consists of a cartoon of multiple frames (eg gensai output) then individual frames or subsequences of frames may be selected from the input using [[-]frame=a[-b]]. Input frames are numbered 0,1,2,...,frames-1 frame=a Select just the a'th frame. frame=a-b Select frames from the a'th to b'th inclusive. The strings "min" and "max" can be used as selectors, meaning eg: frame=min Select the first frame. frame=max Select the last frame. frame=a-max Select frames from the a'th to the last inclusive. frame=min-b Select frames from the first to the b'th inclusive. The default selector is for all frames, (ie frame=min-max). The units of the frame selector are s or ms, each specifying a frame which is "closest" to the given time, being the frame number which is the greatest integer multiple of the framestep (frstep_aid) which does not exceed the given time, measured from the start of the input file. If no units are appended, then the selector is interpreted as a frame number. The output frames are preceded by a model header, so that the partition for each frame can be plotted using the option "useprevious=on". The "Header" option controls the output of the modified header. When it is set Header=off then a header is not output. The "Transpose" option is a matrix transpose (swap rows and columns) of the output partition of each input frame. When a frame partition has a height greater than it's width (ie. cols < rows) then setting Transpose=on may provide a preferable display orientation. For example, this enables a very narrow (eg. single column) time-slice to be plotted horizontally, so that a time-slice of filterbank output may be plotted as a spectrum on a horizontal frequency axis. Examples: --------- Edited output may be displayed using the "useprevious" option, for example: genXXX ... output=stdout file1 | edframe ... > file2.XXX genXXX useprevious=on file2 Note that that file2.XXX must have a different base-name to the genXXX input (file1) because genXXX will remove any file1.XXX as a side-effect. Information on the output is printed on the stdout. For example: Print size information for gensai output for all frames. gensai output=stdout ... | edframe -info Print channel centre-frequency information for genbmm output for the 1kHz channel, and then for channel numbers 37 to 50. (To print the exact centre-frequency occupied by a given channel). genbmm output=stdout ... | edframe info=fbank freq=1kHz genbmm output=stdout ... | edframe info=fbank freq=37-50 Selecting particular frames from AIM output. ------------------------------------------- 1. Plot gennap output and its transpose. gennap output=stdout ... | edframe > file1.sai gennap output=stdout ... | edframe Tran=on > file2.sai gensai useprevious=on file1 gensai useprevious=on file2 2. Select and plot frame 2 (ie. the 3rd frame) of gensai output. gensai output=stdout ... | edframe frame=2 > file.sai gensai useprevious=on file 3. Select the frames of gensai output which start between 16ms and 47ms from the start of it's input. (When the option frstep_aid=16ms then this would select the 2nd and 3rd frames). gensai output=stdout ... | edframe frame=16ms-47ms > file.sai 4. Select the 5th to the last frame inclusively of gensai output. gensai output=stdout ... | edframe frame=4-max > file.sai 5. Select the first frame of genepn output and plot the spectrum. genepn output=stdout ... | edframe frame=min > file1.epn genepn useprevious=on file1 Editing frames to select particular frequency ranges or channels (ie rows). -------------------------------------------------------------------------- 6. Select and plot the channel with centre-frequency closest to 1kHz from gennap output. gennap output=stdout ... | edframe freq=1kHz > file.nap gennap useprevious=on file 7. Select and plot channel 40 then the channel with the lowest and then the highest centre-frequency over all frames of gensai output. gensai output=stdout ... | edframe freq=40 > file.sai gensai useprevious=on file gensai output=stdout ... | edframe freq=min > file.sai gensai useprevious=on file gensai output=stdout ... | edframe freq=max > file.sai gensai useprevious=on file 8. Select and plot all channels of genbmm output from channel 10 to the channel with centre-frequency closest to 1kHz inclusively. genbmm output=stdout ... | edframe freq=10-1000Hz > file.bmm genbmm useprevious=on file 9. Select and plot a portion of the spectrum from the first frame of genepn output between 1kHz and 2kHz. Note: frequency controls the horizontal (ie cols) dimension for genepn. genepn output=stdout ... | edframe frame=min freq=1kHz-2kHz > file.epn genepn useprevious=on file Editing frames to select particular time slices (ie cols). --------------------------------------------------------- 10. Plot column (ie sample) 100 of the 3rd frame of gensai output as a row. gensai output=stdout ... | edframe frame=2 time=100 Tran=on > file.sai gensai useprevious=on file 11. Plot column of sample at 20ms from start of gennap output as a row gennap output=stdout ... | edframe time=20ms Tran=on > file.nap gennap useprevious=on file 12. Edit a wave to select the stretch between 4ms and 16ms, strip the header and plot the resulting wave. genwav output=stdout ... | edframe time=4ms-16ms Header=off > file genwav file Editing frames to select partitions. ----------------------------------- 13. Plot a partition of channels 40 to 44 over the last 5ms (ie near the trigger point on the right of the image) of all frames of gensai output. Then plot a partition of frequency range 1kHz to 1.5kHz over the first 20ms (on the left of the image) of all frames of gensai output. gensai pwidth=35ms nwidth=0 output=stdout ... | edframe time=30ms-max > file.sai gensai useprevious=on file gensai output=stdout ... | edframe freq=1kHz-1.5kHz time=min-20ms > file.sai gensai useprevious=on file 14. Plot the highest-frequency channel over the last 20ms of gennap output. gennap output=stdout ... | edframe freq=max time=20ms-max > file.sai gennap useprevious=on file */ #include <stdio.h> #include <math.h> #include "header.h" #include "options.h" #include "units.h" #include "strmatch.h" #include "freqs.c" char application[] = "Edit AIM output frames. " ; static char *helpstr, *debugstr, *fstr, *tstr, *cfstr, *infostr, *transtr, *headstr ; static Options option[] = { { "help" , "off" , &helpstr , "help" , DEBUG }, { "debug" , "off" , &debugstr , "debugging switch" , DEBUG }, { "frame" , "min-max" , &fstr , "select frames inclusively" , VAL }, { "time" , "min-max" , &tstr , "time (or sample number) partition" , VAL }, { "freq" , "min-max" , &cfstr , "frequency (or channel number) partition" , VAL }, { "Transpose" , "off" , &transtr , "transpose each output partition" , SETFLAG }, { "Header" , "on" , &headstr , "output header" , SETFLAG }, { "info" , "off" , &infostr , "print size and channel centre-frequency information" , SETFLAG }, ( char * ) 0 } ; char *limitstr ; char *qualstr ; char *minstr ; char *maxstr ; char *denstr ; char *chansstr ; double *frequencies ; int frameheight, framewidth ; /* Parameters read from header */ int frames, framebytes ; int frstep ; int samplerate ; int applic ; int format ; int rows, cols, numframes ; int Newrows, Newcols, Newnumframes ; int Newframeheight, Newframewidth ; int Newframes, Newframebytes ; int Transpose ; main(argc, argv) int argc ; char *argv[] ; { FILE *fopen(), *fp = (FILE *) 0 ; char *header, *Header(); char *val1, *val2, *headerstring() ; short *frame ; int i,j,k, a,b, xa,xb, ya,yb; char c, Info=0 ; fp = openopts( option,argc,argv ) ; if ( !isoff( helpstr ) ) helpopts( helpstr, argv[0], application, option ) ; Transpose = ison( transtr ) ; if ( (header = ReadHeader(fp)) == (char *) 0 ) { fprintf(stderr,"edframe: header not found\n"); exit(1); } frameheight = HeaderInt( header, "frameheight" ); framewidth = HeaderInt( header, "framewidth" ); frames = HeaderInt( header, "frames" ); samplerate = HeaderSamplerate( header ); if ( ( applic = Applic( header) ) < 0 ) { fprintf(stderr,"edframe: application name not found in header\n" ) ; exit( 1 ) ; } format = Format( applic ) ; frame_to_matrix( format, &rows, &cols, &numframes, frameheight, framewidth, frames ) ; framebytes = rows * cols * sizeof(short) ; if ( format > WAV ) { /* if not genwav */ limitstr = headerstring( header, "bwmin_afb" ); qualstr = headerstring( header, "quality_afb" ); minstr = headerstring( header, "mincf_afb" ); maxstr = headerstring( header, "maxcf_afb" ); denstr = headerstring( header, "dencf_afb" ); chansstr = headerstring( header, "channels_afb" ); SetErbParameters( to_Hz( limitstr, samplerate ), atof( qualstr ) ) ; if( OptionInt( chansstr ) == 0 ) frequencies = GenerateCenterFrequencies( to_Hz( minstr, samplerate ), to_Hz( maxstr, samplerate ), atof( denstr ) ) ; else frequencies = NumberedCenterFrequencies( to_Hz( minstr, samplerate ), to_Hz( maxstr, samplerate ), OptionInt( chansstr ) ) ; } else frequencies = (double *)0 ; if ( format == SAI ) /* if gensai or genspl */ frstep = to_p( headerstring( header, "frstep_aid" ), samplerate ) ; else frstep = 1 ; /* Get limits on specified number of frames */ if ( getvals( fstr, &val1, &val2, "-" ) == BADVAL ) { fprintf(stderr,"edframe: bad frame selector [%s]\n", fstr ) ; exit( 1 ) ; } if ( ismin( val1 ) ) a = 0 ; else if ( ismax( val1 ) ) a = numframes - 1 ; else if ( Units( val1 ) ) a = (int)to_p( val1, samplerate ) / frstep ; else a = atoi( val1 ) ; if ( isempty( val2 ) ) b = a ; else if ( ismin( val2 ) ) b = 0 ; else if ( ismax( val2 ) ) b = numframes - 1 ; else if ( Units( val2 ) ) b = (int)to_p( val2, samplerate ) / frstep ; else b = atoi( val2 ) ; if ( ison( debugstr ) ) { printf("samplerate=%d val1=[%s] val2=[%s] a=%d b=%d numframes=%d\n", samplerate, val1,val2,a,b,numframes); } if ( a<0 || a>b || b>numframes ) { if ( b>numframes ) fprintf(stderr,"edframe: bad frame selector [just %d frames available]\n", numframes ); else fprintf(stderr,"edframe: bad frame selector \n" ); exit(1); } if ( format == EPN ) /* kludge for excitation patterns with horizontal freq axis */ swap( &rows, &cols ) ; /* Get limits on specified time (ie samples or cols) */ if ( getvals( tstr, &val1, &val2, "-" ) == BADVAL ) { fprintf(stderr,"edframe: bad time selector [%s]\n", tstr ) ; exit( 1 ) ; } if ( ismin( val1 ) ) xa = 0 ; else if ( ismax( val1 ) ) xa = cols-1 ; else if ( Units( val1 ) ) xa = to_p( val1, samplerate ) ; else xa = atoi( val1 ) ; if ( isempty( val2 ) ) xb = xa ; else if ( ismin( val2 ) ) xb = 0 ; else if ( ismax( val2 ) ) xb = cols-1 ; else if ( Units( val2 ) ) xb = to_p( val2, samplerate ) ; else xb = atoi( val2 ) ; /* Get limits on specified freqency (ie channels or rows) */ if ( getvals( cfstr, &val1, &val2, "-" ) == BADVAL ) { fprintf(stderr,"edframe: bad frequency selector [%s]\n", cfstr ) ; exit( 1 ) ; } if ( ismin( val1 ) ) ya = 0 ; else if ( ismax( val1 ) ) ya = rows-1 ; else if ( Units( val1 ) ) ya = closest( to_Hz( val1, samplerate ), frequencies, rows ) ; else ya = atoi( val1 ) ; if ( isempty( val2 ) ) yb = ya ; else if ( ismin( val2 ) ) yb = 0 ; else if ( ismax( val2 ) ) yb = rows-1 ; else if ( Units( val2 ) ) yb = closest( to_Hz( val2, samplerate ), frequencies, rows ) ; else yb = atoi( val2 ) ; if ( format == EPN ) { /* excitation patterns have horizontal freq axis */ swap( &xa, &ya ) ; swap( &xb, &yb ) ; swap( &rows, &cols ) ; } if ( ya<0 || yb>=rows || ya>yb || xa<0 || xb>=cols || xa>xb ) { fprintf(stderr,"edframe: bad specifiers [xa=%d xb=%d ya=%d yb=%d]\n", xa,xb,ya,yb ) ; fprintf(stderr," input frames have %d rows and %d columns \n", rows, cols ) ; exit(1); } Newrows = yb - ya + 1 ; Newcols = xb - xa + 1 ; Newnumframes = b - a + 1 ; if ( Transpose ) swap( &Newrows, &Newcols ) ; matrix_to_frame( format, Newrows, Newcols, Newnumframes, &Newframeheight, &Newframewidth, &Newframes ) ; Newframebytes = Newframewidth * Newframeheight * sizeof(short) ; if ( !isoff( infostr ) ) { if ( ison( infostr ) ) printinfo() ; if ( isstr( infostr, "fbank" ) ) printfbank( xa, xb, ya, yb ) ; exit( 0 ) ; } if ( ison( debugstr ) ) { printf( "rows=%d cols=%d numframes=%d\n", rows,cols,numframes); printf( "a=%d b=%d ya=%d yb=%d xa=%d xb=%d\n", a,b,ya,yb,xa,xb ) ; printf( "Newrows=%d Newcols=%d Newnumframes=%d\n", Newrows,Newcols,Newnumframes); printf( "Newframeheight=%d Newframewidth=%d Newframes=%d\n", Newframeheight, Newframewidth, Newframes ) ; printf( "framebytes=%d Newframebytes=%d\n", framebytes, Newframebytes ) ; exit( 1 ) ; } if ( ison( headstr ) ) WriteHeader( Header(header, ya,yb), stdout ); /* Allocate space for framebytes of data */ if ( (frame = (short *)malloc( framebytes )) == NULL ) { fprintf(stderr,"edframe: malloc out of space\n"); exit(1); } /* seeks past `a' frames */ for ( i = 0 ; i < a && fread( frame,framebytes,1,fp ) ; i++ ) ; /* edit frames `a' to `b' */ if ( Transpose ) { for ( ; i <= b && fread( frame,framebytes,1,fp ) ; i++ ) { if ( format == SAI || format == EPN ) for ( j=xa ; j<=xb ; j++ ) for ( k=ya ; k<=yb ; k++ ) fwrite( frame + k*framewidth + j, sizeof(short), 1, stdout ) ; else for ( j=ya ; j<=yb ; j++ ) for ( k=xa ; k<=xb ; k++ ) fwrite( frame + k*frameheight + j, sizeof(short), 1, stdout ) ; } } else { /* direct (un-transposed) output */ for ( ; i <= b && fread( frame,framebytes,1,fp ) ; i++ ) { if ( format == SAI || format == EPN ) for ( j=ya ; j<=yb ; j++ ) fwrite( frame + j*framewidth + xa, sizeof(short), Newcols, stdout ) ; else for ( j=xa ; j<=xb ; j++ ) fwrite( frame + j*frameheight + ya, sizeof(short), Newrows, stdout ) ; } } fclose(fp); } /* Return an allocated string to the value part of an option in the header with the given name. Exit if option not found in header. */ char *headerstring( header, name ) char *header, *name ; { char *valuestr ; if ( (valuestr = HeaderStringOnly( header, name )) == (char *) 0) { fprintf(stderr,"edframe: option %s not found in header\n", name); exit( 1 ) ; } return ( valuestr ) ; } 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 ) ) ; } /* Copy the original nap header to a new sai header, changing in order: maxcf_afb mincf_afb channels_afb frames framewidth frameheight framebytes view Finally, update the new header_bytes, and return the new header. */ char *Header( oldheader, ya,yb ) char *oldheader ; int ya,yb ; { char *saiheader; char *p0, *p1, *p2, *s, str[64]; saiheader = (char *)malloc( strlen(oldheader) + 64 ) ; p0 = saiheader ; p1 = oldheader ; if ( format > WAV ) { /* if not genwav */ /** copy up to maxcf_afb **/ p2 = HeaderString( oldheader , "maxcf_afb" ) ; while( p1 < p2 ) *p0++ = *p1++ ; sprintf(str,"%.2fHz\n", frequencies[yb]); for (s = str ; *s != '\n' ; ) *p0++ = *s++; *p0++ = *s; while (*p1 != '\n') *p1++; *p1++; /** copy up to mincf_afb **/ p2 = HeaderString( oldheader , "mincf_afb" ) ; while( p1 < p2 ) *p0++ = *p1++ ; sprintf(str,"%.2fHz\n", frequencies[ya]); for (s = str ; *s != '\n' ; ) *p0++ = *s++; *p0++ = *s; while (*p1 != '\n') *p1++; *p1++; /** copy up to channels_afb **/ p2 = HeaderString( oldheader , "channels_afb" ) ; 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 frames **/ p2 = HeaderString( oldheader , "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 framewidth **/ p2 = HeaderString( oldheader , "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( oldheader , "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( oldheader , "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 rest of header **/ p2 = HeaderString( oldheader , "Version" ) ; while ( p1 < p2 ) *p0++ = *p1++ ; 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; } /* Return the index of the frequency closest to the given "freq" */ int closest( freq, frequencies, channels ) double freq, *frequencies ; int channels ; { int i; if ( frequencies == (double *)0 ) return 0 ; for (i=0 ; i<channels && frequencies[i]<freq ; i++) ; if (i==channels) return ( i-1 ) ; if (i==0) return i ; if ( frequencies[i]-freq < freq-frequencies[i-1] ) return i ; else return ( i-1 ) ; } /* Return 1 if the str has appended units. Otherwise return 0. */ /* (A freqency specifier with no units is interpreted as a channel number) */ Units(str) char *str ; { char *eptr = str + strlen( str ) ; if( isdigit( *--eptr ) ) return 0 ; /* last char is digit, so no units */ else return 1 ; } printinfo() { printf( "gen%s output file\n", gen_applics[ applic ] ) ; switch ( format ) { case WAV : printf( " wave format (array of time points)\n" ) ; break ; case NAP : printf( " activity-pattern format (by columns, lowest centre-frequency first in each)\n" ) ; break ; case SGM : printf( " spectrogram format (by columns, lowest centre-frequency first in each)\n" ) ; break ; case EPN : printf( " excitation-pattern format (array of frequency points per frame)\n" ) ; break ; case SAI : printf( " auditory-image format (by rows, lowest centre-frequency first per frame)\n" ) ; break ; } if ( format != WAV && format != EPN ) /* frameheight meaningless for wav and epn */ printf( " frameheight = %4d channels (%.2fHz to %.2fHz) \n", rows, to_Hz( minstr, samplerate ), to_Hz( maxstr, samplerate ) ) ; if ( format == EPN ) /* horiz axis is freq for epn, otherwise is time */ printf( " framewidth = %4d channels (%.2fHz to %.2fHz) \n", cols, to_Hz( minstr, samplerate ), to_Hz( maxstr, samplerate ) ) ; else printf( " framewidth = %4d samples (%d ms at %dHz samplerate) \n", cols, (int)to_ms( itoa( cols ), samplerate ), samplerate ) ; printf( " frames = %4d \n", numframes ) ; printf( " framesize = %4d bytes \n", rows*cols*2 ) ; } printfbank( xa, xb, ya, yb ) /* print filterbank info */ int xa, xb, ya, yb ; { int i ; if ( format > WAV ) { /* no filterbank for genwav */ if ( format == EPN ) /* freq axis is horiz for epn */ for (i=xa ; i<=xb ; i++) printf( "channel %2d. %7.2fHz, %4.2fms, %5.2f samples \n", i, frequencies[i], 1000./frequencies[i], (double)samplerate/frequencies[i] ); else for (i=ya ; i<=yb ; i++) printf( "channel %2d. %7.2fHz, %4.2fms, %5.2f samples \n", i, frequencies[i], 1000./frequencies[i], (double)samplerate/frequencies[i] ); } } /* Swap the values in integer addresses p1 and p2 */ swap( p1, p2 ) int *p1 , *p2 ; { int tmp ; tmp = *p1 ; *p1 = *p2 ; *p2 = tmp ; }