ftp.nice.ch/pub/next/audio/apps/LPC.1.0.s.tar.gz#/LPC/tools.c

This is tools.c in view mode; [Download] [Up]

/* Standalone analysis program, reading fixed-point monaural sound files.
 * Currently set for maximum of 34 poles, & max anal segment of 500 samples,
 * meaning that the frame slices cannot exceed 250 samples.
 * Program size expands linearly with slice size, and as square of npoles.
 */

#include "sysdep.h"
#include <stdio.h>
#include <sys/file.h>
#include <fcntl.h>
#include <math.h>
#include <pwd.h>

#define NEXT
#include "sfheader.h"
#include "lpsf.h"
#include "lp.h"

#define INCR 4
#define readin read

extern char soundFile[], lpFile[], *comment;
extern int npoles, lpframeoffset;
extern float lpinskip, lpdur;
extern void report(char *s);
static int NPOLE;			/* why are these external?  -dll */
static int FRAME;
static int NPP1;
static int alpol(), gauss(), dies(), die();

static int debug=0, verbose=0;

#define NDATA 	4	/* number of data values stored with frame */

int anallpc ()
{
        int	jj, slice, counter;
        float	coef[POLEMAX+NDATA], inskip, dur;
        char	*sfname;
	char    *iname;
	char    *oname;
        double	errn, rms1, rms2, cc[40];
        double	sigi[FRAMAX];
        long	i, nsamps, skipbytes, outskip;
        struct	SFDESC sfdesc;
        int	anal, sfd, nbytes, nblpc, firstframe, nread;

	int	n, hsize, esize;		/* new declarations */
	char	inbuf[SIZEOF_HEADER], framerpt[64];
	SFHEADER *sfh;
	int Hflag = 0;
	LPHEADER *lph;
	char	*lpbuf, *tp;
	char    c;
	int nframes;
	
	lpbuf = (char *) calloc(LPBUFSIZ, sizeof(char));
	lph = (LPHEADER *) lpbuf;
	tp = lph->text;

	iname = &soundFile[0];		/* '\0' ==> stdin */
	oname = &lpFile[0];		/* '\0' ==> stdout */
	NPOLE = npoles;	
	slice = lpframeoffset;
	inskip = lpinskip;
	dur = lpdur;		/* should implement an EOF dur */
	strncat(tp, comment, (LPBUFSIZ - sizeof(LPHEADER) + 4));
	tp += strlen(tp);

	if ((anal = creat (oname,0644)) < 0) {
		dies ("cannot open output data file: %s", oname);
		return 0;
		}
	sfname = iname;
	if ((sfd = open (sfname,O_RDONLY)) < 0) {
		dies("cannot open sound file %s", sfname);
		close (anal);
		return 0;
		}
	if ((n = readin (sfd, inbuf, sizeof (SNDSoundStruct)))
			< sizeof (SNDSoundStruct)) {
		die("soundfile header read error");
		close (anal); close (sfd);
		return 0;
		}
	sfh = (SFHEADER *) inbuf;
	if (sfh->sfinfo.NeXTheader.magic != SND_MAGIC) {
/*	if (sfmagic (sfh) != SF_MAGIC) { */
		dies("%s is not a soundfile", iname);
		close (anal); close (sfd);
		return 0;
		}
/*	sfdesc.sf_chans = sfchans(sfh);
	sfdesc.sf_class = sfclass(sfh);
	sfdesc.sf_srate = sfsrate(sfh);*/
	sfdesc.sf_chans = sfh->sfinfo.NeXTheader.channelCount;
	switch (sfh->sfinfo.NeXTheader.dataFormat) {
		case SND_FORMAT_LINEAR_16:
			sfdesc.sf_class = SF_SHORT;
			break;
		case SND_FORMAT_FLOAT:
			sfdesc.sf_class = SF_FLOAT;
			break;
		default:
			die ("data format must be short or float");
			close (anal); close (sfd);
			return 0;
		}
	sfdesc.sf_srate = sfh->sfinfo.NeXTheader.samplingRate;
	if (debug) {
		fprintf(stderr, "sf_chans=%d sf_srate=%d sf_class=%d\n", 
		sfdesc.sf_chans, sfdesc.sf_srate, sfdesc.sf_class);
		}
	if(sfdesc.sf_chans != 1) {
		die("takes monaural files only");
		close (anal); close (sfd);
		return 0;
		}
	if (NPOLE > POLEMAX) {
		dies("poles exceeds maximum allowed");
		close (anal); close (sfd);
		return 0;
		}
	FRAME = slice * 2;
	if (FRAME > FRAMAX) {
	  die("framesize (inter-frame-offset*2) exceeds maximum allowed");
		close (anal); close (sfd);
		return 0;
		}

	lph->lpmagic = LP_MAGIC;
	lph->srate = sfdesc.sf_srate;
	lph->npoles = NPOLE;
	lph->nvals = NPOLE + 4;
	lph->framrate = lph->srate / (float) slice;
	lph->duration = dur;

	/* compute header size */
	hsize = tp - (char *) lph;	/* sizeof text */
	esize = INCR - (hsize % INCR);	/* round up to 4 byte boundary */
	if (esize == 4) esize = 0;	/* if we need it */
	lph->headersize = hsize + esize;
	if (lph->headersize >= (LPBUFSIZ - sizeof(LPHEADER) + 4))
		lph->headersize = LPBUFSIZ;
	if (write(anal, (char *) lph, lph->headersize) < lph->headersize) {
		die("anallpc: can't write header");
		close (anal); close (sfd);
		return 0;
		}
	
	lseek (sfd, sfh->sfinfo.NeXTheader.dataLocation, L_SET);
	skipbytes = (long)(inskip * sfdesc.sf_srate) * (long)sfdesc.sf_class;
	if (lseek (sfd, skipbytes, L_INCR) < 0) {
		die ("bad sflseek on skip");
		close (anal); close (sfd);
		return 0;
		}

/*	fprintf(stderr,"Specify starting output frame number\t");
/*	scanf("%d",&firstframe);			
/*  for now we'll just say to start at 0 ('C' mind set)  	*/

	firstframe = 0;

	NPP1 = NPOLE+1;
	nblpc = (NPOLE + NDATA)*FLOAT;
	outskip = firstframe * nblpc + lph->headersize;	/* headersize is new */

	if ((lseek (anal,outskip,0)) < 0) {
	  	die("Bad lseek on analysis file");
		close (anal); close (sfd);
	  	return 0;
		}

	nsamps = dur * sfdesc.sf_srate;
	nbytes = FRAME * sfdesc.sf_class;	/* bytes for whole frame */
	if ((nread = readin(sfd, (char *)sigi, nbytes)) != nbytes) {
		die("soundfile read error: couldn't fill first frame");
		close (anal); close (sfd);
		return 0;
		}
	if (sfdesc.sf_class == SF_SHORT) {
		short *pt = (short *) &sigi[0];
		for (i = FRAME - 1; i >= 0; i--) sigi[i] = (double) pt[i];
		}
	else { /* SF_FLOAT */
		float *pt = (float *) &sigi[0];
		for (i = FRAME - 1; i >= 0; i--) sigi[i] = (double) pt[i];
		}
/*	for(i=0;i<FRAME;i++) printf("%d ",sigi[i]); 	*/

	nbytes >>= 1;				/* bytes to refill halfframe */
	counter = 1;
	nframes = nsamps / slice;

	for (i = 0; i < nsamps; ) {
		if (!alpol(sigi,&errn,&rms1,&rms2,cc)) {
			close (anal); close (sfd);
			return 0;
			}
		coef[0] = (float)rms2; 
		coef[1] = (float)rms1; 
		coef[2] = (float)errn; 
		coef[3] = 0.;			  /* for pitch of this frame */

			/* reverse the coefs & change sign */
		for(jj=NDATA; jj<NPOLE+NDATA; jj++)
			coef[jj] = (float)-cc[NPOLE-jj+(NDATA - 1)];  
						/* then write the anal frame */
		if ((n = write(anal, (char *)coef, nblpc)) != nblpc) {
			die("write error");
			close (anal); close (sfd);
			return 0;
			}
		sprintf (framerpt, "frame %5d of %5d", counter++, nframes);
		report (framerpt);
		for(jj=0; jj<slice; jj++,i++)	   /* now move slice forward */
			sigi[jj] = sigi[jj+slice];	/*   & refill:	     */
		for (jj = slice; jj < FRAME; jj++) sigi[jj] = 0.0;
		if ((n = readin(sfd, (char *)(sigi+slice), nbytes)) <= 0)
		  break;	/* ran up against eof */
		if (sfdesc.sf_class == SF_SHORT) {
			short *pt = (short *) &sigi[slice];
			for (jj = FRAME - 1; jj >= slice; jj--)
				sigi[jj] = (double) pt[jj - slice];
			}
		else { /* SF_FLOAT */
			float *pt = (float *) &sigi[slice];
			for (jj = FRAME - 1; jj >= slice; jj--)
				sigi[jj] = (double) pt[jj - slice];
			}
		}
	close (anal); close (sfd);
	return 1;
}

