- Fixed two bugs in FMODSoundRenderer::HandleChannelDelay():

* Looping sounds that have been playing for a very long time, were evicted,
    and then were restarted need to have their positions clamped to lie
    within the bounds of the sounds. If we try to set a start position very
    far beyond the end, it will overflow inside FMOD and not work.
  * A start time of 0 is not actually valid and means the sound was never
    assigned a start time.
- The latter bug also reveals a problem with starting looped sounds evicted:
  They need to be assigned a start time so if they should have the opportunity
  to start later, they will be properly synchronized.


SVN r1987 (trunk)
This commit is contained in:
Randy Heit 2009-11-18 04:45:20 +00:00
parent 424c6e8963
commit 51eb6465a2
7 changed files with 61 additions and 5 deletions

View file

@ -1,3 +1,15 @@
November 17, 2009
- Fixed two bugs in FMODSoundRenderer::HandleChannelDelay():
* Looping sounds that have been playing for a very long time, were evicted,
and then were restarted need to have their positions clamped to lie
within the bounds of the sounds. If we try to set a start position very
far beyond the end, it will overflow inside FMOD and not work.
* A start time of 0 is not actually valid and means the sound was never
assigned a start time.
- The latter bug also reveals a problem with starting looped sounds evicted:
They need to be assigned a start time so if they should have the opportunity
to start later, they will be properly synchronized.
November 17, 2009 (Changes by Graf Zahl) November 17, 2009 (Changes by Graf Zahl)
- fixed: P_NowayTraverse was called with a trace distance of 128 instead of - fixed: P_NowayTraverse was called with a trace distance of 128 instead of
the 64 that should have been used. the 64 that should have been used.

View file

@ -1053,6 +1053,7 @@ static FSoundChan *S_StartSound(AActor *actor, const sector_t *sec, const FPolyO
if (chan == NULL && (chanflags & CHAN_LOOP)) if (chan == NULL && (chanflags & CHAN_LOOP))
{ {
chan = (FSoundChan*)S_GetChannel(NULL); chan = (FSoundChan*)S_GetChannel(NULL);
GSnd->MarkStartTime(chan);
chanflags |= CHAN_EVICTED; chanflags |= CHAN_EVICTED;
} }
if (attenuation > 0) if (attenuation > 0)

View file

@ -1650,6 +1650,10 @@ FISoundChannel *FMODSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener *
} }
if (!HandleChannelDelay(chan, reuse_chan, flags & (SNDF_ABSTIME | SNDF_LOOP), freq)) if (!HandleChannelDelay(chan, reuse_chan, flags & (SNDF_ABSTIME | SNDF_LOOP), freq))
{ {
// FMOD seems to get confused if you stop a channel right after
// starting it, so hopefully this function will never fail.
// (Presumably you need an update between them, but I haven't
// tested this hypothesis.)
chan->stop(); chan->stop();
return NULL; return NULL;
} }
@ -1674,6 +1678,19 @@ FISoundChannel *FMODSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener *
return 0; return 0;
} }
//==========================================================================
//
// FMODSoundRenderer :: MarkStartTime
//
// Marks a channel's start time without actually playing it.
//
//==========================================================================
void FMODSoundRenderer::MarkStartTime(FISoundChannel *chan)
{
Sys->getDSPClock(&chan->StartTime.Hi, &chan->StartTime.Lo);
}
//========================================================================== //==========================================================================
// //
// FMODSoundRenderer :: HandleChannelDelay // FMODSoundRenderer :: HandleChannelDelay
@ -1704,11 +1721,26 @@ bool FMODSoundRenderer::HandleChannelDelay(FMOD::Channel *chan, FISoundChannel *
} }
reuse_chan->StartTime.AsOne = QWORD(nowtime.AsOne - seekpos * OutputRate / freq); reuse_chan->StartTime.AsOne = QWORD(nowtime.AsOne - seekpos * OutputRate / freq);
} }
else else if (reuse_chan->StartTime.AsOne != 0)
{ {
QWORD difftime = nowtime.AsOne - reuse_chan->StartTime.AsOne; QWORD difftime = nowtime.AsOne - reuse_chan->StartTime.AsOne;
if (difftime > 0) if (difftime > 0)
{ {
// Clamp the position of looping sounds to be within the sound.
// If we try to start it several minutes past its normal end,
// FMOD doesn't like that.
if (flags & SNDF_LOOP)
{
FMOD::Sound *sound;
if (FMOD_OK == chan->getCurrentSound(&sound))
{
unsigned int len;
if (FMOD_OK == sound->getLength(&len, FMOD_TIMEUNIT_MS))
{
difftime %= len;
}
}
}
return chan->setPosition((unsigned int)(difftime / OutputRate), FMOD_TIMEUNIT_MS) == FMOD_OK; return chan->setPosition((unsigned int)(difftime / OutputRate), FMOD_TIMEUNIT_MS) == FMOD_OK;
} }
} }

