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