- Revised underwater effect now uses a lowpass filter in combination with an

optional freeverb unit.
- Removed ResetEnvironment hack, since with software reverb, losing the
  existing reverb when focus is lost isn't a problem.
- Commented out the TiMidity FIXME messages.


SVN r973 (trunk)
This commit is contained in:
Randy Heit 2008-05-15 04:51:57 +00:00
parent ff4446a3a0
commit 5a066788b5
8 changed files with 139 additions and 31 deletions

View file

@ -1,4 +1,9 @@
May 14, 2008
- Revised underwater effect now uses a lowpass filter in combination with an
optional freeverb unit.
- Removed ResetEnvironment hack, since with software reverb, losing the
existing reverb when focus is lost isn't a problem.
- Commented out the TiMidity FIXME messages.
- Fixed: FBarShader::GetColumn() passed incorrect information to the software
renderer for horizontal bars.

View file

@ -1142,6 +1142,7 @@ EXTERN_CVAR (Int, snd_buffercount)
EXTERN_CVAR (Int, snd_samplerate)
EXTERN_CVAR (Bool, snd_hrtf)
EXTERN_CVAR (Bool, snd_waterreverb)
EXTERN_CVAR (Float, snd_waterlp)
EXTERN_CVAR (Int, snd_mididevice)
static void MakeSoundChanges ();
@ -1243,6 +1244,7 @@ static menuitem_t SoundItems[] =
{ discrete, "MIDI device", {&snd_mididevice}, {0.0}, {0.0}, {0.0}, {NULL} },
{ redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} },
{ discrete, "Underwater reverb", {&snd_waterreverb}, {2.0}, {0.0}, {0.0}, {OnOff} },
{ slider, "Underwater cutoff", {&snd_waterlp}, {0.0}, {2000.0},{50.0}, {NULL} },
{ discrete, "Randomize pitches", {&snd_pitched}, {2.0}, {0.0}, {0.0}, {OnOff} },
{ redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} },
{ more, "Restart sound", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)MakeSoundChanges} },

View file

