mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-11-11 07:11:39 +00:00
- maintain ambient sounds in a separate structure.
This commit is contained in:
parent
52d13f5ee0
commit
92c8e4c110
6 changed files with 372 additions and 324 deletions
|
@ -28,7 +28,7 @@ enum EChanFlag
|
|||
CHANF_FORGETTABLE = 4, // internal: Forget channel data when sound stops.
|
||||
CHANF_JUSTSTARTED = 512, // internal: Sound has not been updated yet.
|
||||
CHANF_ABSTIME = 1024, // internal: Start time is absolute and does not depend on current time.
|
||||
CHANF_VIRTUAL = 2048, // Channel only plays on demand but won't get deleted automatically.
|
||||
CHANF_VIRTUAL = 2048, // internal: Channel is currently virtual
|
||||
CHANF_NOSTOP = 4096, // only for A_PlaySound. Does not start if channel is playing something.
|
||||
CHANF_OVERLAP = 8192, // [MK] Does not stop any sounds in the channel and instead plays over them.
|
||||
};
|
||||
|
|
|
@ -479,7 +479,7 @@ FSoundChan *SoundEngine::StartSound(int type, const void *source,
|
|||
// If the sound is blocked and not looped, return now. If the sound
|
||||
// is blocked and looped, pretend to play it so that it can
|
||||
// eventually play for real.
|
||||
if ((chanflags & (CHANF_EVICTED | CHANF_LOOP | CHANF_VIRTUAL)) == CHANF_EVICTED)
|
||||
if ((chanflags & (CHANF_EVICTED | CHANF_LOOP)) == CHANF_EVICTED)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
@ -550,7 +550,7 @@ FSoundChan *SoundEngine::StartSound(int type, const void *source,
|
|||
|
||||
// sound is paused and a non-looped sound is being started.
|
||||
// Such a sound would play right after unpausing which wouldn't sound right.
|
||||
if (!(chanflags & (CHANF_LOOP|CHANF_VIRTUAL)) && !(chanflags & (CHANF_UI|CHANF_NOPAUSE)) && SoundPaused)
|
||||
if (!(chanflags & CHANF_LOOP) && !(chanflags & (CHANF_UI|CHANF_NOPAUSE)) && SoundPaused)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
@ -587,7 +587,7 @@ FSoundChan *SoundEngine::StartSound(int type, const void *source,
|
|||
chan = (FSoundChan*)GSnd->StartSound (sfx->data, float(volume), pitch, startflags, NULL);
|
||||
}
|
||||
}
|
||||
if (chan == NULL && (chanflags & CHANF_LOOP|CHANF_VIRTUAL))
|
||||
if (chan == NULL && (chanflags & CHANF_LOOP))
|
||||
{
|
||||
chan = (FSoundChan*)GetChannel(NULL);
|
||||
GSnd->MarkStartTime(chan);
|
||||
|
@ -640,7 +640,7 @@ FSoundChan *SoundEngine::StartSound(int type, const void *source,
|
|||
|
||||
void SoundEngine::RestartChannel(FSoundChan *chan)
|
||||
{
|
||||
if (!(chan->ChanFlags & CHANF_EVICTED)) return;
|
||||
assert(chan->ChanFlags & CHANF_EVICTED);
|
||||
|
||||
FSoundChan *ochan;
|
||||
sfxinfo_t *sfx = &S_sfx[chan->SoundID];
|
||||
|
@ -1014,7 +1014,7 @@ void SoundEngine::RelinkSound (int sourcetype, const void *from, const void *to,
|
|||
{
|
||||
chan->Source = to;
|
||||
}
|
||||
else if (!(chan->ChanFlags & (CHANF_LOOP|CHANF_VIRTUAL)) && optpos)
|
||||
else if (!(chan->ChanFlags & CHANF_LOOP) && optpos)
|
||||
{
|
||||
chan->Source = NULL;
|
||||
chan->SourceType = SOURCE_Unattached;
|
||||
|
@ -1175,31 +1175,6 @@ bool SoundEngine::IsSourcePlayingSomething (int sourcetype, const void *actor, i
|
|||
return false;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// S_EvictChannel
|
||||
//
|
||||
// Forcibly evicts one single channel.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void SoundEngine::EvictChannel(FSoundChan *chan)
|
||||
{
|
||||
if (!(chan->ChanFlags & CHANF_EVICTED))
|
||||
{
|
||||
chan->ChanFlags |= CHANF_EVICTED;
|
||||
if (chan->SysChannel != NULL)
|
||||
{
|
||||
if (!(chan->ChanFlags & CHANF_ABSTIME))
|
||||
{
|
||||
chan->StartTime = GSnd ? GSnd->GetPosition(chan) : 0;
|
||||
chan->ChanFlags |= CHANF_ABSTIME;
|
||||
}
|
||||
StopChannel(chan);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// S_EvictAllChannels
|
||||
|
@ -1216,7 +1191,21 @@ void SoundEngine::EvictAllChannels()
|
|||
for (chan = Channels; chan != NULL; chan = next)
|
||||
{
|
||||
next = chan->NextChan;
|
||||
EvictChannel(chan);
|
||||
|
||||
if (!(chan->ChanFlags & CHANF_EVICTED))
|
||||
{
|
||||
chan->ChanFlags |= CHANF_EVICTED;
|
||||
if (chan->SysChannel != NULL)
|
||||
{
|
||||
if (!(chan->ChanFlags & CHANF_ABSTIME))
|
||||
{
|
||||
chan->StartTime = GSnd ? GSnd->GetPosition(chan) : 0;
|
||||
chan->ChanFlags |= CHANF_ABSTIME;
|
||||
}
|
||||
StopChannel(chan);
|
||||
}
|
||||
// assert(chan->NextChan == next);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1238,7 +1227,7 @@ void SoundEngine::RestoreEvictedChannel(FSoundChan *chan)
|
|||
if (chan->ChanFlags & CHANF_EVICTED)
|
||||
{
|
||||
RestartChannel(chan);
|
||||
if (!(chan->ChanFlags & (CHANF_LOOP|CHANF_VIRTUAL)))
|
||||
if (!(chan->ChanFlags & CHANF_LOOP))
|
||||
{
|
||||
if (chan->ChanFlags & CHANF_EVICTED)
|
||||
{ // Still evicted and not looping? Forget about it.
|
||||
|
@ -1250,7 +1239,7 @@ void SoundEngine::RestoreEvictedChannel(FSoundChan *chan)
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (chan->SysChannel == NULL && (chan->ChanFlags & (CHANF_FORGETTABLE | CHANF_LOOP | CHANF_VIRTUAL)) == CHANF_FORGETTABLE)
|
||||
else if (chan->SysChannel == NULL && (chan->ChanFlags & (CHANF_FORGETTABLE | CHANF_LOOP)) == CHANF_FORGETTABLE)
|
||||
{
|
||||
ReturnChannel(chan);
|
||||
}
|
||||
|
@ -1359,14 +1348,14 @@ void SoundEngine::ChannelEnded(FISoundChannel *ichan)
|
|||
if (schan != NULL)
|
||||
{
|
||||
// If the sound was stopped with GSnd->StopSound(), then we know
|
||||
// it wasn't evicted. Otherwise, if it's looping or declared virtual, it must have
|
||||
// it wasn't evicted. Otherwise, if it's looping, it must have
|
||||
// been evicted. If it's not looping, then it was evicted if it
|
||||
// didn't reach the end of its playback.
|
||||
if (schan->ChanFlags & CHANF_FORGETTABLE)
|
||||
{
|
||||
evicted = false;
|
||||
}
|
||||
else if (schan->ChanFlags & (CHANF_LOOP | CHANF_VIRTUAL | CHANF_EVICTED))
|
||||
else if (schan->ChanFlags & (CHANF_LOOP | CHANF_EVICTED))
|
||||
{
|
||||
evicted = true;
|
||||
}
|
||||
|
|
|
@ -174,8 +174,7 @@ struct FSoundChan : public FISoundChannel
|
|||
uint8_t SourceType;
|
||||
float LimitRange;
|
||||
const void *Source;
|
||||
float Point[3]; // Sound is not attached to any source, can also be used as auxiliary storage for sounds with a real source.
|
||||
int UserData[2]; // storage for user-specific data (Shadow Warrior's intermittent sounds use this as a counter.
|
||||
float Point[3]; // Sound is not attached to any source.
|
||||
};
|
||||
|
||||
|
||||
|
@ -253,6 +252,7 @@ private:
|
|||
void LinkChannel(FSoundChan* chan, FSoundChan** head);
|
||||
void UnlinkChannel(FSoundChan* chan);
|
||||
void ReturnChannel(FSoundChan* chan);
|
||||
void RestartChannel(FSoundChan* chan);
|
||||
void RestoreEvictedChannel(FSoundChan* chan);
|
||||
|
||||
bool IsChannelUsed(int sourcetype, const void* actor, int channel, int* seen);
|
||||
|
@ -272,7 +272,6 @@ protected:
|
|||
|
||||
public:
|
||||
virtual ~SoundEngine() = default;
|
||||
void EvictChannel(FSoundChan *chan);
|
||||
void EvictAllChannels();
|
||||
|
||||
void StopChannel(FSoundChan* chan);
|
||||
|
@ -292,7 +291,6 @@ public:
|
|||
void SetVolume(FSoundChan* chan, float vol);
|
||||
|
||||
FSoundChan* GetChannel(void* syschan);
|
||||
void RestartChannel(FSoundChan* chan);
|
||||
void RestoreEvictedChannels();
|
||||
void CalcPosVel(FSoundChan* chan, FVector3* pos, FVector3* vel);
|
||||
|
||||
|
|
|
@ -2087,6 +2087,7 @@ short SoundDist(int x, int y, int z, int basedist);
|
|||
short SoundAngle(int x, int y);
|
||||
//void PlaySound(int num, short angle, short vol);
|
||||
int _PlaySound(int num, SPRITEp sprite, PLAYERp player, vec3_t *pos, Voc3D_Flags flags, int channel);
|
||||
void InitAmbient(int num, SPRITEp sprite);
|
||||
inline void PlaySound(int num, SPRITEp sprite, Voc3D_Flags flags, int channel = 8)
|
||||
{
|
||||
_PlaySound(num, sprite, nullptr, nullptr, flags, channel);
|
||||
|
|
|
@ -251,8 +251,7 @@ JS_SpriteSetup(void)
|
|||
PlaySound(DIGI_WATERFLOW1, sp, v3df_follow|v3df_dontpan|v3df_doppler);
|
||||
break;
|
||||
case 460: // Wind Chimes
|
||||
PlaySound(79, sp, v3df_ambient | v3df_init
|
||||
| v3df_doppler | v3df_follow);
|
||||
InitAmbient(79, sp);
|
||||
break;
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//-------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (C) 1997, 2005 - 3D Realms Entertainment
|
||||
Copyright (C) 2019 Christoph Oelckers
|
||||
|
||||
This file is part of Shadow Warrior version 1.2
|
||||
|
||||
|
@ -56,11 +57,8 @@ BEGIN_SW_NS
|
|||
|
||||
enum EChanExFlags
|
||||
{
|
||||
CHANEXF_AMBIENT = 0x40000000,
|
||||
CHANEXF_NODOPPLER = 0x20000000,
|
||||
CHANEXF_DONTPAN = 0x10000000,
|
||||
CHANEXF_INTERMIT = 0x08000000,
|
||||
|
||||
CHANEXF_DONTPAN = 0x40000000,
|
||||
};
|
||||
|
||||
// Parentally locked sounds list
|
||||
|
@ -98,69 +96,18 @@ AMB_INFO ambarray[] =
|
|||
#define MAX_AMBIENT_SOUNDS 82
|
||||
|
||||
|
||||
class SWSoundEngine : public SoundEngine
|
||||
{
|
||||
// client specific parts of the sound engine go in this class.
|
||||
void CalcPosVel(int type, const void* source, const float pt[3], int channum, int chanflags, FSoundID chanSound, FVector3* pos, FVector3* vel, FSoundChan* chan) override;
|
||||
TArray<uint8_t> ReadSound(int lumpnum);
|
||||
|
||||
public:
|
||||
SWSoundEngine()
|
||||
{
|
||||
S_Rolloff.RolloffType = ROLLOFF_Doom;
|
||||
S_Rolloff.MinDistance = 0; // These are the default values, SW uses a few different rolloff settings.
|
||||
S_Rolloff.MaxDistance = 1187;
|
||||
}
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
TArray<uint8_t> SWSoundEngine::ReadSound(int lumpnum)
|
||||
float S_ConvertPitch(int lpitch)
|
||||
{
|
||||
auto wlump = fileSystem.OpenFileReader(lumpnum);
|
||||
return wlump.Read();
|
||||
return pow(2, lpitch / 1200.);
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void InitFX(void)
|
||||
{
|
||||
if (soundEngine) return; // just in case.
|
||||
soundEngine = new SWSoundEngine;
|
||||
|
||||
auto &S_sfx = soundEngine->GetSounds();
|
||||
S_sfx.Resize(countof(voc));
|
||||
for (auto& sfx : S_sfx) { sfx.Clear(); sfx.lumpnum = sfx_empty; }
|
||||
for (size_t i = 1; i < countof(voc); i++)
|
||||
{
|
||||
auto& entry = voc[i];
|
||||
auto lump = fileSystem.FindFile(entry.name);
|
||||
if (lump > 0)
|
||||
{
|
||||
auto& newsfx = S_sfx[i];
|
||||
newsfx.name = entry.name;
|
||||
newsfx.lumpnum = lump;
|
||||
newsfx.NearLimit = 6;
|
||||
newsfx.bTentative = false;
|
||||
}
|
||||
}
|
||||
soundEngine->HashSounds();
|
||||
for (auto& sfx : S_sfx)
|
||||
{
|
||||
soundEngine->CacheSound(&sfx);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Sound Distance Calculation
|
||||
|
@ -251,10 +198,132 @@ FRolloffInfo GetRolloff(int basedist)
|
|||
//==========================================================================
|
||||
//
|
||||
//
|
||||
// Ambient sounds
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int RandomizeAmbientSpecials(int handle)
|
||||
struct AmbientSound
|
||||
{
|
||||
SPRITEp sp;
|
||||
FSoundChan* sndChan;
|
||||
int ambIndex;
|
||||
int vocIndex;
|
||||
int ChanFlags;
|
||||
int maxIndex;
|
||||
int curIndex;
|
||||
bool intermit;
|
||||
};
|
||||
|
||||
static TArray<AmbientSound*> ambients;
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void StopAmbientSound(void)
|
||||
{
|
||||
for (auto& amb : ambients)
|
||||
{
|
||||
if (amb->sndChan)
|
||||
{
|
||||
soundEngine->StopChannel(amb->sndChan);
|
||||
}
|
||||
}
|
||||
ambients.Clear();
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Play a sound
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void InitAmbient(int num, SPRITEp sp)
|
||||
{
|
||||
VOC_INFOp vp;
|
||||
int pitch = 0;
|
||||
short angle, sound_dist;
|
||||
int tx, ty, tz;
|
||||
uint8_t priority;
|
||||
int maxtics = 0;
|
||||
|
||||
if (!snd_ambience) return;
|
||||
|
||||
// Ambient sounds need special treatment
|
||||
if (num < 0 || num > MAX_AMBIENT_SOUNDS)
|
||||
{
|
||||
sprintf(ds, "Invalid or out of range ambient sound number %d\n", num);
|
||||
PutStringInfo(Player + screenpeek, ds);
|
||||
return;
|
||||
}
|
||||
auto vnum = ambarray[num].diginame;
|
||||
if (!soundEngine->isValidSoundId(vnum))
|
||||
{
|
||||
return; // linked sound does not exist.
|
||||
}
|
||||
|
||||
auto amb = new AmbientSound;
|
||||
amb->sp = sp;
|
||||
amb->ambIndex = num;
|
||||
amb->vocIndex = vnum;
|
||||
amb->sndChan = nullptr;
|
||||
amb->ChanFlags = 0;
|
||||
if (ambarray[num].ambient_flags & v3df_dontpan) amb->ChanFlags |= EChanFlags::FromInt(CHANEXF_DONTPAN);
|
||||
if (voc[vnum].voc_flags & vf_loop) amb->ChanFlags |= CHANF_LOOP;
|
||||
amb->maxIndex = ambarray[num].maxtics * 8;
|
||||
amb->curIndex = 0;
|
||||
amb->intermit = !!(ambarray[num].ambient_flags & v3df_intermit);
|
||||
ambients.Push(amb);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void StartAmbientSound(void)
|
||||
{
|
||||
short i, nexti;
|
||||
extern SWBOOL InMenuLevel;
|
||||
|
||||
if (InMenuLevel || !SoundEnabled()) return; // Don't restart ambience if no level is active! Will crash game.
|
||||
|
||||
TRAVERSE_SPRITE_STAT(headspritestat[STAT_AMBIENT], i, nexti)
|
||||
{
|
||||
SPRITEp sp = &sprite[i];
|
||||
InitAmbient(sp->lotag, sp);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void RestartAmbient(AmbientSound* amb)
|
||||
{
|
||||
auto& vp = voc[amb->vocIndex];
|
||||
auto rolloff = GetRolloff(vp.voc_distance);
|
||||
int pitch = 0;
|
||||
if (vp.pitch_hi <= vp.pitch_lo) pitch = vp.pitch_lo;
|
||||
else pitch = vp.pitch_lo + (STD_RANDOM_RANGE(vp.pitch_hi - vp.pitch_lo));
|
||||
|
||||
soundEngine->StartSound(SOURCE_Ambient, amb, nullptr, CHAN_BODY, EChanFlags::FromInt(amb->ChanFlags), amb->vocIndex, 1.f, ATTN_NORM, &rolloff, S_ConvertPitch(pitch));
|
||||
}
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static int RandomizeAmbientSpecials(int handle)
|
||||
{
|
||||
#define MAXRNDAMB 12
|
||||
int ambrand[] =
|
||||
|
@ -280,29 +349,155 @@ int RandomizeAmbientSpecials(int handle)
|
|||
//==========================================================================
|
||||
|
||||
|
||||
void DoTimedSound(FSoundChan *chan)
|
||||
static void DoTimedSound(AmbientSound* amb)
|
||||
{
|
||||
chan->UserData[1] += synctics; // This got called 5x a second, incrementing by 3 each time, meaning that 15 units are one second. Now it gets called 40x a second.
|
||||
|
||||
if (chan->UserData[1] >= chan->UserData[0] * 8) // account for the 8x higher update frequency.
|
||||
amb->curIndex += synctics;
|
||||
if (amb->curIndex >= amb->maxIndex)
|
||||
{
|
||||
if (chan->ChanFlags & CHANF_EVICTED)
|
||||
if (amb->sndChan == nullptr)
|
||||
{
|
||||
// Check for special case ambient sounds. Since the sound is stopped and doesn't occupy a real channel at this time we can just swap out the sound ID before restarting it.
|
||||
int ambid = RandomizeAmbientSpecials(chan->SoundID);
|
||||
int ambid = RandomizeAmbientSpecials(amb->vocIndex);
|
||||
if (ambid != -1)
|
||||
{
|
||||
chan->SoundID = FSoundID(ambarray[ambid].maxtics);
|
||||
chan->UserData[0] = STD_RANDOM_RANGE(ambarray[ambid].maxtics);
|
||||
amb->vocIndex = ambid;
|
||||
amb->maxIndex = STD_RANDOM_RANGE(ambarray[ambid].maxtics);
|
||||
}
|
||||
|
||||
soundEngine->RestartChannel(chan);
|
||||
RestartAmbient(amb);
|
||||
}
|
||||
|
||||
chan->UserData[1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void UpdateAmbients()
|
||||
{
|
||||
for (auto& amb : ambients)
|
||||
{
|
||||
auto sp = amb->sp;
|
||||
auto sdist = SoundDist(sp->pos.x, sp->pos.y, sp->pos.z, voc[amb->vocIndex].voc_distance);
|
||||
|
||||
if (sdist < 255 && amb->vocIndex == DIGI_WHIPME)
|
||||
{
|
||||
PLAYERp pp = Player + screenpeek;
|
||||
if (!FAFcansee(sp->pos.x, sp->pos.y, sp->pos.z, sp->sectnum, pp->posx, pp->posy, pp->posz, pp->cursectnum))
|
||||
{
|
||||
sdist = 255;
|
||||
}
|
||||
}
|
||||
if (sdist < 255)
|
||||
{
|
||||
if (amb->intermit) DoTimedSound(amb);
|
||||
else RestartAmbient(amb);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (amb->sndChan)
|
||||
{
|
||||
soundEngine->StopChannel(amb->sndChan);
|
||||
amb->sndChan = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// end of ambient sounds
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class SWSoundEngine : public SoundEngine
|
||||
{
|
||||
// client specific parts of the sound engine go in this class.
|
||||
void CalcPosVel(int type, const void* source, const float pt[3], int channum, int chanflags, FSoundID chanSound, FVector3* pos, FVector3* vel, FSoundChan* chan) override;
|
||||
TArray<uint8_t> ReadSound(int lumpnum) override;
|
||||
void ChannelEnded(FISoundChannel* chan) override;
|
||||
|
||||
public:
|
||||
SWSoundEngine()
|
||||
{
|
||||
S_Rolloff.RolloffType = ROLLOFF_Doom;
|
||||
S_Rolloff.MinDistance = 0; // These are the default values, SW uses a few different rolloff settings.
|
||||
S_Rolloff.MaxDistance = 1187;
|
||||
}
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
TArray<uint8_t> SWSoundEngine::ReadSound(int lumpnum)
|
||||
{
|
||||
auto wlump = fileSystem.OpenFileReader(lumpnum);
|
||||
return wlump.Read();
|
||||
}
|
||||
|
||||
void SWSoundEngine::ChannelEnded(FISoundChannel* chan)
|
||||
{
|
||||
// if this channel belongs to an ambient sound we have to delete the reference to it.
|
||||
for (auto amb : ambients)
|
||||
{
|
||||
if (amb->sndChan == chan)
|
||||
{
|
||||
amb->sndChan = nullptr;
|
||||
}
|
||||
}
|
||||
SoundEngine::ChannelEnded(chan);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void InitFX(void)
|
||||
{
|
||||
if (soundEngine) return; // just in case.
|
||||
soundEngine = new SWSoundEngine;
|
||||
|
||||
auto &S_sfx = soundEngine->GetSounds();
|
||||
S_sfx.Resize(countof(voc));
|
||||
for (auto& sfx : S_sfx) { sfx.Clear(); sfx.lumpnum = sfx_empty; }
|
||||
for (size_t i = 1; i < countof(voc); i++)
|
||||
{
|
||||
auto& entry = voc[i];
|
||||
auto lump = fileSystem.FindFile(entry.name);
|
||||
if (lump > 0)
|
||||
{
|
||||
auto& newsfx = S_sfx[i];
|
||||
newsfx.name = entry.name;
|
||||
newsfx.lumpnum = lump;
|
||||
newsfx.NearLimit = 6;
|
||||
newsfx.bTentative = false;
|
||||
}
|
||||
}
|
||||
soundEngine->HashSounds();
|
||||
for (auto& sfx : S_sfx)
|
||||
{
|
||||
soundEngine->CacheSound(&sfx);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
@ -316,8 +511,8 @@ void SWSoundEngine::CalcPosVel(int type, const void* source, const float pt[3],
|
|||
{
|
||||
PLAYERp pp = Player + screenpeek;
|
||||
FVector3 campos = GetSoundPos((vec3_t*)pp);
|
||||
vec3_t *vpos = nullptr;
|
||||
|
||||
//S_GetCamera(&campos, nullptr, &camsect);
|
||||
if (vel) vel->Zero();
|
||||
|
||||
if (type == SOURCE_Unattached)
|
||||
|
@ -328,49 +523,50 @@ void SWSoundEngine::CalcPosVel(int type, const void* source, const float pt[3],
|
|||
}
|
||||
else if (type == SOURCE_Actor || type == SOURCE_Player)
|
||||
{
|
||||
vpos = type == SOURCE_Actor ? &((SPRITEp)source)->pos : (vec3_t*)&((PLAYERp)source)->posx;
|
||||
FVector3 npos = GetSoundPos(vpos);
|
||||
|
||||
*pos = npos;
|
||||
if (!(chanflags & CHANEXF_NODOPPLER) && vel)
|
||||
{
|
||||
// Hack alert. Velocity may only be set if a) the sound is already running and b) an actual sound channel is modified.
|
||||
// It remains to be seen if this is actually workable. I have my doubts. The velocity should be taken from a stable source.
|
||||
if (chan && !(chanflags & (CHANF_JUSTSTARTED | CHANF_EVICTED)))
|
||||
{
|
||||
*vel = (npos - FVector3(pt[0], pt[1], pt[2])) * 40; // SW ticks 40 times a second.
|
||||
chan->Point[0] = npos.X;
|
||||
chan->Point[1] = npos.Y;
|
||||
chan->Point[2] = npos.Z;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type == SOURCE_Ambient)
|
||||
{
|
||||
auto sp = ((AmbientSound*)source)->sp;
|
||||
vec3_t* vpos = type == SOURCE_Actor ? &((SPRITEp)source)->pos : (vec3_t*)&((PLAYERp)source)->posx;
|
||||
FVector3 npos = GetSoundPos(vpos);
|
||||
|
||||
// Can the ambient sound see the player? If not, tone it down some.
|
||||
if ((chanflags & CHANF_LOOP) && (chanflags & CHANEXF_AMBIENT) && type == SOURCE_Actor)
|
||||
if ((chanflags & CHANF_LOOP))
|
||||
{
|
||||
auto sp = (SPRITEp)source;
|
||||
//MONO_PRINT("PlaySound:Checking sound cansee");
|
||||
if (!FAFcansee(vpos->x, vpos->y, vpos->z, sp->sectnum, pp->posx, pp->posy, pp->posz, pp->cursectnum))
|
||||
{
|
||||
//MONO_PRINT("PlaySound:Reducing sound distance");
|
||||
auto distvec = npos - campos;
|
||||
// Special Cases
|
||||
npos = campos + distvec * 1.75f; // Play more quietly
|
||||
chanflags |= CHANEXF_NODOPPLER; // Ambient sounds should be stationary, but let's make sure that no doppler gets applied after messing up the position.
|
||||
}
|
||||
}
|
||||
|
||||
if (chanflags & CHANEXF_DONTPAN)
|
||||
{
|
||||
// For unpanned sounds the volume must be set directly and the position taken from the listener.
|
||||
*pos = campos;
|
||||
auto sdist = SoundDist(vpos->x, vpos->y, vpos->z, voc[chanSound].voc_distance);
|
||||
if (chan) SetVolume(chan, (255 - sdist) * (1 / 255.f));
|
||||
}
|
||||
else
|
||||
{
|
||||
*pos = npos;
|
||||
// Doppler only makes sense for sounds that are actually positioned in the world (i.e. not in combination with DONTPAN)
|
||||
if (!(chanflags & CHANEXF_NODOPPLER) && vel)
|
||||
{
|
||||
// Hack alert. Velocity may only be set if a) the sound is already running and b) an actual sound channel is modified.
|
||||
// It remains to be seen if this is actually workable. I have my doubts. The velocity should be taken from a stable source.
|
||||
if (chan && !(chanflags & (CHANF_JUSTSTARTED|CHANF_EVICTED)))
|
||||
{
|
||||
*vel = (npos - FVector3(pt[0], pt[1], pt[2])) * 40; // SW ticks 40 times a second.
|
||||
chan->Point[0] = npos.X;
|
||||
chan->Point[1] = npos.Y;
|
||||
chan->Point[2] = npos.Z;
|
||||
}
|
||||
}
|
||||
}
|
||||
*pos = npos;
|
||||
}
|
||||
|
||||
if (chanflags & CHANEXF_DONTPAN)
|
||||
{
|
||||
// For unpanned sounds the volume must be set directly and the position taken from the listener.
|
||||
*pos = campos;
|
||||
auto sdist = SoundDist(vpos->x, vpos->y, vpos->z, voc[chanSound].voc_distance);
|
||||
if (chan) SetVolume(chan, (255 - sdist) * (1 / 255.f));
|
||||
}
|
||||
|
||||
|
||||
if ((chanflags & CHANF_LISTENERZ) && campos != nullptr && type != SOURCE_None)
|
||||
{
|
||||
pos->Y = campos.Y;
|
||||
|
@ -402,172 +598,77 @@ void DoUpdateSounds(void)
|
|||
listener.ListenerObject = pp;
|
||||
soundEngine->SetListener(listener);
|
||||
|
||||
soundEngine->EnumerateChannels([](FSoundChan* chan)
|
||||
{
|
||||
if (chan->ChanFlags & EChanFlags::FromInt(CHANEXF_INTERMIT))
|
||||
{
|
||||
DoTimedSound(chan);
|
||||
}
|
||||
|
||||
if (chan->SoundID == DIGI_WHIPME && chan->SourceType == SOURCE_Actor)
|
||||
{
|
||||
auto sp = (SPRITEp)chan->Source;
|
||||
PLAYERp pp = Player + screenpeek;
|
||||
if (!FAFcansee(sp->pos.x, sp->pos.y, sp->pos.z, sp->sectnum, pp->posx, pp->posy, pp->posz, pp->cursectnum))
|
||||
{
|
||||
soundEngine->EvictChannel(chan);
|
||||
}
|
||||
else if (chan->ChanFlags & CHANF_EVICTED)
|
||||
{
|
||||
soundEngine->RestartChannel(chan);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
UpdateAmbients();
|
||||
soundEngine->UpdateSounds((int)totalclock);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
float S_ConvertPitch(int lpitch)
|
||||
{
|
||||
return pow(2, lpitch / 1200.);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Play a sound
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int _PlaySound(int num, SPRITEp sp, PLAYERp pp, vec3_t *pos, Voc3D_Flags flags, int channel)
|
||||
int _PlaySound(int num, SPRITEp sp, PLAYERp pp, vec3_t* pos, Voc3D_Flags flags, int channel)
|
||||
{
|
||||
VOC_INFOp vp;
|
||||
int pitch = 0;
|
||||
short angle, sound_dist;
|
||||
int tx, ty, tz;
|
||||
uint8_t priority;
|
||||
int maxtics = 0;
|
||||
EChanFlags cflags = channel == 8 ?CHANF_OVERLAP : CHANF_NONE; // for the default channel we do not want to have sounds stopping each other.
|
||||
if (Prediction || !SoundEnabled() || !soundEngine->isValidSoundId(num))
|
||||
return -1;
|
||||
|
||||
// Weed out parental lock sounds if PLock is active
|
||||
if (adult_lockout || Global_PLock)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i=0; i<sizeof(PLocked_Sounds); i++)
|
||||
for (unsigned i = 0; i < sizeof(PLocked_Sounds); i++)
|
||||
{
|
||||
if (num == PLocked_Sounds[i])
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (Prediction || !SoundEnabled())
|
||||
return -1;
|
||||
|
||||
if (TEST(flags,v3df_ambient) && !TEST(flags,v3df_nolookup)) // Look for invalid ambient numbers
|
||||
auto vp = &voc[num];
|
||||
int sourcetype = SOURCE_None;
|
||||
EChanFlags cflags = channel == 8 ? CHANF_OVERLAP : CHANF_NONE; // for the default channel we do not want to have sounds stopping each other.
|
||||
void* source = nullptr;
|
||||
// If the sound is not supposd to be positioned, it may not be linked to the launching actor.
|
||||
if (!(flags & v3df_follow))
|
||||
{
|
||||
// Ambient sounds need special treatment
|
||||
if (!snd_ambience) return -1;
|
||||
if (num < 0 || num > MAX_AMBIENT_SOUNDS)
|
||||
if (sp && !pos)
|
||||
{
|
||||
sprintf(ds,"Invalid or out of range ambient sound number %d\n",num);
|
||||
PutStringInfo(Player+screenpeek, ds);
|
||||
return -1;
|
||||
pos = &sp->pos;
|
||||
sp = nullptr;
|
||||
}
|
||||
maxtics = STD_RANDOM_RANGE(ambarray[num].maxtics);
|
||||
|
||||
// If the ambient flag is set, do a name conversion to point to actual
|
||||
// digital sound entry.
|
||||
flags |= ambarray[num].ambient_flags; // Add to flags if any
|
||||
num = ambarray[num].diginame;
|
||||
cflags |= EChanFlags::FromInt(CHANEXF_AMBIENT); // flag the sound as being an ambient sound.
|
||||
}
|
||||
//else
|
||||
{
|
||||
if (!soundEngine->isValidSoundId(num))
|
||||
else if (pp && !pos)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
vp = &voc[num];
|
||||
int sourcetype = SOURCE_None;
|
||||
void* source = nullptr;
|
||||
// If the sound is not supposd to be positioned, it may not be linked to the launching actor.
|
||||
if (!(flags & v3df_follow))
|
||||
{
|
||||
if (sp && !pos)
|
||||
{
|
||||
pos = &sp->pos;
|
||||
sp = nullptr;
|
||||
}
|
||||
else if (pp && !pos)
|
||||
{
|
||||
pos = (vec3_t*)&pp->posx;
|
||||
pp = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (pos != nullptr)
|
||||
{
|
||||
sourcetype = SOURCE_Unattached;
|
||||
}
|
||||
else if (sp != nullptr)
|
||||
{
|
||||
source = sp;
|
||||
sourcetype = SOURCE_Actor;
|
||||
}
|
||||
else if (pp != nullptr)
|
||||
{
|
||||
source = pp;
|
||||
sourcetype = SOURCE_Player;
|
||||
}
|
||||
// Otherwise it's an unpositioned sound.
|
||||
|
||||
if (!(flags & v3df_doppler))
|
||||
{
|
||||
cflags |= EChanFlags::FromInt(CHANEXF_NODOPPLER); // this must ensure that CalcPosVel always zeros the velocity.
|
||||
}
|
||||
if (flags & v3df_dontpan)
|
||||
{
|
||||
cflags |= EChanFlags::FromInt(CHANEXF_DONTPAN); // beware of hackery to emulate this.
|
||||
}
|
||||
/*
|
||||
if (flags & v3df_init)
|
||||
{
|
||||
// this only gets used for starting looped sounds that are outside hearing range - something the sound engine handles transparently.
|
||||
}
|
||||
*/
|
||||
if (vp->voc_flags & vf_loop)
|
||||
{
|
||||
cflags |= CHANF_LOOP; // with the new sound engine these can just be started and don't have to be stopped ever.
|
||||
}
|
||||
|
||||
if (vp->pitch_hi <= vp->pitch_lo)
|
||||
pitch = vp->pitch_lo;
|
||||
else if (vp->pitch_hi != vp->pitch_lo)
|
||||
pitch = vp->pitch_lo + (STD_RANDOM_RANGE(vp->pitch_hi - vp->pitch_lo));
|
||||
|
||||
float fpitch = S_ConvertPitch(pitch);
|
||||
|
||||
auto rolloff = GetRolloff(vp->voc_distance);
|
||||
FVector3 spos = pos ? GetSoundPos(pos) : FVector3(0, 0, 0);
|
||||
auto chan = soundEngine->StartSound(sourcetype, source, &spos, CHAN_BODY, cflags, num, 1.f, ATTN_NORM, &rolloff, fpitch);
|
||||
if (chan)
|
||||
{
|
||||
if (flags & v3df_intermit)
|
||||
{
|
||||
chan->ChanFlags |= CHANF_VIRTUAL | EChanFlags::FromInt(CHANEXF_INTERMIT); // for intermittent sounds this must be set after starting the sound so that it actually plays.
|
||||
}
|
||||
chan->UserData[0] = maxtics; // counter for intermittent delay.
|
||||
chan->UserData[1] = 0;
|
||||
pos = (vec3_t*)&pp->posx;
|
||||
pp = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (pos != nullptr)
|
||||
{
|
||||
sourcetype = SOURCE_Unattached;
|
||||
}
|
||||
else if (sp != nullptr)
|
||||
{
|
||||
source = sp;
|
||||
sourcetype = SOURCE_Actor;
|
||||
}
|
||||
else if (pp != nullptr)
|
||||
{
|
||||
source = pp;
|
||||
sourcetype = SOURCE_Player;
|
||||
}
|
||||
// Otherwise it's an unpositioned sound.
|
||||
|
||||
if (flags & v3df_doppler) cflags |= EChanFlags::FromInt(CHANEXF_NODOPPLER); // this must ensure that CalcPosVel always zeros the velocity.
|
||||
if (flags & v3df_dontpan) cflags |= EChanFlags::FromInt(CHANEXF_DONTPAN); // beware of hackery to emulate this.
|
||||
if (vp->voc_flags & vf_loop) cflags |= CHANF_LOOP; // with the new sound engine these can just be started and don't have to be stopped ever.
|
||||
|
||||
int pitch = 0;
|
||||
if (vp->pitch_hi <= vp->pitch_lo) pitch = vp->pitch_lo;
|
||||
else if (vp->pitch_hi != vp->pitch_lo) pitch = vp->pitch_lo + (STD_RANDOM_RANGE(vp->pitch_hi - vp->pitch_lo));
|
||||
|
||||
auto rolloff = GetRolloff(vp->voc_distance);
|
||||
FVector3 spos = pos ? GetSoundPos(pos) : FVector3(0, 0, 0);
|
||||
soundEngine->StartSound(sourcetype, source, &spos, CHAN_BODY, cflags, num, 1.f, ATTN_NORM, &rolloff, S_ConvertPitch(pitch));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -633,46 +734,6 @@ void DeleteNoFollowSoundOwner(short spritenum)
|
|||
soundEngine->StopSound(SOURCE_Actor, sp, -1); // all non-follow sounds are SOURCE_Unattached
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void StopAmbientSound(void)
|
||||
{
|
||||
soundEngine->EnumerateChannels([](FSoundChan* chan)
|
||||
{
|
||||
if (chan->ChanFlags & EChanFlags::FromInt(CHANEXF_AMBIENT))
|
||||
{
|
||||
soundEngine->StopChannel(chan);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void StartAmbientSound(void)
|
||||
{
|
||||
short i, nexti;
|
||||
extern SWBOOL InMenuLevel;
|
||||
|
||||
if (InMenuLevel) return; // Don't restart ambience if no level is active! Will crash game.
|
||||
|
||||
TRAVERSE_SPRITE_STAT(headspritestat[STAT_AMBIENT], i, nexti)
|
||||
{
|
||||
SPRITEp sp = &sprite[i];
|
||||
|
||||
PlaySound(sp->lotag, sp, v3df_ambient | v3df_init | v3df_doppler | v3df_follow);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Terminate the sounds list
|
||||
|
|
Loading…
Reference in a new issue