#ifndef lint
static char sccsid[] = "@(#)soundio.c	1.4 (mg@ukc.ac.uk) 5/18/90";
#endif
#include "cs.h"			/*						SOUNDIO.C	*/
#include "soundio.h"

	char	sfout[60];
static	char	*outbuf;			    /* (unused if nosound)  */
static	short	*outbufp;			    /*	    ditto	    */
static	float	*floutbufp;			    /*	    ditto	    */
static	char	*uloutbufp;
static	int	sfd, sfopen = 0, bufrem = 4;	    /* (real set in sfinit) */
static	float	fzero = 0.;

extern	float	*spout, maxamp[], omaxamp[];
extern  long	maxloc[], omaxloc[], rngcnt[];
extern	short	rngflg;
extern	int	nspout, nrecs, nchnls, ksmps;
extern	int	output_format, sampsize, bufsmps;
extern	int	remotein, remoteout;
extern	char	*buildsfname();

sfinit()					/* init for sound out */
{						/* (not called if nosound) */
register SFHEADER *sfh;
register char	*sfname, *wherecolon;

	if (outfile != NULL && strcmp(outfile, "-") == 0) {
		extern int outfd;
		/* Send sound output to what used to be stdout */
		sfd = outfd;
		sfname = "stdout";
	} else {
		sfname = buildsfname((outfile != NULL) ? outfile : DEFAULT_NAME);
		if (index(sfname,':') != NULL) 		/* if : in name,     */
			sfd = rsfopen(sfname,'>');	/*  open remote file */
#ifdef THINK_C
		else if ((sfd = open(sfname,O_TRUNC|O_CREAT|O_RDWR|O_BINARY)) < 0)
#else
		else if ((sfd = open(sfname,O_TRUNC|O_CREAT|O_RDWR, PMODE)) < 0)
#endif
			dies("sfinit: cannot open %s", sfname);
	}
        outbuf = mmalloc((long) OUTBUFSIZ);             /*  & alloc bufspace */
#ifdef SFIRCAM					/* for soundfiles w. headers */
	sfh = (SFHEADER *)outbuf;			/* positn header blk */
	sfsrate(sfh) = esr;				/*   at begin outbuf */
	sfchans(sfh) = nchnls;				/* & assgn headrvals */
	sfclass(sfh) = ((output_format == OF_FLOAT) ? SF_FLOAT : SF_SHORT);
	sfmagic(sfh) = SF_MAGIC;
	outbufp = (short *) (outbuf+sizeof(SFHEADER));	/* step over hdrblk */
	floutbufp = (float *) outbufp;			/*  for fix & float */
	bufrem = (OUTBUFSIZ - sizeof(SFHEADER)) / sampsize;
#else
	outbufp = (short *) outbuf;
	floutbufp = (float *) outbuf;
	uloutbufp = (char *) outbuf;
	bufrem = OUTBUFSIZ / sampsize;
#endif
#ifdef SFDIGDES
        AddMacHeader(sfname,nchnls,esr,(floatout ? 4:2));
#endif
	sfopen = 1;
 	printf("writing ");
	switch (output_format) {
	case OF_FLOAT: fputs("floats", stdout); break;
	case OF_SHORT: fputs("shorts", stdout); break;
#ifdef ULAW
	case OF_ULAW : fputs("ulaw bytes", stdout); break;
#endif
	default: abort();
	}
	printf(" to %s\n", sfname);

	strcpy(sfout, sfname);
}

