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

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

/* cspline - to compile this beastie utter: cc -O cspline.c -lsf -lm */

#include <stdio.h>
#include <carl/carl.h>
extern int      arg_index;	/* from crack() in -libsf */
extern char    *arg_option;	/* from crack() in -libsf */
int     otty;

#define NP 1024
#define INF 1.e37

struct proj {
	int     lbf,
	        ubf;
	float   a,
	        b,
	        lb,
	        ub,
	        quant,
	        mult,
	        val[NP];
}               x, y;
float  *diag,
       *r;
float   dx = 1.;
float   ni = 1024.;
int     n,
        Lflag = 0;
int     auta;
int     periodic;
float   konst = 0.0;
float   zero = 0.;

float
        rhs (i) {
	int     i_;
	double  zz;
	i_ = i == n - 1 ? 0 : i;
	zz = (y.val[i] - y.val[i - 1]) / (x.val[i] - x.val[i - 1]);
	return (6 * ((y.val[i_ + 1] - y.val[i_]) / (x.val[i + 1] - x.val[i]) - zz));
}

spline () {
	float   d,
	        s,
	        u,
	        v,
	        hi,
	        hi1;
	float   h;
	float   D2yi,
	        D2yi1,
	        D2yn1,
	        x0,
	        x1,
	        yy,
	        a;
	int     end;
	float   corr;
	int     i,
	        j,
	        m;
	if (n < 3)
		return (0);
	if (periodic)
		konst = 0;
	d = 1;
	r[0] = 0;
	s = periodic ? -1 : 0;
	for (i = 0; ++i < n - !periodic;) {/* triangularize */
		hi = x.val[i] - x.val[i - 1];
		hi1 = i == n - 1 ? x.val[1] - x.val[0] :
			x.val[i + 1] - x.val[i];
		if (hi1 * hi <= 0)
			return (0);
		u = i == 1 ? zero : u - s * s / d;
		v = i == 1 ? zero : v - s * r[i - 1] / d;
		r[i] = rhs (i) - hi * r[i - 1] / d;
		s = -hi * s / d;
		a = 2 * (hi + hi1);
		if (i == 1)
			a += konst * hi;
		if (i == n - 2)
			a += konst * hi1;
		diag[i] = d = i == 1 ? a :
			a - hi * hi / d;
	}
	D2yi = D2yn1 = 0;
	for (i = n - !periodic; --i >= 0;) {/* back substitute */
		end = i == n - 1;
		hi1 = end ? x.val[1] - x.val[0] :
			x.val[i + 1] - x.val[i];
		D2yi1 = D2yi;
		if (i > 0) {
			hi = x.val[i] - x.val[i - 1];
			corr = end ? 2 * s + u : zero;
			D2yi = (end * v + r[i] - hi1 * D2yi1 - s * D2yn1) /
				(diag[i] + corr);
			if (end)
				D2yn1 = D2yi;
			if (i > 1) {
				a = 2 * (hi + hi1);
				if (i == 1)
					a += konst * hi;
				if (i == n - 2)
					a += konst * hi1;
				d = diag[i - 1];
				s = -s * d / hi;
			}
		}
		else
			D2yi = D2yn1;
		if (!periodic) {
			if (i == 0)
				D2yi = konst * D2yi1;
			if (i == n - 2)
				D2yi1 = konst * D2yi;
		}
		if (end)
			continue;
		m = hi1 > 0 ? ni : -ni;
		m = 1.001 * m * hi1 / (x.ub - x.lb);
		if (m <= 0)
			m = 1;
		h = hi1 / m;
		for (j = m; j > 0 || i == 0 && j == 0; j--) {
				/* interpolate */
			x0 = (m - j) * h / hi1;
			x1 = j * h / hi1;
			yy = D2yi * (x0 - x0 * x0 * x0) + D2yi1 * (x1 - x1 * x1 * x1);
			yy = y.val[i] * x0 + y.val[i + 1] * x1 - hi1 * hi1 * yy / 6;
			save (yy);
		}
	}
	return (1);
}