@ -119,6 +119,20 @@ CVAR (String, snd_output_format, "PCM-16", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (String, snd_midipatchset, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Bool, snd_profile, false, 0)
// Underwater low-pass filter cutoff frequency. Set to 0 to disable the filter.
CUSTOM_CVAR (Float, snd_waterlp, 250, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
{
// Clamp to the DSP unit's limits.
if (*self < 10 && *self != 0)
{
self = 10;
}
else if (*self > 22000)
{
self = 22000;
}
}
// PRIVATE DATA DEFINITIONS ------------------------------------------------
static const ReverbContainer *PrevEnvironment;
@ -569,6 +583,9 @@ bool FMODSoundRenderer::Init()
MusicGroup = NULL;
SfxGroup = NULL;
PausableSfx = NULL;
SfxConnection = NULL;
WaterLP = NULL;
WaterReverb = NULL;
PrevEnvironment = DefaultEnvironments[0];
DSPClockLo = 0;
DSPClockHi = 0;
@ -830,9 +847,55 @@ bool FMODSoundRenderer::Init()
result = SfxGroup->addGroup(PausableSfx);
if (result != FMOD_OK)
{
Printf(TEXTCOLOR_BLUE" Could not create attach pausable sfx to sfx channel group. (Error %d)\n", result);
Printf(TEXTCOLOR_BLUE" Could not attach pausable sfx to sfx channel group. (Error %d)\n", result);
}
// Create DSP units for underwater effect
result = Sys->createDSPByType(FMOD_DSP_TYPE_LOWPASS, &WaterLP);
if (result != FMOD_OK)
{
Printf(TEXTCOLOR_BLUE" Could not create underwater lowpass unit. (Error %d)\n", result);
}
else
{
result = Sys->createDSPByType(FMOD_DSP_TYPE_REVERB, &WaterReverb);
if (result != FMOD_OK)
{
Printf(TEXTCOLOR_BLUE" Could not create underwater reverb unit. (Error %d)\n", result);
}
}
// Connect underwater DSP unit between PausableSFX and SFX groups, while
// retaining the connection established by SfxGroup->addGroup().
if (WaterLP != NULL)
{
FMOD::DSP *sfx_head, *pausable_head;
result = SfxGroup->getDSPHead(&sfx_head);
result = sfx_head->getInput(0, &pausable_head, &SfxConnection);
result = WaterLP->addInput(pausable_head, NULL);
WaterLP->setActive(false);
WaterLP->setParameter(FMOD_DSP_LOWPASS_CUTOFF, snd_waterlp);
WaterLP->setParameter(FMOD_DSP_LOWPASS_RESONANCE, 2);
if (WaterReverb != NULL)
{
FMOD::DSPConnection *dry;
result = WaterReverb->addInput(pausable_head, &dry);
result = dry->setMix(0.1f);
result = WaterReverb->addInput(WaterLP, NULL);
result = sfx_head->addInput(WaterReverb, NULL);
WaterReverb->setParameter(FMOD_DSP_REVERB_ROOMSIZE, 0.001f);
WaterReverb->setParameter(FMOD_DSP_REVERB_DAMP, 0.2f);
WaterReverb->setActive(false);
}
else
{
result = sfx_head->addInput(WaterLP, NULL);
}
}
LastWaterLP = snd_waterlp;
result = SPC_CreateCodec(Sys);
if (result != FMOD_OK)
{
@ -878,6 +941,16 @@ void FMODSoundRenderer::Shutdown()
SfxGroup->release();
SfxGroup = NULL;
}
if (WaterLP != NULL)
{
WaterLP->release();
WaterLP = NULL;
}
if (WaterReverb != NULL)
{
WaterReverb->release();
WaterReverb = NULL;
}
// Free all loaded samples
for (i = 0; i < S_sfx.Size(); i++)
@ -1490,17 +1563,6 @@ void FMODSoundRenderer::UpdateSoundParams3D(FSoundChan *chan, float pos[3], floa
fchan->set3DAttributes((FMOD_VECTOR *)pos, (FMOD_VECTOR *)vel);
}
//==========================================================================
//
// FMODSoundRenderer :: ResetEnvironment
//
//==========================================================================
void FMODSoundRenderer::ResetEnvironment()
{
PrevEnvironment = NULL;
}
//==========================================================================
//
// FMODSoundRenderer :: UpdateListener
@ -1549,26 +1611,72 @@ void FMODSoundRenderer::UpdateListener()
}
else
{
underwater = (listener->waterlevel == 3 && snd_waterreverb);
underwater = (listener->waterlevel == 3 && snd_waterlp);
assert (zones != NULL);
env = zones[listener->Sector->ZoneNumber].Environment;
if (env == NULL)
{
env = DefaultEnvironments[0];
}
if (env == DefaultEnvironments[0] && underwater)
/* if (env == DefaultEnvironments[0] && underwater)
{
env = DefaultEnvironments[22];
}
*/
}
if (env != PrevEnvironment || env->Modified)
{
DPrintf ("Reverb Environment %s\n", env->Name);
const_cast<ReverbContainer*>(env)->Modified = false;
Sys->setReverbProperties((FMOD_REVERB_PROPERTIES *)(&env->Properties));
PausableSfx->setPitch(underwater ? 0.64171f : 1);
PrevEnvironment = env;
}
if (underwater)
{
//PausableSfx->setPitch(0.64171f); // This appears to be what Duke 3D uses
PausableSfx->setPitch(0.7937005f); // Approx. 4 semitones lower; what Nash suggesetd
if (WaterLP != NULL)
{
if (LastWaterLP != snd_waterlp)
{
LastWaterLP = snd_waterlp;
WaterLP->setParameter(FMOD_DSP_LOWPASS_CUTOFF, snd_waterlp);
}
WaterLP->setActive(true);
if (WaterReverb != NULL && snd_waterreverb)
{
WaterReverb->setActive(true);
WaterReverb->setBypass(false);
SfxConnection->setMix(0);
}
else
{
// Let some of the original mix through so that high frequencies are
// not completely lost. The reverb unit has its own connection and
// preserves dry sounds itself if used.
SfxConnection->setMix(0.1f);
if (WaterReverb != NULL)
{
WaterReverb->setActive(true);
WaterReverb->setBypass(true);
}
}
}
}
else
{
PausableSfx->setPitch(1);
if (WaterLP != NULL)
{
SfxConnection->setMix(1);
WaterLP->setActive(false);
if (WaterReverb != NULL)
{
WaterReverb->setActive(false);
}
}
}
}
//==========================================================================

