📄 snd_dsp.cpp
字号:
{
default:
case OP_LEFT:
while (count--)
{
pb->left = DFR_GetNext( pdfr, pb->left );
pb++;
}
return;
case OP_RIGHT:
while (count--)
{
pb->right = DFR_GetNext( pdfr, pb->right );
pb++;
}
return;
case OP_LEFT_DUPLICATE:
while (count--)
{
pb->left = pb->right = DFR_GetNext( pdfr, pb->left );
pb++;
}
return;
}
}
#define DFR_BASEN 2 // base number of series allpass delays
// nominal diffusor delay and feedback values
//float dfrdlys[] = {20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95};
float dfrdlys[] = {13, 19, 26, 21, 32, 36, 38, 16, 24, 28, 41, 35, 10, 46, 50, 27};
float dfrfbs[] = {0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15};
// diffusor parameter order
typedef enum
{
// parameter order
dfr_isize,
dfr_idensity,
dfr_idecay,
dfr_cparam // # of params
} dfr_e;
// diffusor parameter ranges
prm_rng_t dfr_rng[] = {
{dfr_cparam, 0, 0}, // first entry is # of parameters
{dfr_isize, 0.0, 1.0}, // 0-1.0 scales all delays
{dfr_idensity, 0.0, 1.0}, // 0-1.0 controls # of series delays
{dfr_idecay, 0.0, 1.0}, // 0-1.0 scales all feedback parameters
};
dfr_t * DFR_Params ( prc_t *pprc )
{
dfr_t *pdfr;
int i;
int s;
float size = pprc->prm[dfr_isize]; // 0-1.0 scales all delays
float density = pprc->prm[dfr_idensity]; // 0-1.0 controls # of series delays
float diffusion = pprc->prm[dfr_idecay]; // 0-1.0 scales all feedback parameters
// 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 (CRVB_S_DLYS)
// b gain of each reverb section
// n - number of series delays
int D[CDFR_DLYS];
int a[CDFR_DLYS];
int b[CDFR_DLYS];
int n = DFR_BASEN;
// increase # of series diffusors with increased density
n += density * 2;
// limit m, n to half max number of delays
n = min (CDFR_DLYS/2, n);
// compute delays for diffusors
for (i = 0; i < n; i++)
{
s = (int)( dfrdlys[i] * size );
// delay of diffusor
D[i] = MSEC_TO_SAMPS(s);
// feedback and gain of diffusor
a[i] = min (0.9 * PMAX, dfrfbs[i] * PMAX * diffusion);
b[i] = PMAX;
}
pdfr = DFR_Alloc ( D, a, b, n );
return pdfr;
}
inline void * DFR_VParams ( void *p )
{
PRC_CheckParams ((prc_t *)p, dfr_rng);
return (void *) DFR_Params ((prc_t *)p);
}
inline void DFR_Mod ( void *p, float v ) { return; }
//////////////////////
// LFO wav definitions
//////////////////////
#define CLFOSAMPS 512 // samples per wav table - single cycle only
#define LFOBITS 14 // bits of peak amplitude of lfo wav
#define LFOAMP ((1<<LFOBITS)-1) // peak amplitude of lfo wav
//types of lfo wavs
#define LFO_SIN 0 // sine wav
#define LFO_TRI 1 // triangle wav
#define LFO_SQR 2 // square wave, 50% duty cycle
#define LFO_SAW 3 // forward saw wav
#define LFO_RND 4 // random wav
#define LFO_LOG_IN 5 // logarithmic fade in
#define LFO_LOG_OUT 6 // logarithmic fade out
#define LFO_LIN_IN 7 // linear fade in
#define LFO_LIN_OUT 8 // linear fade out
#define LFO_MAX LFO_LIN_OUT
#define CLFOWAV 9 // number of LFO wav tables
struct lfowav_t // lfo or envelope wave table
{
int type; // lfo type
dly_t *pdly; // delay holds wav values and step pointers
};
lfowav_t lfowavs[CLFOWAV];
// deallocate lfo wave table. Called only when sound engine exits.
void LFOWAV_Free( lfowav_t *plw )
{
// free delay
if ( plw )
DLY_Free( plw->pdly );
Q_memset( plw, 0, sizeof (lfowav_t) );
}
// deallocate all lfo wave tables. Called only when sound engine exits.
void LFOWAV_FreeAll( void )
{
for ( int i = 0; i < CLFOWAV; i++ )
LFOWAV_Free( &lfowavs[i] );
}
// fill lfo array w with count samples of lfo type 'type'
// all lfo wavs except fade out, rnd, and log_out should start with 0 output
void LFOWAV_Fill( int *w, int count, int type )
{
int i,x;
switch (type)
{
default:
case LFO_SIN: // sine wav, all values 0 <= x <= LFOAMP, initial value = 0
for (i = 0; i < count; i++ )
{
x = ( int )( (float)(LFOAMP) * sinf( (2.0 * M_PI_F * (float)i / (float)count ) + (M_PI_F * 1.5) ) );
w[i] = (x + LFOAMP)/2;
}
break;
case LFO_TRI: // triangle wav, all values 0 <= x <= LFOAMP, initial value = 0
for (i = 0; i < count; i++)
{
w[i] = ( int ) ( (float)(2 * LFOAMP * i ) / (float)(count) );
if ( i > count / 2 )
w[i] = ( int ) ( (float) (2 * LFOAMP) - (float)( 2 * LFOAMP * i ) / (float)(count) );
}
break;
case LFO_SQR: // square wave, 50% duty cycle, all values 0 <= x <= LFOAMP, initial value = 0
for (i = 0; i < count; i++)
w[i] = i > count / 2 ? 0 : LFOAMP;
break;
case LFO_SAW: // forward saw wav, aall values 0 <= x <= LFOAMP, initial value = 0
for (i = 0; i < count; i++)
w[i] = ( int ) ( (float)(LFOAMP) * (float)i / (float)(count) );
break;
case LFO_RND: // random wav, all values 0 <= x <= LFOAMP
for (i = 0; i < count; i++)
w[i] = ( int ) ( g_pSoundServices->RandomLong(0, LFOAMP) );
break;
case LFO_LOG_IN: // logarithmic fade in, all values 0 <= x <= LFOAMP, initial value = 0
for (i = 0; i < count; i++)
w[i] = ( int ) ( (float)(LFOAMP) * powf( (float)i / (float)count, 2));
break;
case LFO_LOG_OUT: // logarithmic fade out, all values 0 <= x <= LFOAMP, initial value = LFOAMP
for (i = 0; i < count; i++)
w[i] = ( int ) ( (float)(LFOAMP) * powf( 1.0 - ((float)i / (float)count), 2 ));
break;
case LFO_LIN_IN: // linear fade in, all values 0 <= x <= LFOAMP, initial value = 0
for (i = 0; i < count; i++)
w[i] = ( int ) ( (float)(LFOAMP) * (float)i / (float)(count) );
break;
case LFO_LIN_OUT: // linear fade out, all values 0 <= x <= LFOAMP, initial value = LFOAMP
for (i = 0; i < count; i++)
w[i] = LFOAMP - ( int ) ( (float)(LFOAMP) * (float)i / (float)(count) );
break;
}
}
// allocate all lfo wave tables. Called only when sound engine loads.
void LFOWAV_InitAll()
{
int i;
dly_t *pdly;
Q_memset( lfowavs, 0, sizeof( lfowavs ) );
// alloc space for each lfo wav type
for (i = 0; i < CLFOWAV; i++)
{
pdly = DLY_Alloc( CLFOSAMPS, 0, 0 , DLY_PLAIN);
lfowavs[i].pdly = pdly;
lfowavs[i].type = i;
LFOWAV_Fill( pdly->w, CLFOSAMPS, i );
}
// if any dlys fail to alloc, free all
for (i = 0; i < CLFOWAV; i++)
{
if ( !lfowavs[i].pdly )
LFOWAV_FreeAll();
}
}
////////////////////////////////////////
// LFO iterators - one shot and looping
////////////////////////////////////////
#define CLFO 16 // max active lfos (this steals from active delays)
struct lfo_t
{
bool fused; // true if slot take
dly_t *pdly; // delay points to lfo wav within lfowav_t (don't free this)
float f; // playback frequency in hz
pos_t pos; // current position within wav table, looping
pos_one_t pos1; // current position within wav table, one shot
int foneshot; // true - one shot only, don't repeat
};
lfo_t lfos[CLFO];
void LFO_Init( lfo_t *plfo ) { if ( plfo ) Q_memset( plfo, 0, sizeof (lfo_t) ); }
void LFO_InitAll( void ) { for (int i = 0; i < CLFO; i++) LFO_Init(&lfos[i]); }
void LFO_Free( lfo_t *plfo ) { if ( plfo ) Q_memset( plfo, 0, sizeof (lfo_t) ); }
void LFO_FreeAll( void ) { for (int i = 0; i < CLFO; i++) LFO_Free(&lfos[i]); }
// get step value given desired playback frequency
inline float LFO_HzToStep ( float freqHz )
{
float lfoHz;
// calculate integer and fractional step values,
// assume an update rate of SOUND_DMA_SPEED samples/sec
// 1 cycle/CLFOSAMPS * SOUND_DMA_SPEED samps/sec = cycles/sec = current lfo rate
//
// lforate * X = freqHz so X = freqHz/lforate = update rate
lfoHz = (float)(SOUND_DMA_SPEED) / (float)(CLFOSAMPS);
return freqHz / lfoHz;
}
// return pointer to new lfo
lfo_t * LFO_Alloc( int wtype, float freqHz, bool foneshot )
{
int i;
int type = min ( CLFOWAV - 1, wtype );
float lfostep;
for (i = 0; i < CLFO; i++)
if (!lfos[i].fused)
{
lfo_t *plfo = &lfos[i];
LFO_Init( plfo );
plfo->fused = true;
plfo->pdly = lfowavs[type].pdly; // pdly in lfo points to wav table data in lfowavs
plfo->f = freqHz;
plfo->foneshot = foneshot;
lfostep = LFO_HzToStep( freqHz );
// init positional pointer (ie: fixed point updater for controlling pitch of lfo)
if ( !foneshot )
POS_Init(&(plfo->pos), plfo->pdly->D, lfostep );
else
POS_ONE_Init(&(plfo->pos1), plfo->pdly->D,lfostep );
return plfo;
}
DevMsg ("DSP: Warning, failed to allocate LFO.\n" );
return NULL;
}
// get next lfo value
// Value returned is 0..LFOAMP. can be normalized by shifting right by LFOBITS
// To play back at correct passed in frequency, routien should be
// called once for every output sample (ie: at SOUND_DMA_SPEED)
// x is dummy param
inline int LFO_GetNext( lfo_t *plfo, int x )
{
int i;
// get current position
if ( !plfo->foneshot )
i = POS_GetNext( &plfo->pos );
else
i = POS_ONE_GetNext( &plfo->pos1 );
// return current sample
return plfo->pdly->w[i];
}
// batch version for performance
inline void LFO_GetNextN( lfo_t *plfo, 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 = LFO_GetNext( plfo, pb->left );
pb++;
}
return;
case OP_RIGHT:
while (count--)
{
pb->right = LFO_GetNext( plfo, pb->right );
pb++;
}
return;
case OP_LEFT_DUPLICATE:
while (count--)
{
pb->left = pb->right = LFO_GetNext( plfo, pb->left );
pb++;
}
return;
}
}
// uses lfowav, rate, foneshot
typedef enum
{
// parameter order
lfo_iwav,
lfo_irate,
lfo_ifoneshot,
lfo_cparam // # of params
} lfo_e;
// parameter ranges
prm_rng_t lfo_rng[] = {
{lfo_cparam, 0, 0}, // first entry is # of parameters
{lfo_iwav, 0.0, LFO_MAX}, // lfo type to use (LFO_SIN, LFO_RND...)
{lfo_irate, 0.0, 16000.0}, // modulation rate in hz. for MDY, 1/rate = 'glide' time in seconds
{lfo_ifoneshot, 0.0, 1.0}, // 1.0 if lfo is oneshot
};
lfo_t * LFO_Params ( prc_t *pprc )
{
lfo_t *plfo;
bool foneshot = pprc->prm[lfo_ifoneshot] > 0 ? true : false;
plfo = LFO_Alloc ( pprc->prm[lfo_iwav], pprc->prm[lfo_irate], foneshot );
return plfo;
}
void LFO_ChangeVal ( lfo_t *plfo, float fhz )
{
float fstep = LFO_HzToStep( fhz );
// change lfo playback rate to new frequency fhz
if ( plfo->foneshot )
POS_ChangeVal( &plfo->pos, fstep );
else
POS_ChangeVal( &plfo->pos1.p, fstep );
}
inline void * LFO_VParams ( void *p )
{
PRC_CheckParams ( (prc_t *)p, lfo_rng );
return (void *) LFO_Params ((prc_t *)p);
}
// v is +/- 0-1.0
// v changes current lfo frequency up/down by +/- v%
inline void LFO_Mod ( lfo_t *plfo, float v )
{
float fhz;
float fhznew;
fhz = plfo->f;
fhznew = fhz * (1.0 + v);
LFO_ChangeVal ( plfo, fhznew );
return;
}
/////////////////////////////////////////////////////////////////////////////
// Ramp - used for varying smoothly between int parameters ie: modulation delays
/////////////////////////////////////////////////////////////////////////////
struct rmp_t
{
int initval; // initial ramp value
int target; // final ramp value
int sign; // increasing (1) or decreasing (-1) ramp
int yprev; // previous output value
bool fhitend; // true if hit end of ramp
pos_one_t ps; // current ramp output
};
// ramp smoothly between initial value and target value in approx 'ramptime' seconds.
// (initial value may be greater or less than target value)
// never changes output by more than +1 or -1 (which can cause the ramp to take longer to complete than ramptime)
// called once per sample while ramping
// ramptime - duration of ramp in seconds
// initval - initial ramp value
// targetval - target ramp value
void RMP_Init( rmp_t *prmp, float ramptime, int initval, int targetval )
{
int rise;
int run;
if (prmp)
Q_memset( prmp, 0, sizeof (rmp_t) );
run = (int) (ramptime * SOUND_DMA_SPEED); // 'samples' in ramp
rise = (targetval - initval); // height of ramp
// init fixed poi
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -