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

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

/* Spatial Processing Unit Generator */

#include "mm.head.h"
#include "ug.head.h"
#include <stdio.h>
#include <math.h>

#define UNUSED	1
#define DBUF	2
#define DLEN	3
#define NOW	4
#define DARRAY	5
#define CARRAY	6
#define AARRAY	7
#define FARRAY	8
#define XS	9
#define YS	10
#define THETAS	11
#define AMPS	12
#define BACKS	13
#define X	14
#define Y	15
#define THETA   16
#define AMP     17
#define BACK    18


#define CI	.00029851	/* 1/335 (meters per second) */
#define PI2	6.283185308
#define PI	3.141592654
#define IPI	.318309886
#define D270	4.712388981
#define D90	1.570796327
#define DIST(x1,y1,x2,y2) sqrt( (double) ( (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2) ) )
#define TAU	50		/* milliseconds in cross-fade */

space

UGHEAD{
    UGINIT;
    float *Out = Outblock, *Grev = Grevblock;
    float *dbuf;
    float ***cut, ***delay, ***atten, ***fader, delsamp;
    float *xs, *ys, *ts, *as, *bs;
    float x1, y1, x2, y2, t1, t2, fff;
    float maxdist, maxdelay, d, di, chanval[4], radiant;
    float ***fp3alloc(), do_delay();
    int place, change, inside;
    long dlen, now, j, k, nrv, dim, c, r, s, ns;
    float fade, rx, ry, dx, dy, dt, phi, getcut(), val, tsn;
    float RCI = CI*Srate;

    if(STARTNOTE){
	Spacewason = Spaceon = 1;	/* Turn on global reverberator */
	maxdist = 0.;
	for(j=0; j<NAs; j++){ /* Find largest distance in acoustic space */
	    for(k=0; k<NAs; k++){
		if(j == k) continue;
		d = DIST(Ax[j], Ay[j], Ax[k], Ay[k]);
		if(d > maxdist) maxdist = d;
	    }
	}
	maxdelay = 2.*maxdist;
	dlen = LVAL(DLEN) = maxdelay*RCI + 0.5;
	now = LVAL(NOW) = 0;
	FPTR(DBUF) = (float *) calloc(dlen, sizeof(float));
	nrv = (narg - X)/5;	/* number of radiation vectors specified */
	ns = NAs + 1; 	/* Extra surface is for direct path values */
	FPTR(CARRAY) = (float *) fp3alloc(nrv,ns,Nchan);
	FPTR(DARRAY) = (float *) fp3alloc(nrv,ns,Nchan);
	FPTR(AARRAY) = (float *) fp3alloc(nrv,ns,Nchan);
	FPTR(FARRAY) = (float *) fp3alloc(nrv,ns,Nchan);
	FPTR(XS) = (float *) calloc(nrv, sizeof(float));
	FPTR(YS) = (float *) calloc(nrv, sizeof(float));
	FPTR(THETAS) = (float *) calloc(nrv, sizeof(float));
	FPTR(AMPS) = (float *) calloc(nrv, sizeof(float));
	FPTR(BACKS) = (float *) calloc(nrv, sizeof(float));
    }
    dbuf = FPTR(DBUF);
    dlen = LVAL(DLEN);
    now = LVAL(NOW);
    cut = (float ***) FPTR(CARRAY);
    delay = (float ***) FPTR(DARRAY);
    atten = (float ***) FPTR(AARRAY);
    fader = (float ***) FPTR(FARRAY);
    nrv = (narg - X)/5;
    xs = FPTR(XS);
    ys = FPTR(YS);
    ts = FPTR(THETAS);
    as = FPTR(AMPS);
    bs = FPTR(BACKS);
    ns = NAs + 1;
    fade = 1000./(TAU*Srate);
    UGLOOP{
	dbuf[now] = VAL(0); /* install current sample in delay buffer */
	change = (i==0) ;
	for(j=0; j<nrv; j++){
	    place = j*5;
	    if(xs[j] != VAL(X+place)){change=1; xs[j]=VAL(X+place);}
	    if(ys[j] != VAL(Y+place)){change=1; ys[j]=VAL(Y+place);}
	    if(ts[j] != VAL(THETA+place)){change=1; ts[j]=VAL(THETA+place);}
	    if(as[j] != VAL(AMP+place)){change=1; as[j]=VAL(AMP+place);}
	    if(bs[j] != VAL(BACK+place)){change=1; bs[j]= VAL(BACK+place);}
	}
/*
 * get the cut, delay, and atten arrays computed for all current
 * radiation vectors, surface reflection (and direct) paths, and 
 * channels
 */
/* do only one first loop or when something varies */
/* do direct paths first */
	if(change){
	    for(r=0; r<nrv; r++)
	     for(c=0; c<Nchan; c++){
		x1 = xs[r]; y1 = ys[r];
		x2 = Sx[c]; y2 = Sy[c];
		cut[r][0][c] = getcut(x1,y1,x2,y2);
		dx = x2 - x1 ;
		dx *= dx ;
		dy = y2 - y1 ;
		dy *= dy ;
		d = sqrt( (double) ( dx + dy ) ) ;
		delay[r][0][c] = d*RCI;
		if ( Direct != 1. )
		    d = pow( (double) d, (double) Direct ) ;
		if(bs[r] < 1.0){
		    dy = y1 - y2;
		    dx = x1 - x2;
		    phi = dx ? 
			atan2( (double) dy, (double) dx) : 
			(dy > 0 ? D270 : D90 );
		    tsn = ts[r];
		    if(tsn > PI)tsn = PI2 - tsn;
		    dt = tsn - phi;
		    dt = ( dt >= 0. ? dt : -dt ) ;
		    if(dt > PI)dt = PI2 - dt;
		    radiant = 1. + (sqrt( (double) ( bs[r]) - 1. ) )*dt*IPI;
		    radiant *= radiant;
/*
* attenuation depends on amplitude of vector, angle of vector,
* and distance to vector origin
*/
		    atten[r][0][c] = as[r]*radiant/(1. + d) ;
		} else atten[r][0][c] = as[r]/(1. + d) ;
	    }
/* now do surface reflections */
	    for(r=0; r<nrv; r++)
	     for(s=1; s<ns; s++)
	      for(c=0; c<Nchan; c++){
		x1 = xs[r]; y1 = ys[r];
		x2 = Sx[c]; y2 = Sy[c];
		getrefl(x1,y1,x2,y2,s-1,&rx,&ry);
		cut[r][s][c] = 0.;
		if( getcut(rx,ry,x2,y2) != 0.)
		 if(getcut(x1,y1,rx,ry) != 0.) cut[r][s][c] = 1.;
		dx = x1 - rx ;
		dx *= dx ;
		dy = y1 - ry ;
		dy *= dy ;
		d = sqrt( (double) ( dx + dy ) ) ;
		dx = x2 - rx ;
		dx *= dx ;
		dy = y2 - ry ;
		dy *= dy ;
		d += sqrt( (double) ( dx + dy ) ) ;
		delay[r][s][c] = d*RCI;
		if ( Reflect != 1. )
		    d = pow( (double) d, (double) Reflect ) ;
		if(bs[r] < 1.0){
		    dy = y1 - ry;
		    dx = x1 - rx;
		    phi = dx ? atan2(dy,dx) : (dy > 0 ? D270 : D90 );
		    tsn = ts[r];
		    if(tsn > PI)tsn = PI2 - tsn;
		    dt = tsn - phi ;
		    dt = ( dt >= 0. ? dt : -dt ) ;
		    if(dt > PI)dt = PI2 - dt;
		    radiant = 1. + (sqrt( (double) ( bs[r]) - 1. ) )*dt*IPI;
		    radiant *= radiant;
		    atten[r][s][c] = as[r]*radiant/(1. + d) ;
		} else atten[r][s][c] = as[r]/(1. + d) ;
	    }
	}
	for(c=0; c<Nchan; c++){
	    chanval[c] = 0;
	    for(r=0; r<nrv; r++)
	     for(s=0; s<ns; s++){
		d = delay[r][s][c];
		delsamp = do_delay(dbuf,dlen,now,d);
		if(s == 0){
		    if(!within(xs[r],ys[r])){  /* Outside? */
			*Grev += delsamp * atten[r][s][c];
			inside = 0;
		    } else {
			inside = 1;
		    }
		} else if(!inside) 
			*Grev += delsamp * atten[r][s][c];
		if(cut[r][s][c] == 1.){ 
		    fff = fader[r][s][c] ;
		    if(fff < 1.){
			fff += fade;
			if(fff > 1.)fff = 1.;
			val = delsamp * atten[r][s][c] * fff ;
			chanval[c] += val;
			if(inside) *Grev += val;
		    } else {
			val = delsamp * atten[r][s][c];
			chanval[c] += val;
			if(inside) *Grev += val;
		    }
		    fader[r][s][c] = fff ;
		} else { 
			fff = fader[r][s][c] ;
			if(fff > 0.){
			    fff -= fade;
			    if(fff < 0.)fff = 0.;
			    val = delsamp * atten[r][s][c] * fff ;
			    chanval[c] += val;
			    if(inside) *Grev += val;
			}
		    fader[r][s][c] = fff ;
		}
	    }
	    di = chanval[c];
	    *Out++ += di ;
	    val = ( di >= 0 ? di : -di ) ;
	    if(val > Maxecho)Maxecho = di ;
	}
	Grev++;
	now -= 1;
	if(now < 0)now = dlen - 1;
	LVAL(NOW) = now;
	LVAL(DLEN) = dlen;
	UGEND(0);
    }
    if(ENDNOTE){
	free(dbuf);
	fp3free(cut,nrv,ns,Nchan);
	fp3free(delay,nrv,ns,Nchan);
	fp3free(atten,nrv,ns,Nchan);
	fp3free(fader,nrv,ns,Nchan);
	free(xs);
	free(ys);
	free(ts);
	free(as);
	free(bs);
    }
}
/*
 * getcut returns 0.0 if the line defined by x1,x2 and x2,y2 crosses 
 * (cuts) any surface of the inner room, and 1.0 if it doesn't
 */