static int alpol(sig, errn, rms1, rms2, c)
double *sig, *errn, *rms1, *rms2, *c;
{
	double a[POLEMAX][POLEMAX], v[POLEMAX], b[POLEMAX];
	double *vp=v, *bp=b;
	double sum, sumx, sumy;
	int k1, i, l, k, limit, j;

	k1 = NPOLE + 1;
	for (i = 0; i < NPOLE; ++i)  {
		sum = (double) 0.0;
		for (k = NPOLE; k < FRAME; ++k) sum += sig[k-(i+1)] * sig[k];
		v[i] = -sum;
		if (i != NPOLE - 1)  {
			limit = NPOLE - (i+1);
			for (l=0; l < limit ;++l)  {
				sum +=	sig[NPOLE-(i+1)-(l+1)] *
					sig[NPOLE-(l+1)] -
					sig[FRAME-(i+1)-(l+1)] *
					sig[FRAME-(l+1)];
				a[(i+1)+l][l] = a[l][(i+1)+l] = sum;
				}
			}
		}
	sum = (double) 0.0;
	for (k = NPOLE; k < FRAME; ++k) sum += sig[k] * sig[k];
	sumy = sumx = sum;
	for (l = 0; l < NPOLE; ++l)  {
		sum +=	sig[NPOLE-(l+1)] * sig[NPOLE-(l+1)] -
			sig[FRAME-(l+1)] * sig[FRAME-(l+1)];
		a[l][l] = sum;
		}
	if (!gauss (a, v, b)) return 0;
	for (i = 0; i < NPOLE; ++i) sumy = sumy - b[i] * v[i];
	*rms1 = sqrt(sumx/(double) (FRAME - k1 + 1) );
	*rms2 = sqrt(sumy/(double) (FRAME - k1 + 1) );
	*errn = (*rms2 * *rms2) / (*rms1 * *rms1);
	for (bp = b; bp - b < NPOLE; ++bp, ++c) *c = *bp;
	return 1;
}

static int gauss(aold, bold, b)
double aold[POLEMAX][POLEMAX], *bold, *b;
{
	double amax, dum, pivot;
	double c[POLEMAX], a[POLEMAX][POLEMAX];
	int i, j, k, l, istar, ii, lp;

	/* aold and bold untouched by this subroutine */
	for (i=0; i < NPOLE ;++i)  {
		c[i] = bold[i];
		for (j = 0; j < NPOLE; ++j) a[i][j] = aold[i][j];
		}
	/* eliminate i-th unknown */
	for (i = 0; i < NPOLE - 1; ++i)  {        /* find largest pivot */
		amax = 0.0;
		for (ii = i; ii < NPOLE; ++ii)  {
			if (fabs (a[ii][i]) >= amax)  {
				istar = ii;
				amax = fabs (a[ii][i]);
				}
			}
		if (amax < 1e-20) {
			die("gauss: ill-conditioned");
			return 0;
			}

		for (j = 0; j < NPOLE; ++j)  {    /* switch rows */
			dum = a[istar][j];
			a[istar][j] = a[i][j];
			a[i][j] = dum;
			}
		dum = c[istar];
		c[istar] = c[i];
		c[i] = dum;
		/* pivot */
		for (j = i + 1; j < NPOLE; ++j)  {
			pivot = a[j][i] / a[i][i];
			c[j] = c[j] - pivot * c[i];
			for (k = 0; k < NPOLE; ++k)
				a[j][k] = a[j][k] - pivot * a[i][k];
			}
		}       /* return if last pivot is too small */
	if (fabs (a[NPOLE-1][NPOLE-1]) < 1e-20) {
		die("gauss: ill-conditioned");
		return 0;
		}

	*(b+NPOLE-1) = c[NPOLE-1] / a[NPOLE-1][NPOLE-1];
	/* back substitute */
	for (k = 0; k < NPOLE - 1; ++k)  {
		l = NPOLE-1 -(k+1);
		*(b+l) = c[l];
		lp = l + 1;
		for (j = lp; j < NPOLE; ++j) *(b+l) += -a[l][j] * *(b+j);
		*(b+l) /= a[l][l];
		}
	return(1);
}

static char errmsg[60];

static int dies(s,t)
 char *s, *t;
{
	sprintf(errmsg,s,t);
	return die(errmsg);
}

static int die(s)
char *s;
{
	report (s);
	return 0;
}

#define PFRAMSIZ  2                    /* words per frame (pitch&rms */
#define PCHSIZE   16                   /* record size in float words */
#define BPPFRAME  FLOAT*PFRAMSIZ       /* bytes per frame */
#define BPPREC    BPPFRAME*PCHSIZE     /* bytes per record */
#define FPPREC    PCHSIZE/PFRAMSIZ     /* frames per record */

static float PFPS;                     /* pitch frames per second */
static float sampspf;
static int pitches;
static int lpclast;
static float getfreq();

extern char ptFile[];
extern float ptframerate;

int lpconcat ()
{
        int anal,j;
	int npoles,lpcframe,pchframe,pchlast,nbpch;
	long nskiplpc,nskippch,nblpc;
	char  *input, *output;
	float pch[2],val,sr,time;
	LPHEADER *lph;
	char lpbuf[LPBUFSIZ];
	char c;

	input = &ptFile[0];
	output = &lpFile[0];
	PFPS = ptframerate;	/* this is ptrack.c default SR/JSLIDE */
	lpcframe = 0;
	lpclast = -1;		/* to EOF */

	if((anal = open (output,2)) < 0) {
		report ("Can't open lpc analysis file");
		return 0;
		}
	if((pitches = open (input,0)) < 0) {
		report ("Can't open pitch analysis file");
		return 0;
		}
	if ((j = read (anal, lpbuf, LPBUFSIZ)) <= 0)	{
		report ("Can't read header on lpc analysis file");
		return 0;
		}
	lph = (LPHEADER *) lpbuf;
	npoles = lph->npoles;
	sr = lph->srate;
	sampspf = sr / lph->framrate;

	nblpc = (npoles+4)*FLOAT - FLOAT;/*to beginning of next pchloc*/
	nskiplpc = (long)(lpcframe)*(long)(nblpc+FLOAT) + (3*FLOAT);  
				 /* pch is 4th data value in fr*/
	if((lseek (anal,nskiplpc + lph->headersize,0)) < 0)  { /* add */
		report ("Bad lseek on analysis file");	/* headersize */
		return 0;
		}
	for(j = lpcframe; ;j++) {
		time = (float)j*sampspf/sr;
		if ((j > lpclast && lpclast != -1) || (time > lph->duration))
			break;
/*
*		if((read(pitches,(char *)pch,nbpch)) != nbpch) {
*			printf("Bad read on pitch analysis file\n");
*			exit(1);
*			}
*/

		if ((val = getfreq (time)) < 0.0) return 0;
		if((write(anal,(char *)&val,FLOAT)) != FLOAT) {
			report ("Bad write on lpc analysis file");
			return 0;
			}
		lseek (anal,nblpc,1);
	}
	return 1;
}

static float getfreq(time) 
float time;
{


	int i,j,frame;
	float fframe,fraction,cps,error;
	static int oldframe = 0;
	static int endframe = 0;
	static float parray[PCHSIZE*2];

	fframe = time * PFPS;
	frame = (int)fframe;
	fraction = fframe - (float)frame;
	if(!((frame >= oldframe) && (frame < endframe))) {
		if(lseek(pitches,((long)frame*(long)BPPFRAME),0) < 0) {
			report ("Bad lseek on pitch file");
			return -1.0;
			} 
		read (pitches,(char *)parray,BPPREC);
		oldframe = frame;
		endframe = oldframe + FPPREC - 1;
		}
	cps = (1.-fraction) * *(parray+(frame-oldframe)*PFRAMSIZ) +
	    fraction  * *((parray+(frame-oldframe)*PFRAMSIZ)+2);
	error = (1.-fraction) * *(parray+(frame-oldframe)*PFRAMSIZ+1) +
	    fraction  * *((parray+(frame-oldframe)*PFRAMSIZ)+3);
	return(cps);
}

