ftp.nice.ch/pub/next/unix/audio/cmusic.bs.N.tar.gz#/src/frm/oldspect.c

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

#include <stdio.h>
#include <math.h>
#include <carl/carl.h>
#include <carl/defaults.h>
#include <carl/procom.h>

/*------------------------------------------------------
			spect.c

This is a general purpose spectral display program for
	terminals without graphics capability.  

To compile: cc -O spect.c -lieee -lI77 -lF77 -lcarl -lm

-------------------------------------------------------*/


#define SI (*(sbuf+i))

main(narg,argv)
	int narg;
	char *argv[]; 
{
	char 	d[64][20];	/* array for terminal display */

	int 	i, j,
		v,
		iter, 
		niter = 1;

	long	sampa = 0, 	/* number of samples to skip at start */
		ns,		/* counter for skipping sampa samples */
		sdur = 1024, 	/* number of samples in window */
		N,		/* number of points in FFT (N >= sdur) */
		N2,		/* N/2 */
		order,		/* order of lpc filter */
		skip = 0,	/* number of samples to skip between iter */
		fanin;		/* reduction factor for display */

	int 	flagno = 0, magspec = 0, powspec = 0, comspec = 0, phaspec = 0,
		dbspec = 0, rect = 0, un = 0, joffset, aspec = 0, 
		lpcauto = 0, lpccovar = 0, lpspec = 0, fspec = 0, first = 0;

	float 	*sbuf,		/* array for FFT */
		*tbuf,		/* array for buffering input */
		*wind,		/* array for window */
		*abuf,		/* array for accumulating FFT's to average */
		*tpnt,		/* pointer to locations in tbuf */
		*cbuf,		/* array for lpc coefficients */
		*grc,		/* array for lpc reflection coefs */
		alpha,		/* lpc goodness of fit parameter */
		Smax,		/* maximum spectral magnitude */
		Speak,		/* maximum spectral magnitude */
		fac,		/* factor for Hamming window */
		norm = 1.,	/* factor for rectangular window */
		sum = 0.,	/* for normalizing Hamming window */
		pmax;

	char 	ch;
	PROP	*proplist;	/* from header on stdin */
	float	srate = 1.;	/* input sampling rate */
	char	*dbuf;		/* buffer for strings read from header */
	char	chbuf[72];	/* buffer for strings to write to header */

/* read header from stdin */

	if (isatty(0)) usage(1);

	if ((proplist =  getheader(stdin)) != NULL) {	/* there is a header */

		if ((dbuf = getprop(stdin,H_SRATE)) != NULL) {
			srate = atof(dbuf);		/* get input srate */
		}
	}

/* call crack to interpet commandline */

    while ((ch = crack(narg, argv, "R|", 1)) != NULL) 
	{
	switch (ch) 
		{
		case 'R': srate = sfexpr(arg_option, 1.0); break;
		}
	}

    arg_index = 0;	/* reset for second call to crack() */

    while ((ch = crack(narg, argv, "l|k|b|w|s|n|R|adfpmtcruh", 0)) != NULL) {
	switch (ch) {
		case 'R':
			break;
		case 'b':
			sampa = sfexpr(arg_option, srate);
			flagno++;
			break;
		case 'w':
			sdur = sfexpr(arg_option, srate);
			flagno++;
			break;
		case 's':
			skip = sfexpr(arg_option, srate);
			flagno++;
			break;
		case 'n':
			niter = sfexpr(arg_option,1.);
			flagno++;
			break;
		case 'l':
			order = sfexpr(arg_option,1.);
			flagno++;
			rect = 1;
			lpcauto = 1;
			lpspec = 1;
			break;
		case 'k':
			order = sfexpr(arg_option,1.);
			flagno++;
			rect = 1;
			lpccovar = 1;
			lpspec = 1;
			break;
		case 'd':
			flagno++;
			dbspec = 1;
			break;
		case 'a':
			flagno++;
			aspec = 1;
			break;
		case 'r':
			flagno++;
			rect = 1;
			break;
		case 'f':
			flagno++;
			fspec = 1;
			rect = 1;
			un = 1;
			break;
		case 'u':
			flagno++;
			un = 1;
			break;
		case 'p':
			/* does not set flagno */
			powspec = 1;
			break;
		case 'm':
			/* does not set flagno */
			magspec = 1;
			break;
		case 'c':
			/* does not set flagno */
			comspec = 1;
			break;
		case 't':
			/* does not set flagno */
			phaspec = 1;
			break;
		case 'h':
			usage(0);
		default:
			usage(1);
	}
	if (exprerr) {
	    fprintf(stderr,"Expression error:'%s'\n",argv[arg_index]);
	    exit(1);
	}
    }

/* no flags given, and there are remaining arguments ? (This is included
	to provide backwards compatibility.) */

    if (!flagno && narg - arg_index != 0) {
	if (narg - arg_index != 3) {
		fprintf(stderr, "spect: must have three arguments\n");
		usage(1);
	}
	sampa = expr(argv[arg_index+0]);
	if (exprerr) {
	    fprintf(stderr,"Expression error:'%s'\n",argv[flagno+1]);
	    exit(1);
	}
	sdur = expr(argv[arg_index+1]);
	if (exprerr) {
	    fprintf(stderr,"Expression error:'%s'\n",argv[flagno+1]);
	    exit(1);
	}
	niter = expr(argv[arg_index+2]);
	if (exprerr) {
	    fprintf(stderr,"Expression error:'%s'\n",argv[flagno+1]);
	    exit(1);
	}
    }


/* N is the smallest power of two which is greater or equal to sdur */

	for (N=2; N <= 32*1024; N *= 2) if (N >= sdur) break;

	if (N >= 32*1024) {
		printf("You've got to be kidding!\n"); 
		exit(1);
	}

	N2 = N / 2;

	if (skip == 0) skip = sdur / 2;

	if ((sbuf = (float *) calloc(N+2, sizeof(float))) == NULL)
		malerr("spect: insufficient memory", 1);
	if ((tbuf = (float *) calloc(sdur, sizeof(float))) == NULL)
		malerr("spect: insufficient memory", 1);
	if ((wind = (float *) calloc(sdur, sizeof(float))) == NULL)
		malerr("spect: insufficient memory", 1);
	if (lpspec)
		if ((cbuf = (float *) calloc((order+1), sizeof(float))) == NULL)
			malerr("spect: insufficient memory", 1);
	if (lpspec)
		if ((grc = (float *) calloc(order, sizeof(float))) == NULL)
			malerr("spect: insufficient memory", 1);
	if (aspec)
		if ((abuf = (float *) calloc(N2, sizeof(float))) == NULL)
			malerr("spect: insufficient memory", 1);
	tpnt = tbuf;

/* write header to stdout */

	sprintf(chbuf,"%d",N);
	addprop(stdin,"BlockSize",chbuf);

	addprop(stdin,H_SNDOUT_FORMAT,H_FLOATSAM);	/* -of */

	cpoheader(proplist,stdout);
	putheader(stdout);			/* write header to stdout */

/* skip over sampa input samples, then read next sdur samples */

	for (ns=0; ns<sampa; ns++) if (getfloat(sbuf) <= 0){ 
		fprintf(stderr,"spect: only %d input samples\n",ns);
		exit(1);
	}
	for (i=0; i<sdur;  i++) if (getfloat(tbuf+i) <= 0){
		*(tbuf+i) = 0.;
		if (first++ == 0)
		fprintf(stderr,"spect: warning - only %d input samples\n",i);
	}
	for (i=0; i<sdur;  i++) *(sbuf+i) = *(tbuf+i);

/* set up normalized hamming window */

	fac = 8.0*atan(1.)/(sdur-1.0);
	for (i=0; i<sdur; i++) *(wind+i) = .54 -.46*cos(fac*i);
	for (i=0; i<sdur; i++) sum += *(wind+i);
	sum = 1. / sum;
	for (i=0; i<sdur; i++) *(wind+i) *= sum;

	if (fspec != 1) norm = 1. / sdur;

/* main loop: step through niter times, skipping by skip samples */

	for (iter=0; iter<niter; iter++) {

		Smax = 0.;

		if (iter != 0) {
			if (skip >= sdur) {

				for (i=0; i < (skip - sdur); i++)
				if (getfloat(sbuf) <= 0) exit(0);

				for (i=0; i < sdur; i++)
				if (getfloat(sbuf+i) <= 0) exit(0);

			}
			else {

				for (i=0; i < skip; i++){

				if (getfloat(tpnt++) <= 0) exit(0);
				if (tpnt >= (tbuf + sdur)) tpnt = tbuf;

				}

				for (i=0; i < sdur ; i++){

				*(sbuf+i) = *tpnt++;
				if (tpnt >= (tbuf + sdur)) tpnt = tbuf;

				}

			}
		}

/* apply Hamming window (unless -r flag is used) */

		if (!rect) for (i=0; i<sdur; i++) SI *= *(wind+i);
		else for (i=0; i<sdur; i++) SI *= norm;

		for (i=sdur; i < N+2; i++) SI = 0.;

/* optional linear prediction: replace signal to be transformed by lp estimate*/

		if (lpspec){

			if (lpcauto) auto_(&sdur,sbuf,&order,cbuf,&alpha,grc);
			if (lpccovar) covar_(&sdur,sbuf,&order,cbuf,&alpha,grc);

			*sbuf = 1.;
			for (i=1; i < N; i++){
				sum = 0.;
				for (j = 1; j <= order; j++){
					if ((i - j) >= 0) sum += *(cbuf + j) *
						*(sbuf + i - j);
				}
				SI = - sum;
			}
		}

/* call fast_ to perform FFT */

		fast_(sbuf,&N);

/* if -c then write out complex values */

		if (comspec) {

			if (isatty(1)) {
				for (i=0; i<N/2; i++)
			printf("[%d] %f  %f\n",i, *(sbuf+i*2), *(sbuf+i*2+1));

			} else {

				for (i=0; i<N; i++) putfloat(sbuf+i);
				flushfloat();
			}

		continue;		/* go back to start of main loop */

		}

/* if -t then write out phase values */

		if (phaspec) {

		    for (i=0; i<N2; i++)
			SI = 
			 atan2( (double) *(sbuf+i*2+1), (double) *(sbuf+i*2) ) ;
			if (isatty(1)) {
				for (i=0; i<N2; i++)
				    printf("[%d] %f\n",i, SI );
			} else {
				for (i=0; i<N2; i++) putfloat(sbuf+i);
				flushfloat();
			}

		continue;		/* go back to start of main loop */

		}

/* otherwise calculate magnitude-squared */

		for (i=0; i<N2; i++)
		SI = *(sbuf+i*2) * *(sbuf+i*2) + *(sbuf+i*2+1) * *(sbuf+i*2+1);

/* if -m then write out magnitude values */

		if (magspec) {

			for (i=0; i<N2; i++) SI = sqrt( SI );

			if (isatty(1)) {
				for (i=0; i<N2; i++)printf("[%d] %f\n",i, SI );

			} else {

				for (i=0; i<N2; i++)putfloat(sbuf+i);
				flushfloat();
			}

		continue;

		}

/* if -p then write out power values */

		if (powspec) {

			if (isatty(1)) {
				for (i=0; i<N2; i++)printf("[%d] %f\n",i, SI );

			} else {

				for (i=0; i<N2; i++)putfloat(sbuf+i);
				flushfloat();
			}

		continue;

		}

/* if -a then accumulate average magnitude-squared values */

		if (aspec) {

			for (i=0; i<N2; i++) *(abuf+i) += SI ;

		continue;

		}

/* if -d then write out log-magnitude (decibel) values */

		if (dbspec) {

			for (i=0; i<N2; i++) if ( SI > Smax) Smax = SI ;

			if (Smax <= 0.){
				fprintf(stderr,"spect: zero input");
				exit(1);
			}

			if (un) Smax = 1.;

			Smax = 1. / Smax;

			for (i=0; i<N2; i++){ 
				if (( SI * Smax) > 1.e-20)
					SI = 10.* log10( SI * Smax );
				else SI = - 200.;
			}

			if (isatty(1)) {
				for (i=0; i<N2; i++)printf("[%d] %f %f\n",
					i, (float) i*srate/N,  SI );

			} else {

				for (i=0; i<N2; i++)putfloat(sbuf+i);
				flushfloat();
			}

		continue;

		}

/* create terminal display */

	for (i=0; i<N2; i++) if ( SI > Smax) Smax = SI; 

	if (Smax <= 0.){
		fprintf(stderr,"spect: zero input");
		exit(1);
	}

	if (un) Speak = Smax;
		else Speak = 1.;

	Smax = 1. / Smax;

	for (i=0; i<N2; i++){
		if (( SI * Smax) > 1.e-20) SI = 10.* log10( SI * Smax );
		else SI = - 200.;
	}

	fanin = N2/64;
	if (fanin < 1) fanin = 1;

	joffset = ((float) 10. * log10(Speak));

	for (i=0; i<64; i++) for (j=0; j<20; j++) d[i][j] = ' ';

	for (i=0, j=19; i<64; i++) d[i][j] = '_';

	for (i=0, j=0; j<20; j++) d[i][j] = '|';

	for (i=0; i<64; i++) {
		for (pmax = *(sbuf+i*fanin), j = 1; j < fanin; j++) 
			if (*(sbuf+i*fanin+j) > pmax) pmax = *(sbuf+i*fanin+j);

		v =  -pmax/3.;

		for (j = v; j < 19; j++) d[i][j] = '*';

	}

	printf("(dB)\n");

	for (j = 0; j < 20; j++) {

		printf("%4d", -(j*3) + joffset);
		for (i = 0; i < 64; i++) putchar(d[i][j]);
		putchar('\n');

	}

	printf(" Hz: ");
	printf("0      ^      R|8      ^      R|");
	printf("4      ^     3R|8      ^      R|2");
	printf("\nIteration Number: %d\n", iter);

    }

    if (aspec) {

		for (i=0; i<N2; i++) SI = *(abuf+i) / niter;

		for (i=0; i<N2; i++) if ( SI > Smax) Smax = SI ;

		if (Smax <= 0.){
			fprintf(stderr,"spect: zero input");
			exit(1);
		}

		if (un) Smax = 1.;

		Smax = 1. / Smax;

		for (i=0; i<N2; i++){
			if (( SI * Smax) > 1.e-20) SI = 10.* log10( SI * Smax );
			else SI = - 200.;
		}

		if (isatty(1)) {
			for (i=0; i<N2; i++)printf("[%d] %f %f\n",
				i, (float) i*srate/N,  SI );

		} else {

			for (i=0; i<N2; i++)putfloat(sbuf+i);
			flushfloat();
		}

    }

    exit(0);
}

