⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 snd_dsp.cpp

📁 hl2 source code. Do not use it illegal.
💻 CPP
📖 第 1 页 / 共 5 页
字号:
// Parallel reverbs
///////////////////

// Reverb A
// M parallel reverbs, mixed to mono output

#define CRVAS				64				// max number of parallel series reverbs active

#define CRVA_DLYS			12				// max number of delays making up reverb_a

struct rva_t
{
	bool fused;
	int m;						// number of parallel plain or lowpass delays
	int fparallel;				// true if filters in parallel with delays, otherwise single output filter	
	flt_t *pflt;

	dly_t *pdlys[CRVA_DLYS];	// array of pointers to delays
};

rva_t rvas[CRVAS];

void RVA_Init ( rva_t *prva ) {	if ( prva )	Q_memset (prva, 0, sizeof (rva_t)); }
void RVA_InitAll( void ) { for (int i = 0; i < CRVAS; i++) RVA_Init ( &rvas[i] ); }

// free parallel series reverb

void RVA_Free( rva_t *prva )
{
	if ( prva )
	{
	// free all delays
	for (int i = 0; i < CRVA_DLYS; i++)
		DLY_Free ( prva->pdlys[i] );
	
	FLT_Free( prva->pflt );

	Q_memset( prva, 0, sizeof (rva_t) );
	}
}


void RVA_FreeAll( void ) { for (int i = 0; i < CRVAS; i++) RVA_Free( &rvas[i] ); }

// create parallel reverb - m parallel reverbs summed 

// D array of CRVB_DLYS reverb delay sizes max sample index w[0...D] (ie: D+1 samples)
// a array of reverb feedback parms for parallel reverbs (CRVB_P_DLYS)
// b array of CRVB_P_DLYS - mix params for parallel reverbs
// m - number of parallel delays
// pflt - filter template, to be used by all parallel delays
// fparallel - true if filter operates in parallel with delays, otherwise filter output only

rva_t * RVA_Alloc ( int *D, int *a, int *b, int m, flt_t *pflt, int fparallel )
{
	
	int i;
	rva_t *prva;
	flt_t *pflt2 = NULL;

	// find open slot

	for ( i = 0; i < CRVAS; i++ )
	{
		if ( !rvas[i].fused )
			break;
	}

	// return null if no free slots

	if (i == CRVAS)
	{
		DevMsg ("DSP: Warning, failed to allocate reverb.\n" );
		return NULL;
	}
	
	prva = &rvas[i];

	// if series filter specified, alloc

	if ( pflt && !fparallel)
	{
		// use filter data as template for a filter on output

		pflt2 = FLT_Alloc (pflt->M, pflt->L, pflt->a, pflt->b );

		if (!pflt2)
		{
			DevMsg ("DSP: Warning, failed to allocate flt for reverb.\n" );
			return NULL;
		}
	}
	
	// alloc parallel reverbs

	if ( pflt && fparallel )
	{

		// use this filter data as a template to alloc a filter for each parallel delay

		for (i = 0; i < m; i++)
			prva->pdlys[i] = DLY_AllocLP( D[i], a[i], b[i], DLY_LOWPASS, pflt->M, pflt->L, pflt->a, pflt->b );
	}	
	else 
	{
		// no filter specified, use plain delays in parallel sections

		for (i = 0; i < m; i++)
			prva->pdlys[i] = DLY_Alloc( D[i], a[i], b[i], DLY_PLAIN );
	}
	
	
	// if we failed to alloc any reverb, free all, return NULL

	for (i = 0; i < m; i++)
	{
		if ( !prva->pdlys[i])
		{
			FLT_Free( pflt2 );
			RVA_Free( prva );
			DevMsg ("DSP: Warning, failed to allocate delay for reverb.\n" );
			return NULL;
		}
	}

	prva->fused = true;
	prva->m = m;
	prva->fparallel = fparallel;
	prva->pflt = pflt2;

	return prva;
}


// parallel reverberator
//
// for each input sample x do:
//		x0 = plain(D0,w0,&p0,a0,x)
//		x1 = plain(D1,w1,&p1,a1,x)
//		x2 = plain(D2,w2,&p2,a2,x)
//		x3 = plain(D3,w3,&p3,a3,x)
//		y = b0*x0 + b1*x1 + b2*x2 + b3*x3
//
//		rgdly - array of 6 delays:
//		D - Delay values (typical - 29, 37, 44, 50, 27, 31)
//		w - array of delayed values
//		p - array of pointers to circular delay line pointers
//		a - array of 6 feedback values (typical - all equal, like 0.75 * PMAX)
//		b - array of 6 gain values for plain reverb outputs (1, .9, .8, .7)
//		xin - input value
// if fparallel, filters are built into delays,
// otherwise, filter output