float getcut(x1,y1,x2,y2) float x1,y1,x2,y2; {
 register int i;
 int test1, test2 ;
 float dx, dy, dinv, t1, t2, lsintheta, lcostheta, lrho ;
 static float costheta[4], sintheta[4], rho[4] ;
 static float lx1[4], ly1[4], lx2[4], ly2[4] ;
 static int horiz[4], vert[4] ;
 static first = 1 ;
    if( first ) {
/*
 * precompute normal equations for walls
 */
	first = 0 ;
	for( i=0; i<NLs; i++ ) {
	    lx1[i] = Lx[i] ;
	    ly1[i] = Ly[i] ;
	    lx2[i] = Lx[(i+1)%NLs] ;
	    ly2[i] = Ly[(i+1)%NLs] ;
	    if( ly1[i] == ly2[i] ) horiz[i] = 1 ; else horiz[i] = 0 ;
	    if( lx1[i] == lx2[i] ) vert[i] = 1 ; else vert[i] = 0 ;
	    dx = lx2[i] - lx1[i] ;
	    dy = ly2[i] - ly1[i] ;
	    dinv = 1./sqrt( (double) ( dx*dx + dy*dy ) ) ;
	    sintheta[i] = dy*dinv ;
	    costheta[i] = dx*dinv ;
	    rho[i] = ( ly1[i]*lx2[i] - lx1[i]*ly2[i] )*dinv ;
	}
    }
    for( i=0; i<NLs; i++ ) {
	if( horiz[i] ) {
/*
 * if one end of ray touches wall, no cut possible
 */
	    if( y1 == ly1[i] ) continue ;
	    if( y2 == ly2[i] ) continue ;
	    test1 = y1 > ly1[i] ;
	    test2 = y2 > ly2[i] ;
	} else if( vert[i] ) {
	    if( x1 == lx1[i] ) continue ;
	    if( x2 == lx2[i] ) continue ;
	    test1 = x1 > lx1[i] ;
	    test2 = x2 > lx2[i] ;
	} else {
	    t1 = y1*costheta[i] - x1*sintheta[i] ;
	    if( t1 == rho[i] ) continue ;
	    test1 = t1 > rho[i] ;
	    t2 = y2*costheta[i] - x2*sintheta[i] ;
	    if( t2 == rho[i] ) continue ;
	    test2 = t2 > rho[i] ;
	}
/*
 * if both ray endpoints on same side of wall, no cut possible
 */
	if( test1 == test2 ) continue ;
/*
 * come here iff ray endpoints on opposite sides of (infinitely extended) wall
 * compute normal equation of ray
 */
	dx = x2 - x1 ;
	dy = y2 - y1 ;
	dinv = sqrt( (double) ( dx*dx + dy*dy ) ) ;
	if( dinv == 0. ) continue ;
	dinv = 1./dinv ;
	lsintheta = dy*dinv ;
	lcostheta = dx*dinv ;
	lrho = ( y1*x2 - x1*y2 )*dinv ;
	t1 = ly1[i]*lcostheta - lx1[i]*lsintheta ;
/*
 * if wall endpoint touches ray, no cut possible
 */
	if( t1 == lrho ) continue ;
	test1 = t1 > lrho ;
	t2 = ly2[i]*lcostheta - lx2[i]*lsintheta ;
	if( t2 == lrho ) continue ;
	test2 = t2 > lrho ;
/*
 * if wall endpoints also on opposite sides of ray, then cut
 */
	if( test1 != test2 )
	    return( 0. ) ;	/* ray path cut */
    }
    return( 1. ) ;	/* ray path not cut */
}
/*
 * within return 1 if point x,y is inside listening space, else 0
 */