static
fixtran()				/* fix spout vals and put in outbuf */
{					/*	write buffer when full	    */
register float	*sp, *maxampp;
register long   longsmp, *maxlocp, *rngp;
register int	n, spoutrem;
	float	absamp;

	sp = spout;			/* adr spout	*/	
	spoutrem = nspout;		/* smps to go	*/
	maxampp = maxamp;
	maxlocp = maxloc;

nchk:	if ((n = spoutrem) > bufrem)	/* if nspout remaining > buf rem, */
		n = bufrem;		/*	prepare to send in parts  */
	spoutrem -= n;
	bufrem -= n;
	do {
		if ((longsmp = *sp) >= 0) {		/* +ive samp:	*/
			if (*sp > *maxampp) {		/*  maxamp this seg  */
				*maxampp = *sp;		/*  and its location */
				*maxlocp = nrecstobytes(nrecs)
						+ ((char *) outbufp - outbuf);
			}
			if (longsmp > 32767) {		/* out of range?     */
				longsmp = 32767;	/*   clip and report */
				rngp = rngcnt + (maxampp - maxamp);
				(*rngp)++;
				rngflg = 1;
			}
		}
		else {					/* ditto -ive samp */
			if ((absamp = -*sp) > *maxampp) {
				*maxampp = absamp;
				*maxlocp = nrecstobytes(nrecs)
						+ ((char *) outbufp - outbuf);
			}
			if (longsmp < -32768) {
				longsmp = -32768;
				rngp = rngcnt + (maxampp - maxamp);
				(*rngp)++;
				rngflg = 1;
			}
		}
		if (sfopen)
			*outbufp++ = (short) longsmp;
		if (nchnls > 1) {
			maxlocp++;
			if (++maxampp - maxamp >= nchnls) {
				maxlocp = maxloc;
				maxampp = maxamp;
			}
		}
		sp++;
	} while (--n);
	if (!bufrem) {
		if (sfopen) {
			if ((n = write(sfd,outbuf,OUTBUFSIZ)) < OUTBUFSIZ)
				sounderr('w',n);
			nrecs++;
			outbufp = (short *) outbuf;
		}
		bufrem = bufsmps;
		if (spoutrem) goto nchk;
	}
}

#ifdef ULAW
/*
** This routine converts from linear to ulaw.
**
** Craig Reese: IDA/Supercomputing Research Center
** Joe Campbell: Department of Defense
** 29 September 1989
**
** References:
** 1) CCITT Recommendation G.711  (very difficult to follow)
** 2) "A New Digital Technique for Implementation of Any
**     Continuous PCM Companding Law," Villeret, Michel,
**     et al. 1973 IEEE Int. Conf. on Communications, Vol 1,
**     1973, pg. 11.12-11.17
** 3) MIL-STD-188-113,"Interoperability and Performance Standards
**     for Analog-to_Digital Conversion Techniques,"
**     17 February 1987
**
** Input: Signed 16 bit linear sample
** Output: 8 bit ulaw sample
*/

#define ZEROTRAP    /* turn on the trap as per the MIL-STD */
#define BIAS 0x84   /* define the add-in bias for 16 bit samples */
#define CLIP 32635

static unsigned char
lintoulaw( sample )
int sample;
    {
    static int exp_lut[256] = {0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
                               4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
                               5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
                               5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
                               6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
                               6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
                               6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
                               6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
                               7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
                               7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
                               7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
                               7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
                               7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
                               7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
                               7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
                               7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7};
    int sign, exponent, mantissa;
    unsigned char ulawbyte;

    /* Get the sample into sign-magnitude. */
    sign = (sample >> 8) & 0x80;		/* set aside the sign */
    if ( sign != 0 ) sample = -sample;		/* get magnitude */
    if ( sample > CLIP ) sample = CLIP;		/* clip the magnitude */

    /* Convert from 16 bit linear to ulaw. */
    sample = sample + BIAS;
    exponent = exp_lut[( sample >> 7 ) & 0xFF];
    mantissa = ( sample >> ( exponent + 3 ) ) & 0x0F;
    ulawbyte = ~ ( sign | ( exponent << 4 ) | mantissa );
#ifdef ZEROTRAP
    if ( ulawbyte == 0 ) ulawbyte = 0x02;	/* optional CCITT trap */
#endif

    return ulawbyte;
    }

