ftp.nice.ch/pub/next/unix/audio/Cmix.N.s.tar.gz#/cmix/rooms/move/space.c

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

#include <math.h>
#include <stdio.h>
#include "ugens.h"
#include "sfheader.h"
#include "debug.h"
#define MACH1 1080.0
#define NACFS 2048
#define FABS(x) (((x)>=0.0)?x:-(x))
extern SFHEADER sfdesc[NFILES];

/* These are the global arrays and variables that are passed between the
   various routines used for move, reverb, and the setup routine space. */

int Nsdelay[2][6];
int primes[1000];
int tapsize;    	/* for allocation use in move */
int rvbdelsize;	/* for allocation use in RVB */
int space_called;	/* flag to indicate routine called */
double Allpass_del[2][502], Rvb_air[2][6][3];
double Dimensions[5], Walldata[2][13][3];
double Rand_info[2][6][6];
double *Rvb_del[2][6]; 	/* The delay lines for RVB -- mallocd here */
double SINARRAY[1025], COSARRAY[1025], ATANARRAY[1025];

/* MFP_samps computes the mean free path of reflections in the given room,
   and returns a value equal to the no. of samps delay for that path.  */ 

   long MFP_samps ()
   {
       double volume, length, width, height, area, MFP, mean_delay;
       long val;

       /* volume & surface area */

       length = Dimensions[0] - Dimensions[2];
       width = Dimensions[1] - Dimensions[3];
       height = Dimensions[4];
       volume = length * width * height;
       area = 2.0 * (length * width + length * height + width * height);
       
       fprintf(stderr, "This room is %.1f ft. long,", length);
       fprintf(stderr, " %.1f ft. wide, & %.1f ft. high.\n\n", width, height);
       
       /* compute MFP */

       MFP = 4.0 * volume/area;
       mean_delay = 2.0 * MFP/MACH1;
       fprintf (stderr, "The average delay is %.2f ms.\n\n", mean_delay *
	        1000.0);

       val = mean_delay * SR + .5;
       return (val);
}


/* get-primes loads a global array with up to 1000 prime numbers for use
   in determining prime delay lengths.                                */

get_primes (x)
    int x;
{
    int val = 5, flag, i, index = 2;

    /* first 2 vals initialized */

    primes[0] = 2;
    primes[1] = 3;
    while (index < x)
    {
	flag = 1;
	for (i = 1; flag && val/primes[i] >= primes[i]; ++i)
	    if (val % primes[i] == 0) flag = 0;
        if (flag)
	{
	    primes[index] = val;
	    ++index;
        }
	val += 2;
    }
}


/* close_prime returns the closest prime number to a given input number,
   up through the 1000th prime. For use in determining delay lengths.  */

int close_prime (x)
    int x;
{
    /* 1000 primes stored by another routine */
    int i;
   
    for (i = 0; i < 1000; ++i)
    {
	if (primes[i] >= x)
	    return (primes[i]);
    }
    return (primes[999]);
}


/* get_lengths computes the lengths for the 2x6 delays used in reverb
   and determines the max number of elements needed for allocation    */

get_lengths (m_length)
    long m_length;
{
    static float delfac[2][6] =   /* These determine the distribution */
	{
	{0.819, 0.918, 1.0, 1.11, 1.18, 1.279},
	{0.811, 0.933, 0.987, 1.13, 1.21, 1.247}
	};
    int val, pval, i, j, max=0;

    for (i = 0; i < 2; ++i)
    {   
	for (j = 0; j < 6; ++j)
	{
	    val = m_length * delfac[i][j] + .5; /* 2x6 different lengths */
	    pval = close_prime (val);           /* all lengths prime nos.*/
	    Nsdelay[i][j] = pval;

	    /* the number of elements (max) for allocation */

	    max = (pval > max)?pval:max;
        }
    }
    rvbdelsize = max * 1.2; /* to allow for varying taps dur to random tap */
}

/* alloc_delays sets aside the memory needed for the delays in RVB and
   returns globally a length for the move tap delay.                     */