within(x,y) float x,y;{
    if(x < Lx[0] && y < Ly[0])
     if(x > Lx[1] && y < Ly[1])
      if(x > Lx[2] && y > Ly[2])
       if(x < Lx[3] && y > Ly[3])
	return(1);
    return(0);
}
/*
 * getrefl calculates the reflection point (rx,ry) of a ray path from
 * source point (sx,sy) to surface s and back to channel output at (cx,cy)
 */
getrefl(sx,sy,cx,cy,s,rx,ry)
 float sx,sy,cx,cy,*rx,*ry; int s;
{
 float lx1,lx2,ly1,ly2,d2,s2,c2,r2,x,y,a;
 float dx1, dy1, dx2, dy2, m1, m2, b1, b2;
 static float d[]={0.,0.,0.,0.}, sint[4],cost[4],rho[4],sin2t[4],cos2t[4],
 f1[4], f2[4];

    s = s%NAs;
    lx1 = Ax[s];
    ly1 = Ay[s];
    lx2 = Ax[(s+1)%NAs];
    ly2 = Ay[(s+1)%NAs];
/*
 * find normal equations for walls (needs to be done only once)
 */
    if(d[s] == 0.){	
	d[s] = 1./sqrt( (double) ( (lx2-lx1)*(lx2-lx1) + (ly2-ly1)*(ly2-ly1) ) );
	sint[s] = (ly2-ly1)*d[s];
	cost[s] = (lx2-lx1)*d[s];
	rho[s] = ly1*cost[s] - lx1*sint[s];
	if(rho[s]>0.){sint[s]= -sint[s]; cost[s]= -cost[s]; rho[s]= -rho[s]; }
	sin2t[s] = 2.*sint[s]*cost[s];
	cos2t[s] = 2.*cost[s]*cost[s] - 1.;
	f1[s] = -2.*rho[s]*sint[s];
	f2[s] =  2.*rho[s]*cost[s];
    }
/*
 * find phantom source location
 */
    x = f1[s] + sy*sin2t[s] + sx*cos2t[s];
    y = f2[s] - sy*cos2t[s] + sx*sin2t[s];
/*
 * calculate and return wall intercept of ray from phantom source to speaker
 */
    if( (dx1 = x - cx) != 0.){ 
	m1 = (y - cy)/dx1; 
	b1 = y - m1*x; 
    }
    if( (dx2 = lx2 - lx1) != 0.){ 
	m2 = (ly2 - ly1)/dx2; 
	b2 = ly1 - m2*lx1; 
    } else { 
	*ry = m1*lx1 + b1; 
	*rx = lx1; 
	return; 
    }
    if(dx1 == 0.){ 
	*ry = m2*x + b2; 
	*rx = cx; 
	return; 
    }
    *rx = (b2 - b1)/(m1 - m2); 
    *ry = m1*(*rx) + b1; 
    return;

/*
 * alternative method using normal equations (slower)
 */
/*
 *     d2 = 1./sqrt( (double) ( (x-cx)*(x-cx) + (y-cy)*(y-cy) ) );
 *     s2 = (y-cy)*d2;
 *     c2 = (x-cx)*d2;
 *     r2 = y*c2 - x*s2;
 *     if(r2>0.){s2= -s2; c2= -c2; r2= -r2;}
 *     a = 1./(sint[s]*c2 - cost[s]*s2);
 *     dy1 = (r2*sint[s] - rho[s]*s2)*a;
 *     dx1 = (r2*cost[s] - rho[s]*c2)*a;
 */
}
/*
 * do_delay looks up a sample delayed by tau samples using interpolation
 * on a circular buffer of length len with present sample at buf[now]
 */