static
ulawtran()				/* fix spout vals and put in outbuf */
{					/*	write buffer when full	    */
register float	*sp, *maxampp;
register long   longsmp, *maxlocp, *rngp;
register int	n, spoutrem;
	float	absamp;

	sp = spout;			/* adr spout	*/	
	spoutrem = nspout;		/* smps to go	*/
	maxampp = maxamp;
	maxlocp = maxloc;

nchk:	if ((n = spoutrem) > bufrem)	/* if nspout remaining > buf rem, */
		n = bufrem;		/*	prepare to send in parts  */
	spoutrem -= n;
	bufrem -= n;
	do {
		if ((longsmp = *sp) >= 0) {		/* +ive samp:	*/
			if (*sp > *maxampp) {		/*  maxamp this seg  */
				*maxampp = *sp;		/*  and its location */
				*maxlocp = nrecstobytes(nrecs)
						+ (uloutbufp - outbuf);
			}
			if (longsmp > 32767) {		/* out of range?     */
				longsmp = 32767;	/*   clip and report */
				rngp = rngcnt + (maxampp - maxamp);
				(*rngp)++;
				rngflg = 1;
			}
		}
		else {					/* ditto -ive samp */
			if ((absamp = -*sp) > *maxampp) {
				*maxampp = absamp;
				*maxlocp = nrecstobytes(nrecs)
						+ (uloutbufp - outbuf);
			}
			if (longsmp < -32768) {
				longsmp = -32768;
				rngp = rngcnt + (maxampp - maxamp);
				(*rngp)++;
				rngflg = 1;
			}
		}
		if (sfopen)
			*uloutbufp++ = lintoulaw((int)longsmp);
		if (nchnls > 1) {
			maxlocp++;
			if (++maxampp - maxamp >= nchnls) {
				maxlocp = maxloc;
				maxampp = maxamp;
			}
		}
		sp++;
	} while (--n);
	if (!bufrem) {
		if (sfopen) {
			if ((n = write(sfd,outbuf,OUTBUFSIZ)) < OUTBUFSIZ)
				sounderr('w',n);
			nrecs++;
			uloutbufp = (char *) outbuf;
		}
		bufrem = bufsmps;
		if (spoutrem) goto nchk;
	}
}
#endif

static
floatran()				/* send float spout vals to outbuf */
{					/*	write buffer when full	    */
register float	*sp, *maxampp;
register long	*maxlocp;
register int	n, spoutrem;
register float	absamp;

	sp = spout;			/* adr spout	*/	
	spoutrem = nspout;		/* smps to go	*/
	maxampp = maxamp;
	maxlocp = maxloc;

nchk:	if ((n = spoutrem) > bufrem)	/* if nspout remaining > buf rem, */
		n = bufrem;		/*	prepare to send in parts  */
	spoutrem -= n;
	bufrem -= n;
	do {
		if ((absamp = *sp) < 0.)
			absamp = -absamp;
		if (absamp > *maxampp) {	/*  maxamp this seg  */
			*maxampp = absamp;	/*  and its location */
			*maxlocp = nrecstobytes(nrecs)
					+ ((char *) floutbufp - outbuf);
		}
		if (sfopen)
			*floutbufp++ = *sp;
		if (nchnls > 1) {
			maxlocp++;
			if (++maxampp - maxamp >= nchnls) {
				maxlocp = maxloc;
				maxampp = maxamp;
			}
		}
		sp++;
	} while (--n);
	if (!bufrem) {
		if (sfopen) {
			if ((n = write(sfd,outbuf,OUTBUFSIZ)) < OUTBUFSIZ)
				sounderr('w',n);
			nrecs++;
			floutbufp = (float *) outbuf;
		}
		bufrem = bufsmps;
		if (spoutrem) goto nchk;
	}
}

/* Select one of the above */
tran()
{
	switch (output_format) {
	case OF_FLOAT: floatran(); break;
	case OF_SHORT: fixtran(); break;
#ifdef ULAW
	case OF_ULAW: ulawtran(); break;
#endif
	default: abort();
	}
}

static
szerotran(kcnt)			/* copy kcnt zerospouts to short soundbuf, */
 long kcnt;			/*	sending buffer whenever full	 */
{
register long	n, smpsrem, clearcnt = 0;

	if (!sfopen)  return;
	smpsrem = nspout * kcnt;	/* calculate total smps to go	*/
nchk:	if ((n = smpsrem) > bufrem)	/* if smps remaining > buf rem, */
		n = bufrem;		/*	prepare to send in parts  */
	smpsrem -= n;
	bufrem -= n;
	if (clearcnt < bufsmps) {
		clearcnt += n;		/* clear buf only till clean */
		do *outbufp++ = (short) 0;
		while (--n);
	}
	else outbufp += n;
	if (!bufrem) {
		if ((n = write(sfd,outbuf,OUTBUFSIZ)) < OUTBUFSIZ)
			sounderr('w',(int)n);
		nrecs++;
		outbufp = (short *) outbuf;
		bufrem = bufsmps;
		if (smpsrem) goto nchk;
	}
}

