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 ;
}