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

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

#include <math.h>
#include <stdio.h>
#include <carl/sndio.h>
#include <carl/carl.h>

/*-------------------------------------------------------
			fastfir.c

This program designs FIR filters via the classical windowing
	technique.  The specifications are given via flags
	on the command line, and the coefficients are written
	to a specified file in the standard filter format.
	An optional output to stdout is the filter impulse
	response.  This is essentially a c version of the
	main program WINDOW from the IEEE Programs for Digital
	Signal Processing.

	cc fastfir.c -ljos -lieee -lI77 -lF77 -lcarl -lm

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

main(argc, argv)
	int argc;
	char **argv;
{
	float	srate = 1.,	/* sample rate */
		fc,		/* cutoff frequency */
		fl,		/* low-frequency band edge */
		fh,		/* high-frequency band edge */
		att = 70,	/* parameter for kaiser */
		alpha = -1.,	/* parameter for hamming */
		beta,		/* parameter for hamming, kaiser */
		dplog = 0.,	/* parameter for chebyshev */
		dp,		/* parameter for chebyshev */
		df = 0.,	/* parameter for chebyshev */
		x0,		/* for chebyshev */
		xn,		/* for chebyshev */
		c,		/* for impulse response calculation */
		c1,		/* for impulse response calculation */
		c3,		/* for impulse response calculation */
		pi,		/* 3.14159... */
		zero = 0.,	/* zero (for putfloat) */
		norm;		/* for normalizing filter */

	float	f[20],		/* holds cutoff frequency info */
		*w,		/* holds left half of window */
		*h;		/* holds left half of ideal response */

	int	i = -1,
		ia,		/* absolute value of i */
		nf = 3,		/* impulse response length */
		n,		/* half length */
		itype = 6,	/* window type */
		jtype = 1,	/* filter type */
		ieo = 0;	/* indicate even (0) or odd (1) */

	char	cbuf[72];	/* buffer for strings to write to header */

	char ch;

	FILE *fp;

/* Interpret commandline by calling dgl's subroutine crack. */

	while ((ch = crack(argc, argv, "n|x|w|f|a|b|c|d|R|h", 0)) != NULL) {
		switch (ch) {

			case 'n': nf = expr(arg_option); break;
			case 'x': jtype = expr(arg_option); break;
			case 'w': itype = expr(arg_option); break;
			case 'R': srate = expr(arg_option); break;
			case 'f': f[++i] = expr(arg_option); break;
			case 'a': att = expr(arg_option); break;
			case 'b': alpha = expr(arg_option); break;
			case 'c': dplog = expr(arg_option); break;
			case 'd': df = expr(arg_option); break;
			case 'h': usage(0);
			default:  usage(1);	/* this exits with error */
		}
	}

	if (arg_index < argc)
		fp = fopen(argv[arg_index],"w");
	else
		fp = fopen("tmp.flt","w");

	if ((jtype == 1) || (jtype == 2)){
		if (i != 0) {
			fprintf(stderr,"fastfir: specify ONE -f\n");
			fprintf(stderr,"fastfir: specify -h for help\n");
			exit(1);
		}
		fc = f[0] / srate;
	}
	else if((jtype == 3) || (jtype == 4)){
		if (i != 1) {
			fprintf(stderr,"fastfir: specify TWO -f's\n");
			exit(1);
		}
		if (f[0] < f[1]){
			fl = f[0] / srate;
			fh = f[1] / srate;
		}
		else if (f[0] > f[1]){
			fl = f[1] / srate;
			fh = f[0] / srate;
		}
		else {
			fprintf(stderr,"fastfir: impossible -f pair\n");
			exit(1);
		}
	} 
	else {
		fprintf(stderr,"fastfir: invalid -x = %d\n",jtype);
		exit(1);
	}

	if ((nf == 3) && (jtype != 7))
		nf = 127;

	if ((nf < 3) || (nf > 16384)){
		fprintf(stderr,"fastfir: invalid -n = %d\n",nf);
		exit(1);
	}

	if ((( jtype % 2) == 0 ) && (( nf % 2) == 0 )){
		nf -= 1;
		fprintf(stderr,"fastfir: warning > -n changed to %d\n",nf);
	}

	n = (nf + 1) / 2;
	if (2*n != nf)
		ieo = 1;

	pi = 4. * atan(1.);

	if ((w = (float *) calloc(n, sizeof(float))) == NULL)
		malerr("fastfir: insufficient memory",1);
	if ((h = (float *) calloc(n, sizeof(float))) == NULL)
		malerr("fastfir: insufficient memory",1);