#ifdef ULAW
static
uzerotran(kcnt)
int kcnt;
{
register int	n, smpsrem, clearcnt = 0;
	char ulaw_zero = lintoulaw(0);	/* precalculate */

	if (!sfopen)  return;
	smpsrem = nspout * kcnt;	/* calculate total smps to go	*/
nchk:	if ((n = smpsrem) > bufrem)	/* if smps remaining > buf rem, */
		n = bufrem;		/*	prepare to send in parts  */
	smpsrem -= n;
	bufrem -= n;
	if (clearcnt < bufsmps) {
		clearcnt += n;		/* clear buf only till clean */
		do *uloutbufp++ = ulaw_zero;
		while (--n);
	}
	else uloutbufp += n;
	if (!bufrem) {
		if ((n = write(sfd,outbuf,OUTBUFSIZ)) < OUTBUFSIZ)
			sounderr('w',n);
		nrecs++;
		uloutbufp = (char *) outbuf;
		bufrem = bufsmps;
		if (smpsrem) goto nchk;
	}
}
#endif

static
fzerotran(kcnt)			/* copy kcnt zerospouts to float soundbuf, */
 long kcnt;			/*	sending buffer whenever full	 */
{
register long	n, smpsrem, clearcnt = 0;

	if (!sfopen)  return;
	smpsrem = nspout * kcnt;	/* calculate total smps to go	*/
nchk:	if ((n = smpsrem) > bufrem)	/* if smps remaining > buf rem, */
		n = bufrem;		/*	prepare to send in parts  */
	smpsrem -= n;
	bufrem -= n;
	if (clearcnt < bufsmps) {
		clearcnt += n;		/* clear buf only till clean */
		do *floutbufp++ = fzero;
		while (--n);
	}
	else floutbufp += n;
	if (!bufrem) {
		if ((n = write(sfd,outbuf,OUTBUFSIZ)) < OUTBUFSIZ)
			sounderr('w',(int)n);
		nrecs++;
		floutbufp = (float *) outbuf;
		bufrem = bufsmps;
		if (smpsrem) goto nchk;
	}
}

zerotran(kcnt)			/* copy kcnt zerospouts to short soundbuf, */
 int kcnt;			/*	sending buffer whenever full	 */
{

	switch (output_format) {
	case OF_FLOAT: fzerotran(kcnt); break;
	case OF_SHORT: szerotran(kcnt); break;
#ifdef ULAW
	case OF_ULAW: uzerotran(kcnt); break;
#endif
	default: abort();
	}
}

static SFCODE	ampcode = {
	SF_MAXAMP,
	sizeof(SFMAXAMP) + sizeof(SFCODE)
}; 

sfclose()
{
register int	nb, n;

	SFHEADER hd;
	SFMAXAMP sfm;

	if (!sfopen) return;
	if ((nb = (bufsmps - bufrem) * sampsize) > 0) {
		if ((n = write(sfd,outbuf,nb)) < nb)
			sounderr('w',n);
		nrecs++;
	}
#ifdef SFIRCAM
	if (!remoteout)		/* if perf is writing sound over the net,    */
	{			/* no backward seeks, so omit the following: */
		lseek(sfd,0L,0);
		rheader(sfd,&hd);		/* Update header with maxamp */
		for(n = 0; n < 4; n++) {
			sfmaxamp(&sfm,n) = omaxamp[n];
				/* First buf included header so subtract it */
			sfmaxamploc(&sfm,n) = (omaxloc[n]-sizeof(SFHEADER))>>1;
		}
	/*	sfmaxamptime(&sfm) = time(0);   */
		sfmaxamptime(&sfm) = 0;
		putsfcode(&hd,&sfm,&ampcode);
		lseek(sfd,0L,0);
		wheader(sfd,&hd);
	}
#endif
#ifdef SFDIGDES                  /* for Digidesign soundfile, */
        MacSetCreator(sfout);    /*   set creator & file type */
#endif
	close(sfd);
}