readin (argi, argc, argv)
char  **argv; {
	extern double   atof ();
	if (!Lflag)
		ni = expr (argv[argi++]);
	for (n = 0; n < NP; n++) {
		if (auta)
			x.val[n] = n * dx + x.lb;
		else {
			if (argi < argc) {
				x.val[n] = expr (argv[argi++]);
				y.val[n] = expr (argv[argi++]);
			}
			else
				break;
		}
	}
}

getlim (p)
struct proj    *p; {
	int     i;
	for (i = 0; i < n; i++) {
		if (!p -> lbf && p -> lb > (p -> val[i]))
			p -> lb = p -> val[i];
		if (!p -> ubf && p -> ub < (p -> val[i]))
			p -> ub = p -> val[i];
	}
}


main (argc, argv)
char   *argv[]; {
	char    ch,
	        crack ();	/* from <CARL> -libsf */
	int     i;
	otty = isatty (1);
	x.lbf = x.ubf = y.lbf = y.ubf = 0;
	x.lb = INF;
	x.ub = -INF;
	y.lb = INF;
	y.ub = -INF;
	while ((ch = crack (argc, argv, "a|k|n|L|ocpl|u|h", 0)) != NULL) {
		switch (ch) {
			case 'a': 
				auta = 1;
				dx = expr (arg_option);
				break;
			case 'k': 
				konst = expr (arg_option);
				break;
			case 'n': 
			case 'L': 
				ni = expr (arg_option);
				Lflag++;
				break;
			case 'o': 
				break;/* "open" form is default */
			case 'c': /* "closed" same as "periodic" */
			case 'p': 
				periodic = 1;
				break;
			case 'l': 
				x.lb = expr (arg_option);
				x.lbf = 1;
				break;
			case 'u': 
				x.ub = expr (arg_option);
				x.ubf = 1;
				break;
			default: 
				fprintf (stderr, "Bad flag agrument\n");
			case 'h':
				usage(1);
		}
	}
	if (auta && !x.lbf)
		x.lb = 0;
	if (arg_index >= argc)
		usage(1);
	readin (arg_index, argc, argv);
	getlim (&x);
	getlim (&y);
	i = (n + 1) * sizeof (dx);
	diag = (float *) malloc ((unsigned) i);
	r = (float *) malloc ((unsigned) i);
	if (r == NULL || !spline ())
		exit (-1);
	send ();
	exit (0);
}

usage(x)
{
fprintf(stderr,
"usage: cspline len_flag [flags] x0 y0 x1 y1 ... xN yN\n",
"where len_flag is e.g.: -L1024\n");
exit(x);
}

static float   *buf;
static long     cnt,
                len;

save (x)
float   x;
{

	if (buf == NULL) {
		buf = (float *) malloc (sizeof (float) * BUFSIZ);
		len = BUFSIZ;
	}

	if (cnt < len)
		buf[cnt++] = x;
	else {
		len += BUFSIZ;
		buf = (float *) realloc (buf, len * sizeof (BUFSIZ));
		buf[cnt++] = x;
	}
}


float  *ibuf;

interp () {
	register int    i,
	                c;
	register float  rat,
	                fc,
	                frat;
	rat = cnt * 1.0 / ni;
	ibuf = (float *) malloc (sizeof (float) * (int) ni);
	if (ibuf == NULL) {
		perror("malloc");
		exit(1);
	}
	for (i = fc = c = 0; i < ni; fc += rat, i++) {
		c = fc;		/* truncate */
		frat = fc - c;	/* get fraction */
		ibuf[i] = (1.0 - frat) * buf[c] + frat * buf[c + 1];
	}
}


send () {
	register long   i,
	                j;

	interp ();

	if (otty)
		for (j = 0, i = ni - 1; i >= 0; i--)
			printf ("%d:\t%f\n", j++, ibuf[i]);
	else {
		for (i = ni - 1; i >= 0; i--)
			putfloat (&ibuf[i]);
		flushfloat ();
	}
}

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