usage(x)
{
fprintf(stderr,"usage: %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
"spect [flags] < floatsams > output (input must be file or pipe)\n",
"\tflags:	(defaults in parenthesis)\n",
"\t-p	output power spectrum as floatsams\n",
"\t-m	output magnitude (amplitude) spectrum as floatsams\n",
"\t-d	output power spectrum in db as floatsams\n",
"\t-t	output phase spectrum (range: [-pi,+pi]) as floatsams\n",
"\t-c	output complex spectrum as floatsams\n",
"\t-a	output average power spectrum (over -n iterations) in db \n",
"\t	(if none of above, a crude CRT plot of the spectrum is written)\n",
"\t-RN	set sample rate to N (default is read from stdin)\n",
"\t-bN	begin at time N (0)\n",
"\t-wN	window duration for FFT set to N seconds (1024S) \n",
"\t-nN	number of iterations: FFT N successive windows of input data (1)\n",
"\t-sN	skip window by N seconds between successive FFT's (-w / 2)\n",
"\t-lM	use M pole linear prediction estimate of input (autocorrelate)\n",
"\t-kM	use M pole linear prediction estimate of input (covariance)\n",
"\t-r	rectangular window: suppresses default hamming window\n",
"\t-u	un-normalize: suppresses default normalization of FFT to 0 db\n",
"\t-f	filter evaluation: input is filter impulse response\n",
"or\n",
"spect [-p, -c] start_sample n_samples n_iterations < floatsams > output\n",
"(this usage is supported for backwards compatability)\n"
);
exit(x);
}

malerr(str, ex)
	char *str;
	int ex;
{
	fprintf(stderr, "%s\n", str);
	exit(ex);
}

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