/*  PTRACK - Standalone pitch analysis program.  Revised dll@ems.
 *     Reads a fixed-point monaural sound file (with or without header).
 *     
 *     Program accepts command-line data (see man entry),
 *     or with -q will querie the user for the following:
 *
 *    -Name of soundfile.
 *    -Sampling rate (if no header).
 *    -Name of file to contain analysis data--can be an old or null file.
 *    -Framesize.  The size of the frame to be analyzed, in samples.
 *     Maximum is 350, which has been good working number.  Frame should
 *     be able to contain at least one expected pitch period of signal.
 *    -JSLIDE.  The number of new samples to add per frame.  This number 
 *     should normally be less than half of LSLICE.  125 is good for 15k
 *     and 250 is good for 30k sampling rate.
 *     This number reflects the real time period of the frame, i.e. how
 *     far you creep up for each frame in the signal.
 *    -pchlow and pchigh-- expected lower and upper bounds of analysis.
 *     the better you guess at this, the better the quantization will
 *     be in the analysis.
 *     At the present time the highest fundamental analyzable is about SR/20
 *     cps, due to the settings of the lowpass filter.  This can be fixed
 *     by using interpolation, as in the fortran version of this program, 
 *     or, more sensibly, different filters.
 *    -inskip, amount of time to skip on input file before beginning analysis.
 *     The program is now written to write data sequentially beginning at the
 *     start of the data file, but this can be changed by simple adding an
 *     lseek.  
 *     (inskip should match the -s value in soundout).
 *    -dur,   amount of time to analyze. This should equal, but not
 *     exceed the -d value from soundout. 
 *  The following is good for a 15k signal, for example:
 *
 *	inname 15000 outname
 *	350 125
 *	200 300
 *	0 .5
 *    
 */
 
#include "ptrack.h"

extern float ptinskip, ptdur, sr, ptlowest, pthighest;
extern int ptframesize, ptframeoffset;
extern double lowpass();
extern void init_lowpass();

int LSLICE, JSLIDE, JMAX, MM;
float SR, NYQ; 

static float gtphi[50][5][MAXMM],gtpsi[50][6][MAXMM];
static float gtgamph[50][5],gtgamps[50][6];

int ptrack ()
{
	double sig[PFRAMAX];
	int MIDPOINT,needed,howmuch;
	float freq[50];
	float getpch(),getrms(), ptable();
	float pchlow,pchigh,input[4];
	FILE *pdata;
	int i,n,jj,anal,framesize,sampsize;
	long nsamps;
	float data[2],inskip,dur;
	char *name, *fullsfname, ptrpt[64];
	char *sigp,*sigtemp;
	double rmsm,freqm,rmsx,freqx;
	SFHEADER *sfh;
	char sfbuf[SIZEOF_HEADER];
	char  *sfname;
	int sfd, sfn, counter;
	int Hflag = 0;
	char c;
	int rflag = 0;

	sfname = &soundFile[0];		/* '\0' => stdin */
	name = &ptFile[0];		/* '\0' => stdout */
	LSLICE = ptframesize;		/* 350 is max! */
	JSLIDE = ptframeoffset;
	pchlow = ptlowest;
	pchigh = pthighest;
	inskip = ptinskip;
	dur = ptdur;		/* should implement an EOF dur! */
	SR = sr;

	if ((anal = creat (name,0644)) < 0) { /* create if not exists */
		dies("ptrack: can't open output data file %s", name);
		return 0;
		}
	fullsfname = sfname;
	if ((sfd = open (fullsfname,O_RDONLY)) < 0) {
		dies("Ptrack: can't open soundfile %s",fullsfname);
		close (anal);
		return 0;
		}
	if ((sfn = readin (sfd,sfbuf,sizeof (SNDSoundStruct)))
			< sizeof (SNDSoundStruct)) {
		die("Ptrack: error reading soundfile header");
		close (anal);
		close (sfd);
		return 0;
		}
	sfh = (SFHEADER *) sfbuf;
/*	if (!ismagic(sfh)) {*/
	if (sfh->sfinfo.NeXTheader.magic != SND_MAGIC) {
		dies("Ptrack: %s is not a soundfile",sfname);
		close (anal);
		close (sfd);
		return 0;
		}
	switch (sfh->sfinfo.NeXTheader.dataFormat) {
		case SND_FORMAT_LINEAR_16:
			sampsize = SF_SHORT;
			break;
		case SND_FORMAT_FLOAT:
			sampsize = SF_FLOAT;
			break;
		default:
			die ("data format must be short or float");
			close (anal); close (sfd);
			return 0;
		}
	{			/* do input skipping */
	  long skipbytes;
	  int nread;
	  lseek (sfd, sfh->sfinfo.NeXTheader.dataLocation, L_SET);
	  skipbytes = (long) (inskip * SR * sampsize);
	  if (lseek (sfd,skipbytes,L_INCR) < 0) {
	  	die("bad sflseek on skip");
		close (anal);
		close (sfd);
		return 0;
		}
	}

	NYQ = SR/2.;
	JMAX = LSLICE/10;
	MM = ((LSLICE/10+1)/2);
	MIDPOINT = LSLICE - JSLIDE;
	sigp = (char *)(sig+MIDPOINT);
	ptable(pchlow,pchigh,gtphi,gtpsi,gtgamph,gtgamps,freq,n); 

	if ((jj = readin(sfd,(char *)sig,LSLICE*sampsize))
			!= LSLICE*sampsize) {
		die("Ptrack: couldn't fill first frame");
		close (anal);
		close (sfd);
		return 0;
		}
	if (sampsize == SF_SHORT) {
		short *pt = (short *) &sig[0];
		for (i = LSLICE - 1; i >= 0; i--) sig[i] = (double) pt[i];
		}
	else { /* SF_FLOAT */
		float *pt = (float *) &sig[0];
		for (i = LSLICE - 1; i >= 0; i--) sig[i] = (double) pt[i];
		}
	init_lowpass ();
	for (i = 0; i < LSLICE; i++) sig[i] = lowpass (sig[i]);
	nsamps = SR * dur;
	counter = 1;
	while (nsamps) {
		data[0] = getpch(sig,gtphi,gtpsi,gtgamph,gtgamps,freq,n);
		data[1] = getrms(sig);
		write (anal,(char *)data,8);
		sprintf (ptrpt, "frame %5d, pitch = %8.2f", counter++,
				data[0]);
		report (ptrpt);
		sigp = (char *)(sig+MIDPOINT);
		for (i = 0; i < MIDPOINT; i++) sig[i] = sig[i+JSLIDE];
		howmuch = 0;
		needed = JSLIDE * sampsize;

		if ((howmuch = readin (sfd,sigp,needed)) != needed) break;		
		if (sampsize == SF_SHORT) {
			short *pt = (short *) &sig[MIDPOINT];
			for (jj = LSLICE - 1; jj >= MIDPOINT; jj--)
				sig[jj] = (double) pt[jj - MIDPOINT];
			}
		else { /* SF_FLOAT */
			float *pt = (float *) &sig[MIDPOINT];
			for (jj = LSLICE - 1; jj >= MIDPOINT; jj--)
				sig[jj] = (double) pt[jj - MIDPOINT];
			}
		for(i = MIDPOINT; i < LSLICE; i++) sig[i] = lowpass (sig[i]); 
		nsamps -= JSLIDE; 
		}
	close (anal); close (sfd);
	return 1;
}