View file

@ -33,6 +33,9 @@ public:
// Stops a sound channel. // Stops a sound channel.
void StopChannel (FISoundChannel *chan); void StopChannel (FISoundChannel *chan);
// Marks a channel's start time without actually playing it.
void MarkStartTime (FISoundChannel *chan);
// Returns position of sound on this channel, in samples. // Returns position of sound on this channel, in samples.
unsigned int GetPosition(FISoundChannel *chan); unsigned int GetPosition(FISoundChannel *chan);

View file

@ -159,7 +159,7 @@ public:
return NULL; return NULL;
} }
// Starts a sound. (No, not really.) // Starts a sound.
FISoundChannel *StartSound (SoundHandle sfx, float vol, int pitch, int chanflags, FISoundChannel *reuse_chan) FISoundChannel *StartSound (SoundHandle sfx, float vol, int pitch, int chanflags, FISoundChannel *reuse_chan)
{ {
return NULL; return NULL;
@ -169,6 +169,11 @@ public:
return NULL; return NULL;
} }
// Marks a channel's start time without actually playing it.
void MarkStartTime (FISoundChannel *chan)
{
}
// Returns position of sound on this channel, in samples. // Returns position of sound on this channel, in samples.
unsigned int GetPosition(FISoundChannel *chan) unsigned int GetPosition(FISoundChannel *chan)
{ {

View file

@ -109,6 +109,9 @@ public:
// Stops a sound channel. // Stops a sound channel.
virtual void StopChannel (FISoundChannel *chan) = 0; virtual void StopChannel (FISoundChannel *chan) = 0;
// Marks a channel's start time without actually playing it.
virtual void MarkStartTime (FISoundChannel *chan) = 0;
// Returns position of sound on this channel, in samples. // Returns position of sound on this channel, in samples.
virtual unsigned int GetPosition(FISoundChannel *chan) = 0; virtual unsigned int GetPosition(FISoundChannel *chan) = 0;

View file

@ -232,7 +232,7 @@ public:
uint32 fillcolor; uint32 fillcolor;
FRemapTable *remap; FRemapTable *remap;
const BYTE *translation; const BYTE *translation;
DWORD colorOverlay; uint32 colorOverlay;
INTBOOL alphaChannel; INTBOOL alphaChannel;
INTBOOL flipX; INTBOOL flipX;
fixed_t shadowAlpha; fixed_t shadowAlpha;
@ -404,7 +404,7 @@ public:
virtual bool WipeDo(int ticks); virtual bool WipeDo(int ticks);
virtual void WipeCleanup(); virtual void WipeCleanup();
DWORD GetLastFPS() const { return LastCount; } uint32 GetLastFPS() const { return LastCount; }
#ifdef _WIN32 #ifdef _WIN32
virtual void PaletteChanged () = 0; virtual void PaletteChanged () = 0;
@ -418,7 +418,7 @@ protected:
DFrameBuffer () {} DFrameBuffer () {}
private: private:
DWORD LastMS, LastSec, FrameCount, LastCount, LastTic; uint32 LastMS, LastSec, FrameCount, LastCount, LastTic;
}; };