/* Call subroutines from IEEE library. */

	switch(itype) {

		case 1:	for (i = 0; i < n; i++) *(w+i) = 1.;	/*rectangular*/
			break;

		case 2: triang_(&nf,w,&n,&ieo);			/*triangular */
			break;

		case 3: alpha = .54;				/*  hamming  */
			beta = 1. - alpha;
			hammin_(&nf,w,&n,&ieo,&alpha,&beta);
			break;

		case 4: if ((alpha < 0.) || (alpha > 1.)){	/*generalized*/
				fprintf(stderr,"fastfir: no valid -b\n");
				exit(1);
			}
			beta = 1. - alpha;
			hammin_(&nf,w,&n,&ieo,&alpha,&beta);
			break;

		case 5: alpha = .5;				/*  hanning  */
			beta = 1. - alpha;
			nf += 2;
			n += 1;
			hammin_(&nf,w,&n,&ieo,&alpha,&beta);
			nf -= 2;
			n -= 1;
			break;

		case 6:	if (att < 0.){				/*   kaiser  */
				fprintf(stderr,"fastfir: no valid -a\n");
				exit(1);
			}
			if (att > 50.)
				beta = .1102 * (att - 8.7);
			if ((att <= 50.) && (att >= 20.96)) {
				beta = pow((.58417 * (att - 20.96)), 0.4);
				beta += .07886 * (att - 20.96);
			}
			if (att < 20.)
				beta = 0.;
			kaiser_(&nf,w,&n,&ieo,&beta);
			break;

		case 7:	df = df / srate;			/* chebyshev */
			if ((df < 0.) || (df > .5)){
				fprintf(stderr,"fastfir: illegal -d\n");
				exit(1);
			}
			if ((df == 0.) && (nf == 3)){
				fprintf(stderr,"fastfir: need -n or -d\n");
				exit(1);
			}
			if ((df == 0.) && (dplog == 0.))
				dplog = 70.;
			if (nf == 3)
				nf = 0;
			dp = pow(10., -.05*dplog);
			chebc_(&nf,&dp,&df,&n,&x0,&xn);
			n = (nf + 1) / 2;
			if (2*n != nf)
				ieo = 1;
			cheby_(&nf,w,&n,&ieo,&dp,&df,&x0,&xn);
			break;

	}

/* Ideal impulse response calculation. */

	if (jtype < 3)
		c1 = fc;
	else
		c1 = fh - fl;
	if (ieo)
		*h = 2. * c1;

	for (i = ieo; i < n; i++){
		if (ieo)
			c = pi * i;
		else
			c = pi * ((float) i + .5);
		if (jtype < 3)
			c3 = 2. * c * c1;
		else
			c3 = c * c1;
		if (jtype < 3)
			*(h + i) = sin(c3) / c;
		else
			*(h + i) = 2. * cos(c * (fl + fh)) * sin(c3) / c;
	}

/* Actual impulse response calculation is window * ideal. */

	for (i = 0; i < n; i++)
		*(h + i) *= *(w + i);

	if (jtype < 3){					/* normalize */
		if (ieo)
			norm = *h;
		else
			norm = 2. * *h;
		for (i = 1; i < n; i++)
			norm += 2. * *(h + i);
		norm = (float) 1. / norm;
		for (i = 0; i < n; i++)
			*(h + i) *= norm;
	}

	if (jtype % 2 == 0){				/*highpass & bandstop*/
		*h = 1. - *h;
		for (i = 1; i < n; i++)
			*(h + i) = - *(h + i);
	}

	if (isatty(1) == 0){				/* optional output */
		sprintf(cbuf, "%f", srate);
		stdheader(stdout, NULL, cbuf, 1, H_FLOATSAM);
		for (i = -n + 1; i < n; i++){
			ia = (i > 0) ? i : -i;
			putfloat(h + ia);
			if ((ieo != 1) && (i == 0))
				putfloat(h);
		}
		for (i = nf ; i < 1024; i++)
			putfloat(&zero);
		flushfloat();
	}

/* Write filter file in standard format. */

	fprintf(stderr,"\nWriting filter file.\n");
    	fprintf(fp,"# FIR filter\n");
	fprintf(fp,"#\n#To see its response, type:\n"); 
	fprintf(fp,"#\timpulse 1024 512 | convolve filter_file | show\n#\n");
	fprintf(fp,"#To see its spectrum, type:\n");
	fprintf(fp,"\#\timpulse 1024 512 | convolve filter_file |");
	fprintf(fp," spect -f | btoa -F \n#\n");
	fprintf(fp,"#(where filter_file is this file)\n#\n");
	fprintf(fp,"filter;\n");
	fprintf(fp,"NIcoeffs = %d\n",nf);
	fprintf(fp,"NOcoeffs = 1\n");
	fprintf(fp,"ICoeffs = \n");
	for(i = -n + 1; i < n; i++){
		ia = (i > 0) ? i : -i;
		fprintf(fp," %-17.10e",*(h + ia)); 
		if (i%4 == 0)
			fprintf(fp,"\n");
		if ((ieo != 1) && (i == 0))
			fprintf(fp," %-17.10e",*(h + ia)); 
		if (i%4 == 0)
			fprintf(fp,"\n");
	}
	fprintf(fp,"\nOCoeffs = \n");
	fprintf(fp," 1.00\n");
	fclose(fp);

	exit(0);
}

usage(exitcode)
	int exitcode;
{
fprintf(stderr,"usage: %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
"fastfir [flags] filter_file [ > floatsams ]\n",
"\tflags:	(defaults in parenthesis)\n",
"\t-R	sample rate (1.)\n",
"\t-n	length of impulse response in samples (127)\n",
"\t-x	filter type: (1)\n\t\t1\tlowpass\n\t\t2\thighpass\n\t\t3\tbandpass\n",
	"\t\t4\tbandstop\n",
"\t-w	window type: (6)\n\t\t1\trectangular\n\t\t2\ttriangular\n\t\t3\tHamming\n",
"\t\t4\tgeneralized Hamming\n\t\t5\tHanning\n\t\t6\tKaiser\n\t\t7\tChebyshev\n",
"\t-f	filter cutoff frequency (use two -f's for bandpass or bandstop)\n",
"\t-a	Kaiser only:  stopband attenuation in db (70)\n",
"\t-b	generalized Hamming only:  w(i) = b + (1-b) * cos(2*pi*i/(n-1))\n",
"\t-c	Chebyshev only:  desired filter ripple attenuation in db (70)\n",
"\t-d	Chebyshev only:  transition width (0)\n",
"\t	(for Chebyshev, any two of -n, -c, and -d is sufficient)\n",
"\t if filter_file is not specified the file tmp.flt will be created");
	exit(exitcode);
}

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.