This repository has been archived on 2022-06-27. You can view files and clone it, but cannot push or open issues or pull requests.
Xash3DArchive/engine/client/s_dsp.c

907 lines
21 KiB
C
Raw Normal View History

2011-05-09 22:00:00 +02:00
/*
s_dsp.c - digital signal processing algorithms for audio FX
Copyright (C) 2009 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
2009-10-10 22:00:00 +02:00
2010-11-20 22:00:00 +01:00
#include "common.h"
2016-08-12 23:00:00 +02:00
#include "client.h"
2009-10-10 22:00:00 +02:00
#include "sound.h"
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
#define MAX_DELAY 0.4f
#define MAX_ROOM_TYPES ARRAYSIZE( rgsxpre )
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
#define MONODLY 0
#define MAX_MONO_DELAY 0.4f
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
#define REVERBPOS 1
#define MAX_REVERB_DELAY 0.1f
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
#define STEREODLY 3
#define MAX_STEREO_DELAY 0.1f
2011-03-15 22:00:00 +01:00
2016-12-12 22:00:00 +01:00
#define REVERB_XFADE 32
2016-08-12 23:00:00 +02:00
#define MAXDLY (STEREODLY + 1)
#define MAXLP 10
2018-09-20 23:00:00 +02:00
#define MAXPRESETS 29
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
typedef struct sx_preset_s
{
float room_lp; // lowpass
float room_mod; // modulation
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
// reverb
float room_size;
float room_refl;
float room_rvblp;
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
// delay
float room_delay;
float room_feedback;
float room_dlylp;
float room_left;
} sx_preset_t;
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
typedef struct dly_s
{
size_t cdelaysamplesmax; // delay line array size
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
// delay line pointers
size_t idelayinput;
size_t idelayoutput;
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
// crossfade
size_t idelayoutputxf; // output pointer
int xfade; // value
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
int delaysamples; // delay setting
int delayfeedback; // feedback setting
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
// lowpass
int lp; // is lowpass enabled
int lp0, lp1, lp2; // lowpass buffer
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
// modulation
int mod;
int modcur;
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
// delay line
int *lpdelayline;
} dly_t;
2011-03-15 22:00:00 +01:00
2018-09-20 23:00:00 +02:00
const sx_preset_t rgsxpre[MAXPRESETS] =
2016-08-12 23:00:00 +02:00
{
// -------reverb-------- -------delay--------
// lp mod size refl rvblp delay feedback dlylp left
{ 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 2.0, 0.0 }, // 0 off
{ 0.0, 0.0, 0.0, 0.0, 1.0, 0.065, 0.1, 0.0, 0.01 }, // 1 generic
{ 0.0, 0.0, 0.0, 0.0, 1.0, 0.02, 0.75, 0.0, 0.01 }, // 2 metalic
{ 0.0, 0.0, 0.0, 0.0, 1.0, 0.03, 0.78, 0.0, 0.02 }, // 3
{ 0.0, 0.0, 0.0, 0.0, 1.0, 0.06, 0.77, 0.0, 0.03 }, // 4
{ 0.0, 0.0, 0.05, 0.85, 1.0, 0.008, 0.96, 2.0, 0.01 }, // 5 tunnel
{ 0.0, 0.0, 0.05, 0.88, 1.0, 0.01, 0.98, 2.0, 0.02 }, // 6
{ 0.0, 0.0, 0.05, 0.92, 1.0, 0.015, 0.995, 2.0, 0.04 }, // 7
{ 0.0, 0.0, 0.05, 0.84, 1.0, 0.0, 0.0, 2.0, 0.012 }, // 8 chamber
{ 0.0, 0.0, 0.05, 0.9, 1.0, 0.0, 0.0, 2.0, 0.008 }, // 9
{ 0.0, 0.0, 0.05, 0.95, 1.0, 0.0, 0.0, 2.0, 0.004 }, // 10
{ 0.0, 0.0, 0.05, 0.7, 0.0, 0.0, 0.0, 2.0, 0.012 }, // 11 brite
{ 0.0, 0.0, 0.055, 0.78, 0.0, 0.0, 0.0, 2.0, 0.008 }, // 12
{ 0.0, 0.0, 0.05, 0.86, 0.0, 0.0, 0.0, 2.0, 0.002 }, // 13
{ 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 2.0, 0.01 }, // 14 water
{ 1.0, 0.0, 0.0, 0.0, 1.0, 0.06, 0.85, 2.0, 0.02 }, // 15
{ 1.0, 0.0, 0.0, 0.0, 1.0, 0.2, 0.6, 2.0, 0.05 }, // 16
{ 0.0, 0.0, 0.05, 0.8, 1.0, 0.0, 0.48, 2.0, 0.016 }, // 17 concrete
{ 0.0, 0.0, 0.06, 0.9, 1.0, 0.0, 0.52, 2.0, 0.01 }, // 18
{ 0.0, 0.0, 0.07, 0.94, 1.0, 0.3, 0.6, 2.0, 0.008 }, // 19
{ 0.0, 0.0, 0.0, 0.0, 1.0, 0.3, 0.42, 2.0, 0.0 }, // 20 outside
{ 0.0, 0.0, 0.0, 0.0, 1.0, 0.35, 0.48, 2.0, 0.0 }, // 21
{ 0.0, 0.0, 0.0, 0.0, 1.0, 0.38, 0.6, 2.0, 0.0 }, // 22
{ 0.0, 0.0, 0.05, 0.9, 1.0, 0.2, 0.28, 0.0, 0.0 }, // 23 cavern
{ 0.0, 0.0, 0.07, 0.9, 1.0, 0.3, 0.4, 0.0, 0.0 }, // 24
{ 0.0, 0.0, 0.09, 0.9, 1.0, 0.35, 0.5, 0.0, 0.0 }, // 25
{ 0.0, 1.0, 0.01, 0.9, 0.0, 0.0, 0.0, 2.0, 0.05 }, // 26 weirdo
{ 0.0, 0.0, 0.0, 0.0, 1.0, 0.009, 0.999, 2.0, 0.04 }, // 27
{ 0.0, 0.0, 0.001, 0.999, 0.0, 0.2, 0.8, 2.0, 0.05 } // 28
};
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
// cvars
convar_t *dsp_off; // disable dsp
convar_t *roomwater_type; // water room_type
convar_t *room_type; // current room type
2016-12-12 22:00:00 +01:00
convar_t *hisound; // DSP quality
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
// underwater/special fx modulations
convar_t *sxmod_mod;
convar_t *sxmod_lowpass;
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
// stereo delay(no feedback)
convar_t *sxste_delay; // straight left delay
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
// mono reverb
convar_t *sxrvb_lp; // lowpass
convar_t *sxrvb_feedback; // reverb decay. Higher -- longer
convar_t *sxrvb_size; // room size. Higher -- larger
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
// mono delay
convar_t *sxdly_lp; // lowpass
convar_t *sxdly_feedback; // cycles
convar_t *sxdly_delay; // current delay in seconds
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
convar_t *dsp_room; // for compability
2016-12-12 22:00:00 +01:00
int idsp_dma_speed;
2016-08-12 23:00:00 +02:00
int idsp_room;
int room_typeprev;
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
// routines
int sxamodl, sxamodr; // amplitude modulation values
int sxamodlt, sxamodrt; // modulation targets
int sxmod1cur, sxmod2cur;
2016-12-12 22:00:00 +01:00
int sxmod1, sxmod2;
int sxhires;
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
portable_samplepair_t *paintto = NULL;
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
dly_t rgsxdly[MAXDLY]; // stereo is last
int rgsxlp[MAXLP];
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
void SX_Profiling_f( void );
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
/*
============
SX_ReloadRoomFX
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
============
*/
void SX_ReloadRoomFX( void )
{
if( !dsp_room ) return; // not initialized
2011-03-15 22:00:00 +01:00
2017-02-12 22:00:00 +01:00
SetBits( sxste_delay->flags, FCVAR_CHANGED );
SetBits( sxrvb_feedback->flags, FCVAR_CHANGED );
SetBits( sxdly_delay->flags, FCVAR_CHANGED );
SetBits( room_type->flags, FCVAR_CHANGED );
2016-08-12 23:00:00 +02:00
}
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
/*
============
SX_Init()
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
Starts sound crackling system
============
*/
void SX_Init( void )
{
2016-12-12 22:00:00 +01:00
memset( rgsxdly, 0, sizeof( rgsxdly ));
memset( rgsxlp, 0, sizeof( rgsxlp ));
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
sxamodr = sxamodl = sxamodrt = sxamodlt = 255;
2016-12-12 22:00:00 +01:00
idsp_dma_speed = SOUND_11k;
2011-03-15 22:00:00 +01:00
2017-02-12 22:00:00 +01:00
hisound = Cvar_Get( "room_hires", "2", FCVAR_ARCHIVE, "dsp quality. 1 for 22k, 2 for 44k(recommended) and 3 for 96k" );
2016-12-12 22:00:00 +01:00
sxhires = 2;
2011-03-15 22:00:00 +01:00
2016-12-12 22:00:00 +01:00
sxmod1cur = sxmod1 = 350 * ( idsp_dma_speed / SOUND_11k );
sxmod2cur = sxmod2 = 450 * ( idsp_dma_speed / SOUND_11k );
2011-03-15 22:00:00 +01:00
2018-09-08 23:00:00 +02:00
dsp_off = Cvar_Get( "dsp_off", "0", FCVAR_ARCHIVE, "disable DSP processing" );
2016-08-12 23:00:00 +02:00
roomwater_type = Cvar_Get( "waterroom_type", "14", 0, "water room type" );
room_type = Cvar_Get( "room_type", "0", 0, "current room type preset" );
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
sxmod_lowpass = Cvar_Get( "room_lp", "0", 0, "for water fx, lowpass for entire room" );
sxmod_mod = Cvar_Get( "room_mod", "0", 0, "stereo amptitude modulation for room" );
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
sxrvb_size = Cvar_Get( "room_size", "0", 0, "reverb: initial reflection size" );
sxrvb_feedback = Cvar_Get( "room_refl", "0", 0, "reverb: decay time" );
sxrvb_lp = Cvar_Get( "room_rvblp", "1", 0, "reverb: low pass filtering level" );
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
sxdly_delay = Cvar_Get( "room_delay", "0.8", 0, "mono delay: delay time" );
sxdly_feedback = Cvar_Get( "room_feedback", "0.2", 0, "mono delay: decay time" );
sxdly_lp = Cvar_Get( "room_dlylp", "1", 0, "mono delay: low pass filtering level" );
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
sxste_delay = Cvar_Get( "room_left", "0", 0, "left channel delay time" );
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
Cmd_AddCommand( "dsp_profile", SX_Profiling_f, "dsp stress-test, first argument is room_type" );
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
// for compability
dsp_room = room_type;
2017-02-12 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
SX_ReloadRoomFX();
}
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
/*
===========
DLY_Free
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
Free memory allocated for DSP
===========
*/
void DLY_Free( int idelay )
{
Assert( idelay >= 0 && idelay < MAXDLY );
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
if( rgsxdly[idelay].lpdelayline )
{
Z_Free( rgsxdly[idelay].lpdelayline );
rgsxdly[idelay].lpdelayline = NULL;
2011-03-15 22:00:00 +01:00
}
2010-09-16 22:00:00 +02:00
}
2009-10-10 22:00:00 +02:00
2016-08-12 23:00:00 +02:00
/*
==========
SX_Shutdown
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
Stop DSP processor
==========
*/
void SX_Free( void )
{
int i;
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
for( i = 0; i <= 3; i++ )
DLY_Free( i );
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
Cmd_RemoveCommand( "dsp_profile" );
}
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
/*
===========
DLY_Init
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
Initialize dly
===========
*/
int DLY_Init( int idelay, float delay )
{
dly_t *cur;
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
// DLY_Init called anytime with constants. So valid it in debug builds only.
Assert( idelay >= 0 && idelay < MAXDLY );
Assert( delay > 0.0f && delay <= MAX_DELAY );
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
DLY_Free( idelay ); // free dly if it's allocated
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
cur = &rgsxdly[idelay];
2016-12-12 22:00:00 +01:00
cur->cdelaysamplesmax = ((int)(delay * idsp_dma_speed) << sxhires) + 1;
2018-05-26 23:00:00 +02:00
cur->lpdelayline = (int *)Z_Calloc( cur->cdelaysamplesmax * sizeof( int ));
2016-08-12 23:00:00 +02:00
cur->xfade = 0;
2009-10-10 22:00:00 +02:00
2016-08-12 23:00:00 +02:00
// init modulation
cur->mod = cur->modcur = 0;
2009-10-10 22:00:00 +02:00
2016-08-12 23:00:00 +02:00
// init lowpass
cur->lp = 1;
cur->lp0 = cur->lp1 = cur->lp2 = 0;
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
cur->idelayinput = 0;
cur->idelayoutput = cur->cdelaysamplesmax - cur->delaysamples; // NOTE: delaysamples must be set!!!
2009-10-10 22:00:00 +02:00
2016-08-12 23:00:00 +02:00
return 1;
2009-10-10 22:00:00 +02:00
}
2016-08-12 23:00:00 +02:00
/*
============
DLY_MovePointer
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
Checks overflow and moves pointer
============
*/
_inline void DLY_MovePointer( dly_t *dly )
2011-03-15 22:00:00 +01:00
{
2016-08-12 23:00:00 +02:00
if( ++dly->idelayinput >= dly->cdelaysamplesmax )
dly->idelayinput = 0;
if( ++dly->idelayoutput >= dly->cdelaysamplesmax )
dly->idelayoutput = 0;
2011-03-15 22:00:00 +01:00
}
2016-08-12 23:00:00 +02:00
/*
=============
DLY_CheckNewStereoDelayVal
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
Update stereo processor settings if we are in new room
=============
*/
void DLY_CheckNewStereoDelayVal( void )
2009-10-10 22:00:00 +02:00
{
2016-08-12 23:00:00 +02:00
dly_t *const dly = &rgsxdly[STEREODLY];
float delay = sxste_delay->value;
2009-10-10 22:00:00 +02:00
2017-02-12 22:00:00 +01:00
if( !FBitSet( sxste_delay->flags, FCVAR_CHANGED ))
2016-08-12 23:00:00 +02:00
return;
if( delay == 0 )
2009-11-13 22:00:00 +01:00
{
2016-08-12 23:00:00 +02:00
DLY_Free( STEREODLY );
2011-03-15 22:00:00 +01:00
}
2016-08-12 23:00:00 +02:00
else
{
int samples;
2011-03-15 22:00:00 +01:00
2016-12-12 22:00:00 +01:00
delay = Q_min( delay, MAX_STEREO_DELAY );
samples = (int)(delay * idsp_dma_speed) << sxhires;
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
// re-init dly
if( !dly->lpdelayline )
{
dly->delaysamples = samples;
DLY_Init( STEREODLY, MAX_STEREO_DELAY );
}
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
if( dly->delaysamples != samples )
{
dly->xfade = 128;
dly->idelayoutputxf = dly->idelayinput - samples;
if( dly->idelayoutputxf < 0 )
dly->idelayoutputxf += dly->cdelaysamplesmax;
}
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
dly->modcur = dly->mod = 0;
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
if( dly->delaysamples == 0 )
DLY_Free( STEREODLY );
2010-09-16 22:00:00 +02:00
}
2017-02-12 22:00:00 +01:00
ClearBits( sxste_delay->flags, FCVAR_CHANGED );
2011-03-15 22:00:00 +01:00
}
2016-08-12 23:00:00 +02:00
/*
=============
DLY_DoStereoDelay
Do stereo processing
=============
*/
void DLY_DoStereoDelay( int count )
2011-03-15 22:00:00 +01:00
{
2016-08-12 23:00:00 +02:00
int delay, samplexf;
dly_t *const dly = &rgsxdly[STEREODLY];
portable_samplepair_t *paint = paintto;
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
if( !dly->lpdelayline )
return; // inactive
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
for( ; count; count--, paint++ )
2011-03-15 22:00:00 +01:00
{
2016-08-12 23:00:00 +02:00
if( dly->mod && --dly->modcur < 0 )
dly->modcur = dly->mod;
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
delay = dly->lpdelayline[dly->idelayoutput];
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
// process only if crossfading, active left value or delayline
if( delay || paint->left || dly->xfade )
{
// set up new crossfade, if not crossfading, not modulating, but going to
if( !dly->xfade && !dly->modcur && dly->mod )
{
2017-02-21 22:00:00 +01:00
dly->idelayoutputxf = dly->idelayoutput + ((COM_RandomLong( 0, 255 ) * dly->delaysamples ) >> 9 );
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
dly->xfade = 128;
}
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
dly->idelayoutputxf %= dly->cdelaysamplesmax;
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
// modify delay, if crossfading
if( dly->xfade )
{
samplexf = dly->lpdelayline[dly->idelayoutputxf] * (128 - dly->xfade) >> 7;
delay = samplexf + ((delay * dly->xfade) >> 7);
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
if( ++dly->idelayoutputxf >= dly->cdelaysamplesmax )
dly->idelayoutputxf = 0;
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
if( --dly->xfade == 0 )
dly->idelayoutput = dly->idelayoutputxf;
}
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
// save left value to delay line
2016-12-12 22:00:00 +01:00
dly->lpdelayline[dly->idelayinput] = CLIP( paint->left );
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
// paint new delay value
2016-12-12 22:00:00 +01:00
paint->left = delay;
2016-08-12 23:00:00 +02:00
}
else
{
// clear delay line
dly->lpdelayline[dly->idelayinput] = 0;
}
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
DLY_MovePointer( dly );
2011-03-15 22:00:00 +01:00
}
}
2016-08-12 23:00:00 +02:00
/*
=============
DLY_CheckNewDelayVal
Update delay processor settings if we are in new room
=============
*/
void DLY_CheckNewDelayVal( void )
2011-03-15 22:00:00 +01:00
{
2016-08-12 23:00:00 +02:00
float delay = sxdly_delay->value;
dly_t *const dly = &rgsxdly[MONODLY];
2011-03-15 22:00:00 +01:00
2017-02-12 22:00:00 +01:00
if( FBitSet( sxdly_delay->flags, FCVAR_CHANGED ))
2016-08-12 23:00:00 +02:00
{
if( delay == 0 )
{
DLY_Free( MONODLY );
}
else
2011-03-15 22:00:00 +01:00
{
2016-08-12 23:00:00 +02:00
delay = min( delay, MAX_MONO_DELAY );
2016-12-12 22:00:00 +01:00
dly->delaysamples = (int)(delay * idsp_dma_speed) << sxhires;
2016-08-12 23:00:00 +02:00
// init dly
if( !dly->lpdelayline )
DLY_Init( MONODLY, MAX_MONO_DELAY );
if( dly->lpdelayline )
2011-03-15 22:00:00 +01:00
{
2016-11-17 22:00:00 +01:00
memset( dly->lpdelayline, 0, dly->cdelaysamplesmax * sizeof( int ) );
2016-08-12 23:00:00 +02:00
dly->lp0 = dly->lp1 = dly->lp2 = 0;
2011-03-15 22:00:00 +01:00
}
2016-08-12 23:00:00 +02:00
dly->idelayinput = 0;
dly->idelayoutput = dly->cdelaysamplesmax - dly->delaysamples;
if( !dly->delaysamples )
DLY_Free( MONODLY );
2011-03-15 22:00:00 +01:00
}
}
2017-02-12 22:00:00 +01:00
ClearBits( sxdly_delay->flags, FCVAR_CHANGED );
dly->lp = sxdly_lp->value;
2016-08-12 23:00:00 +02:00
dly->delayfeedback = 255 * sxdly_feedback->value;
2011-03-15 22:00:00 +01:00
}
2016-08-12 23:00:00 +02:00
/*
=============
DLY_DoDelay
Do delay processing
=============
*/
void DLY_DoDelay( int count )
2011-03-15 22:00:00 +01:00
{
2016-08-12 23:00:00 +02:00
dly_t *const dly = &rgsxdly[MONODLY];
portable_samplepair_t *paint = paintto;
int delay;
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
if( !dly->lpdelayline || !count )
return; // inactive
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
for( ; count; count--, paint++ )
{
delay = dly->lpdelayline[dly->idelayoutput];
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
// don't process if delay line and left/right samples are zero
if( delay || paint->left || paint->right )
{
// calculate delayed value from average
2016-12-12 22:00:00 +01:00
int val = (( paint->left + paint->right ) >> 1 ) + (( dly->delayfeedback * delay ) >> 8);
2016-08-12 23:00:00 +02:00
val = CLIP( val );
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
if( dly->lp ) // lowpass
{
dly->lp0 = dly->lp1;
dly->lp1 = val;
val = ( dly->lp0 + dly->lp1 + (val << 1) ) >> 2;
}
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
dly->lpdelayline[dly->idelayinput] = val;
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
val >>= 2;
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
paint->left = CLIP( paint->left + val );
paint->right = CLIP( paint->right + val );
}
else
2011-03-15 22:00:00 +01:00
{
2016-08-12 23:00:00 +02:00
dly->lpdelayline[dly->idelayinput] = 0;
dly->lp0 = dly->lp1 = 0;
2011-03-15 22:00:00 +01:00
}
2016-08-12 23:00:00 +02:00
DLY_MovePointer( dly );
2011-03-15 22:00:00 +01:00
}
2016-08-12 23:00:00 +02:00
}
/*
===========
RVB_SetUpDly
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
Set up dly for reverb
===========
*/
void RVB_SetUpDly( int pos, float delay, int kmod )
{
int samples;
2011-03-15 22:00:00 +01:00
2016-12-12 22:00:00 +01:00
delay = Q_min( delay, MAX_REVERB_DELAY );
samples = (int)(delay * idsp_dma_speed) << sxhires;
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
if( !rgsxdly[pos].lpdelayline )
2011-03-15 22:00:00 +01:00
{
2016-08-12 23:00:00 +02:00
rgsxdly[pos].delaysamples = samples;
DLY_Init( pos, MAX_REVERB_DELAY );
2010-09-16 22:00:00 +02:00
}
2011-03-15 22:00:00 +01:00
2016-12-12 22:00:00 +01:00
rgsxdly[pos].modcur = rgsxdly[pos].mod = (int)(kmod * idsp_dma_speed / SOUND_11k) << sxhires;
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
// set up crossfade, if delay has changed
if( rgsxdly[pos].delaysamples != samples )
2010-09-16 22:00:00 +02:00
{
2016-08-12 23:00:00 +02:00
rgsxdly[pos].idelayoutputxf = rgsxdly[pos].idelayinput - samples;
if( rgsxdly[pos].idelayoutputxf < 0 )
rgsxdly[pos].idelayoutputxf += rgsxdly[pos].cdelaysamplesmax;
rgsxdly[pos].xfade = 32;
2009-10-10 22:00:00 +02:00
}
2016-08-12 23:00:00 +02:00
if( !rgsxdly[pos].delaysamples )
DLY_Free( pos );
2011-03-15 22:00:00 +01:00
}
2016-08-12 23:00:00 +02:00
/*
===========
RVB_CheckNewReverbVal
Update reverb settings if we are in new room
===========
*/
void RVB_CheckNewReverbVal( void )
2011-03-15 22:00:00 +01:00
{
2016-08-12 23:00:00 +02:00
dly_t *const dly1 = &rgsxdly[REVERBPOS];
dly_t *const dly2 = &rgsxdly[REVERBPOS + 1];
float delay = sxrvb_size->value;
2011-03-15 22:00:00 +01:00
2017-02-12 22:00:00 +01:00
if( FBitSet( sxrvb_size->flags, FCVAR_CHANGED ))
2011-03-15 22:00:00 +01:00
{
2016-08-12 23:00:00 +02:00
if( delay == 0.0f )
2011-03-15 22:00:00 +01:00
{
2016-08-12 23:00:00 +02:00
DLY_Free( REVERBPOS );
DLY_Free( REVERBPOS + 1 );
2011-03-15 22:00:00 +01:00
}
else
{
2016-08-12 23:00:00 +02:00
RVB_SetUpDly( REVERBPOS, sxrvb_size->value, 500 );
RVB_SetUpDly( REVERBPOS+1, sxrvb_size->value * 0.71f, 700 );
2011-03-15 22:00:00 +01:00
}
}
2017-02-12 22:00:00 +01:00
ClearBits( sxrvb_size->flags, FCVAR_CHANGED );
dly1->lp = dly2->lp = sxrvb_lp->value;
2016-08-12 23:00:00 +02:00
dly1->delayfeedback = dly2->delayfeedback = (int)(255 * sxrvb_feedback->value);
2011-03-15 22:00:00 +01:00
}
2016-08-12 23:00:00 +02:00
/*
===========
RVB_DoReverbForOneDly
Do reverberation for one dly
===========
*/
int RVB_DoReverbForOneDly( dly_t *dly, const int vlr, const portable_samplepair_t *samplepair )
2011-03-15 22:00:00 +01:00
{
2016-08-12 23:00:00 +02:00
int delay;
int samplexf;
int val, valt;
int voutm = 0;
if( --dly->modcur < 0 )
dly->modcur = dly->mod;
delay = dly->lpdelayline[dly->idelayoutput];
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
if( dly->xfade || delay || samplepair->left || samplepair->right )
2011-03-15 22:00:00 +01:00
{
2016-08-12 23:00:00 +02:00
// modulate delay rate
2018-09-20 23:00:00 +02:00
if( !dly->xfade && !dly->modcur && dly->mod )
2016-12-12 22:00:00 +01:00
{
2017-02-21 22:00:00 +01:00
dly->idelayoutputxf = dly->idelayoutput + ((COM_RandomLong( 0, 255 ) * delay) >> 9 );
2011-03-15 22:00:00 +01:00
2018-09-20 23:00:00 +02:00
//dly->xfade = 32;
2016-12-12 22:00:00 +01:00
}
2016-08-12 23:00:00 +02:00
2018-09-20 23:00:00 +02:00
dly->idelayoutputxf %= dly->cdelaysamplesmax;
2016-08-12 23:00:00 +02:00
if( dly->xfade )
2011-03-15 22:00:00 +01:00
{
2016-12-12 22:00:00 +01:00
samplexf = (dly->lpdelayline[dly->idelayoutputxf] * (REVERB_XFADE - dly->xfade)) / REVERB_XFADE;
delay = ((delay * dly->xfade) / REVERB_XFADE) + samplexf;
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
if( ++dly->idelayoutputxf >= dly->cdelaysamplesmax )
dly->idelayoutputxf = 0;
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
if( --dly->xfade == 0 )
dly->idelayoutput = dly->idelayoutputxf;
2011-03-15 22:00:00 +01:00
}
2016-12-12 22:00:00 +01:00
if( delay )
{
val = vlr + ( ( dly->delayfeedback * delay ) >> 8 );
val = CLIP( val );
}
else
val = vlr;
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
if( dly->lp )
2011-03-15 22:00:00 +01:00
{
2016-08-12 23:00:00 +02:00
valt = (dly->lp0 + val) >> 1;
dly->lp0 = val;
2011-03-15 22:00:00 +01:00
}
2016-12-12 22:00:00 +01:00
else
valt = val;
2016-08-12 23:00:00 +02:00
voutm = dly->lpdelayline[dly->idelayinput] = valt;
}
else
{
voutm = dly->lpdelayline[dly->idelayinput] = 0;
2016-12-12 22:00:00 +01:00
dly->lp0 = 0;
2011-03-15 22:00:00 +01:00
}
2016-08-12 23:00:00 +02:00
DLY_MovePointer( dly );
return voutm;
2011-03-15 22:00:00 +01:00
}
2016-08-12 23:00:00 +02:00
/*
===========
RVB_DoReverb
Do reverberation processing
===========
*/
void RVB_DoReverb( int count )
2011-03-15 22:00:00 +01:00
{
2016-08-12 23:00:00 +02:00
dly_t *const dly1 = &rgsxdly[REVERBPOS];
dly_t *const dly2 = &rgsxdly[REVERBPOS+1];
portable_samplepair_t *paint = paintto;
int vlr, voutm;
2011-03-15 22:00:00 +01:00
2016-12-12 22:00:00 +01:00
if( !dly1->lpdelayline )
2016-08-12 23:00:00 +02:00
return;
for( ; count; count--, paint++ )
{
vlr = ( paint->left + paint->right ) >> 1;
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
voutm = RVB_DoReverbForOneDly( dly1, vlr, paint );
voutm += RVB_DoReverbForOneDly( dly2, vlr, paint );
2011-03-15 22:00:00 +01:00
2016-12-12 22:00:00 +01:00
voutm = (11 * voutm) >> 6;
2016-08-12 23:00:00 +02:00
2016-12-12 22:00:00 +01:00
paint->left = CLIP( paint->left + voutm );
paint->right = CLIP( paint->right + voutm );
2016-08-12 23:00:00 +02:00
}
2011-03-15 22:00:00 +01:00
}
2016-08-12 23:00:00 +02:00
/*
===========
RVB_DoAMod
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
Do amplification modulation processing
===========
*/
void RVB_DoAMod( int count )
2011-03-15 22:00:00 +01:00
{
2016-08-12 23:00:00 +02:00
portable_samplepair_t *paint = paintto;
2011-03-15 22:00:00 +01:00
2017-02-12 22:00:00 +01:00
if( !sxmod_lowpass->value && !sxmod_mod->value )
2011-03-15 22:00:00 +01:00
return;
2016-08-12 23:00:00 +02:00
for( ; count; count--, paint++ )
{
portable_samplepair_t res = *paint;
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
if( sxmod_lowpass->value )
{
res.left = rgsxlp[0] + rgsxlp[1] + rgsxlp[2] + rgsxlp[3] + rgsxlp[4] + res.left;
res.right = rgsxlp[5] + rgsxlp[6] + rgsxlp[7] + rgsxlp[8] + rgsxlp[9] + res.right;
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
res.left >>= 2;
res.right >>= 2;
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
rgsxlp[0] = rgsxlp[1];
rgsxlp[1] = rgsxlp[2];
rgsxlp[2] = rgsxlp[3];
rgsxlp[3] = rgsxlp[4];
rgsxlp[4] = paint->left;
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
rgsxlp[5] = rgsxlp[6];
rgsxlp[6] = rgsxlp[7];
rgsxlp[7] = rgsxlp[8];
rgsxlp[8] = rgsxlp[9];
rgsxlp[9] = paint->right;
}
2017-02-12 22:00:00 +01:00
if( sxmod_mod->value )
2016-08-12 23:00:00 +02:00
{
if( --sxmod1cur < 0 )
sxmod1cur = sxmod1;
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
if( !sxmod1 )
2017-02-21 22:00:00 +01:00
sxamodlt = COM_RandomLong( 32, 255 );
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
if( --sxmod2cur < 0 )
sxmod2cur = sxmod2;
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
if( !sxmod2 )
2017-02-21 22:00:00 +01:00
sxamodrt = COM_RandomLong( 32, 255 );
2016-08-12 23:00:00 +02:00
res.left = (sxamodl * res.left) >> 8;
res.right = (sxamodr * res.right) >> 8;
if( sxamodl < sxamodlt )
sxamodl++;
else if( sxamodl > sxamodlt )
sxamodl--;
if( sxamodr < sxamodrt )
sxamodr++;
else if( sxamodr > sxamodrt )
sxamodr--;
}
paint->left = CLIP(res.left);
paint->right = CLIP(res.right);
2011-03-15 22:00:00 +01:00
}
2016-08-12 23:00:00 +02:00
}
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
/*
===========
DSP_Process
(xash dsp interface)
===========
*/
void DSP_Process( int idsp, portable_samplepair_t *pbfront, int sampleCount )
{
2017-02-12 22:00:00 +01:00
if( dsp_off->value )
2011-03-15 22:00:00 +01:00
return;
2016-08-12 23:00:00 +02:00
2018-03-13 22:00:00 +01:00
// don't process DSP while in menu
2016-12-12 22:00:00 +01:00
if( cls.key_dest == key_menu || !sampleCount )
2016-08-12 23:00:00 +02:00
return;
// preset is already installed by CheckNewDspPresets
paintto = pbfront;
RVB_DoAMod( sampleCount );
RVB_DoReverb( sampleCount );
DLY_DoDelay( sampleCount );
DLY_DoStereoDelay( sampleCount );
2011-03-15 22:00:00 +01:00
}
2016-08-12 23:00:00 +02:00
/*
===========
DSP_ClearState
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
(xash dsp interface)
===========
*/
void DSP_ClearState( void )
2011-03-15 22:00:00 +01:00
{
2017-02-12 22:00:00 +01:00
Cvar_SetValue( "room_type", 0.0f );
2016-08-12 23:00:00 +02:00
SX_ReloadRoomFX();
2011-03-15 22:00:00 +01:00
}
2009-10-10 22:00:00 +02:00
2016-08-12 23:00:00 +02:00
/*
===========
CheckNewDspPresets
(xash dsp interface)
===========
*/
void CheckNewDspPresets( void )
{
if( dsp_off->value != 0.0f )
return;
2011-01-06 22:00:00 +01:00
2016-08-13 23:00:00 +02:00
if( s_listener.waterlevel > 2 )
2016-08-12 23:00:00 +02:00
idsp_room = roomwater_type->value;
else idsp_room = room_type->value;
2009-10-10 22:00:00 +02:00
2018-09-20 23:00:00 +02:00
// don't pass invalid presets
idsp_room = bound( 0, idsp_room, MAXPRESETS - 1 );
2017-02-12 22:00:00 +01:00
if( FBitSet( hisound->flags, FCVAR_CHANGED ))
2016-12-12 22:00:00 +01:00
{
2017-02-12 22:00:00 +01:00
sxhires = hisound->value;
ClearBits( hisound->flags, FCVAR_CHANGED );
2016-12-12 22:00:00 +01:00
}
2016-08-12 23:00:00 +02:00
if( idsp_room == room_typeprev && idsp_room == 0 )
return;
2009-10-10 22:00:00 +02:00
2016-08-12 23:00:00 +02:00
if( idsp_room > MAX_ROOM_TYPES )
return;
2009-10-10 22:00:00 +02:00
2016-08-12 23:00:00 +02:00
if( idsp_room != room_typeprev )
2010-09-16 22:00:00 +02:00
{
2016-08-12 23:00:00 +02:00
const sx_preset_t *cur = rgsxpre + idsp_room;
2009-10-10 22:00:00 +02:00
2017-02-12 22:00:00 +01:00
Cvar_SetValue( "room_lp", cur->room_lp );
Cvar_SetValue( "room_mod", cur->room_mod );
Cvar_SetValue( "room_size", cur->room_size );
Cvar_SetValue( "room_refl", cur->room_refl );
Cvar_SetValue( "room_rvblp", cur->room_rvblp );
Cvar_SetValue( "room_delay", cur->room_delay );
Cvar_SetValue( "room_feedback", cur->room_feedback );
Cvar_SetValue( "room_dlylp", cur->room_dlylp );
Cvar_SetValue( "room_left", cur->room_left );
2010-09-16 22:00:00 +02:00
}
2016-08-12 23:00:00 +02:00
room_typeprev = idsp_room;
RVB_CheckNewReverbVal( );
DLY_CheckNewDelayVal( );
DLY_CheckNewStereoDelayVal();
2010-09-16 22:00:00 +02:00
}
2009-10-10 22:00:00 +02:00
2016-08-12 23:00:00 +02:00
/*
===========
DSP_GetGain
2011-03-15 22:00:00 +01:00
2016-08-12 23:00:00 +02:00
(xash dsp interface)
===========
*/
float DSP_GetGain( int idsp )
2009-10-10 22:00:00 +02:00
{
2016-08-12 23:00:00 +02:00
return 1.0f;
}
2009-10-10 22:00:00 +02:00
2016-08-12 23:00:00 +02:00
void SX_Profiling_f( void )
{
portable_samplepair_t testbuffer[512];
float oldroom = room_type->value;
2018-03-03 22:00:00 +01:00
double start, end;
int i, calls;
2012-08-07 22:00:00 +02:00
2016-08-12 23:00:00 +02:00
for( i = 0; i < 512; i++ )
{
2017-02-21 22:00:00 +01:00
testbuffer[i].left = COM_RandomLong( 0, 3000 );
testbuffer[i].right = COM_RandomLong( 0, 3000 );
2016-08-12 23:00:00 +02:00
}
2009-10-10 22:00:00 +02:00
2016-08-12 23:00:00 +02:00
if( Cmd_Argc() > 1 )
2009-10-10 22:00:00 +02:00
{
2017-02-12 22:00:00 +01:00
Cvar_SetValue( "room_type", Q_atof( Cmd_Argv( 1 )));
2016-08-12 23:00:00 +02:00
SX_ReloadRoomFX();
CheckNewDspPresets(); // we just need idsp_room immediately, for message below
2009-10-10 22:00:00 +02:00
}
2018-03-03 22:00:00 +01:00
Con_Printf( "Profiling 10000 calls to DSP. Sample count is 512, room_type is %i\n", idsp_room );
2016-08-12 23:00:00 +02:00
start = Sys_DoubleTime();
2018-03-03 22:00:00 +01:00
for( calls = 10000; calls; calls-- )
2009-10-10 22:00:00 +02:00
{
2016-08-12 23:00:00 +02:00
DSP_Process( idsp_room, testbuffer, 512 );
}
end = Sys_DoubleTime();
2009-10-10 22:00:00 +02:00
2018-03-03 22:00:00 +01:00
Con_Printf( "----------\nTook %g seconds.\n", end - start );
2016-08-12 23:00:00 +02:00
if( Cmd_Argc() > 1 )
{
2017-02-12 22:00:00 +01:00
Cvar_SetValue( "room_type", oldroom );
2016-08-12 23:00:00 +02:00
SX_ReloadRoomFX();
CheckNewDspPresets();
2010-09-16 22:00:00 +02:00
}
2009-10-10 22:00:00 +02:00
}