1298 lines
35 KiB
C
1298 lines
35 KiB
C
//=======================================================================
|
|
// Copyright XashXT Group 2009 ©
|
|
// s_dsp.c - digital signal processing algorithms for audio FX
|
|
//=======================================================================
|
|
|
|
#include "sound.h"
|
|
|
|
#define SXDLY_MAX 0.400 // max delay in seconds
|
|
#define SXRVB_MAX 0.100 // max reverb reflection time
|
|
#define SXSTE_MAX 0.100 // max stereo delay line time
|
|
#define SOUNDCLIP(x) ((x) > (32767*256) ? (32767*256) : ((x) < (-32767*256) ? (-32767*256) : (x)))
|
|
#define CSXROOM 29
|
|
#define DSP_CONSTANT_GAIN 128
|
|
|
|
typedef int sample_t; // delay lines must be 32 bit, now that we have 16 bit samples
|
|
|
|
typedef struct dlyline_s
|
|
{
|
|
int cdelaysamplesmax; // size of delay line in samples
|
|
int lp; // lowpass flag 0 = off, 1 = on
|
|
|
|
int idelayinput; // i/o indices into circular delay line
|
|
int idelayoutput;
|
|
int idelayoutputxf; // crossfade output pointer
|
|
int xfade; // crossfade value
|
|
|
|
int delaysamples; // current delay setting
|
|
int delayfeed; // current feedback setting
|
|
|
|
int lp0, lp1, lp2, lp3, lp4, lp5; // lowpass filter buffer
|
|
|
|
int mod; // sample modulation count
|
|
int modcur;
|
|
sample_t *lpdelayline; // buffer
|
|
} dlyline_t;
|
|
|
|
#define ISXMONODLY 0 // mono delay line
|
|
#define ISXRVB 1 // first of the reverb delay lines
|
|
#define CSXRVBMAX 2
|
|
#define ISXSTEREODLY 3 // 50ms left side delay
|
|
#define CSXDLYMAX 4
|
|
|
|
dlyline_t rgsxdly[CSXDLYMAX]; // array of delay lines
|
|
|
|
#define gdly0 (rgsxdly[ISXMONODLY])
|
|
#define gdly1 (rgsxdly[ISXRVB])
|
|
#define gdly2 (rgsxdly[ISXRVB + 1])
|
|
#define gdly3 (rgsxdly[ISXSTEREODLY])
|
|
|
|
#define CSXLPMAX 10 // lowpass filter memory
|
|
|
|
int rgsxlp[CSXLPMAX];
|
|
int sxamodl, sxamodr; // amplitude modulation values
|
|
int sxamodlt, sxamodrt; // modulation targets
|
|
int sxmod1, sxmod2;
|
|
int sxmod1cur, sxmod2cur;
|
|
|
|
// Mono Delay parameters
|
|
cvar_t *sxdly_delay; // current delay in seconds
|
|
cvar_t *sxdly_feedback; // cycles
|
|
cvar_t *sxdly_lp; // lowpass filter
|
|
|
|
// Mono Reverb parameters
|
|
cvar_t *sxrvb_size; // room size 0 (off) 0.1 small - 0.35 huge
|
|
cvar_t *sxrvb_feedback; // reverb decay 0.1 short - 0.9 long
|
|
cvar_t *sxrvb_lp; // lowpass filter
|
|
|
|
// stereo delay (no feedback)
|
|
cvar_t *sxste_delay; // straight left delay
|
|
|
|
// Underwater/special fx modulations
|
|
cvar_t *sxmod_lowpass;
|
|
cvar_t *sxmod_mod;
|
|
int sxroom_typeprev;
|
|
|
|
// Main interface
|
|
cvar_t *sxroom_type; // legacy support
|
|
cvar_t *sxroomwater_type; // legacy support
|
|
cvar_t *sxroom_off; // legacy support
|
|
|
|
bool SXDLY_Init( int idelay, float delay );
|
|
void SXDLY_Free( int idelay );
|
|
void SXDLY_DoDelay( int count );
|
|
void SXRVB_DoReverb( int count );
|
|
void SXDLY_DoStereoDelay( int count );
|
|
void SXRVB_DoAMod( int count );
|
|
|
|
//=====================================================================
|
|
// Init/release all structures for sound effects
|
|
//=====================================================================
|
|
void SX_Init( void )
|
|
{
|
|
sxdly_delay = Cvar_Get( "room_delay", "0", 0, "current delay in seconds" );
|
|
sxdly_feedback = Cvar_Get( "room_feedback", "0.2", 0, "cycles" );
|
|
sxdly_lp = Cvar_Get( "room_dlylp", "1", 0, "lowpass filter" );
|
|
|
|
sxrvb_size = Cvar_Get( "room_size", "0", 0, "room size 0 (off) 0.1 small - 0.35 huge" );
|
|
sxrvb_feedback = Cvar_Get( "room_refl", "0.7", 0, "reverb decay 0.1 short - 0.9 long" );
|
|
sxrvb_lp = Cvar_Get( "room_rvblp", "1", 0, "lowpass filter" );
|
|
|
|
sxste_delay = Cvar_Get( "room_left", "0", 0, "straight left delay" );
|
|
sxmod_lowpass = Cvar_Get( "room_lp", "0", 0, "no description" );
|
|
sxmod_mod = Cvar_Get( "room_mod", "0", 0, "no description" );
|
|
|
|
sxroom_type = Cvar_Get( "room_type", "0", 0, "no description" );
|
|
sxroomwater_type = Cvar_Get( "waterroom_type", "14", 0, "no description" );
|
|
sxroom_off = Cvar_Get( "room_off", "0", 0, "no description" );
|
|
|
|
Mem_Set( rgsxdly, 0, sizeof( dlyline_t ) * CSXDLYMAX );
|
|
Mem_Set( rgsxlp, 0, sizeof( int ) * CSXLPMAX );
|
|
|
|
sxroom_typeprev = -1;
|
|
|
|
// init amplitude modulation params
|
|
sxamodl = sxamodr = 255;
|
|
sxamodlt = sxamodrt = 255;
|
|
|
|
sxmod1 = 350 * (dma.speed / 11025); // 11k was the original sample rate all dsp was tuned at
|
|
sxmod2 = 450 * (dma.speed / 11025);
|
|
sxmod1cur = sxmod1;
|
|
sxmod2cur = sxmod2;
|
|
|
|
MsgDev( D_INFO, "FX Processor Initialized\n" );
|
|
}
|
|
|
|
void SX_Free( void )
|
|
{
|
|
int i;
|
|
|
|
// release mono delay line
|
|
SXDLY_Free( ISXMONODLY );
|
|
|
|
// release reverb lines
|
|
for( i = 0; i < CSXRVBMAX; i++ )
|
|
SXDLY_Free( i + ISXRVB );
|
|
SXDLY_Free( ISXSTEREODLY );
|
|
}
|
|
|
|
// Set up a delay line buffer allowing a max delay of 'delay' seconds
|
|
// Frees current buffer if it already exists. idelay indicates which of
|
|
// the available delay lines to init.
|
|
bool SXDLY_Init( int idelay, float delay )
|
|
{
|
|
size_t cbsamples;
|
|
dlyline_t *pdly;
|
|
|
|
pdly = &(rgsxdly[idelay]);
|
|
|
|
if( delay > SXDLY_MAX )
|
|
delay = SXDLY_MAX;
|
|
|
|
if( pdly->lpdelayline )
|
|
{
|
|
Mem_Free( pdly->lpdelayline );
|
|
pdly->lpdelayline = NULL;
|
|
}
|
|
|
|
if( delay == 0.0 )
|
|
return true;
|
|
|
|
pdly->cdelaysamplesmax = dma.speed * delay;
|
|
pdly->cdelaysamplesmax += 1;
|
|
|
|
cbsamples = pdly->cdelaysamplesmax * sizeof( sample_t );
|
|
pdly->lpdelayline = (sample_t *)Z_Malloc( cbsamples );
|
|
|
|
// init delay loop input and output counters.
|
|
// NOTE: init of idelayoutput only valid if pdly->delaysamples is set
|
|
// NOTE: before this call!
|
|
|
|
pdly->idelayinput = 0;
|
|
pdly->idelayoutput = pdly->cdelaysamplesmax - pdly->delaysamples;
|
|
pdly->xfade = 0;
|
|
pdly->lp = 1;
|
|
pdly->mod = 0;
|
|
pdly->modcur = 0;
|
|
|
|
// init lowpass filter memory
|
|
pdly->lp0 = pdly->lp1 = pdly->lp2 = pdly->lp3 = pdly->lp4 = pdly->lp5 = 0;
|
|
|
|
return true;
|
|
}
|
|
|
|
// release delay buffer and deactivate delay
|
|
void SXDLY_Free( int idelay )
|
|
{
|
|
dlyline_t *pdly = &(rgsxdly[idelay]);
|
|
|
|
if( pdly->lpdelayline )
|
|
{
|
|
Mem_Free( pdly->lpdelayline );
|
|
pdly->lpdelayline = NULL; // this deactivates the delay
|
|
}
|
|
}
|
|
|
|
|
|
// check for new stereo delay param
|
|
void SXDLY_CheckNewStereoDelayVal( void )
|
|
{
|
|
dlyline_t *pdly = &(rgsxdly[ISXSTEREODLY]);
|
|
int delaysamples;
|
|
|
|
if( dma.channels < 2 )
|
|
return;
|
|
|
|
// set up stereo delay
|
|
if( sxste_delay->modified )
|
|
{
|
|
sxste_delay->modified = false;
|
|
|
|
if( sxste_delay->value == 0.0 )
|
|
{
|
|
// deactivate delay line
|
|
SXDLY_Free( ISXSTEREODLY );
|
|
}
|
|
else
|
|
{
|
|
delaysamples = min( sxste_delay->value, SXSTE_MAX ) * dma.speed;
|
|
|
|
// init delay line if not active
|
|
if( pdly->lpdelayline == NULL )
|
|
{
|
|
pdly->delaysamples = delaysamples;
|
|
SXDLY_Init( ISXSTEREODLY, SXSTE_MAX );
|
|
}
|
|
|
|
// do crossfade to new delay if delay has changed
|
|
if( delaysamples != pdly->delaysamples )
|
|
{
|
|
|
|
// set up crossfade from old pdly->delaysamples to new delaysamples
|
|
pdly->idelayoutputxf = pdly->idelayinput - delaysamples;
|
|
|
|
if( pdly->idelayoutputxf < 0 )
|
|
pdly->idelayoutputxf += pdly->cdelaysamplesmax;
|
|
pdly->xfade = 128;
|
|
}
|
|
|
|
pdly->mod = 0;
|
|
pdly->modcur = pdly->mod;
|
|
|
|
// deactivate line if rounded down to 0 delay
|
|
if( pdly->delaysamples == 0 )
|
|
SXDLY_Free( ISXSTEREODLY );
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
// stereo delay, left channel only, no feedback
|
|
|
|
void SXDLY_DoStereoDelay( int count )
|
|
{
|
|
int left;
|
|
sample_t sampledly;
|
|
sample_t samplexf;
|
|
portable_samplepair_t *pbuf;
|
|
int countr;
|
|
|
|
if( dma.channels < 2 )
|
|
return;
|
|
|
|
// process delay line if active
|
|
if( rgsxdly[ISXSTEREODLY].lpdelayline )
|
|
{
|
|
pbuf = paintbuffer;
|
|
countr = count;
|
|
|
|
// process each sample in the paintbuffer...
|
|
while( countr-- )
|
|
{
|
|
if( gdly3.mod && ( --gdly3.modcur < 0 ))
|
|
gdly3.modcur = gdly3.mod;
|
|
|
|
// get delay line sample from left line
|
|
sampledly = *(gdly3.lpdelayline + gdly3.idelayoutput);
|
|
left = pbuf->left;
|
|
|
|
// only process if left value or delayline value are non-zero or xfading
|
|
if( gdly3.xfade || sampledly || left )
|
|
{
|
|
// if we're not crossfading, and we're not modulating, but we'd like to be modulating,
|
|
// then setup a new crossfade.
|
|
|
|
if( !gdly3.xfade && !gdly3.modcur && gdly3.mod )
|
|
{
|
|
// set up crossfade to new delay value, if we're not already doing an xfade
|
|
gdly3.idelayoutputxf = gdly3.idelayoutput + ((Com_RandomLong(0, 0xFF) * gdly3.delaysamples) >> 9); // 100 = ~ 9ms
|
|
|
|
if( gdly3.idelayoutputxf >= gdly3.cdelaysamplesmax )
|
|
gdly3.idelayoutputxf -= gdly3.cdelaysamplesmax;
|
|
|
|
gdly3.xfade = 128;
|
|
}
|
|
|
|
// modify sampledly if crossfading to new delay value
|
|
if( gdly3.xfade )
|
|
{
|
|
samplexf = (*(gdly3.lpdelayline + gdly3.idelayoutputxf) * (128 - gdly3.xfade)) >> 7;
|
|
sampledly = ((sampledly * gdly3.xfade) >> 7) + samplexf;
|
|
|
|
if( ++gdly3.idelayoutputxf >= gdly3.cdelaysamplesmax )
|
|
gdly3.idelayoutputxf = 0;
|
|
|
|
if( --gdly3.xfade == 0 )
|
|
gdly3.idelayoutput = gdly3.idelayoutputxf;
|
|
}
|
|
|
|
// save output value into delay line
|
|
|
|
// left = CLIP(left);
|
|
*(gdly3.lpdelayline + gdly3.idelayinput) = SOUNDCLIP( left );
|
|
|
|
// save delay line sample into output buffer
|
|
pbuf->left = SOUNDCLIP( sampledly );
|
|
|
|
}
|
|
else
|
|
{
|
|
// keep clearing out delay line, even if no signal in or out
|
|
*(gdly3.lpdelayline + gdly3.idelayinput) = 0;
|
|
}
|
|
|
|
// update delay buffer pointers
|
|
if( ++gdly3.idelayinput >= gdly3.cdelaysamplesmax )
|
|
gdly3.idelayinput = 0;
|
|
|
|
if( ++gdly3.idelayoutput >= gdly3.cdelaysamplesmax )
|
|
gdly3.idelayoutput = 0;
|
|
pbuf++;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
// If sxdly_delay or sxdly_feedback have changed, update delaysamples
|
|
// and delayfeed values. This applies only to delay 0, the main echo line.
|
|
|
|
void SXDLY_CheckNewDelayVal( void )
|
|
{
|
|
dlyline_t *pdly = &(rgsxdly[ISXMONODLY]);
|
|
|
|
if( sxdly_delay->modified )
|
|
{
|
|
sxdly_delay->modified = false;
|
|
|
|
if( sxdly_delay->value == 0.0f )
|
|
{
|
|
// deactivate delay line
|
|
SXDLY_Free( ISXMONODLY );
|
|
}
|
|
else
|
|
{
|
|
// init delay line if not active
|
|
|
|
pdly->delaysamples = min( sxdly_delay->value, SXDLY_MAX ) * dma.speed;
|
|
|
|
if( pdly->lpdelayline == NULL )
|
|
SXDLY_Init( ISXMONODLY, SXDLY_MAX );
|
|
|
|
// flush delay line and filters
|
|
|
|
if( pdly->lpdelayline )
|
|
{
|
|
Mem_Set( pdly->lpdelayline, 0, pdly->cdelaysamplesmax * sizeof( sample_t ));
|
|
pdly->lp0 = 0;
|
|
pdly->lp1 = 0;
|
|
pdly->lp2 = 0;
|
|
pdly->lp3 = 0;
|
|
pdly->lp4 = 0;
|
|
pdly->lp5 = 0;
|
|
}
|
|
|
|
// init delay loop input and output counters
|
|
pdly->idelayinput = 0;
|
|
pdly->idelayoutput = pdly->cdelaysamplesmax - pdly->delaysamples;
|
|
|
|
// deactivate line if rounded down to 0 delay
|
|
if( pdly->delaysamples == 0 )
|
|
SXDLY_Free( ISXMONODLY );
|
|
|
|
}
|
|
}
|
|
|
|
pdly->lp = sxdly_lp->integer;
|
|
pdly->delayfeed = sxdly_feedback->value * 255;
|
|
}
|
|
|
|
|
|
// This routine updates both left and right output with
|
|
// the mono delayed signal. Delay is set through console vars room_delay
|
|
// and room_feedback.
|
|
void SXDLY_DoDelay( int count )
|
|
{
|
|
int val[2];
|
|
int valt, valt2;
|
|
int samp[2];
|
|
int sampsum, dfdly;
|
|
sample_t sampledly;
|
|
portable_samplepair_t *pbuf;
|
|
int countr;
|
|
int gain;
|
|
|
|
// process mono delay line if active
|
|
if( rgsxdly[ISXMONODLY].lpdelayline )
|
|
{
|
|
gain = DSP_CONSTANT_GAIN;
|
|
pbuf = paintbuffer;
|
|
countr = count;
|
|
|
|
// process each sample in the paintbuffer...
|
|
while( countr-- )
|
|
{
|
|
// get delay line sample
|
|
sampledly = *(gdly0.lpdelayline + gdly0.idelayoutput);
|
|
|
|
if( dma.channels == 2 )
|
|
{
|
|
samp[0] = pbuf->left;
|
|
samp[1] = pbuf->right;
|
|
sampsum = samp[0] + samp[1];
|
|
}
|
|
else
|
|
{
|
|
samp[0] = pbuf->left;
|
|
sampsum = samp[0];
|
|
}
|
|
|
|
// only process if delay line and paintbuffer samples are non zero
|
|
if( sampledly || sampsum )
|
|
{
|
|
// get current sample from delay buffer
|
|
dfdly = ((gdly0.delayfeed * sampledly) >> 8);
|
|
|
|
if( dma.channels == 2 )
|
|
{
|
|
val[0] = SOUNDCLIP( samp[0] + dfdly );
|
|
val[1] = SOUNDCLIP( samp[1] + dfdly );
|
|
valt = SOUNDCLIP(( sampsum + (dfdly * 2)) >> 1);
|
|
}
|
|
else
|
|
{
|
|
val[0] = SOUNDCLIP(samp[0] + dfdly);
|
|
valt = val[0];
|
|
}
|
|
|
|
// lowpass
|
|
if( gdly0.lp )
|
|
{
|
|
if( dma.channels == 2 )
|
|
{
|
|
val[0] = (gdly0.lp0 + gdly0.lp1 + gdly0.lp2 + gdly0.lp3 + val[0]) / 5;
|
|
val[1] = (gdly0.lp0 + gdly0.lp1 + gdly0.lp2 + gdly0.lp3 + val[1]) / 5;
|
|
valt2 = (val[0] + val[1]) >> 1;
|
|
}
|
|
else
|
|
{
|
|
val[0] = (gdly0.lp0 + gdly0.lp1 + gdly0.lp2 + gdly0.lp3 + val[0]) / 5;
|
|
valt2 = val[0];
|
|
}
|
|
|
|
gdly0.lp0 = gdly0.lp1;
|
|
gdly0.lp1 = gdly0.lp2;
|
|
gdly0.lp2 = gdly0.lp3;
|
|
gdly0.lp3 = valt;
|
|
}
|
|
else
|
|
{
|
|
valt2 = valt;
|
|
}
|
|
|
|
// store delay output value into output buffer
|
|
|
|
*(gdly0.lpdelayline + gdly0.idelayinput) = SOUNDCLIP( valt2 );
|
|
|
|
// decrease output value by max gain of delay with feedback
|
|
// to provide for unity gain reverb
|
|
// note: this gain varies with the feedback value.
|
|
if( dma.channels == 2 )
|
|
{
|
|
pbuf->left = ((val[0] * gain) >> 8);
|
|
pbuf->right = ((val[1] * gain) >> 8);
|
|
}
|
|
else
|
|
{
|
|
pbuf->left = ((val[0] * gain) >> 8);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// not playing samples, but must still flush lowpass buffer and delay line
|
|
gdly0.lp0 = gdly0.lp1 = gdly0.lp2 = gdly0.lp3 = 0;
|
|
*(gdly0.lpdelayline + gdly0.idelayinput) = valt2;
|
|
|
|
}
|
|
|
|
// update delay buffer pointers
|
|
if( ++gdly0.idelayinput >= gdly0.cdelaysamplesmax )
|
|
gdly0.idelayinput = 0;
|
|
|
|
if( ++gdly0.idelayoutput >= gdly0.cdelaysamplesmax )
|
|
gdly0.idelayoutput = 0;
|
|
pbuf++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// check for a parameter change on the reverb processor
|
|
#define RVB_XFADE (32 * dma.speed / 11025) // xfade time between new delays
|
|
#define RVB_MODRATE1 (500 * (dma.speed / 11025)) // how often, in samples, to change delay (1st rvb)
|
|
#define RVB_MODRATE2 (700 * (dma.speed / 11025)) // how often, in samples, to change delay (2nd rvb)
|
|
|
|
void SXRVB_CheckNewReverbVal( void )
|
|
{
|
|
dlyline_t *pdly;
|
|
int delaysamples;
|
|
int i, mod;
|
|
|
|
if( sxrvb_size->modified )
|
|
{
|
|
sxrvb_size->modified = false;
|
|
|
|
if( sxrvb_size->value == 0.0 )
|
|
{
|
|
// deactivate all delay lines
|
|
SXDLY_Free( ISXRVB );
|
|
SXDLY_Free( ISXRVB + 1 );
|
|
}
|
|
else
|
|
{
|
|
for( i = ISXRVB; i < ISXRVB + CSXRVBMAX; i++ )
|
|
{
|
|
// init delay line if not active
|
|
pdly = &(rgsxdly[i]);
|
|
|
|
switch( i )
|
|
{
|
|
case ISXRVB:
|
|
delaysamples = min(sxrvb_size->value, SXRVB_MAX) * dma.speed;
|
|
pdly->mod = RVB_MODRATE1;
|
|
break;
|
|
case ISXRVB+1:
|
|
delaysamples = min(sxrvb_size->value * 0.71, SXRVB_MAX) * dma.speed;
|
|
pdly->mod = RVB_MODRATE2;
|
|
break;
|
|
default:
|
|
delaysamples = 0;
|
|
break;
|
|
}
|
|
|
|
mod = pdly->mod;
|
|
|
|
if( pdly->lpdelayline == NULL )
|
|
{
|
|
pdly->delaysamples = delaysamples;
|
|
SXDLY_Init( i, SXRVB_MAX );
|
|
}
|
|
|
|
pdly->modcur = pdly->mod = mod;
|
|
|
|
// do crossfade to new delay if delay has changed
|
|
if( delaysamples != pdly->delaysamples )
|
|
{
|
|
// set up crossfade from old pdly->delaysamples to new delaysamples
|
|
pdly->idelayoutputxf = pdly->idelayinput - delaysamples;
|
|
|
|
if( pdly->idelayoutputxf < 0 )
|
|
pdly->idelayoutputxf += pdly->cdelaysamplesmax;
|
|
|
|
pdly->xfade = RVB_XFADE;
|
|
}
|
|
|
|
// deactivate line if rounded down to 0 delay
|
|
if( pdly->delaysamples == 0 )
|
|
SXDLY_Free( i );
|
|
}
|
|
}
|
|
}
|
|
|
|
rgsxdly[ISXRVB].delayfeed = (sxrvb_feedback->value) * 255;
|
|
rgsxdly[ISXRVB].lp = sxrvb_lp->value;
|
|
|
|
rgsxdly[ISXRVB + 1].delayfeed = (sxrvb_feedback->value) * 255;
|
|
rgsxdly[ISXRVB + 1].lp = sxrvb_lp->value;
|
|
|
|
}
|
|
|
|
// main routine for updating the paintbuffer with new reverb values.
|
|
// This routine updates both left and right lines with
|
|
// the mono reverb signal. Delay is set through console vars room_reverb
|
|
// and room_feedback. 2 reverbs operating in parallel.
|
|
void SXRVB_DoReverbMono( int count )
|
|
{
|
|
portable_samplepair_t *pbuf;
|
|
int val;
|
|
int valt;
|
|
int mono;
|
|
sample_t sampledly;
|
|
sample_t samplexf;
|
|
int countr;
|
|
int voutm;
|
|
int gain;
|
|
|
|
// process reverb lines if active
|
|
if( rgsxdly[ISXRVB].lpdelayline )
|
|
{
|
|
gain = DSP_CONSTANT_GAIN;
|
|
|
|
pbuf = paintbuffer;
|
|
countr = count;
|
|
|
|
// process each sample in the paintbuffer...
|
|
|
|
while( countr-- )
|
|
{
|
|
mono = pbuf->left;
|
|
voutm = 0;
|
|
|
|
if( --gdly1.modcur < 0 )
|
|
gdly1.modcur = gdly1.mod;
|
|
|
|
// ========================== ISXRVB============================
|
|
|
|
// get sample from delay line
|
|
|
|
sampledly = *(gdly1.lpdelayline + gdly1.idelayoutput);
|
|
|
|
// only process if something is non-zero
|
|
if( gdly1.xfade || sampledly || mono )
|
|
{
|
|
// modulate delay rate
|
|
// UNDONE: modulation disabled
|
|
if( 0 && !gdly1.xfade && !gdly1.modcur && gdly1.mod )
|
|
{
|
|
// set up crossfade to new delay value, if we're not already doing an xfade
|
|
gdly1.idelayoutputxf = gdly1.idelayoutput + ((Com_RandomLong(0, 0xFF) * gdly1.delaysamples) >> 9); // 100 = ~ 9ms
|
|
|
|
if( gdly1.idelayoutputxf >= gdly1.cdelaysamplesmax )
|
|
gdly1.idelayoutputxf -= gdly1.cdelaysamplesmax;
|
|
|
|
gdly1.xfade = RVB_XFADE;
|
|
}
|
|
|
|
// modify sampledly if crossfading to new delay value
|
|
|
|
if( gdly1.xfade )
|
|
{
|
|
samplexf = (*(gdly1.lpdelayline + gdly1.idelayoutputxf) * (RVB_XFADE - gdly1.xfade)) / RVB_XFADE;
|
|
sampledly = ((sampledly * gdly1.xfade) / RVB_XFADE) + samplexf;
|
|
|
|
if( ++gdly1.idelayoutputxf >= gdly1.cdelaysamplesmax )
|
|
gdly1.idelayoutputxf = 0;
|
|
|
|
if( --gdly1.xfade == 0 )
|
|
gdly1.idelayoutput = gdly1.idelayoutputxf;
|
|
}
|
|
|
|
if( sampledly )
|
|
{
|
|
// get current sample from delay buffer
|
|
// calculate delayed value
|
|
val = SOUNDCLIP(mono + ((gdly1.delayfeed * sampledly) >> 8));
|
|
}
|
|
else
|
|
{
|
|
val = mono;
|
|
}
|
|
|
|
// lowpass
|
|
if( gdly1.lp )
|
|
{
|
|
valt = (gdly1.lp0 + gdly1.lp1 + (val<<1)) >> 2;
|
|
gdly1.lp1 = gdly1.lp0;
|
|
gdly1.lp0 = val;
|
|
}
|
|
else
|
|
{
|
|
valt = val;
|
|
}
|
|
|
|
// store delay output value into output buffer
|
|
*(gdly1.lpdelayline + gdly1.idelayinput) = valt;
|
|
voutm = valt;
|
|
}
|
|
else
|
|
{
|
|
// not playing samples, but still must flush lowpass buffer & delay line
|
|
|
|
gdly1.lp0 = gdly1.lp1 = 0;
|
|
*(gdly1.lpdelayline + gdly1.idelayinput) = 0;
|
|
voutm = 0;
|
|
}
|
|
|
|
// update delay buffer pointers
|
|
if( ++gdly1.idelayinput >= gdly1.cdelaysamplesmax )
|
|
gdly1.idelayinput = 0;
|
|
|
|
if( ++gdly1.idelayoutput >= gdly1.cdelaysamplesmax )
|
|
gdly1.idelayoutput = 0;
|
|
|
|
// ========================== ISXRVB + 1========================
|
|
|
|
if( --gdly2.modcur < 0 )
|
|
gdly2.modcur = gdly2.mod;
|
|
|
|
if( gdly2.lpdelayline )
|
|
{
|
|
// get sample from delay line
|
|
|
|
sampledly = *(gdly2.lpdelayline + gdly2.idelayoutput);
|
|
|
|
// only process if something is non-zero
|
|
if( gdly2.xfade || sampledly || mono )
|
|
{
|
|
// UNDONE: modulation disabled
|
|
if( 0 && !gdly2.xfade && gdly2.modcur && gdly2.mod )
|
|
{
|
|
// set up crossfade to new delay value, if we're not already doing an xfade
|
|
gdly2.idelayoutputxf = gdly2.idelayoutput + ((Com_RandomLong(0,0xFF) * gdly2.delaysamples) >> 9); // 100 = ~ 9ms
|
|
|
|
if( gdly2.idelayoutputxf >= gdly2.cdelaysamplesmax )
|
|
gdly2.idelayoutputxf -= gdly2.cdelaysamplesmax;
|
|
|
|
gdly2.xfade = RVB_XFADE;
|
|
}
|
|
|
|
// modify sampledly if crossfading to new delay value
|
|
if( gdly2.xfade )
|
|
{
|
|
samplexf = (*(gdly2.lpdelayline + gdly2.idelayoutputxf) * (RVB_XFADE - gdly2.xfade)) / RVB_XFADE;
|
|
sampledly = ((sampledly * gdly2.xfade) / RVB_XFADE) + samplexf;
|
|
|
|
if( ++gdly2.idelayoutputxf >= gdly2.cdelaysamplesmax )
|
|
gdly2.idelayoutputxf = 0;
|
|
|
|
if( --gdly2.xfade == 0 )
|
|
gdly2.idelayoutput = gdly2.idelayoutputxf;
|
|
}
|
|
|
|
if( sampledly )
|
|
{
|
|
// get current sample from delay buffer
|
|
val = SOUNDCLIP(mono + ((gdly2.delayfeed * sampledly) >> 8));
|
|
}
|
|
else
|
|
{
|
|
val = mono;
|
|
}
|
|
|
|
// lowpass
|
|
if( gdly2.lp )
|
|
{
|
|
valt = (gdly2.lp0 + gdly2.lp1 + (val<<1)) >> 2;
|
|
gdly2.lp0 = val;
|
|
}
|
|
else
|
|
{
|
|
valt = val;
|
|
}
|
|
|
|
// store delay output value into output buffer
|
|
*(gdly2.lpdelayline + gdly2.idelayinput) = valt;
|
|
voutm += valt;
|
|
}
|
|
else
|
|
{
|
|
// not playing samples, but still must flush lowpass buffer
|
|
gdly2.lp0 = gdly2.lp1 = 0;
|
|
*(gdly2.lpdelayline + gdly2.idelayinput) = 0;
|
|
}
|
|
|
|
// update delay buffer pointers
|
|
if( ++gdly2.idelayinput >= gdly2.cdelaysamplesmax )
|
|
gdly2.idelayinput = 0;
|
|
|
|
if( ++gdly2.idelayoutput >= gdly2.cdelaysamplesmax )
|
|
gdly2.idelayoutput = 0;
|
|
}
|
|
|
|
// ============================ Mix ================================
|
|
|
|
// add mono delay to left and right channels
|
|
// drop output by inverse of cascaded gain for both reverbs
|
|
|
|
voutm = (gain * voutm) >> 8;
|
|
|
|
pbuf->left = SOUNDCLIP( voutm );
|
|
pbuf++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SXRVB_DoReverb( int count )
|
|
{
|
|
int val[2];
|
|
int valt[2];
|
|
int left;
|
|
int right;
|
|
sample_t sampledly;
|
|
sample_t samplexf;
|
|
portable_samplepair_t *pbuf;
|
|
int countr;
|
|
int voutm[2];
|
|
int gain;
|
|
|
|
if( dma.channels < 2 )
|
|
{
|
|
SXRVB_DoReverbMono( count );
|
|
return;
|
|
}
|
|
|
|
// process reverb lines if active
|
|
if( rgsxdly[ISXRVB].lpdelayline )
|
|
{
|
|
gain = DSP_CONSTANT_GAIN;
|
|
|
|
pbuf = paintbuffer;
|
|
countr = count;
|
|
|
|
// process each sample in the paintbuffer...
|
|
|
|
while( countr-- )
|
|
{
|
|
left = pbuf->left;
|
|
right = pbuf->right;
|
|
voutm[0] = 0;
|
|
voutm[1] = 0;
|
|
|
|
if( --gdly1.modcur < 0 )
|
|
gdly1.modcur = gdly1.mod;
|
|
|
|
// ========================== ISXRVB============================
|
|
|
|
// get sample from delay line
|
|
|
|
sampledly = *(gdly1.lpdelayline + gdly1.idelayoutput);
|
|
|
|
// only process if something is non-zero
|
|
if( gdly1.xfade || sampledly || left || right )
|
|
{
|
|
// modulate delay rate
|
|
// UNDONE: modulation disabled
|
|
if( 0 && !gdly1.xfade && !gdly1.modcur && gdly1.mod )
|
|
{
|
|
// set up crossfade to new delay value, if we're not already doing an xfade
|
|
gdly1.idelayoutputxf = gdly1.idelayoutput + ((Com_RandomLong(0, 0xFF) * gdly1.delaysamples) >> 9); // 100 = ~ 9ms
|
|
|
|
if( gdly1.idelayoutputxf >= gdly1.cdelaysamplesmax )
|
|
gdly1.idelayoutputxf -= gdly1.cdelaysamplesmax;
|
|
|
|
gdly1.xfade = RVB_XFADE;
|
|
}
|
|
|
|
// modify sampledly if crossfading to new delay value
|
|
|
|
if( gdly1.xfade )
|
|
{
|
|
samplexf = (*(gdly1.lpdelayline + gdly1.idelayoutputxf) * (RVB_XFADE - gdly1.xfade)) / RVB_XFADE;
|
|
sampledly = ((sampledly * gdly1.xfade) / RVB_XFADE) + samplexf;
|
|
|
|
if( ++gdly1.idelayoutputxf >= gdly1.cdelaysamplesmax )
|
|
gdly1.idelayoutputxf = 0;
|
|
|
|
if( --gdly1.xfade == 0 )
|
|
gdly1.idelayoutput = gdly1.idelayoutputxf;
|
|
}
|
|
|
|
if( sampledly )
|
|
{
|
|
// get current sample from delay buffer
|
|
// calculate delayed value
|
|
val[0] = SOUNDCLIP(left + ((gdly1.delayfeed * sampledly) >> 8));
|
|
val[1] = SOUNDCLIP(right + ((gdly1.delayfeed * sampledly) >> 8));
|
|
|
|
}
|
|
else
|
|
{
|
|
val[0] = left;
|
|
val[1] = right;
|
|
}
|
|
|
|
// lowpass
|
|
if( gdly1.lp )
|
|
{
|
|
valt[0] = (gdly1.lp0 + gdly1.lp1 + (val[0]<<1)) >> 2;
|
|
valt[1] = (gdly1.lp0 + gdly1.lp1 + (val[1]<<1)) >> 2;
|
|
|
|
gdly1.lp1 = gdly1.lp0;
|
|
gdly1.lp0 = (val[0] + val[1]) >> 1;
|
|
}
|
|
else
|
|
{
|
|
valt[0] = val[0];
|
|
valt[1] = val[1];
|
|
}
|
|
|
|
// store delay output value into output buffer
|
|
*(gdly1.lpdelayline + gdly1.idelayinput) = (valt[0] + valt[1]) >> 1;
|
|
voutm[0] = valt[0];
|
|
voutm[1] = valt[1];
|
|
}
|
|
else
|
|
{
|
|
// not playing samples, but still must flush lowpass buffer & delay line
|
|
|
|
gdly1.lp0 = gdly1.lp1 = 0;
|
|
*(gdly1.lpdelayline + gdly1.idelayinput) = 0;
|
|
voutm[0] = 0;
|
|
voutm[1] = 0;
|
|
}
|
|
|
|
// update delay buffer pointers
|
|
if( ++gdly1.idelayinput >= gdly1.cdelaysamplesmax )
|
|
gdly1.idelayinput = 0;
|
|
|
|
if( ++gdly1.idelayoutput >= gdly1.cdelaysamplesmax )
|
|
gdly1.idelayoutput = 0;
|
|
|
|
// ========================== ISXRVB + 1========================
|
|
|
|
if( --gdly2.modcur < 0 )
|
|
gdly2.modcur = gdly2.mod;
|
|
|
|
if( gdly2.lpdelayline )
|
|
{
|
|
// get sample from delay line
|
|
|
|
sampledly = *(gdly2.lpdelayline + gdly2.idelayoutput);
|
|
|
|
// only process if something is non-zero
|
|
if( gdly2.xfade || sampledly || left || right )
|
|
{
|
|
// UNDONE: modulation disabled
|
|
if( 0 && !gdly2.xfade && gdly2.modcur && gdly2.mod )
|
|
{
|
|
// set up crossfade to new delay value, if we're not already doing an xfade
|
|
gdly2.idelayoutputxf = gdly2.idelayoutput + ((Com_RandomLong(0,0xFF) * gdly2.delaysamples) >> 9); // 100 = ~ 9ms
|
|
|
|
if( gdly2.idelayoutputxf >= gdly2.cdelaysamplesmax )
|
|
gdly2.idelayoutputxf -= gdly2.cdelaysamplesmax;
|
|
|
|
gdly2.xfade = RVB_XFADE;
|
|
}
|
|
|
|
// modify sampledly if crossfading to new delay value
|
|
if( gdly2.xfade )
|
|
{
|
|
samplexf = (*(gdly2.lpdelayline + gdly2.idelayoutputxf) * (RVB_XFADE - gdly2.xfade)) / RVB_XFADE;
|
|
sampledly = ((sampledly * gdly2.xfade) / RVB_XFADE) + samplexf;
|
|
|
|
if( ++gdly2.idelayoutputxf >= gdly2.cdelaysamplesmax )
|
|
gdly2.idelayoutputxf = 0;
|
|
|
|
if( --gdly2.xfade == 0 )
|
|
gdly2.idelayoutput = gdly2.idelayoutputxf;
|
|
}
|
|
|
|
if( sampledly )
|
|
{
|
|
// get current sample from delay buffer
|
|
val[0] = SOUNDCLIP(left + ((gdly2.delayfeed * sampledly) >> 8));
|
|
val[1] = SOUNDCLIP(right + ((gdly2.delayfeed * sampledly) >> 8));
|
|
}
|
|
else
|
|
{
|
|
val[0] = left;
|
|
val[1] = right;
|
|
}
|
|
|
|
// lowpass
|
|
if( gdly2.lp )
|
|
{
|
|
valt[0] = (gdly2.lp0 + gdly2.lp1 + (val[0]<<1)) >> 2;
|
|
valt[1] = (gdly2.lp0 + gdly2.lp1 + (val[1]<<1)) >> 2;
|
|
gdly2.lp0 = (val[0] + val[1]) >> 1;
|
|
}
|
|
else
|
|
{
|
|
valt[0] = val[0];
|
|
valt[1] = val[1];
|
|
}
|
|
|
|
// store delay output value into output buffer
|
|
*(gdly2.lpdelayline + gdly2.idelayinput) = (valt[0] + valt[1]) >> 1;
|
|
voutm[0] += valt[0];
|
|
voutm[1] += valt[1];
|
|
}
|
|
else
|
|
{
|
|
// not playing samples, but still must flush lowpass buffer
|
|
gdly2.lp0 = gdly2.lp1 = 0;
|
|
*(gdly2.lpdelayline + gdly2.idelayinput) = 0;
|
|
}
|
|
|
|
// update delay buffer pointers
|
|
if( ++gdly2.idelayinput >= gdly2.cdelaysamplesmax )
|
|
gdly2.idelayinput = 0;
|
|
|
|
if( ++gdly2.idelayoutput >= gdly2.cdelaysamplesmax )
|
|
gdly2.idelayoutput = 0;
|
|
}
|
|
|
|
// ============================ Mix================================
|
|
|
|
// add mono delay to left and right channels
|
|
// drop output by inverse of cascaded gain for both reverbs
|
|
|
|
voutm[0] = (gain * voutm[0]) >> 8;
|
|
voutm[1] = (gain * voutm[1]) >> 8;
|
|
|
|
pbuf->left = SOUNDCLIP( voutm[0] );
|
|
pbuf->right = SOUNDCLIP( voutm[1] );
|
|
|
|
pbuf++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// amplitude modulator, low pass filter for underwater weirdness
|
|
void SXRVB_DoAMod( int count )
|
|
{
|
|
int sample[2];
|
|
int valtsample[2];
|
|
portable_samplepair_t *pbuf;
|
|
int countr;
|
|
int fLowpass;
|
|
int fmod;
|
|
|
|
// process reverb lines if active
|
|
if( sxmod_lowpass->integer > 0 || sxmod_mod->integer > 0 )
|
|
{
|
|
pbuf = paintbuffer;
|
|
countr = count;
|
|
|
|
fLowpass = (sxmod_lowpass->integer > 0);
|
|
fmod = (sxmod_mod->integer > 0);
|
|
|
|
// process each sample in the paintbuffer...
|
|
|
|
while( countr-- )
|
|
{
|
|
if( dma.channels == 2 )
|
|
{
|
|
sample[0] = pbuf->left;
|
|
sample[1] = pbuf->right;
|
|
}
|
|
else
|
|
{
|
|
sample[0] = pbuf->left;
|
|
}
|
|
|
|
// only process if non-zero
|
|
if( fLowpass )
|
|
{
|
|
valtsample[0] = sample[0];
|
|
sample[0] = (rgsxlp[0] + rgsxlp[1] + rgsxlp[2] + rgsxlp[3] + rgsxlp[4] + sample[0]);
|
|
sample[0] = ((sample[0] << 1) + (sample[0] << 3)) >> 6;
|
|
|
|
rgsxlp[0] = rgsxlp[1];
|
|
rgsxlp[1] = rgsxlp[2];
|
|
rgsxlp[2] = rgsxlp[3];
|
|
rgsxlp[3] = rgsxlp[4];
|
|
rgsxlp[4] = valtsample[0];
|
|
|
|
if (dma.channels > 1)
|
|
{
|
|
valtsample[1] = sample[1];
|
|
sample[1] = (rgsxlp[5] + rgsxlp[6] + rgsxlp[7] + rgsxlp[8] + rgsxlp[9] + sample[1]);
|
|
sample[1] = ((sample[1] << 1) + (sample[1] << 3)) >> 6;
|
|
|
|
rgsxlp[5] = rgsxlp[6];
|
|
rgsxlp[6] = rgsxlp[7];
|
|
rgsxlp[7] = rgsxlp[8];
|
|
rgsxlp[8] = rgsxlp[9];
|
|
rgsxlp[9] = valtsample[1];
|
|
}
|
|
|
|
}
|
|
|
|
if( fmod )
|
|
{
|
|
if( --sxmod1cur < 0 )
|
|
sxmod1cur = sxmod1;
|
|
|
|
if( !sxmod1cur )
|
|
sxamodlt = Com_RandomLong(32,255);
|
|
|
|
if( --sxmod2cur < 0 )
|
|
sxmod2cur = sxmod2;
|
|
|
|
if( !sxmod2cur )
|
|
sxamodrt = Com_RandomLong(32,255);
|
|
|
|
if( dma.channels == 2 )
|
|
{
|
|
sample[0] = (sample[0] * sxamodl) >> 8;
|
|
sample[1] = (sample[1] * sxamodr) >> 8;
|
|
}
|
|
else
|
|
{
|
|
sample[0] = (sample[0] * (sxamodl+sxamodr)) >> 9;
|
|
}
|
|
|
|
if( sxamodl < sxamodlt )
|
|
sxamodl++;
|
|
else if( sxamodl > sxamodlt )
|
|
sxamodl--;
|
|
|
|
if( sxamodr < sxamodrt )
|
|
sxamodr++;
|
|
else if( sxamodr > sxamodrt )
|
|
sxamodr--;
|
|
}
|
|
|
|
if( dma.channels == 2 )
|
|
{
|
|
pbuf->left = SOUNDCLIP( sample[0] );
|
|
pbuf->right = SOUNDCLIP( sample[1] );
|
|
}
|
|
else
|
|
{
|
|
pbuf->left = SOUNDCLIP( sample[0] );
|
|
}
|
|
pbuf++;
|
|
}
|
|
}
|
|
}
|
|
|
|
typedef struct sx_preset_s
|
|
{
|
|
float room_lp; // for water fx, lowpass for entire room
|
|
float room_mod; // stereo amplitude modulation for room
|
|
float room_size; // reverb: initial reflection size
|
|
float room_refl; // reverb: decay time
|
|
float room_rvblp; // reverb: low pass filtering level
|
|
float room_delay; // mono delay: delay time
|
|
float room_feedback; // mono delay: decay time
|
|
float room_dlylp; // mono delay: low pass filtering level
|
|
float room_left; // left channel delay time
|
|
} sx_preset_t;
|
|
|
|
sx_preset_t rgsxpre[CSXROOM] =
|
|
{
|
|
// SXROOM_OFF 0
|
|
// lp mod size refl rvblp delay feedbk dlylp left
|
|
{0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 2.0, 0.0},
|
|
|
|
// SXROOM_GENERIC 1 // general, low reflective, diffuse room
|
|
// lp mod size refl rvblp delay feedbk dlylp left
|
|
{0.0, 0.0, 0.0, 0.0, 1.0, 0.065, 0.1, 0.0, 0.01},
|
|
|
|
// SXROOM_METALIC_S 2 // highly reflective, parallel surfaces
|
|
// SXROOM_METALIC_M 3
|
|
// SXROOM_METALIC_L 4
|
|
|
|
// lp mod size refl rvblp delay feedbk dlylp left
|
|
{0.0, 0.0, 0.0, 0.0, 1.0, 0.02, 0.75, 0.0, 0.01}, // 0.001
|
|
{0.0, 0.0, 0.0, 0.0, 1.0, 0.03, 0.78, 0.0, 0.02}, // 0.002
|
|
{0.0, 0.0, 0.0, 0.0, 1.0, 0.06, 0.77, 0.0, 0.03}, // 0.003
|
|
|
|
// SXROOM_TUNNEL_S 5 // resonant reflective, long surfaces
|
|
// SXROOM_TUNNEL_M 6
|
|
// SXROOM_TUNNEL_L 7
|
|
// lp mod size refl rvblp delay feedbk dlylp left
|
|
{0.0, 0.0, 0.05, 0.85, 1.0, 0.018, 0.7, 2.0, 0.01}, // 0.01
|
|
{0.0, 0.0, 0.05, 0.88, 1.0, 0.020, 0.7, 2.0, 0.02}, // 0.02
|
|
{0.0, 0.0, 0.05, 0.92, 1.0, 0.025, 0.7, 2.0, 0.04}, // 0.04
|
|
|
|
// SXROOM_CHAMBER_S 8 // diffuse, moderately reflective surfaces
|
|
// SXROOM_CHAMBER_M 9
|
|
// SXROOM_CHAMBER_L 10
|
|
// lp mod size refl rvblp delay feedbk dlylp left
|
|
{0.0, 0.0, 0.05, 0.84, 1.0, 0.0, 0.0, 2.0, 0.012}, // 0.003
|
|
{0.0, 0.0, 0.05, 0.90, 1.0, 0.0, 0.0, 2.0, 0.008}, // 0.002
|
|
{0.0, 0.0, 0.05, 0.95, 1.0, 0.0, 0.0, 2.0, 0.004}, // 0.001
|
|
|
|
// SXROOM_BRITE_S 11 // diffuse, highly reflective
|
|
// SXROOM_BRITE_M 12
|
|
// SXROOM_BRITE_L 13
|
|
// lp mod size refl rvblp delay feedbk dlylp left
|
|
{0.0, 0.0, 0.05, 0.7, 0.0, 0.0, 0.0, 2.0, 0.012}, // 0.003
|
|
{0.0, 0.0, 0.055, 0.78, 0.0, 0.0, 0.0, 2.0, 0.008}, // 0.002
|
|
{0.0, 0.0, 0.05, 0.86, 0.0, 0.0, 0.0, 2.0, 0.002}, // 0.001
|
|
|
|
// SXROOM_WATER1 14 // underwater fx
|
|
// SXROOM_WATER2 15
|
|
// SXROOM_WATER3 16
|
|
// lp mod size refl rvblp delay feedbk dlylp left
|
|
{1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 2.0, 0.01},
|
|
{1.0, 0.0, 0.0, 0.0, 1.0, 0.06, 0.85, 2.0, 0.02},
|
|
{1.0, 0.0, 0.0, 0.0, 1.0, 0.2, 0.6, 2.0, 0.05},
|
|
|
|
// SXROOM_CONCRETE_S 17 // bare, reflective, parallel surfaces
|
|
// SXROOM_CONCRETE_M 18
|
|
// SXROOM_CONCRETE_L 19
|
|
// lp mod size refl rvblp delay feedbk dlylp left
|
|
{0.0, 0.0, 0.05, 0.8, 1.0, 0.0, 0.48, 2.0, 0.016}, // 0.15 delay, 0.008 left
|
|
{0.0, 0.0, 0.06, 0.9, 1.0, 0.0, 0.52, 2.0, 0.01 }, // 0.22 delay, 0.005 left
|
|
{0.0, 0.0, 0.07, 0.94, 1.0, 0.3, 0.6, 2.0, 0.008}, // 0.001
|
|
|
|
// SXROOM_OUTSIDE1 20 // echoing, moderately reflective
|
|
// SXROOM_OUTSIDE2 21 // echoing, dull
|
|
// SXROOM_OUTSIDE3 22 // echoing, very dull
|
|
// lp mod size refl rvblp delay feedbk dlylp left
|
|
{0.0, 0.0, 0.0, 0.0, 1.0, 0.3, 0.42, 2.0, 0.0},
|
|
{0.0, 0.0, 0.0, 0.0, 1.0, 0.35, 0.48, 2.0, 0.0},
|
|
{0.0, 0.0, 0.0, 0.0, 1.0, 0.38, 0.6, 2.0, 0.0},
|
|
|
|
// SXROOM_CAVERN_S 23 // large, echoing area
|
|
// SXROOM_CAVERN_M 24
|
|
// SXROOM_CAVERN_L 25
|
|
// lp mod size refl rvblp delay feedbk dlylp left
|
|
{0.0, 0.0, 0.05, 0.9, 1.0, 0.2, 0.28, 0.0, 0.0},
|
|
{0.0, 0.0, 0.07, 0.9, 1.0, 0.3, 0.4, 0.0, 0.0},
|
|
{0.0, 0.0, 0.09, 0.9, 1.0, 0.35, 0.5, 0.0, 0.0},
|
|
|
|
// SXROOM_WEIRDO1 26
|
|
// SXROOM_WEIRDO2 27
|
|
// SXROOM_WEIRDO3 28
|
|
// lp mod size refl rvblp delay feedbk dlylp left
|
|
{0.0, 1.0, 0.01, 0.9, 0.0, 0.0, 0.0, 2.0, 0.05},
|
|
{0.0, 0.0, 0.0, 0.0, 1.0, 0.009, 0.999, 2.0, 0.04},
|
|
{0.0, 0.0, 0.001, 0.999, 0.0, 0.2, 0.8, 2.0, 0.05}
|
|
|
|
};
|
|
|
|
// main routine for processing room sound fx
|
|
// if fFilter is true, then run in-line filter (for underwater fx)
|
|
// if fTimefx is true, then run reverb and delay fx
|
|
// NOTE: only processes preset room_types from 0-29 (CSXROOM)
|
|
void SX_RoomFX( int endtime, int fFilter, int fTimefx )
|
|
{
|
|
int i, fReset;
|
|
int sampleCount;
|
|
int roomType;
|
|
|
|
// return right away if fx processing is turned off
|
|
if( sxroom_off->value != 0.0 )
|
|
return;
|
|
|
|
sampleCount = endtime - paintedtime;
|
|
if( sampleCount < 0 )
|
|
return;
|
|
|
|
fReset = false;
|
|
if( listener_waterlevel > 2 )
|
|
roomType = sxroomwater_type->integer;
|
|
else roomType = sxroom_type->integer;
|
|
|
|
// only process legacy roomtypes here
|
|
if( roomType >= CSXROOM )
|
|
return;
|
|
|
|
if( roomType != sxroom_typeprev )
|
|
{
|
|
MsgDev( D_NOTE, "svc_roomtype: set to %i\n", roomType );
|
|
|
|
sxroom_typeprev = roomType;
|
|
|
|
i = roomType;
|
|
if( i < CSXROOM && i >= 0 )
|
|
{
|
|
Cvar_SetValue( "room_lp", rgsxpre[i].room_lp );
|
|
Cvar_SetValue( "room_mod", rgsxpre[i].room_mod );
|
|
Cvar_SetValue( "room_size", rgsxpre[i].room_size );
|
|
Cvar_SetValue( "room_refl", rgsxpre[i].room_refl );
|
|
Cvar_SetValue( "room_rvblp", rgsxpre[i].room_rvblp );
|
|
Cvar_SetValue( "room_delay", rgsxpre[i].room_delay );
|
|
Cvar_SetValue( "room_feedback", rgsxpre[i].room_feedback );
|
|
Cvar_SetValue( "room_dlylp", rgsxpre[i].room_dlylp );
|
|
Cvar_SetValue( "room_left", rgsxpre[i].room_left );
|
|
}
|
|
|
|
SXRVB_CheckNewReverbVal();
|
|
SXDLY_CheckNewDelayVal();
|
|
SXDLY_CheckNewStereoDelayVal();
|
|
|
|
fReset = true;
|
|
}
|
|
|
|
if( fReset || roomType != 0 )
|
|
{
|
|
// debug code
|
|
SXRVB_CheckNewReverbVal();
|
|
SXDLY_CheckNewDelayVal();
|
|
SXDLY_CheckNewStereoDelayVal();
|
|
// debug code
|
|
|
|
if( fFilter ) SXRVB_DoAMod( sampleCount );
|
|
|
|
if( fTimefx )
|
|
{
|
|
SXRVB_DoReverb( sampleCount );
|
|
SXDLY_DoDelay( sampleCount );
|
|
SXDLY_DoStereoDelay( sampleCount );
|
|
}
|
|
}
|
|
} |