alloc_delays()
{
     double hypot(), diag, maxdim, mindim, d1, d0;
     char *calloc();
     int i, j;

     /* the length for the main tape delay */
       
     d0 = Dimensions[0]-Dimensions[2];
     d1 = Dimensions[1]-Dimensions[3];
     maxdim = (d0 > d1)?d0:d1;
     mindim = (d0 > d1)?d1:d0;
     diag = hypot((3*maxdim), mindim);
     tapsize = diag / MACH1 * SR + 32;

     /* allocate memory space for reverb delay lines */

     for(i=0; i<2; i++){
     	for(j=0; j<6; j++){
     		if((Rvb_del[i][j] =
			(double *) calloc((unsigned)(rvbdelsize), sizeof(double)))
		        == (double *) NULL)
     		{
			fprintf(stderr, "Not enough memory for reverb delays!\n");
			exit(-1); 
      		}
	}
     }
}

/* setup_trigfuns loads global arrays with sine and cosine funs for macros */

setup_trigfuns()
{
	double sin(), cos(), atan();
	register int i;

	for(i=0; i<1024; i++) {
		SINARRAY[i] = sin((double) i * PI2/1024.0);
		COSARRAY[i] = cos((double) i * PI2/1024.0);
		ATANARRAY[i] = atan((double) i * PI/1024.0 - (PI/2.0));
	}
	SINARRAY[1024] = 0.0;
	COSARRAY[1024] = 1.0;
	ATANARRAY[1024] = 1.0;
}

/* set_gains determines the proper gains for the feedback filters in
   reverb, based on reverb time and average delay length. It also creates
   the global array of coeffs used here and in move()                    */

float AIRCOEFFS[512];

set_gains (rvbtime)
    float rvbtime;
{
    float rescale, gain, dist, G1, temp = SR/MACH1;
    double adjust, pow();
    static float array[16] =
              {1,.001,10,.1,25,.225,35,.28,50,.35,65,.4,85,.45,95,.475};
    int i, j, fpoint, nvals = 16;
   
    rescale = (.05*SR)/Nsdelay[0][0];      /* compensates for var. del. lens. */
    adjust = 1. - (.42*(SR-25000)/25000.); /* compensates for SR differences  */
    setline(array,nvals,512,AIRCOEFFS);/* creates scaled curve for coeffs */
    for(i=0; i<512; i++) AIRCOEFFS[i] = pow((double) AIRCOEFFS[i], adjust);
    gain = 1.0 - .366/(rvbtime * rescale);                /* a la Moorer */
    gain = (gain < 0.0) ? 0.0 : gain;
#ifdef debug
    printf("number of samples in each reverb delay line.");
#endif
    for (i = 0; i < 2; ++i)
    {   
#ifdef debug
	printf("\nchannel %d:\n\n", i);
#endif
	for (j = 0; j < 6; ++j)
	{
            dist = Nsdelay[i][j] / temp;
	    fpoint = dist * 512.0 / 300.0;   /* 300 ft. max distance */
	    fpoint = (fpoint <= 511)?fpoint:511;  /* to avoid overrunning */
	    G1 = AIRCOEFFS[fpoint - 1];           /* G1 is filter coeff. */
	    Rvb_air[i][j][0] = gain * (1.0 - G1); /* G2 is filt. gain */
	    Rvb_air[i][j][1] = G1;
#ifdef debug
	    printf("delay %d: %d (%7.2f ms.) g1 = %f\n\n", j, Nsdelay[i][j],
		    Nsdelay[i][j]*1000.0/SR, G1);
#endif
        }
    }
}


/* set_walls initializes the tone filters for simulating wall absorption
   in the move routine.                                               */

set_walls (wallfac)
    float wallfac;		/* a value between 0 and 10 */ 
{
    int i, j;
    float cutoff, cf; 
    void toneset();
    
    wallfac /= 10.0;
    wallfac *= wallfac;		/* now an expon. value between 0 and 1 */
    cutoff = wallfac * SR/2;            /* sets -3db pt. between 0 & N.F. */
    cutoff = (cutoff <= SR/2) ? cutoff : SR/2;       /* set limit at N.F. */

    for (i = 0; i < 2; ++i)
    {
	for (j = 1; j < 13; ++j)         /* skip first pair (direct sigs) */
	{
	    cf = (j > 4) ? cutoff * .6 : cutoff; /* more filt for 2nd */
	    toneset (cf, 1, Walldata[i][j]); /* gen. wall reflect */
        }
    }
}


/* set_allpass initializes the allpass filters for reverb */

set_allpass ()
{
    Allpass_del[0][0] = .72;
    Allpass_del[1][0] = .72;              /* the gains */
    Allpass_del[0][1] = 180;
    Allpass_del[1][1] = 183;              /* the delay lengths */
}



/* cycle determines the sampling increment for a table of any size based on
   the frequency desired.                                            */