void lpdump (FILE *outfile)
{
	int fd, nbytes, l, framsize, i, frmno = 0;
	char lpbuf[LPBUFSIZ], dumprpt[32];
	float frmbuf[MAXFRAME];
	LPHEADER *lph;
	
	if ((fd = open (lpFile, O_RDONLY)) < 0)	{
		dies ("lpdump: can't open %s", lpFile);
		return;
		}
	if ((nbytes = read (fd, lpbuf, LPBUFSIZ)) <= 0)	{
		dies ("lpdump: read error on %s", lpFile);
		close (fd);
		return;
		}
	lph = (LPHEADER *) lpbuf;
	if (lph->lpmagic != LP_MAGIC)	{
		dies ("lpdump: %s is not an lpfile", lpFile);
		close (fd);
		return;
		}
	if ((l = lseek (fd, lph->headersize, 0)) < 0)	{
		dies ("lpdump: bad lseek on %s", lpFile);
		close (fd);
		return;
		}
	framsize = lph->nvals * FLOAT;
	while (++frmno)	{
		if ((read (fd, (char *) frmbuf, framsize)) < framsize) {
			die ("End of lp file");
			close (fd);
			return;
			}
		
		fprintf(outfile, "\n\nFrame #%d\n",frmno);
		sprintf (dumprpt, "dumping frame %d", frmno);
		report (dumprpt);
		fprintf(outfile, "rms1: %f	rms2: %f	error: %f	cps: %f\n",frmbuf[0], frmbuf[1], frmbuf[2], frmbuf[3]);
		fprintf(outfile, "Coeffs:");
		for (i = 0; i < lph->npoles; i++) {
			if ((i % 6) == 0) fprintf (outfile, "\n  ");
			fprintf (outfile, "%10.6f ", frmbuf[4 + i]);
			}
		fprintf (outfile, "\n");
	}
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.