sndinset(p)				/* init for soundin, and gen01	*/
 register SOUNDIN *p;			/* all reads kept on		*/
{					/*   INBUFSIZ (4K?) boundaries	*/
register SFHEADER *sfh;
register int	n, hdrsize, insampsize;
	char	*sfname, numstr[10];

	if (p->infd > 0)
		return;
	if ((n = p->OUTCOUNT) != 1 && n != 2 && n != 4) {
		sprintf(errmsg,"illegal no of receiving channels");
		goto errtn;
	}


	/* Open the sound file */
	if ((int) *p->ifilno == 0) {
		/* 0 means read stdin */
		static int seen_stdin = 0;

		if (seen_stdin) {
			die("Cannot use soundin on stdin more than once");
		}
		p->infd = 0;
		seen_stdin = 1;
	} else {
		sfname = buildsfname(SOUNDIN_NAME);
		sprintf(numstr, "%d", (int) *p->ifilno);
		strcat(sfname,numstr);
		if (index(sfname,':') != NULL)		/* open infil remote */
			p->infd = rsfopen(sfname,'<');
		else if ((p->infd = open(sfname,O_RDONLY)) < 0) { /* or local */
			sprintf(errmsg,"soundin cannot open %s",sfname);
			goto errtn;
		}
		fdrecord(&p->infd);			 /* log the fd store */
	}
	p->endfile = 0;					 /* & begin fileread */
	if ((n = readin(p->infd,p->inbuf,INBUFSIZ)) == 0)
		sounderr('r',n);
	p->floatin = 0;					/* set default vals  */
	insampsize = 2;
	p->chanbytes = insampsize * p->OUTCOUNT;
	hdrsize = 0;
#ifdef SFIRCAM
	sfh = (SFHEADER *) p->inbuf;			/* & chk headercodes */
	if (sfmagic(sfh) == SF_MAGIC) {
		if (sfsrate(sfh) != esr) {
			sprintf(errmsg,"%s sr != orch sr",sfname);
			warning(errmsg);
		}
		if (sfchans(sfh) != p->OUTCOUNT) {
			sprintf(errmsg,"soundin cells != %s chnls",sfname);
			warning(errmsg);
		}
		if (sfclass(sfh) == SF_FLOAT) {
			p->floatin = 1;
			insampsize = 4;
		}
		p->chanbytes = insampsize * sfchans(sfh);
		hdrsize = sizeof(SFHEADER);
	}
	else if (BYTREVL(sfmagic(sfh)) == SF_MAGIC) {
		sprintf(errmsg,"%s bytes are in wrong order",sfname);
		goto errtn;
	}
	else {
		sprintf(errmsg,"%s not a soundfile, assuming floats",sfname);
		warning(errmsg);
		p->floatin = 1;
		p->chanbytes = 4 * p->OUTCOUNT;
	}
#endif
#ifdef SFDIGDES
    {
        float   fsr;               /* file sample rate */
        int     fnch, fbpd;        /* file channels & bytes per datum */

	if (ReadMacHeader(sfname,&fnch,&fsr,&fbpd) == 0) {  /* check resource */
		if (fsr != esr) {
			sprintf(errmsg,"%s sr != orch sr",sfname);
			warning(errmsg);
		}
		if (fnch != p->OUTCOUNT) {
			sprintf(errmsg,"soundin cells != %s chnls",sfname);
			warning(errmsg);
		}
		if (fbpd == 4) {        /* 2 means int (default). */
			p->floatin = 1; /* assume 4=float is only alternative. */
			insampsize = 4;
		}
		p->chanbytes = insampsize * fnch;
		hdrsize = 0;
	}                     /* allow default to INT16's if no resource found */
    }
#endif        
	p->inbufp = p->inbuf + hdrsize;			    /* step ovr hdr */
	p->bufend = p->inbuf + n;			    /* record endbuf */
	if (*p->iskptim > 0.) {				/* for pos skiptime: */
		long	nsamps, nbytes, seekbytes;
		nsamps = *p->iskptim * esr;		/* calc bytes to skip*/
		nbytes = nsamps * p->chanbytes + hdrsize;
		p->inbufp = p->inbuf + nbytes;
		if (p->inbufp >= p->bufend) {	   /* if not already in buf: */
			seekbytes = nbytes & (-INBUFSIZ);  /* mask to begin */
			if ((n = seekbytes/INBUFSIZ) > 1) {
				if (remotein)		/* remote? spin read */
					while (--n)	/*  to reqd boundary */
					     readin(p->infd,p->inbuf,INBUFSIZ);
				else if (lseek(p->infd,seekbytes,0) < 0)
					die("soundin seek error");
			}				/* now read for real */
			if ((n = readin(p->infd,p->inbuf,INBUFSIZ)) == 0)
				p->endfile = 1;
			else {
				nbytes -= seekbytes;	 /* then pnt to samp */
				p->inbufp = p->inbuf + nbytes;
				p->bufend = p->inbuf + n;
			}
		}
	}
	if (p->inbufp >= p->bufend)
		p->endfile = 1;
	return;

errtn:	if (p->h.insdshead == NULL) {
		printf(errmsg);			/* error from gen01 call */
		putchar('\n');
		inerrcnt++;
	}
	else initerror(errmsg);			/* else from instr soundin */
}

