diff --git a/docs/rh-log.txt b/docs/rh-log.txt index ec728202a8..1856eee6e3 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -4,6 +4,11 @@ version and removed old compatibility handlings. February 25, 2009 +- The SFX Reverb unit is now moved so that it serves as an input to the water + effect rather than as an input to the ChannelGroup Target Unit. This means + the water effect is now applied after any room reverb, rather than in + parallel with it. +- Fixed: UI sounds should not have reverb applied to them. - Removed the delay for starting all sounds from one tic at exactly the same DSP position. Without also synchronizing the stopping of sounds, it can cause problems with things like the chainsaw where the sound is stopped and diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 20b7cafc60..157a029923 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -1032,6 +1032,7 @@ static FSoundChan *S_StartSound(AActor *actor, const sector_t *sec, const FPolyO if (chanflags & CHAN_LOOP) startflags |= SNDF_LOOP; if (chanflags & CHAN_AREA) startflags |= SNDF_AREA; if (chanflags & (CHAN_UI|CHAN_NOPAUSE)) startflags |= SNDF_NOPAUSE; + if (chanflags & CHAN_UI) startflags |= SNDF_NOREVERB; if (attenuation > 0) { diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index 8689eac4f0..1a50ac2500 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -610,6 +610,8 @@ bool FMODSoundRenderer::Init() PrevEnvironment = DefaultEnvironments[0]; DSPClock.AsOne = 0; ChannelGroupTargetUnit = NULL; + SfxReverbHooked = false; + SfxReverbPlaceholder = NULL; Printf("I_InitSound: Initializing FMOD\n"); @@ -908,6 +910,35 @@ bool FMODSoundRenderer::Init() result = sfx_head->getInput(0, &pausable_head, &SfxConnection); if (result == FMOD_OK) { + // The placeholder mixer is for reference to where to connect the SFX + // reverb unit once it gets created. + result = Sys->createDSPByType(FMOD_DSP_TYPE_MIXER, &SfxReverbPlaceholder); + if (result == FMOD_OK) + { + // Replace the PausableSFX->SFX connection with + // PausableSFX->ReverbPlaceholder->SFX. + result = SfxReverbPlaceholder->addInput(pausable_head, NULL); + if (result == FMOD_OK) + { + FMOD::DSPConnection *connection; + result = sfx_head->addInput(SfxReverbPlaceholder, &connection); + if (result == FMOD_OK) + { + sfx_head->disconnectFrom(pausable_head); + SfxReverbPlaceholder->setActive(true); + SfxReverbPlaceholder->setBypass(true); + // The placeholder now takes the place of the pausable_head + // for the following connections. + pausable_head = SfxReverbPlaceholder; + SfxConnection = connection; + } + } + else + { + SfxReverbPlaceholder->release(); + SfxReverbPlaceholder = NULL; + } + } result = WaterLP->addInput(pausable_head, NULL); WaterLP->setActive(false); WaterLP->setParameter(FMOD_DSP_LOWPASS_CUTOFF, snd_waterlp); @@ -1018,6 +1049,11 @@ void FMODSoundRenderer::Shutdown() WaterReverb->release(); WaterReverb = NULL; } + if (SfxReverbPlaceholder != NULL) + { + SfxReverbPlaceholder->release(); + SfxReverbPlaceholder = NULL; + } Sys->close(); Sys->release(); @@ -1389,6 +1425,15 @@ FISoundChannel *FMODSoundRenderer::StartSound(SoundHandle sfx, float vol, int pi chan->stop(); return NULL; } + if (flags & SNDF_NOREVERB) + { + FMOD_REVERB_CHANNELPROPERTIES reverb = { 0, }; + if (FMOD_OK == chan->getReverbProperties(&reverb)) + { + reverb.Room = -10000; + chan->setReverbProperties(&reverb); + } + } chan->setPaused(false); return CommonChannelSetup(chan, reuse_chan); } @@ -1487,6 +1532,15 @@ FISoundChannel *FMODSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener * chan->stop(); return NULL; } + if (flags & SNDF_NOREVERB) + { + FMOD_REVERB_CHANNELPROPERTIES reverb = { 0, }; + if (FMOD_OK == chan->getReverbProperties(&reverb)) + { + reverb.Room = -10000; + chan->setReverbProperties(&reverb); + } + } chan->setPaused(false); chan->getPriority(&def_priority); FISoundChannel *schan = CommonChannelSetup(chan, reuse_chan); @@ -1784,13 +1838,13 @@ void FMODSoundRenderer::UpdateListener(SoundListener *listener) bool underwater = false; const ReverbContainer *env; + underwater = (listener->underwater && snd_waterlp); if (ForcedEnvironment) { env = ForcedEnvironment; } else { - underwater = (listener->underwater && snd_waterlp); env = listener->Environment; if (env == NULL) { @@ -1803,6 +1857,11 @@ void FMODSoundRenderer::UpdateListener(SoundListener *listener) const_cast(env)->Modified = false; Sys->setReverbProperties((FMOD_REVERB_PROPERTIES *)(&env->Properties)); PrevEnvironment = env; + + if (!SfxReverbHooked) + { + SfxReverbHooked = ReconnectSFXReverbUnit(); + } } if (underwater || env->SoftwareWater) @@ -1852,6 +1911,65 @@ void FMODSoundRenderer::UpdateListener(SoundListener *listener) } } +//========================================================================== +// +// FMODSoundRenderer :: ReconnectSFXReverbUnit +// +// Locates the DSP unit responsible for software 3D reverb. There is only +// one, and it by default is connected directly to the ChannelGroup Target +// Unit. Older versions of FMOD created this at startup; newer versions +// delay creating it until the first call to setReverbProperties, at which +// point it persists until the system is closed. +// +// Upon locating the proper DSP unit, reconnects it to serve as an input to +// our water DSP chain after the Pausable SFX ChannelGroup. +// +//========================================================================== + +bool FMODSoundRenderer::ReconnectSFXReverbUnit() +{ + FMOD::DSP *unit; + FMOD_DSP_TYPE type; + int numinputs, i; + + if (ChannelGroupTargetUnit == NULL || SfxReverbPlaceholder == NULL) + { + return false; + } + // Look for SFX Reverb unit + if (FMOD_OK != ChannelGroupTargetUnit->getNumInputs(&numinputs)) + { + return false; + } + for (i = numinputs - 1; i >= 0; --i) + { + if (FMOD_OK == ChannelGroupTargetUnit->getInput(i, &unit, NULL) && + FMOD_OK == unit->getType(&type)) + { + if (type == FMOD_DSP_TYPE_SFXREVERB) + { + break; + } + } + } + if (i < 0) + { + return false; + } + + // Found it! Now move it in the DSP graph to be done before the water + // effect. + if (FMOD_OK != ChannelGroupTargetUnit->disconnectFrom(unit)) + { + return false; + } + if (FMOD_OK != SfxReverbPlaceholder->addInput(unit, NULL)) + { + return false; + } + return true; +} + //========================================================================== // // FMODSoundRenderer :: Sync diff --git a/src/sound/fmodsound.h b/src/sound/fmodsound.h index 21649d217c..c6f9492996 100644 --- a/src/sound/fmodsound.h +++ b/src/sound/fmodsound.h @@ -72,6 +72,8 @@ private: FISoundChannel *CommonChannelSetup(FMOD::Channel *chan, FISoundChannel *reuse_chan) const; FMOD_MODE SetChanHeadSettings(SoundListener *listener, FMOD::Channel *chan, const FVector3 &pos, bool areasound, FMOD_MODE oldmode) const; + bool ReconnectSFXReverbUnit(); + bool Init (); void Shutdown (); void DumpDriverCaps(FMOD_CAPS caps, int minfrequency, int maxfrequency); @@ -93,6 +95,8 @@ private: FMOD::DSP *WaterLP, *WaterReverb; FMOD::DSPConnection *SfxConnection; FMOD::DSP *ChannelGroupTargetUnit; + FMOD::DSP *SfxReverbPlaceholder; + bool SfxReverbHooked; float LastWaterLP; // Just for snd_status display diff --git a/src/sound/i_sound.h b/src/sound/i_sound.h index 6844a75452..b402fa3d2c 100644 --- a/src/sound/i_sound.h +++ b/src/sound/i_sound.h @@ -49,7 +49,8 @@ enum EStartSoundFlags SNDF_LOOP=1, SNDF_NOPAUSE=2, SNDF_AREA=4, - SNDF_ABSTIME=8 + SNDF_ABSTIME=8, + SNDF_NOREVERB=16, }; class SoundStream