mirror of
https://github.com/ZDoom/gzdoom-gles.git
synced 2024-11-10 23:01:59 +00:00
Set the source gain to 0 before stopping it
Stopping a source in the middle of playback can causing undesirable "popping" from a sudden change in amplitude. Setting the source gain to 0 gives OpenAL the opportunity to ramp the source's output to 0, where it can be safely stopped without causing a sudden change in amplitude.
This commit is contained in:
parent
78231d5ba1
commit
f97efefe7e
2 changed files with 96 additions and 20 deletions
|
@ -230,7 +230,7 @@ class OpenALSoundStream : public SoundStream
|
|||
if(Renderer->FreeSfx.Size() == 0)
|
||||
{
|
||||
FSoundChan *lowest = Renderer->FindLowestChannel();
|
||||
if(lowest) Renderer->StopChannel(lowest);
|
||||
if(lowest) Renderer->ForceStopChannel(lowest);
|
||||
|
||||
if(Renderer->FreeSfx.Size() == 0)
|
||||
return false;
|
||||
|
@ -810,6 +810,14 @@ OpenALSoundRenderer::OpenALSoundRenderer()
|
|||
return;
|
||||
}
|
||||
|
||||
ALCint refresh=0;
|
||||
alcGetIntegerv(Device, ALC_REFRESH, 1, &refresh);
|
||||
if(refresh > 0)
|
||||
{
|
||||
// Round up instead of down
|
||||
UpdateTimeMS = (1000+refresh-1) / refresh;
|
||||
}
|
||||
|
||||
ALCint numMono=0, numStereo=0;
|
||||
alcGetIntegerv(Device, ALC_MONO_SOURCES, 1, &numMono);
|
||||
alcGetIntegerv(Device, ALC_STEREO_SOURCES, 1, &numStereo);
|
||||
|
@ -1315,7 +1323,7 @@ void OpenALSoundRenderer::UnloadSound(SoundHandle sfx)
|
|||
if((ALuint)bufID == buffer)
|
||||
{
|
||||
FSoundChan *next = schan->NextChan;
|
||||
StopChannel(schan);
|
||||
ForceStopChannel(schan);
|
||||
schan = next;
|
||||
continue;
|
||||
}
|
||||
|
@ -1323,6 +1331,20 @@ void OpenALSoundRenderer::UnloadSound(SoundHandle sfx)
|
|||
schan = schan->NextChan;
|
||||
}
|
||||
|
||||
// Make sure to kill any currently fading sounds too
|
||||
for(auto iter = FadingSources.begin();iter != FadingSources.end();)
|
||||
{
|
||||
ALint bufID = 0;
|
||||
alGetSourcei(iter->first, AL_BUFFER, &bufID);
|
||||
if(static_cast<ALuint>(bufID) == buffer)
|
||||
{
|
||||
FreeSource(iter->first);
|
||||
iter = FadingSources.erase(iter);
|
||||
}
|
||||
else
|
||||
++iter;
|
||||
}
|
||||
|
||||
alDeleteBuffers(1, &buffer);
|
||||
getALError();
|
||||
}
|
||||
|
@ -1359,7 +1381,7 @@ FISoundChannel *OpenALSoundRenderer::StartSound(SoundHandle sfx, float vol, int
|
|||
if(FreeSfx.Size() == 0)
|
||||
{
|
||||
FSoundChan *lowest = FindLowestChannel();
|
||||
if(lowest) StopChannel(lowest);
|
||||
if(lowest) ForceStopChannel(lowest);
|
||||
|
||||
if(FreeSfx.Size() == 0)
|
||||
return NULL;
|
||||
|
@ -1462,7 +1484,7 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener
|
|||
{
|
||||
if(lowest->Priority < priority || (lowest->Priority == priority &&
|
||||
lowest->DistanceSqr > dist_sqr))
|
||||
StopChannel(lowest);
|
||||
ForceStopChannel(lowest);
|
||||
}
|
||||
if(FreeSfx.Size() == 0)
|
||||
return NULL;
|
||||
|
@ -1666,16 +1688,8 @@ void OpenALSoundRenderer::ChannelVolume(FISoundChannel *chan, float volume)
|
|||
alSourcef(source, AL_GAIN, SfxVolume * volume);
|
||||
}
|
||||
|
||||
void OpenALSoundRenderer::StopChannel(FISoundChannel *chan)
|
||||
void OpenALSoundRenderer::FreeSource(ALuint source)
|
||||
{
|
||||
if(chan == NULL || chan->SysChannel == NULL)
|
||||
return;
|
||||
|
||||
ALuint source = GET_PTRID(chan->SysChannel);
|
||||
// Release first, so it can be properly marked as evicted if it's being
|
||||
// forcefully killed
|
||||
S_ChannelEnded(chan);
|
||||
|
||||
alSourceRewind(source);
|
||||
alSourcei(source, AL_BUFFER, 0);
|
||||
getALError();
|
||||
|
@ -1685,11 +1699,48 @@ void OpenALSoundRenderer::StopChannel(FISoundChannel *chan)
|
|||
PausableSfx.Delete(i);
|
||||
if((i=ReverbSfx.Find(source)) < ReverbSfx.Size())
|
||||
ReverbSfx.Delete(i);
|
||||
if((i=SfxGroup.Find(source)) < SfxGroup.Size())
|
||||
SfxGroup.Delete(i);
|
||||
|
||||
SfxGroup.Delete(SfxGroup.Find(source));
|
||||
FreeSfx.Push(source);
|
||||
}
|
||||
|
||||
void OpenALSoundRenderer::StopChannel(FISoundChannel *chan)
|
||||
{
|
||||
if(chan == NULL || chan->SysChannel == NULL)
|
||||
return;
|
||||
|
||||
ALuint source = GET_PTRID(chan->SysChannel);
|
||||
// Release first, so it can be properly marked as evicted if it's being killed
|
||||
S_ChannelEnded(chan);
|
||||
|
||||
ALint state = AL_INITIAL;
|
||||
alGetSourcei(source, AL_SOURCE_STATE, &state);
|
||||
if(state != AL_PLAYING)
|
||||
FreeSource(source);
|
||||
else
|
||||
{
|
||||
// The sound is being killed while playing, so set its gain to 0 and track it
|
||||
// as it fades.
|
||||
alSourcef(source, AL_GAIN, 0.f);
|
||||
getALError();
|
||||
|
||||
FadingSources.insert(std::make_pair(
|
||||
source, std::chrono::steady_clock::now().time_since_epoch().count()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
void OpenALSoundRenderer::ForceStopChannel(FISoundChannel *chan)
|
||||
{
|
||||
ALuint source = GET_PTRID(chan->SysChannel);
|
||||
if(!source) return;
|
||||
|
||||
S_ChannelEnded(chan);
|
||||
FreeSource(source);
|
||||
}
|
||||
|
||||
|
||||
unsigned int OpenALSoundRenderer::GetPosition(FISoundChannel *chan)
|
||||
{
|
||||
if(chan == NULL || chan->SysChannel == NULL)
|
||||
|
@ -1946,6 +1997,23 @@ void OpenALSoundRenderer::UpdateSounds()
|
|||
{
|
||||
alProcessUpdatesSOFT();
|
||||
|
||||
if(!FadingSources.empty())
|
||||
{
|
||||
auto cur_time = std::chrono::steady_clock::now().time_since_epoch();
|
||||
for(auto iter = FadingSources.begin();iter != FadingSources.end();)
|
||||
{
|
||||
auto time_diff = std::chrono::duration_cast<std::chrono::milliseconds>(cur_time -
|
||||
std::chrono::steady_clock::time_point::duration(iter->second));
|
||||
if(time_diff.count() >= UpdateTimeMS)
|
||||
{
|
||||
FreeSource(iter->first);
|
||||
iter = FadingSources.erase(iter);
|
||||
}
|
||||
else
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
if(ALC.EXT_disconnect)
|
||||
{
|
||||
ALCint connected = ALC_TRUE;
|
||||
|
@ -2031,17 +2099,18 @@ void OpenALSoundRenderer::PrintStatus()
|
|||
|
||||
FString OpenALSoundRenderer::GatherStats()
|
||||
{
|
||||
ALCint updates = 1;
|
||||
alcGetIntegerv(Device, ALC_REFRESH, 1, &updates);
|
||||
FString out;
|
||||
|
||||
ALCint refresh = 1;
|
||||
alcGetIntegerv(Device, ALC_REFRESH, 1, &refresh);
|
||||
getALCError(Device);
|
||||
|
||||
uint32_t total = Sources.Size();
|
||||
uint32_t used = SfxGroup.Size()+Streams.Size();
|
||||
uint32_t unused = FreeSfx.Size();
|
||||
|
||||
FString out;
|
||||
out.Format("%u sources (" TEXTCOLOR_YELLOW"%u" TEXTCOLOR_NORMAL" active, " TEXTCOLOR_YELLOW"%u" TEXTCOLOR_NORMAL" free), Update interval: " TEXTCOLOR_YELLOW"%d" TEXTCOLOR_NORMAL"ms",
|
||||
total, used, unused, 1000/updates);
|
||||
out.Format("%u sources (" TEXTCOLOR_YELLOW"%u" TEXTCOLOR_NORMAL" active, " TEXTCOLOR_YELLOW"%u" TEXTCOLOR_NORMAL" free), Update interval: " TEXTCOLOR_YELLOW"%.1f" TEXTCOLOR_NORMAL"ms",
|
||||
total, used, unused, 1000.f/static_cast<float>(refresh));
|
||||
return out;
|
||||
}
|
||||
|
||||
|
@ -2106,7 +2175,7 @@ void OpenALSoundRenderer::PurgeStoppedSources()
|
|||
{
|
||||
if(schan->SysChannel != NULL && src == GET_PTRID(schan->SysChannel))
|
||||
{
|
||||
StopChannel(schan);
|
||||
ForceStopChannel(schan);
|
||||
break;
|
||||
}
|
||||
schan = schan->NextChan;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <mutex>
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "i_sound.h"
|
||||
#include "s_sound.h"
|
||||
|
@ -200,8 +201,10 @@ private:
|
|||
void RemoveStream(OpenALSoundStream *stream);
|
||||
|
||||
void LoadReverb(const ReverbContainer *env);
|
||||
void FreeSource(ALuint source);
|
||||
void PurgeStoppedSources();
|
||||
static FSoundChan *FindLowestChannel();
|
||||
void ForceStopChannel(FISoundChannel *chan);
|
||||
|
||||
std::thread StreamThread;
|
||||
std::mutex StreamLock;
|
||||
|
@ -222,6 +225,10 @@ private:
|
|||
TArray<ALuint> ReverbSfx;
|
||||
TArray<ALuint> SfxGroup;
|
||||
|
||||
int UpdateTimeMS;
|
||||
using SourceTimeMap = std::unordered_map<ALuint,int64_t>;
|
||||
SourceTimeMap FadingSources;
|
||||
|
||||
const ReverbContainer *PrevEnvironment;
|
||||
|
||||
typedef TMap<uint16_t,ALuint> EffectMap;
|
||||
|
|
Loading…
Reference in a new issue