soundin(p)
 register SOUNDIN *p;
{
register short	nsmps;
register float	*r1, *r2, *r3, *r4;
	int	chnsout, n, ntogo;

	r1 = p->r1;
	r2 = p->r2;
	r3 = p->r3;
	r4 = p->r4;
	chnsout = p->OUTCOUNT;
	ntogo = ksmps;
	if (p->endfile)
		goto filend;
	nsmps = (p->bufend - p->inbufp) / p->chanbytes;
	if (nsmps > ksmps)
		nsmps = ksmps;
	ntogo -= nsmps;
	if (p->floatin) {
		register float *inbufp = (float *)p->inbufp;
floats:		switch(chnsout) {
		case 1:	do {	*r1++ = *inbufp++;
			} while (--nsmps);
			break;
		case 2:	do {	*r1++ = *inbufp++;
				*r2++ = *inbufp++;
			} while (--nsmps);
			break;
		case 4:	do {	*r1++ = *inbufp++;
				*r2++ = *inbufp++;
				*r3++ = *inbufp++;
				*r4++ = *inbufp++;
			} while (--nsmps);
		}
		if ((char *)inbufp >= p->bufend) {
			if ((n = readin(p->infd,p->inbuf,INBUFSIZ)) == 0) {
				p->endfile = 1;
				if (ntogo) goto filend;
				else return;
			}
			inbufp = (float *) p->inbuf;
			p->bufend = p->inbuf + n;
			if (ntogo > 0) {
				if ((nsmps = n / p->chanbytes) > ntogo)
					nsmps = ntogo;
				ntogo -= nsmps;
				goto floats;
			}
		}
		p->inbufp = (char *) inbufp;
	}
	else {
		register short *inbufp = (short *)p->inbufp;
shorts:		switch(chnsout) {
		case 1:	do {	*r1++ = (float) *inbufp++;
			} while (--nsmps);
			break;
		case 2:	do {	*r1++ = (float) *inbufp++;
				*r2++ = (float) *inbufp++;
			} while (--nsmps);
			break;
		case 4:	do {	*r1++ = (float) *inbufp++;
				*r2++ = (float) *inbufp++;
				*r3++ = (float) *inbufp++;
				*r4++ = (float) *inbufp++;
			} while (--nsmps);
		}
		if (inbufp >= (short *)p->bufend) {
			if ((n = readin(p->infd,p->inbuf,INBUFSIZ)) == 0) {
				p->endfile = 1;
				if (ntogo) goto filend;
				else return;
			}
			inbufp = (short *) p->inbuf;
			p->bufend = p->inbuf + n;
			if (ntogo > 0) {
				if ((nsmps = n / p->chanbytes) > ntogo)
					nsmps = ntogo;
				ntogo -= nsmps;
				goto shorts;
			}
		}
		p->inbufp = (char *) inbufp;
	}
	return;

filend:	nsmps = ntogo;
	switch(chnsout) {			/* if past end of file, */
	case 1:	do *r1++ = fzero;		/*    move zeros	*/
		while (--nsmps);
		break;
	case 2:	do {	*r1++ = fzero;
			*r2++ = fzero;
		} while (--nsmps);
		break;
	case 4:	do {	*r1++ = fzero;
			*r2++ = fzero;
			*r3++ = fzero;
			*r4++ = fzero;
		} while (--nsmps);
	}
}

sounderr(rw,nbytes)		/* report soundfile read/write error	*/
 char rw;			/* especially to check on remote r/w's	*/
 int nbytes;
{
	sprintf(errmsg,"soundfile error.  %s returned bytecount of %d, not %s",
		(rw == 'r')? "read" : "write",
		nbytes,
		(rw == 'r')? "INBUFSIZ" : "OUTBUFSIZ" );
	die(errmsg);
}