float do_delay(buf,len,now,tau) float buf[]; float tau; long len, now;{
 register long t1, t2 ;
    t1 = now + tau;
    while(t1 >= len)t1 -= len;
    t2 = t1 + 1;
    while(t2 >= len)t2 -= len;
    return(buf[t1] + (tau - ( (int) tau ))*(buf[t2] - buf[t1]));
}
/*
 * fp3alloc allocates memory for a 3-D array, C-style
 */
float *** fp3alloc(x,y,z) register int x,y,z; {
 register float ***fp3; register int i,j;
    if ((fp3 = (float ***) calloc(x,sizeof(float **))) == NULL){
	fprintf(stderr,"\nCMUSIC: space generator: fp3alloc failed.\n");
	exit (-1);
    }
    for (i = 0; i < x; i++) {
	if ((fp3[i] = (float **) calloc(y, sizeof(float *))) == NULL){
	    fprintf(stderr,"\nCMUSIC: space generator: fp3alloc failed.\n");
	    exit (-1);
	}
	for (j = 0; j < y; j++) {
	    if ((fp3[i][j] = (float *) calloc(z, sizeof(float))) == NULL){
		fprintf(stderr,"\nCMUSIC: space generator: fp3alloc failed.\n");
		exit (-1);
	    }
	}
    }
    return(fp3);
}
/*
 * fp3free frees memory for a 3-D array, C-style
 */
fp3free(fp3,x,y,z) register float ***fp3; register int x,y,z; {
 register int i,j;
    for (i = 0; i < x; i++) {
	for (j = 0; j < y; j++) {
	    free(fp3[i][j]);
	}
	free(fp3[i]);
    }
    free(fp3);
}

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