View file

@ -47,7 +47,6 @@ public:
void PrintStatus ();
void PrintDriversList ();
FString GatherStats ();
void ResetEnvironment ();
void DrawWaveDebug(int mode);
@ -85,6 +84,9 @@ private:
FMOD::System *Sys;
FMOD::ChannelGroup *SfxGroup, *PausableSfx;
FMOD::ChannelGroup *MusicGroup;
FMOD::DSP *WaterLP, *WaterReverb;
FMOD::DSPConnection *SfxConnection;
float LastWaterLP;
// Just for snd_status display
int Driver_MinFrequency;

View file

@ -208,10 +208,6 @@ void SoundRenderer::DrawWaveDebug(int mode)
{
}
void SoundRenderer::ResetEnvironment ()
{
}
SoundStream::~SoundStream ()
{
}

View file

@ -106,7 +106,6 @@ public:
virtual void PrintStatus () = 0;
virtual void PrintDriversList () = 0;
virtual FString GatherStats ();
virtual void ResetEnvironment ();
virtual void DrawWaveDebug(int mode);
};

View file

@ -138,7 +138,7 @@ static int read_config_file(const char *name, bool ismain)
* before TiMidity kills the note. This may be useful to implement
* later, but I don't see any urgent need for it.
*/
Printf("FIXME: Implement \"timeout\" in TiMidity config.\n");
//Printf("FIXME: Implement \"timeout\" in TiMidity config.\n");
}
else if (!strcmp(w[0], "copydrumset") /* "copydrumset" drumset */
|| !strcmp(w[0], "copybank")) /* "copybank" bank */
@ -148,7 +148,7 @@ static int read_config_file(const char *name, bool ismain)
* the current drumset or bank. May be useful later, but not a
* high priority.
*/
Printf("FIXME: Implement \"%s\" in TiMidity config.\n", w[0]);
//Printf("FIXME: Implement \"%s\" in TiMidity config.\n", w[0]);
}
else if (!strcmp(w[0], "undef")) /* "undef" progno */
{
@ -156,7 +156,7 @@ static int read_config_file(const char *name, bool ismain)
* Undefines the tone "progno" of the current tone bank (or
* drum set?). Not a high priority.
*/
Printf("FIXME: Implement \"undef\" in TiMidity config.\n");
//Printf("FIXME: Implement \"undef\" in TiMidity config.\n");
}
else if (!strcmp(w[0], "altassign")) /* "altassign" prog1 prog2 ... */
{
@ -164,7 +164,7 @@ static int read_config_file(const char *name, bool ismain)
* Sets the alternate assign for drum set. Whatever that's
* supposed to mean.
*/
Printf("FIXME: Implement \"altassign\" in TiMidity config.\n");
//Printf("FIXME: Implement \"altassign\" in TiMidity config.\n");
}
else if (!strcmp(w[0], "soundfont"))
{
@ -261,7 +261,7 @@ static int read_config_file(const char *name, bool ismain)
* apparently it sets some sort of base offset for tone numbers.
* Why anyone would want to do this is beyond me.
*/
Printf("FIXME: Implement \"progbase\" in TiMidity config.\n");
//Printf("FIXME: Implement \"progbase\" in TiMidity config.\n");
}
else if (!strcmp(w[0], "map")) /* "map" name set1 elem1 set2 elem2 */
{
@ -271,7 +271,7 @@ static int read_config_file(const char *name, bool ismain)
* documentation whatsoever for it, but it looks like it's used
* for remapping one instrument to another somehow.
*/
Printf("FIXME: Implement \"map\" in TiMidity config.\n");
//Printf("FIXME: Implement \"map\" in TiMidity config.\n");
}
/* Standard TiMidity config */

View file

@ -737,10 +737,6 @@ LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
if (wParam)
{
SetPriorityClass (GetCurrentProcess (), INGAME_PRIORITY_CLASS);
if (GSnd != NULL)
{
GSnd->ResetEnvironment();
}
}
else if (!noidle && !netgame)
{