inline int RVA_GetNext( rva_t *prva, int x )
{
	int m = prva->m;			
	int sum;

	int y;

	sum = 0;

		for (int i = 0; i < m; i++ )
			sum += DLY_GetNext( prva->pdlys[i], x );

	// m is clamped between RVA_BASEM & CRVA_DLYS
	
	if (m)
		y = sum/m;
	else
		y = x;
#if 0
	// PERFORMANCE:
	// UNDONE: build as array
	int mm;

	switch (m)
	{
	case 12: mm = (PMAX/12); break;
	case 11: mm = (PMAX/11); break;
	case 10: mm = (PMAX/10); break;
	case 9:  mm = (PMAX/9); break;
	case 8:  mm = (PMAX/8); break;
	case 7:  mm = (PMAX/7); break;
	case 6:  mm = (PMAX/6); break;
	case 5:  mm = (PMAX/5); break;
	case 4:  mm = (PMAX/4); break;
	case 3:  mm = (PMAX/3); break;
	case 2:  mm = (PMAX/2); break;
	default:
	case 1:  mm = (PMAX/1); break;
	}

	y = (sum * mm) >> PBITS;

#endif // 0

	// run series filter if present

	if ( prva->pflt && !prva->fparallel )
		y = FLT_GetNext( prva->pflt, y);
	
	return y;
}

// batch version for performance

inline void RVA_GetNextN( rva_t *prva, portable_samplepair_t *pbuffer, int SampleCount, int op )
{
	int count = SampleCount;
	portable_samplepair_t *pb = pbuffer;
	
	switch (op)
	{
	default:
	case OP_LEFT:
		while (count--)
		{
			pb->left = RVA_GetNext( prva, pb->left );
			pb++;
		}
		return;
	case OP_RIGHT:
		while (count--)
		{
			pb->right = RVA_GetNext( prva, pb->right );
			pb++;
		}
		return;
	case OP_LEFT_DUPLICATE:
		while (count--)
		{
			pb->left = pb->right = RVA_GetNext( prva, pb->left );
			pb++;
		}
		return;
	}
}

#define RVA_BASEM		3				// base number of parallel delays

// nominal delay and feedback values

//float rvadlys[] = {29,  37,  44,  50,  62,  75, 96, 118, 127, 143, 164, 175};
float rvadlys[] =   {18,  23,  28,  36,  47,  21, 26, 33,  40,  49,  45,  38};
float rvafbs[] = {0.7, 0.7, 0.7, 0.8, 0.8, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9};

// reverb parameter order
	
typedef enum
{

// parameter order

	rva_isize,		
	rva_idensity,	
	rva_idecay,	
	
	rva_iftype,		
	rva_icutoff,		
	rva_iqwidth,		
					
	rva_ifparallel,

	rva_cparam		// # of params
} rva_e;

// filter parameter ranges

prm_rng_t rva_rng[] = {

	{rva_cparam,	0, 0},			// first entry is # of parameters
	
		// reverb params

	{rva_isize,		0.0, 2.0},	// 0-2.0 scales nominal delay parameters (starting at approx 20ms)
	{rva_idensity,	0.0, 2.0},	// 0-2.0 density of reverbs (room shape) - controls # of parallel or series delays
	{rva_idecay,	0.0, 2.0},	// 0-2.0 scales feedback parameters (starting at approx 0.15)
	
	// filter params for each parallel reverb (quality set to 0 for max execution speed)

	{rva_iftype,	0, FTR_MAX},			
	{rva_icutoff,	10, 22050},
	{rva_iqwidth,	100, 11025},

	{rva_ifparallel, 0,	1}		// if 1, then all filters operate in parallel with delays. otherwise filter output only
};

rva_t * RVA_Params ( prc_t *pprc )
{
	rva_t *prva;
	int i;
	float size		= pprc->prm[rva_isize];			// 0-2.0 controls scale of delay parameters
	float density	= pprc->prm[rva_idensity];		// 0-2.0 density of reverbs (room shape) - controls # of parallel delays
	float decay		= pprc->prm[rva_idecay];		// 0-1.0 controls feedback parameters

	float ftype 	= pprc->prm[rva_iftype];
	float cutoff	= pprc->prm[rva_icutoff];
	float qwidth	= pprc->prm[rva_iqwidth];

	float fparallel = pprc->prm[rva_ifparallel];

	// D array of CRVB_DLYS reverb delay sizes max sample index w[0...D] (ie: D+1 samples)
	// a array of reverb feedback parms for parallel delays 
	// b array of CRVB_P_DLYS - mix params for parallel reverbs
	// m - number of parallel delays
	
	int D[CRVA_DLYS];
	int a[CRVA_DLYS];
	int b[CRVA_DLYS];
	int m = RVA_BASEM;
	
	m = density * CRVA_DLYS / 2;

	// limit # delays 3-12

	m = clamp (m, RVA_BASEM, CRVA_DLYS);

	
	// average time sound takes to travel from most distant wall
	// (cap at 1000 ft room)

	for ( i = 0; i < m; i++ )
	{
		// delays of parallel reverb
		
		D[i] = MSEC_TO_SAMPS( rvadlys[i] * size );
		
		// feedback and gain of parallel reverb

		a[i] = (int) min (0.9 * PMAX, rvafbs[i] * (float)PMAX * decay);
		b[i] = PMAX;
	}

	// add filter

	flt_t *pflt = NULL;

	if ( cutoff )
	{

		// set up dummy lowpass filter to convert params

		prc_t prcf;

		prcf.prm[flt_iquality]	= QUA_LO;	// force filter to low quality for faster execution time
		prcf.prm[flt_icutoff]	= cutoff;
		prcf.prm[flt_iftype]	= ftype;
		prcf.prm[flt_iqwidth]	= qwidth;
	
		pflt = (flt_t *)FLT_Params ( &prcf );	
	}
	
	prva = RVA_Alloc ( D, a, b, m, pflt, fparallel );

	FLT_Free( pflt );

	return prva;
}

