void *impComp(void *Args)
{
    struct arg_s *args = (struct arg_s *)Args;
    
    // Temporary variables and constants (high-pass filter)
	const double W = 2*M_PI*100/args->fs;
	const double R1 = exp(-W);
	const double R2 = R1;
	const double B1 = 2*R1*cos(W);
	const double B2 = -R1 * R1;
	const double A1 = -(1+R2);
	const double A2 = R2;
	double       X0, Y0, Y1, Y2;
       
    
    // Temporary variables and constants (image-method)
    double*             r = new double[3];
	double*             s = new double[3];
	double*             L = new double[3];
    double*             LPI = new double[args->Tw+1];
    double              hu[6];
    double              refl[3];
    double              dist;
    double              strength;
    
    int                 loud_nr;
    int                 mic_nr;
    int                 n1,n2,n3;
    int                 mx,my,mz;
    int                 q, j, k;
    int                 n;
    int                 fdist;
    int                 pos;
    uint64_t  abs_counter;
    
    for (loud_nr = 0; loud_nr < args->nr_of_louds; loud_nr++ )	
	{	
		
			s[0] = args->ss[loud_nr + 0*args->nr_of_louds] / args->cTs;
			s[1] = args->ss[loud_nr + 1*args->nr_of_louds] / args->cTs;
			s[2] = args->ss[loud_nr + 2*args->nr_of_louds] / args->cTs;
        
		for (mic_nr = args->tNum; mic_nr < args->nr_of_mics ; mic_nr=mic_nr+args->tTot)
		{
			
			r[0] = args->rr[mic_nr + 0*args->nr_of_mics] / args->cTs;
			r[1] = args->rr[mic_nr + 1*args->nr_of_mics] / args->cTs;
			r[2] = args->rr[mic_nr + 2*args->nr_of_mics] / args->cTs;
	
			n1 = ceil(args->nsamples/(2*args->L[0]))*args->dim_s[0];
			n2 = ceil(args->nsamples/(2*args->L[1]))*args->dim_s[1];
			n3 = ceil(args->nsamples/(2*args->L[2]))*args->dim_s[2];
	
			// Generate room impulse response
			for (mx = -n1 ; mx <= n1 ; mx++)
			{
				hu[0] = 2*mx*args->L[0];
		
	
				for (my = -n2 ; my <= n2 ; my++)
				{
					hu[1] = 2*my*args->L[1];
	
					for (mz = -n3 ; mz <= n3 ; mz++)
					{
						hu[2] = 2*mz*args->L[2];
	
						for (q = 0 ; q <= 1*args->dim_s[0] ; q++)
						{
                            hu[3] = s[0] - r[0] + 2*q*r[0] + hu[0];
							refl[0] = pow(args->beta[0], abs(mx)) * pow(args->beta[1], abs(mx+q));
							
                            for (j = 0 ; j <= 1*args->dim_s[1] ; j++)
							{
								hu[4] = s[1] - r[1] + 2*j*r[1] + hu[1];
								refl[1] = pow(args->beta[2], abs(my)) * pow(args->beta[3], abs(my+j));
	
								for (k = 0 ; k <= 1*args->dim_s[2] ; k++)
								{
									hu[5] = s[2] - r[2] + 2*k*r[2] + hu[2];
									refl[2] = pow(args->beta[4],abs(mz)) * pow(args->beta[5], abs(mz+k));
	
									dist = sqrt(pow(hu[3], 2) + pow(hu[4], 2) + pow(hu[5], 2));
	
									fdist = (int) floor(dist);
									if (abs(2*mx+q)+abs(2*my+j)+abs(2*mz+k) <= args->order || args->order == -1)
									{
										if (fdist < args->nsamples)
										{
											
                                            //if ( mx == 0 && my == 0 && mz == 0 && q == 0 && j == 0 && k==0)
                                            //{
                                            //    mexPrintf("x: %f | y: %f | z: %f \n",refl[0],refl[1],refl[2]);
                                            //}
                                            
                                            strength = sim_microphone(hu[3], hu[4], args->angle, args->mtype)
												* refl[0]*refl[1]*refl[2]/(4*M_PI*dist*args->cTs);
	
                                            //if ( mx == 0 && my == 0 && mz == 0 && q == 0 && j == 0 && k==0)
                                            //{
                                            //    mexPrintf("str: %f | dist: %f | dist*cTs: %f \n",strength,dist,dist*cTs);
                                            //}
                                            
                                      		if (args->lp_filter == 1)
                                            {
                                                for (n = 0 ; n < args->Tw+1 ; n++)
                                                    LPI[n] = args->hanning_window[n] * args->Fc * sinc( M_PI*args->Fc*(n-(dist-fdist)-(args->Tw/2)) );

                                                pos = fdist-(args->Tw/2);
                                                
                                                for (n = 0; n < args->Tw+1; n++)
                                                {    
                                                  if (pos+n >=0 && pos+n < args->nsamples)
                                                  {
                                                    //if ( mx == 0 && my == 0 && mz == 0)
                                                      abs_counter = (uint64_t)pos+(uint64_t)n +(uint64_t)args->nsamples*(uint64_t)mic_nr + (uint64_t)args->nsamples*(uint64_t)args->nr_of_mics*(uint64_t)loud_nr;//     
                                                      args->imp[ abs_counter] += strength * LPI[n];  
                                                  }
                                                }                                                
                                            }
                                            else
                                            {
                                                //if ( mx == 0 && my == 0 && mz == 0)
                                                abs_counter = (uint64_t)fdist + (uint64_t)args->nsamples*(uint64_t)mic_nr + (uint64_t)args->nsamples*(uint64_t)args->nr_of_mics*(uint64_t)loud_nr;                                                
                                                args->imp[ abs_counter] += strength;
                                            }
										}
									}
								}
							}
						}
					}
				}
			}
	
			// 'Original' high-pass filter as proposed by Allen and Berkley.
			if (args->hp_filter == 1)
			{
				Y0 = 0.0;
				Y1 = 0.0;
				Y2 = 0.0;
				for (int idx = 0 ; idx < args->nsamples ; idx++)
				{                    
                    abs_counter = (uint64_t)idx + (uint64_t)args->nsamples*(uint64_t)mic_nr + (uint64_t)args->nsamples*(uint64_t)args->nr_of_mics*(uint64_t)loud_nr;                                                                    
					X0 = args->imp[abs_counter];
					Y2 = Y1;
					Y1 = Y0;
					Y0 = B1*Y1 + B2*Y2 + X0;
					args->imp[abs_counter] = Y0 + A1*Y1 + A2*Y2;                       
				}
			}
		}
	}
   
    pthread_exit(NULL);
}
Esempio n. 2
0
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
	if (nrhs == 0)
	{
		mexPrintf("--------------------------------------------------------------------\n"
			"| Room Impulse Response Generator                                  |\n"
			"|                                                                  |\n"
			"| Computes the response of an acoustic source to one or more       |\n"
            "| microphones in a reverberant room using the image method [1,2].  |\n"
			"|                                                                  |\n"
			"| Author    : dr.ir. Emanuel Habets ([email protected])  |\n"
			"|                                                                  |\n"
			"| Version   : 2.0.20100920                                         |\n"
			"|                                                                  |\n"
			"| Copyright (C) 2003-2010 E.A.P. Habets, The Netherlands.          |\n"
			"|                                                                  |\n"
			"| [1] J.B. Allen and D.A. Berkley,                                 |\n"
			"|     Image method for efficiently simulating small-room acoustics,|\n"
			"|     Journal Acoustic Society of America,                         |\n"
			"|     65(4), April 1979, p 943.                                    |\n"
			"|                                                                  |\n"
			"| [2] P.M. Peterson,                                               |\n"
			"|     Simulating the response of multiple microphones to a single  |\n"
			"|     acoustic source in a reverberant room, Journal Acoustic      |\n"
			"|     Society of America, 80(5), November 1986.                    |\n"
			"--------------------------------------------------------------------\n\n"
			"function [h, beta_hat] = rir_generator(c, fs, r, s, L, beta, nsample,\n"
            " mtype, order, dim, orientation, hp_filter);\n\n"
			"Input parameters:\n"
			" c           : sound velocity in m/s.\n"
			" fs          : sampling frequency in Hz.\n"
			" r           : M x 3 array specifying the (x,y,z) coordinates of the\n"
            "               receiver(s) in m.\n"
			" s           : 1 x 3 vector specifying the (x,y,z) coordinates of the\n"
            "               source in m.\n"
			" L           : 1 x 3 vector specifying the room dimensions (x,y,z) in m.\n"
			" beta        : 1 x 6 vector specifying the reflection coefficients\n"
			"               [beta_x1 beta_x2 beta_y1 beta_y2 beta_z1 beta_z2] or\n"
            "               beta = Reverberation Time (T_60) in seconds.\n"
			" nsample     : number of samples to calculate, default is T_60*fs.\n"
			" mtype       : [omnidirectional, subcardioid, cardioid, hypercardioid,\n"
            "               bidirectional], default is omnidirectional.\n"
			" order       : reflection order, default is -1, i.e. maximum order.\n"
			" dim         : room dimension (2 or 3), default is 3.\n"
			" orientation : direction in which the microphones are pointed, specified using\n"
            "               azimuth and elevation angles (in radians), default is [0 0].\n"
			" hp_filter   : use 'false' to disable high-pass filter, the high-pass filter\n"
			"               is enabled by default.\n\n"
			"Output parameters:\n"
			" h           : M x nsample matrix containing the calculated room impulse\n"
            "               response(s).\n"
			" beta_hat    : In case a reverberation time is specified as an input parameter\n"
			"               the corresponding reflection coefficient is returned.\n\n");
		return;
	}
	else
	{
		mexPrintf("Room Impulse Response Generator (Version 2.0.20100920) by Emanuel Habets\n"
			"Copyright (C) 2003-2010 E.A.P. Habets, The Netherlands.\n");
	}

	// Check for proper number of arguments
	if (nrhs < 6)
		mexErrMsgTxt("Error: There are at least six input parameters required.");
	if (nrhs > 12)
		mexErrMsgTxt("Error: Too many input arguments.");
	if (nlhs > 2)
		mexErrMsgTxt("Error: Too many output arguments.");

	// Check for proper arguments
	if (!(mxGetN(prhs[0])==1) || !mxIsDouble(prhs[0]) || mxIsComplex(prhs[0]))
		mexErrMsgTxt("Invalid input arguments!");
	if (!(mxGetN(prhs[1])==1) || !mxIsDouble(prhs[1]) || mxIsComplex(prhs[1]))
		mexErrMsgTxt("Invalid input arguments!");
	if (!(mxGetN(prhs[2])==3) || !mxIsDouble(prhs[2]) || mxIsComplex(prhs[2]))
		mexErrMsgTxt("Invalid input arguments!");
	if (!(mxGetN(prhs[3])==3) || !mxIsDouble(prhs[3]) || mxIsComplex(prhs[3]))
		mexErrMsgTxt("Invalid input arguments!");
	if (!(mxGetN(prhs[4])==3) || !mxIsDouble(prhs[4]) || mxIsComplex(prhs[4]))
		mexErrMsgTxt("Invalid input arguments!");
	if (!(mxGetN(prhs[5])==6 || mxGetN(prhs[5])==1) || !mxIsDouble(prhs[5]) || mxIsComplex(prhs[5]))
		mexErrMsgTxt("Invalid input arguments!");

	// Load parameters
	double          c = mxGetScalar(prhs[0]);
	double          fs = mxGetScalar(prhs[1]);
	const double*   rr = mxGetPr(prhs[2]);
	int             nr_of_mics = (int) mxGetM(prhs[2]);
	const double*   ss = mxGetPr(prhs[3]);
	const double*   LL = mxGetPr(prhs[4]);
	const double*   beta_ptr = mxGetPr(prhs[5]);
	double*         beta = new double[6];
	int             nsamples;
	char*           mtype;
	int             order;
	int             dim;
	double          angle[2];
	int             hp_filter;
	double          TR;

	plhs[1] = mxCreateDoubleMatrix(1, 1, mxREAL);
	double* beta_hat = mxGetPr(plhs[1]);
	beta_hat[0] = 0;

	// Reflection coefficients or Reverberation Time?
	if (mxGetN(prhs[5])==1)
	{
		double V = LL[0]*LL[1]*LL[2];
		double S = 2*(LL[0]*LL[2]+LL[1]*LL[2]+LL[0]*LL[1]);
		TR = beta_ptr[0];
		double alfa = 24*V*log(10.0)/(c*S*TR);
		if (alfa > 1)
			mexErrMsgTxt("Error: The reflection coefficients cannot be calculated using the current "
			"room parameters, i.e. room size and reverberation time.\n           Please "
			"specify the reflection coefficients or change the room parameters.");
		beta_hat[0] = sqrt(1-alfa);
		for (int i=0;i<6;i++)
			beta[i] = beta_hat[0];
	}
	else
	{
		for (int i=0;i<6;i++)
			beta[i] = beta_ptr[i];
	}

	// High-pass filter (optional)
	if (nrhs > 11 &&  mxIsEmpty(prhs[11]) == false)
	{
		hp_filter = (int) mxGetScalar(prhs[11]);
	}
	else
	{
		hp_filter = 1;
	}

	// 3D Microphone orientation (optional)
	if (nrhs > 10 &&  mxIsEmpty(prhs[10]) == false)
	{
        const double* orientation = mxGetPr(prhs[10]);
        if (mxGetN(prhs[10]) == 1)
        {     
            angle[0] = orientation[0];
            angle[1] = 0;
        }
        else
        {
            angle[0] = orientation[0];
            angle[1] = orientation[1];
        }
	}
	else
	{
		angle[0] = 0;
        angle[1] = 0;
	}

	// Room Dimension (optional)
	if (nrhs > 9 &&  mxIsEmpty(prhs[9]) == false)
	{
		dim = (int) mxGetScalar(prhs[9]);
		if (dim != 2 && dim != 3)
			mexErrMsgTxt("Invalid input arguments!");

		if (dim == 2)
		{
			beta[4] = 0;
			beta[5] = 0;
		}
	}
	else
	{
		dim = 3;
	}

	// Reflection order (optional)
	if (nrhs > 8 &&  mxIsEmpty(prhs[8]) == false)
	{
		order = (int) mxGetScalar(prhs[8]);
		if (order < -1)
			mexErrMsgTxt("Invalid input arguments!");
	}
	else
	{
		order = -1;
	}

	// Type of microphone (optional)
	if (nrhs > 7 &&  mxIsEmpty(prhs[7]) == false)
	{
		mtype = new char[mxGetN(prhs[7])+1];
		mxGetString(prhs[7], mtype, mxGetN(prhs[7])+1);
	}
	else
	{
		mtype = new char[1];
		mtype[0] = 'o';
	}

	// Number of samples (optional)
	if (nrhs > 6 &&  mxIsEmpty(prhs[6]) == false)
	{
		nsamples = (int) mxGetScalar(prhs[6]);
	}
	else
	{
		if (mxGetN(prhs[5])>1)
		{
			double V = LL[0]*LL[1]*LL[2];
			double S = 2*(LL[0]*LL[2]+LL[1]*LL[2]+LL[0]*LL[1]);
			double alpha = ((1-pow(beta[0],2))+(1-pow(beta[1],2)))*LL[0]*LL[2] +
				((1-pow(beta[2],2))+(1-pow(beta[3],2)))*LL[1]*LL[2] +
				((1-pow(beta[4],2))+(1-pow(beta[5],2)))*LL[0]*LL[1];
			TR = 24*log(10.0)*V/(c*alpha);
			if (TR < 0.128)
				TR = 0.128;
		}
		nsamples = (int) (TR * fs);
	}

	// Create output vector
	plhs[0] = mxCreateDoubleMatrix(nr_of_mics, nsamples, mxREAL);
	double* imp = mxGetPr(plhs[0]);

	// Temporary variables and constants (high-pass filter)
	const double W = 2*M_PI*100/fs;
	const double R1 = exp(-W);
	const double B1 = 2*R1*cos(W);
	const double B2 = -R1 * R1;
	const double A1 = -(1+R1);
	double       X0;
    double*      Y = new double[3];

	// Temporary variables and constants (image-method)
	const double Fc = 1;
	const int    Tw = 2 * ROUND(0.004*fs);
	const double cTs = c/fs;
	double*      hanning_window = new double[Tw+1];
	double*      LPI = new double[Tw+1];
	double*      r = new double[3];
	double*      s = new double[3];
	double*      L = new double[3];
	double       hu[6];
	double       refl[3];
	double       dist;
	double       ll;
	double       strength;
	int          pos, fdist;
	int          n1,n2,n3;
	int          q, j, k;
	int          mx, my, mz;
	int          n;

	s[0] = ss[0]/cTs; s[1] = ss[1]/cTs; s[2] = ss[2]/cTs;
	L[0] = LL[0]/cTs; L[1] = LL[1]/cTs; L[2] = LL[2]/cTs;

	// Hanning window
	for (n = 0 ; n < Tw+1 ; n++)
	{
		hanning_window[n] = 0.5 * (1 + cos(2*M_PI*(n+Tw/2)/Tw));
	}

	for (int mic_nr = 0; mic_nr < nr_of_mics ; mic_nr++)
	{
		// [x_1 x_2 ... x_N y_1 y_2 ... y_N z_1 z_2 ... z_N]
		r[0] = rr[mic_nr + 0*nr_of_mics] / cTs;
		r[1] = rr[mic_nr + 1*nr_of_mics] / cTs;
		r[2] = rr[mic_nr + 2*nr_of_mics] / cTs;

		n1 = (int) ceil(nsamples/(2*L[0]));
		n2 = (int) ceil(nsamples/(2*L[1]));
		n3 = (int) ceil(nsamples/(2*L[2]));

		// Generate room impulse response
		for (mx = -n1 ; mx <= n1 ; mx++)
		{
			hu[0] = 2*mx*L[0];

			for (my = -n2 ; my <= n2 ; my++)
			{
				hu[1] = 2*my*L[1];

				for (mz = -n3 ; mz <= n3 ; mz++)
				{
					hu[2] = 2*mz*L[2];

					for (q = 0 ; q <= 1 ; q++)
					{
						hu[3] = (1-2*q)*s[0] - r[0] + hu[0];
						refl[0] = pow(beta[0], abs(mx-q)) * pow(beta[1], abs(mx));

						for (j = 0 ; j <= 1 ; j++)
						{
							hu[4] = (1-2*j)*s[1] - r[1] + hu[1];
							refl[1] = pow(beta[2], abs(my-j)) * pow(beta[3], abs(my));

							for (k = 0 ; k <= 1 ; k++)
							{
								hu[5] = (1-2*k)*s[2] - r[2] + hu[2];
								refl[2] = pow(beta[4],abs(mz-k)) * pow(beta[5], abs(mz));

								dist = sqrt(pow(hu[3], 2) + pow(hu[4], 2) + pow(hu[5], 2));

								if (abs(2*mx-q)+abs(2*my-j)+abs(2*mz-k) <= order || order == -1)
								{
                                    fdist = (int) floor(dist);
									if (fdist < nsamples)
									{
										strength = sim_microphone(hu[3], hu[4], hu[5], angle, mtype[0])
											* refl[0]*refl[1]*refl[2]/(4*M_PI*dist*cTs);

										for (n = 0 ; n < Tw+1 ; n++)
											LPI[n] = hanning_window[n] * Fc * sinc(M_PI*Fc*(n-(dist-fdist)-(Tw/2)));

										pos = fdist-(Tw/2);
										for (n = 0 ; n < Tw+1; n++)
											if (pos+n >= 0 && pos+n < nsamples)
												imp[mic_nr + nr_of_mics*(pos+n)] += strength * LPI[n];
									}
								}
							}
						}
					}
				}
			}
		}

		// 'Original' high-pass filter as proposed by Allen and Berkley.
		if (hp_filter == 1)
		{
			for (int idx = 0 ; idx < 3 ; idx++) {Y[idx] = 0;}            
			for (int idx = 0 ; idx < nsamples ; idx++)
			{
				X0 = imp[mic_nr+nr_of_mics*idx];
				Y[2] = Y[1];
				Y[1] = Y[0];
				Y[0] = B1*Y[1] + B2*Y[2] + X0;
				imp[mic_nr+nr_of_mics*idx] = Y[0] + A1*Y[1] + R1*Y[2];
			}
		}
	}
}