float cycle (freq, funsize)
    double freq;
    int funsize;
{
    return (freq * funsize / SR);
}


/* set_random initializes the random functions used to vary the del. lengths
   in the reverb routine.                                                */

set_random ()
{
    static float rnd_freq[2][6] =
    {
    {4.9, 5.2, 6.7, 3.4, 2.7, 3.8},
    {5.1, 6.3, 7.0, 3.6, 2.8, 4.4}      /* the freq of rand variations */
    };
    static float rnd_pcnt[2][6] =
    {
    {.0016, .0013, .0021, .0018, .0019, .0014},
    {.0027, .0014, .0020, .0016, .0012, .0015}  /* the amt. of delay to vary */
    };
    static float seed[2][6] =
    {
    {.314, .159, .265, .358, .979, .323}, 
    {.142, .857, .685, .246, .776, .456}  /* the seeds for randi */
    };
    int i, j;

    for (i = 0; i < 2; ++i)               /* loop for 2 chans worth */
    {                              
	for (j = 0; j < 6; ++j)           /* loop for 6 delays per chan */ 
	{
            Rand_info[i][j][0] = rnd_pcnt[i][j] * SR/2.0; /* nsamps jitter */
	    Rand_info[i][j][1] = cycle (rnd_freq[i][j], 512);    /* SI  */
	    Rand_info[i][j][2] = 1.0;
	    Rand_info[i][j][4] = seed[i][j];              /* load seeds */
        }
    }
}

fill_matrix()
{
	int i, j;
	extern double Matrix[12][12];
	extern int matrix_flag;
	static double default_matrix[12][12] =
	{
	 {0,  0,  0, -1,  0,  0,  0,  1,  0,  0,  0,  0},
	 {0,  0,  0,  0,  0, -1,  0,  0,  1,  0,  0,  0},
	 {0, -1,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0},
	 {0,  0,  0,  0,  1,  0,  0, -1,  0,  0,  0,  0},
	 {1,  0,  0,  0,  0,  0,  0,  0,  0,  0, -1,  0},
	 {0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  -1},
	 {0,  0,  0,  0, -1,  0,  0,  0,  0,  1,  0,  0},
	 {0,  0,  0,  1,  0,  0,  0,  0, -1,  0,  0,  0},
	 {-1, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1},
	 {0,  0,  0,  0,  0,  1,  0, -1,  0,  0,  0,  0},
	 {0,  0, -1,  0,  0,  0,  1,  0,  0,  0,  0,  0},
	 {0,  1,  0,  0,  0,  0,  0,  0,  0, -1,  0,  0}
	};

	if(matrix_flag) return; /* matrix already loaded in score file */

	for(i=0; i<12; i++){
	   for(j=0; j<12; j++){
		Matrix[j][i] = 0.72 * default_matrix[j][i];
	   }
	}
	fprintf(stderr, "Default matrix loaded.\n");
}

/**************************************************************************/
/*
   This is the setup routine for the binaural/room simulator, move.  It is
   invoked by the command space(), which takes arguments as follows:

   space (front, right, -back, -left, ceiling, abs_fac, rvbtime)

   The first four are the coordinates of the four walls, in relation to
   the listener, in feet.  Since the listener is at point 0, the back and
   left walls must be specified as negative values. abs_fac is wall absorp-
   tion factor, between 0 (total absorption) and 10 (total reflection).   
									  */

float rvb_time;     /* For use by move.c  */

space (p, n_args)
    float *p;
    int n_args;
{
    extern float rvb_time;
    long m_length; 
    int i;
    if(n_args < 7)
        {
        fprintf(stderr,"Not enough args for space\n");
        closesf();
        }
    /* load room dimensions into global array */

    for (i = 0; i < 5; ++i)
        Dimensions[i] = p[i];

    rvb_time = p[6];
    if (!rvb_time) rvb_time = .001;  /* shortest rvb time allowed */

    m_length = MFP_samps();          /* mean delay length for reverb */
    setup_trigfuns();
    get_primes(999);                 /* load array with prime numbers */
    get_lengths(m_length);           /* sets up delay lengths */
    alloc_delays();		     /* allocates memory for delays */
    set_gains(rvb_time);             /* sets gains for filters */
    set_walls(p[5]);                 /* sets wall filts for move routine */
    set_allpass();
    set_random();                    /* sets up random variation of delays */
    fill_matrix();                   /* fills default matrix if necessary */
    space_called = 1;		     /* set flag for place */
}

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