inline void * RVA_VParams ( void *p ) 
{
	PRC_CheckParams ( (prc_t *)p, rva_rng ); 
	return (void *) RVA_Params ((prc_t *)p); 
}

inline void RVA_Mod ( void *p, float v ) { return; }



////////////
// Diffusor
///////////

// (N series allpass reverbs)

#define CDFRS				64				// max number of series reverbs active

#define CDFR_DLYS			16				// max number of delays making up diffusor

struct dfr_t
{
	bool fused;
	int n;						// series allpass delays
	int w[CDFR_DLYS];			// internal state array for series allpass filters

	dly_t *pdlys[CDFR_DLYS];	// array of pointers to delays
};

dfr_t dfrs[CDFRS];

void DFR_Init ( dfr_t *pdfr ) {	if ( pdfr )	Q_memset (pdfr, 0, sizeof (dfr_t)); }
void DFR_InitAll( void ) { for (int i = 0; i < CDFRS; i++) DFR_Init ( &dfrs[i] ); }

// free parallel series reverb

void DFR_Free( dfr_t *pdfr )
{
	if ( pdfr )
	{
	// free all delays

	for (int i = 0; i < CDFR_DLYS; i++)
		DLY_Free ( pdfr->pdlys[i] );
	
	Q_memset( pdfr, 0, sizeof (dfr_t) );
	}
}


void DFR_FreeAll( void ) { for (int i = 0; i < CDFRS; i++) DFR_Free( &dfrs[i] ); }

// create n series allpass reverbs

// D array of CRVB_DLYS reverb delay sizes max sample index w[0...D] (ie: D+1 samples)
// a array of reverb feedback parms for series delays
// b array of gain params for parallel reverbs
// n - number of series delays

dfr_t * DFR_Alloc ( int *D, int *a, int *b, int n )
{
	
	int i;
	dfr_t *pdfr;

	// find open slot

	for (i = 0; i < CDFRS; i++)
	{
		if (!dfrs[i].fused)
			break;
	}
	
	// return null if no free slots

	if (i == CDFRS)
	{
		DevMsg ("DSP: Warning, failed to allocate diffusor.\n" );
		return NULL;
	}
	
	pdfr = &dfrs[i];

	DFR_Init( pdfr );

	// alloc reverbs

	for (i = 0; i < n; i++)
		pdfr->pdlys[i] = DLY_Alloc( D[i], a[i], b[i], DLY_ALLPASS );
		
	// if we failed to alloc any reverb, free all, return NULL

	for (i = 0; i < n; i++)
	{
		if ( !pdfr->pdlys[i])
		{
			DFR_Free( pdfr );
			DevMsg ("DSP: Warning, failed to allocate delay for diffusor.\n" );
			return NULL;
		}
	}
	
	pdfr->fused = true;
	pdfr->n = n;

	return pdfr;
}


// series reverberator

inline int DFR_GetNext( dfr_t *pdfr, int x )
{
	int i;
	int n = pdfr->n;			
	int y;

	y = x;
	for (i = 0; i < n; i++)
		y = DLY_GetNext(pdfr->pdlys[i], y);
	return y;

#if 0
	// alternate method, using internal state - causes PREDELAY = sum of delay times

	int *v = pdfr->w;			// intermediate results

	v[0] = x;

	// reverse evaluate series delays

	//    w[0]   w[1]   w[2]      w[n-1]      w[n]
	// x---->D[0]--->D[1]--->D[2]...-->D[n-1]--->out
	//

	for (i = n; i > 0; i--)
		v[i] = DLY_GetNext(pdfr->pdlys[i-1], v[i-1]);
	
	return v[n];
#endif 
}

// batch version for performance

inline void DFR_GetNextN( dfr_t *pdfr, portable_samplepair_t *pbuffer, int SampleCount, int op )
{
	int count = SampleCount;
	portable_samplepair_t *pb = pbuffer;
	
	switch (op)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -