Merge branch 'soundsource_refactor'

This commit is contained in:
Christoph Oelckers 2019-12-08 22:19:51 +01:00
commit 298e29ffcc
30 changed files with 3122 additions and 2748 deletions

View file

@ -878,7 +878,9 @@ set (PCH_SOURCES
rendering/r_videoscale.cpp rendering/r_videoscale.cpp
sound/s_advsound.cpp sound/s_advsound.cpp
sound/s_environment.cpp sound/s_environment.cpp
sound/s_reverbedit.cpp
sound/s_sndseq.cpp sound/s_sndseq.cpp
sound/s_doomsound.cpp
sound/s_sound.cpp sound/s_sound.cpp
sound/s_music.cpp sound/s_music.cpp
serializer.cpp serializer.cpp

View file

@ -1134,6 +1134,11 @@ FString BuildString (int argc, FString *argv)
// //
//=========================================================================== //===========================================================================
void FConsoleCommand::PrintCommand()
{
Printf("%s\n", m_Name);
}
FString SubstituteAliasParams (FString &command, FCommandLine &args) FString SubstituteAliasParams (FString &command, FCommandLine &args)
{ {
// Do substitution by replacing %x with the argument x. // Do substitution by replacing %x with the argument x.

View file

@ -34,7 +34,9 @@
#ifndef __C_DISPATCH_H__ #ifndef __C_DISPATCH_H__
#define __C_DISPATCH_H__ #define __C_DISPATCH_H__
#include "doomtype.h" #include <stdint.h>
#include "tarray.h"
#include "zstring.h"
class FConfigFile; class FConfigFile;
@ -63,7 +65,7 @@ struct FExecList
TArray<FString> Commands; TArray<FString> Commands;
TArray<FString> Pullins; TArray<FString> Pullins;
void AddCommand(const char *cmd, const char *file = NULL); void AddCommand(const char *cmd, const char *file = nullptr);
void ExecCommands() const; void ExecCommands() const;
void AddPullins(TArray<FString> &wads) const; void AddPullins(TArray<FString> &wads) const;
}; };
@ -107,7 +109,7 @@ public:
FConsoleCommand (const char *name, CCmdRun RunFunc); FConsoleCommand (const char *name, CCmdRun RunFunc);
virtual ~FConsoleCommand (); virtual ~FConsoleCommand ();
virtual bool IsAlias (); virtual bool IsAlias ();
void PrintCommand () { Printf ("%s\n", m_Name); } void PrintCommand();
virtual void Run (FCommandLine &args, AActor *instigator, int key); virtual void Run (FCommandLine &args, AActor *instigator, int key);
static FConsoleCommand* FindByName (const char* name); static FConsoleCommand* FindByName (const char* name);
@ -208,9 +210,7 @@ extern bool ParsingKeyConf, UnsafeExecutionContext;
void ResetButtonTriggers (); // Call ResetTriggers for all buttons void ResetButtonTriggers (); // Call ResetTriggers for all buttons
void ResetButtonStates (); // Same as above, but also clear bDown void ResetButtonStates (); // Same as above, but also clear bDown
extern unsigned int MakeKey (const char *s); #include "superfasthash.h"
extern unsigned int MakeKey (const char *s, size_t len);
extern unsigned int SuperFastHash (const char *data, size_t len);
void execLogfile(const char *fn, bool append = false); void execLogfile(const char *fn, bool append = false);

View file

@ -40,6 +40,7 @@
#include "c_dispatch.h" #include "c_dispatch.h"
#include "c_cvars.h" #include "c_cvars.h"
#include "doomtype.h"
// MACROS ------------------------------------------------------------------ // MACROS ------------------------------------------------------------------

View file

@ -34,7 +34,6 @@
#ifndef __V_TEXT_H__ #ifndef __V_TEXT_H__
#define __V_TEXT_H__ #define __V_TEXT_H__
#include "doomtype.h"
#include "v_font.h" #include "v_font.h"
struct FBrokenLines struct FBrokenLines

View file

@ -364,7 +364,7 @@ static FSoundID T_FindSound(const char * name)
} }
int id = S_AddSound(name, buffer); int id = S_AddSound(name, buffer);
S_HashSounds(); soundEngine->HashSounds();
return FSoundID(id); return FSoundID(id);
} }

View file

@ -4387,11 +4387,11 @@ int DLevelScript::GetActorProperty (int tid, int property)
return 0; return 0;
} }
case APROP_SeeSound: return GlobalACSStrings.AddString(actor->SeeSound); case APROP_SeeSound: return GlobalACSStrings.AddString(S_GetSoundName(actor->SeeSound));
case APROP_AttackSound: return GlobalACSStrings.AddString(actor->AttackSound); case APROP_AttackSound: return GlobalACSStrings.AddString(S_GetSoundName(actor->AttackSound));
case APROP_PainSound: return GlobalACSStrings.AddString(actor->PainSound); case APROP_PainSound: return GlobalACSStrings.AddString(S_GetSoundName(actor->PainSound));
case APROP_DeathSound: return GlobalACSStrings.AddString(actor->DeathSound); case APROP_DeathSound: return GlobalACSStrings.AddString(S_GetSoundName(actor->DeathSound));
case APROP_ActiveSound: return GlobalACSStrings.AddString(actor->ActiveSound); case APROP_ActiveSound: return GlobalACSStrings.AddString(S_GetSoundName(actor->ActiveSound));
case APROP_Species: return GlobalACSStrings.AddString(actor->GetSpecies()); case APROP_Species: return GlobalACSStrings.AddString(actor->GetSpecies());
case APROP_NameTag: return GlobalACSStrings.AddString(actor->GetTag()); case APROP_NameTag: return GlobalACSStrings.AddString(actor->GetTag());
case APROP_StencilColor:return actor->fillcolor; case APROP_StencilColor:return actor->fillcolor;
@ -4464,11 +4464,11 @@ int DLevelScript::CheckActorProperty (int tid, int property, int value)
// Strings are covered by GetActorProperty, but they're fairly // Strings are covered by GetActorProperty, but they're fairly
// heavy-duty, so make the check here. // heavy-duty, so make the check here.
case APROP_SeeSound: string = actor->SeeSound; break; case APROP_SeeSound: string = S_GetSoundName(actor->SeeSound); break;
case APROP_AttackSound: string = actor->AttackSound; break; case APROP_AttackSound: string = S_GetSoundName(actor->AttackSound); break;
case APROP_PainSound: string = actor->PainSound; break; case APROP_PainSound: string = S_GetSoundName(actor->PainSound); break;
case APROP_DeathSound: string = actor->DeathSound; break; case APROP_DeathSound: string = S_GetSoundName(actor->DeathSound); break;
case APROP_ActiveSound: string = actor->ActiveSound; break; case APROP_ActiveSound: string = S_GetSoundName(actor->ActiveSound); break;
case APROP_Species: string = actor->GetSpecies(); break; case APROP_Species: string = actor->GetSpecies(); break;
case APROP_NameTag: string = actor->GetTag(); break; case APROP_NameTag: string = actor->GetTag(); break;
case APROP_DamageType: string = actor->DamageType; break; case APROP_DamageType: string = actor->DamageType; break;
@ -5265,7 +5265,7 @@ int DLevelScript::SwapActorTeleFog(AActor *activator, int tid)
} }
else if (rettype == TypeSound) else if (rettype == TypeSound)
{ {
retval = GlobalACSStrings.AddString(FSoundID(retval)); retval = GlobalACSStrings.AddString(S_GetSoundName(FSoundID(retval)));
} }
} }
else if (rettype == TypeFloat64) else if (rettype == TypeFloat64)
@ -5953,7 +5953,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
if (args[0] == 0) if (args[0] == 0)
{ {
S_ChangeSoundVolume(activator, chan, volume); S_ChangeActorSoundVolume(activator, chan, volume);
} }
else else
{ {
@ -5962,7 +5962,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
while ((spot = it.Next()) != NULL) while ((spot = it.Next()) != NULL)
{ {
S_ChangeSoundVolume(spot, chan, volume); S_ChangeActorSoundVolume(spot, chan, volume);
} }
} }
} }

View file

@ -28,6 +28,7 @@
#include "templates.h" #include "templates.h"
#include "c_cvars.h" #include "c_cvars.h"
#include "w_wad.h" #include "w_wad.h"
#include "doomtype.h"
#ifdef _DEBUG #ifdef _DEBUG
#include "c_dispatch.h" #include "c_dispatch.h"
#endif #endif

View file

@ -731,7 +731,7 @@ void R_InitSkins (void)
} }
else else
{ {
int sndref = S_FindSoundNoHash (key); int sndref = soundEngine->FindSoundNoHash (key);
if (sndref != 0) if (sndref != 0)
{ {
S_AddPlayerSound (Skins[i].Name, Skins[i].gender, sndref, lump, true); S_AddPlayerSound (Skins[i].Name, Skins[i].gender, sndref, lump, true);
@ -911,7 +911,7 @@ void R_InitSkins (void)
if (Skins.Size() > PlayerClasses.Size ()) if (Skins.Size() > PlayerClasses.Size ())
{ // The sound table may have changed, so rehash it. { // The sound table may have changed, so rehash it.
S_HashSounds (); soundEngine->HashSounds ();
S_ShrinkPlayerSoundLists (); S_ShrinkPlayerSoundLists ();
} }
} }

View file

@ -1243,7 +1243,7 @@ FxExpression *FxStringCast::Resolve(FCompileContext &ctx)
if (basex->isConstant()) if (basex->isConstant())
{ {
ExpVal constval = static_cast<FxConstant *>(basex)->GetValue(); ExpVal constval = static_cast<FxConstant *>(basex)->GetValue();
FxExpression *x = new FxConstant(S_sfx[constval.GetInt()].name, ScriptPosition); FxExpression *x = new FxConstant(S_GetSoundName(constval.GetInt()), ScriptPosition);
delete this; delete this;
return x; return x;
} }

View file

@ -1184,7 +1184,7 @@ PSound::PSound()
void PSound::WriteValue(FSerializer &ar, const char *key,const void *addr) const void PSound::WriteValue(FSerializer &ar, const char *key,const void *addr) const
{ {
const char *cptr = *(const FSoundID *)addr; const char *cptr = S_GetSoundName(*(const FSoundID *)addr);
ar.StringPtr(key, cptr); ar.StringPtr(key, cptr);
} }

View file

@ -51,7 +51,7 @@ static void CastN2S(FString *a, int b) { FName name = FName(ENamedName(b)); *a =
static int CastS2Co(FString *b) { return V_GetColor(nullptr, *b); } static int CastS2Co(FString *b) { return V_GetColor(nullptr, *b); }
static void CastCo2S(FString *a, int b) { PalEntry c(b); a->Format("%02x %02x %02x", c.r, c.g, c.b); } static void CastCo2S(FString *a, int b) { PalEntry c(b); a->Format("%02x %02x %02x", c.r, c.g, c.b); }
static int CastS2So(FString *b) { return FSoundID(*b); } static int CastS2So(FString *b) { return FSoundID(*b); }
static void CastSo2S(FString *a, int b) { *a = S_sfx[b].name; } static void CastSo2S(FString* a, int b) { *a = S_GetSoundName(b); }
static void CastSID2S(FString *a, unsigned int b) { *a = (b >= sprites.Size()) ? "TNT1" : sprites[b].name; } static void CastSID2S(FString *a, unsigned int b) { *a = (b >= sprites.Size()) ? "TNT1" : sprites[b].name; }
static void CastTID2S(FString *a, int b) { auto tex = TexMan.GetTexture(*(FTextureID*)&b); *a = (tex == nullptr) ? "(null)" : tex->GetName().GetChars(); } static void CastTID2S(FString *a, int b) { auto tex = TexMan.GetTexture(*(FTextureID*)&b); *a = (tex == nullptr) ? "(null)" : tex->GetName().GetChars(); }

View file

@ -1837,7 +1837,7 @@ static void DoCast(const VMRegisters &reg, const VMFrame *f, int a, int b, int c
case CAST_So2S: case CAST_So2S:
ASSERTS(a); ASSERTD(b); ASSERTS(a); ASSERTD(b);
reg.s[a] = S_sfx[reg.d[b]].name; reg.s[a] = S_GetSoundName(reg.d[b]);
break; break;
case CAST_SID2S: case CAST_SID2S:

View file

@ -142,21 +142,21 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_StopSound, NativeStopSound)
return 0; return 0;
} }
DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_SoundPitch, S_ChangeSoundPitch) DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_SoundPitch, S_ChangeActorSoundPitch)
{ {
PARAM_SELF_PROLOGUE(AActor); PARAM_SELF_PROLOGUE(AActor);
PARAM_INT(channel); PARAM_INT(channel);
PARAM_FLOAT(pitch); PARAM_FLOAT(pitch);
S_ChangeSoundPitch(self, channel, pitch); S_ChangeActorSoundPitch(self, channel, pitch);
return 0; return 0;
} }
DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_SoundVolume, S_ChangeSoundVolume) DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_SoundVolume, S_ChangeActorSoundVolume)
{ {
PARAM_SELF_PROLOGUE(AActor); PARAM_SELF_PROLOGUE(AActor);
PARAM_INT(channel); PARAM_INT(channel);
PARAM_FLOAT(volume); PARAM_FLOAT(volume);
S_ChangeSoundVolume(self, channel, volume); S_ChangeActorSoundVolume(self, channel, volume);
return 0; return 0;
} }

View file

@ -1663,7 +1663,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FSoundID &sid, FSoundI
if (!arc.w->inObject() || def == nullptr || sid != *def) if (!arc.w->inObject() || def == nullptr || sid != *def)
{ {
arc.WriteKey(key); arc.WriteKey(key);
const char *sn = (const char*)sid; const char *sn = S_GetSoundName(sid);
if (sn != nullptr) arc.w->String(sn); if (sn != nullptr) arc.w->String(sn);
else arc.w->Null(); else arc.w->Null();
} }

View file

@ -35,8 +35,6 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "doomtype.h"
#include "oalsound.h" #include "oalsound.h"
#include "i_module.h" #include "i_module.h"
@ -49,9 +47,9 @@
#include "v_text.h" #include "v_text.h"
#include "c_cvars.h" #include "c_cvars.h"
#include "stats.h" #include "stats.h"
#include "s_music.h"
#include "zmusic/zmusic.h" #include "zmusic/zmusic.h"
EXTERN_CVAR (Float, snd_sfxvolume) EXTERN_CVAR (Float, snd_sfxvolume)
EXTERN_CVAR (Float, snd_musicvolume) EXTERN_CVAR (Float, snd_musicvolume)
CVAR (Int, snd_samplerate, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (Int, snd_samplerate, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
@ -260,20 +258,12 @@ void I_InitSound ()
return; return;
} }
#ifndef NO_OPENAL // Keep it simple: let everything except "null" init the sound.
// Simplify transition to OpenAL backend
if (stricmp(snd_backend, "fmod") == 0)
{
Printf (TEXTCOLOR_ORANGE "FMOD Ex sound system was removed, switching to OpenAL\n");
snd_backend = "openal";
}
#endif // NO_OPENAL
if (stricmp(snd_backend, "null") == 0) if (stricmp(snd_backend, "null") == 0)
{ {
GSnd = new NullSoundRenderer; GSnd = new NullSoundRenderer;
} }
else if(stricmp(snd_backend, "openal") == 0) else
{ {
#ifndef NO_OPENAL #ifndef NO_OPENAL
if (IsOpenALPresent()) if (IsOpenALPresent())
@ -282,11 +272,6 @@ void I_InitSound ()
} }
#endif #endif
} }
else
{
Printf (TEXTCOLOR_RED"%s: Unknown sound system specified\n", *snd_backend);
snd_backend = "null";
}
if (!GSnd || !GSnd->IsValid ()) if (!GSnd || !GSnd->IsValid ())
{ {
I_CloseSound(); I_CloseSound();
@ -300,8 +285,8 @@ void I_InitSound ()
void I_CloseSound () void I_CloseSound ()
{ {
// Free all loaded samples // Free all loaded samples. Beware that the sound engine may already have been deleted.
S_UnloadAllSounds(); if (soundEngine) soundEngine->UnloadAllSounds();
delete GSnd; delete GSnd;
GSnd = NULL; GSnd = NULL;

View file

@ -174,11 +174,7 @@ extern bool nosfx;
extern bool nosound; extern bool nosound;
void I_InitSound (); void I_InitSound ();
void I_CloseSound();
void S_ChannelEnded(FISoundChannel *schan);
void S_ChannelVirtualChanged(FISoundChannel *schan, bool is_virtual);
float S_GetRolloff(FRolloffInfo *rolloff, float distance, bool logarithmic);
FISoundChannel *S_GetChannel(void *syschan);
extern ReverbContainer *DefaultEnvironments[26]; extern ReverbContainer *DefaultEnvironments[26];

View file

@ -3,7 +3,6 @@
#include <stdio.h> #include <stdio.h>
#include "doomtype.h"
#include "vectors.h" #include "vectors.h"
#include "tarray.h" #include "tarray.h"
#include "zmusic/sounddecoder.h" #include "zmusic/sounddecoder.h"
@ -77,6 +76,7 @@ struct SoundListener
bool underwater; bool underwater;
bool valid; bool valid;
ReverbContainer *Environment; ReverbContainer *Environment;
void* ListenerObject;
}; };
// Default rolloff information. // Default rolloff information.
@ -121,4 +121,5 @@ class SoundStream;
#endif #endif

View file

@ -35,17 +35,18 @@
#include <functional> #include <functional>
#include <chrono> #include <chrono>
#include "doomstat.h" #include "c_cvars.h"
#include "templates.h" #include "templates.h"
#include "oalsound.h" #include "oalsound.h"
#include "c_dispatch.h" #include "c_dispatch.h"
#include "v_text.h" #include "v_text.h"
#include "i_module.h" #include "i_module.h"
#include "cmdlib.h" #include "cmdlib.h"
#include "menu/menu.h" #include "m_fixed.h"
#include "zmusic/sounddecoder.h" #include "zmusic/sounddecoder.h"
#include "filereadermusicinterface.h" #include "filereadermusicinterface.h"
const char *GetSampleTypeName(SampleType type); const char *GetSampleTypeName(SampleType type);
const char *GetChannelConfigName(ChannelConfig chan); const char *GetChannelConfigName(ChannelConfig chan);
@ -96,58 +97,6 @@ bool IsOpenALPresent()
void I_BuildALDeviceList(FOptionValues *opt)
{
opt->mValues.Resize(1);
opt->mValues[0].TextValue = "Default";
opt->mValues[0].Text = "Default";
#ifndef NO_OPENAL
if (IsOpenALPresent())
{
const ALCchar *names = (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") ?
alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER) :
alcGetString(NULL, ALC_DEVICE_SPECIFIER));
if (!names)
Printf("Failed to get device list: %s\n", alcGetString(NULL, alcGetError(NULL)));
else while (*names)
{
unsigned int i = opt->mValues.Reserve(1);
opt->mValues[i].TextValue = names;
opt->mValues[i].Text = names;
names += strlen(names) + 1;
}
}
#endif
}
void I_BuildALResamplersList(FOptionValues *opt)
{
opt->mValues.Resize(1);
opt->mValues[0].TextValue = "Default";
opt->mValues[0].Text = "Default";
#ifndef NO_OPENAL
if (!IsOpenALPresent())
return;
if (!alcGetCurrentContext() || !alIsExtensionPresent("AL_SOFT_source_resampler"))
return;
LPALGETSTRINGISOFT alGetStringiSOFT = reinterpret_cast<LPALGETSTRINGISOFT>(alGetProcAddress("alGetStringiSOFT"));
ALint num_resamplers = alGetInteger(AL_NUM_RESAMPLERS_SOFT);
unsigned int idx = opt->mValues.Reserve(num_resamplers);
for(ALint i = 0;i < num_resamplers;++i)
{
const ALchar *name = alGetStringiSOFT(AL_RESAMPLER_NAME_SOFT, i);
opt->mValues[idx].TextValue = name;
opt->mValues[idx].Text = name;
++idx;
}
#endif
}
ReverbContainer *ForcedEnvironment; ReverbContainer *ForcedEnvironment;
@ -544,22 +493,7 @@ static size_t GetChannelCount(ChannelConfig chans)
static float GetRolloff(const FRolloffInfo *rolloff, float distance) static float GetRolloff(const FRolloffInfo *rolloff, float distance)
{ {
if(distance <= rolloff->MinDistance) return soundEngine->GetRolloff(rolloff, distance);
return 1.f;
// Logarithmic rolloff has no max distance where it goes silent.
if(rolloff->RolloffType == ROLLOFF_Log)
return rolloff->MinDistance /
(rolloff->MinDistance + rolloff->RolloffFactor*(distance-rolloff->MinDistance));
if(distance >= rolloff->MaxDistance)
return 0.f;
float volume = (rolloff->MaxDistance - distance) / (rolloff->MaxDistance - rolloff->MinDistance);
if(rolloff->RolloffType == ROLLOFF_Linear)
return volume;
if(rolloff->RolloffType == ROLLOFF_Custom && S_SoundCurve.Size() > 0)
return S_SoundCurve[int(S_SoundCurve.Size() * (1.f - volume))] / 127.f;
return (powf(10.f, volume) - 1.f) / 9.f;
} }
ALCdevice *OpenALSoundRenderer::InitDevice() ALCdevice *OpenALSoundRenderer::InitDevice()
@ -983,7 +917,7 @@ void OpenALSoundRenderer::SetSfxVolume(float volume)
{ {
SfxVolume = volume; SfxVolume = volume;
FSoundChan *schan = Channels; FSoundChan *schan = soundEngine->GetChannels();
while(schan) while(schan)
{ {
if(schan->SysChannel != NULL) if(schan->SysChannel != NULL)
@ -1359,7 +1293,7 @@ void OpenALSoundRenderer::UnloadSound(SoundHandle sfx)
return; return;
ALuint buffer = GET_PTRID(sfx.data); ALuint buffer = GET_PTRID(sfx.data);
FSoundChan *schan = Channels; FSoundChan *schan = soundEngine->GetChannels();
while(schan) while(schan)
{ {
if(schan->SysChannel) if(schan->SysChannel)
@ -1495,7 +1429,7 @@ FISoundChannel *OpenALSoundRenderer::StartSound(SoundHandle sfx, float vol, int
FreeSfx.Pop(); FreeSfx.Pop();
FISoundChannel *chan = reuse_chan; FISoundChannel *chan = reuse_chan;
if(!chan) chan = S_GetChannel(MAKE_PTRID(source)); if(!chan) chan = soundEngine->GetChannel(MAKE_PTRID(source));
else chan->SysChannel = MAKE_PTRID(source); else chan->SysChannel = MAKE_PTRID(source);
chan->Rolloff.RolloffType = ROLLOFF_Log; chan->Rolloff.RolloffType = ROLLOFF_Log;
@ -1706,7 +1640,7 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener
FreeSfx.Pop(); FreeSfx.Pop();
FISoundChannel *chan = reuse_chan; FISoundChannel *chan = reuse_chan;
if(!chan) chan = S_GetChannel(MAKE_PTRID(source)); if(!chan) chan = soundEngine->GetChannel(MAKE_PTRID(source));
else chan->SysChannel = MAKE_PTRID(source); else chan->SysChannel = MAKE_PTRID(source);
chan->Rolloff = *rolloff; chan->Rolloff = *rolloff;
@ -1765,7 +1699,7 @@ void OpenALSoundRenderer::StopChannel(FISoundChannel *chan)
ALuint source = GET_PTRID(chan->SysChannel); ALuint source = GET_PTRID(chan->SysChannel);
// Release first, so it can be properly marked as evicted if it's being killed // Release first, so it can be properly marked as evicted if it's being killed
S_ChannelEnded(chan); soundEngine->ChannelEnded(chan);
ALint state = AL_INITIAL; ALint state = AL_INITIAL;
alGetSourcei(source, AL_SOURCE_STATE, &state); alGetSourcei(source, AL_SOURCE_STATE, &state);
@ -1789,7 +1723,7 @@ void OpenALSoundRenderer::ForceStopChannel(FISoundChannel *chan)
ALuint source = GET_PTRID(chan->SysChannel); ALuint source = GET_PTRID(chan->SysChannel);
if(!source) return; if(!source) return;
S_ChannelEnded(chan); soundEngine->ChannelEnded(chan);
FreeSource(source); FreeSource(source);
} }
@ -2009,7 +1943,7 @@ void OpenALSoundRenderer::UpdateListener(SoundListener *listener)
alFilterf(EnvFilters[1], AL_LOWPASS_GAINHF, 1.f); alFilterf(EnvFilters[1], AL_LOWPASS_GAINHF, 1.f);
// Apply the updated filters on the sources // Apply the updated filters on the sources
FSoundChan *schan = Channels; FSoundChan *schan = soundEngine->GetChannels();
while (schan) while (schan)
{ {
ALuint source = GET_PTRID(schan->SysChannel); ALuint source = GET_PTRID(schan->SysChannel);
@ -2022,7 +1956,7 @@ void OpenALSoundRenderer::UpdateListener(SoundListener *listener)
} }
} }
FSoundChan *schan = Channels; FSoundChan *schan = soundEngine->GetChannels();
while (schan) while (schan)
{ {
ALuint source = GET_PTRID(schan->SysChannel); ALuint source = GET_PTRID(schan->SysChannel);
@ -2047,7 +1981,7 @@ void OpenALSoundRenderer::UpdateListener(SoundListener *listener)
alFilterf(EnvFilters[1], AL_LOWPASS_GAIN, 1.f); alFilterf(EnvFilters[1], AL_LOWPASS_GAIN, 1.f);
alFilterf(EnvFilters[1], AL_LOWPASS_GAINHF, 1.f); alFilterf(EnvFilters[1], AL_LOWPASS_GAINHF, 1.f);
FSoundChan *schan = Channels; FSoundChan *schan = soundEngine->GetChannels();
while (schan) while (schan)
{ {
ALuint source = GET_PTRID(schan->SysChannel); ALuint source = GET_PTRID(schan->SysChannel);
@ -2060,7 +1994,7 @@ void OpenALSoundRenderer::UpdateListener(SoundListener *listener)
} }
} }
FSoundChan *schan = Channels; FSoundChan *schan = soundEngine->GetChannels();
while (schan) while (schan)
{ {
ALuint source = GET_PTRID(schan->SysChannel); ALuint source = GET_PTRID(schan->SysChannel);
@ -2236,7 +2170,7 @@ void OpenALSoundRenderer::PurgeStoppedSources()
if(state == AL_INITIAL || state == AL_PLAYING || state == AL_PAUSED) if(state == AL_INITIAL || state == AL_PLAYING || state == AL_PAUSED)
continue; continue;
FSoundChan *schan = Channels; FSoundChan *schan = soundEngine->GetChannels();
while(schan) while(schan)
{ {
if(schan->SysChannel != NULL && src == GET_PTRID(schan->SysChannel)) if(schan->SysChannel != NULL && src == GET_PTRID(schan->SysChannel))
@ -2358,7 +2292,7 @@ void OpenALSoundRenderer::LoadReverb(const ReverbContainer *env)
FSoundChan *OpenALSoundRenderer::FindLowestChannel() FSoundChan *OpenALSoundRenderer::FindLowestChannel()
{ {
FSoundChan *schan = Channels; FSoundChan *schan = soundEngine->GetChannels();
FSoundChan *lowest = NULL; FSoundChan *lowest = NULL;
while(schan) while(schan)
{ {
@ -2374,4 +2308,60 @@ FSoundChan *OpenALSoundRenderer::FindLowestChannel()
return lowest; return lowest;
} }
#include "menu/menu.h"
void I_BuildALDeviceList(FOptionValues* opt)
{
opt->mValues.Resize(1);
opt->mValues[0].TextValue = "Default";
opt->mValues[0].Text = "Default";
#ifndef NO_OPENAL
if (IsOpenALPresent())
{
const ALCchar* names = (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") ?
alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER) :
alcGetString(NULL, ALC_DEVICE_SPECIFIER));
if (!names)
Printf("Failed to get device list: %s\n", alcGetString(NULL, alcGetError(NULL)));
else while (*names)
{
unsigned int i = opt->mValues.Reserve(1);
opt->mValues[i].TextValue = names;
opt->mValues[i].Text = names;
names += strlen(names) + 1;
}
}
#endif
}
void I_BuildALResamplersList(FOptionValues* opt)
{
opt->mValues.Resize(1);
opt->mValues[0].TextValue = "Default";
opt->mValues[0].Text = "Default";
#ifndef NO_OPENAL
if (!IsOpenALPresent())
return;
if (!alcGetCurrentContext() || !alIsExtensionPresent("AL_SOFT_source_resampler"))
return;
LPALGETSTRINGISOFT alGetStringiSOFT = reinterpret_cast<LPALGETSTRINGISOFT>(alGetProcAddress("alGetStringiSOFT"));
ALint num_resamplers = alGetInteger(AL_NUM_RESAMPLERS_SOFT);
unsigned int idx = opt->mValues.Reserve(num_resamplers);
for (ALint i = 0; i < num_resamplers; ++i)
{
const ALchar* name = alGetStringiSOFT(AL_RESAMPLER_NAME_SOFT, i);
opt->mValues[idx].TextValue = name;
opt->mValues[idx].Text = name;
++idx;
}
#endif
}
#endif // NO_OPENAL #endif // NO_OPENAL

View file

@ -61,12 +61,6 @@
// TYPES ------------------------------------------------------------------- // TYPES -------------------------------------------------------------------
struct FRandomSoundList
{
TArray<uint32_t> Choices;
uint32_t Owner = 0;
};
struct FPlayerClassLookup struct FPlayerClassLookup
{ {
FString Name; FString Name;
@ -200,11 +194,9 @@ static int S_AddSound (const char *logicalname, int lumpnum, FScanner *sc=NULL);
// EXTERNAL DATA DECLARATIONS ---------------------------------------------- // EXTERNAL DATA DECLARATIONS ----------------------------------------------
extern int sfx_empty;
// PUBLIC DATA DEFINITIONS ------------------------------------------------- // PUBLIC DATA DEFINITIONS -------------------------------------------------
TArray<sfxinfo_t> S_sfx (128); //TArray<sfxinfo_t> S_sfx (128);
TMap<int, FString> HexenMusic; TMap<int, FString> HexenMusic;
// PRIVATE DATA DEFINITIONS ------------------------------------------------ // PRIVATE DATA DEFINITIONS ------------------------------------------------
@ -239,7 +231,6 @@ static const char *SICommandStrings[] =
NULL NULL
}; };
static TArray<FRandomSoundList> S_rnd;
static FMusicVolume *MusicVolumes; static FMusicVolume *MusicVolumes;
static TArray<FSavedPlayerSoundInfo> SavedPlayerSounds; static TArray<FSavedPlayerSoundInfo> SavedPlayerSounds;
@ -255,8 +246,6 @@ static int DefPlayerClass;
static uint8_t CurrentPitchMask; static uint8_t CurrentPitchMask;
static FRandom pr_randsound ("RandSound");
// CODE -------------------------------------------------------------------- // CODE --------------------------------------------------------------------
//========================================================================== //==========================================================================
@ -281,36 +270,6 @@ float S_GetMusicVolume (const char *music)
return 1.f; return 1.f;
} }
//==========================================================================
//
// S_HashSounds
//
// Fills in the next and index fields of S_sfx to form a working hash table.
//==========================================================================
void S_HashSounds ()
{
unsigned int i;
unsigned int j;
unsigned int size;
S_sfx.ShrinkToFit ();
size = S_sfx.Size ();
// Mark all buckets as empty
for (i = 0; i < size; i++)
S_sfx[i].index = 0;
// Now set up the chains
for (i = 1; i < size; i++)
{
j = MakeKey (S_sfx[i].name) % size;
S_sfx[i].next = S_sfx[j].index;
S_sfx[j].index = i;
}
}
//========================================================================== //==========================================================================
// //
// S_CheckIntegrity // S_CheckIntegrity
@ -320,6 +279,7 @@ void S_HashSounds ()
static bool S_CheckSound(sfxinfo_t *startsfx, sfxinfo_t *sfx, TArray<sfxinfo_t *> &chain) static bool S_CheckSound(sfxinfo_t *startsfx, sfxinfo_t *sfx, TArray<sfxinfo_t *> &chain)
{ {
auto &S_sfx = soundEngine->GetSounds();
sfxinfo_t *me = sfx; sfxinfo_t *me = sfx;
bool success = true; bool success = true;
unsigned siz = chain.Size(); unsigned siz = chain.Size();
@ -339,7 +299,7 @@ static bool S_CheckSound(sfxinfo_t *startsfx, sfxinfo_t *sfx, TArray<sfxinfo_t *
if (me->bRandomHeader) if (me->bRandomHeader)
{ {
const FRandomSoundList *list = &S_rnd[me->link]; const FRandomSoundList* list = soundEngine->ResolveRandomSound(me);
for (unsigned i = 0; i < list->Choices.Size(); ++i) for (unsigned i = 0; i < list->Choices.Size(); ++i)
{ {
auto rsfx = &S_sfx[list->Choices[i]]; auto rsfx = &S_sfx[list->Choices[i]];
@ -385,6 +345,7 @@ void S_CheckIntegrity()
TArray<sfxinfo_t *> chain; TArray<sfxinfo_t *> chain;
TArray<bool> broken; TArray<bool> broken;
auto &S_sfx = soundEngine->GetSounds();
broken.Resize(S_sfx.Size()); broken.Resize(S_sfx.Size());
memset(&broken[0], 0, sizeof(bool)*S_sfx.Size()); memset(&broken[0], 0, sizeof(bool)*S_sfx.Size());
for (unsigned i = 0; i < S_sfx.Size(); i++) for (unsigned i = 0; i < S_sfx.Size(); i++)
@ -404,34 +365,18 @@ void S_CheckIntegrity()
} }
} }
//==========================================================================
//
// S_PickReplacement
//
// Picks a replacement sound from the associated random list. If this sound
// is not the head of a random list, then the sound passed is returned.
//==========================================================================
int S_PickReplacement(int refid)
{
while (S_sfx[refid].bRandomHeader)
{
const FRandomSoundList *list = &S_rnd[S_sfx[refid].link];
refid = list->Choices[pr_randsound(list->Choices.Size())];
}
return refid;
}
//========================================================================== //==========================================================================
// //
// S_GetSoundMSLength // S_GetSoundMSLength
// //
// Returns duration of sound // Returns duration of sound
// This cannot be made a sound engine function due to the player sounds.
// //
//========================================================================== //==========================================================================
unsigned int S_GetMSLength(FSoundID sound) unsigned int S_GetMSLength(FSoundID sound)
{ {
auto &S_sfx = soundEngine->GetSounds();
if ((unsigned int)sound >= S_sfx.Size()) if ((unsigned int)sound >= S_sfx.Size())
{ {
return 0; return 0;
@ -453,7 +398,7 @@ unsigned int S_GetMSLength(FSoundID sound)
// I think the longest one makes more sense. // I think the longest one makes more sense.
int length = 0; int length = 0;
const FRandomSoundList *list = &S_rnd[sfx->link]; const FRandomSoundList* list = soundEngine->ResolveRandomSound(sfx);
for (auto &me : list->Choices) for (auto &me : list->Choices)
{ {
@ -469,7 +414,7 @@ unsigned int S_GetMSLength(FSoundID sound)
} }
} }
sfx = S_LoadSound(sfx); sfx = soundEngine->LoadSound(sfx, nullptr);
if (sfx != NULL) return GSnd->GetMSLength(sfx->data); if (sfx != NULL) return GSnd->GetMSLength(sfx->data);
else return 0; else return 0;
} }
@ -481,157 +426,6 @@ DEFINE_ACTION_FUNCTION(DObject,S_GetLength)
ACTION_RETURN_FLOAT(S_GetMSLength(sound_id)/1000.0); ACTION_RETURN_FLOAT(S_GetMSLength(sound_id)/1000.0);
} }
//==========================================================================
//
// S_CacheRandomSound
//
// Loads all sounds a random sound might play.
//
//==========================================================================
void S_CacheRandomSound (sfxinfo_t *sfx)
{
if (sfx->bRandomHeader)
{
const FRandomSoundList *list = &S_rnd[sfx->link];
for (unsigned i = 0; i < list->Choices.Size(); ++i)
{
sfx = &S_sfx[list->Choices[i]];
sfx->bUsed = true;
S_CacheSound (&S_sfx[list->Choices[i]]);
}
}
}
//==========================================================================
//
// S_FindSound
//
// Given a logical name, find the sound's index in S_sfx.
//==========================================================================
int S_FindSound (const char *logicalname)
{
int i;
if (logicalname != NULL)
{
i = S_sfx[MakeKey (logicalname) % S_sfx.Size ()].index;
while ((i != 0) && stricmp (S_sfx[i].name, logicalname))
i = S_sfx[i].next;
return i;
}
else
{
return 0;
}
}
//==========================================================================
//
// S_FindSoundNoHash
//
// Given a logical name, find the sound's index in S_sfx without
// using the hash table.
//==========================================================================
int S_FindSoundNoHash (const char *logicalname)
{
unsigned int i;
for (i = 1; i < S_sfx.Size (); i++)
{
if (stricmp (S_sfx[i].name, logicalname) == 0)
{
return i;
}
}
return 0;
}
//==========================================================================
//
// S_FindSoundByLump
//
// Given a sound lump, find the sound's index in S_sfx.
//==========================================================================
int S_FindSoundByLump (int lump)
{
if (lump != -1)
{
unsigned int i;
for (i = 1; i < S_sfx.Size (); i++)
if (S_sfx[i].lumpnum == lump)
return i;
}
return 0;
}
//==========================================================================
//
// S_AddSoundLump
//
// Adds a new sound mapping to S_sfx.
//==========================================================================
int S_AddSoundLump (const char *logicalname, int lump)
{
sfxinfo_t newsfx;
newsfx.data.Clear();
newsfx.data3d.Clear();
newsfx.name = logicalname;
newsfx.lumpnum = lump;
newsfx.next = 0;
newsfx.index = 0;
newsfx.Volume = 1;
newsfx.Attenuation = 1;
newsfx.PitchMask = CurrentPitchMask;
newsfx.NearLimit = 2;
newsfx.LimitRange = 256*256;
newsfx.bRandomHeader = false;
newsfx.bPlayerReserve = false;
newsfx.bLoadRAW = false;
newsfx.bPlayerCompat = false;
newsfx.b16bit = false;
newsfx.bUsed = false;
newsfx.bSingular = false;
newsfx.bTentative = false;
newsfx.bPlayerSilent = false;
newsfx.RawRate = 0;
newsfx.link = sfxinfo_t::NO_LINK;
newsfx.Rolloff.RolloffType = ROLLOFF_Doom;
newsfx.Rolloff.MinDistance = 0;
newsfx.Rolloff.MaxDistance = 0;
newsfx.LoopStart = -1;
return (int)S_sfx.Push (newsfx);
}
//==========================================================================
//
// S_FindSoundTentative
//
// Given a logical name, find the sound's index in S_sfx without
// using the hash table. If it does not exist, a new sound without
// an associated lump is created.
//==========================================================================
int S_FindSoundTentative (const char *name)
{
int id = S_FindSoundNoHash (name);
if (id == 0)
{
id = S_AddSoundLump (name, -1);
S_sfx[id].bTentative = true;
}
return id;
}
//========================================================================== //==========================================================================
// //
// S_AddSound // S_AddSound
@ -648,9 +442,10 @@ int S_AddSound (const char *logicalname, const char *lumpname, FScanner *sc)
static int S_AddSound (const char *logicalname, int lumpnum, FScanner *sc) static int S_AddSound (const char *logicalname, int lumpnum, FScanner *sc)
{ {
auto &S_sfx = soundEngine->GetSounds();
int sfxid; int sfxid;
sfxid = S_FindSoundNoHash (logicalname); sfxid = soundEngine->FindSoundNoHash (logicalname);
if (sfxid > 0) if (sfxid > 0)
{ // If the sound has already been defined, change the old definition { // If the sound has already been defined, change the old definition
@ -674,7 +469,7 @@ static int S_AddSound (const char *logicalname, int lumpnum, FScanner *sc)
} }
if (sfx->bRandomHeader) if (sfx->bRandomHeader)
{ {
FRandomSoundList *rnd = &S_rnd[sfx->link]; FRandomSoundList* rnd = soundEngine->ResolveRandomSound(sfx);
rnd->Choices.Reset(); rnd->Choices.Reset();
rnd->Owner = 0; rnd->Owner = 0;
} }
@ -691,7 +486,7 @@ static int S_AddSound (const char *logicalname, int lumpnum, FScanner *sc)
} }
else else
{ // Otherwise, create a new definition. { // Otherwise, create a new definition.
sfxid = S_AddSoundLump (logicalname, lumpnum); sfxid = soundEngine->AddSoundLump (logicalname, lumpnum, CurrentPitchMask);
} }
return sfxid; return sfxid;
@ -719,6 +514,7 @@ int S_AddPlayerSound (const char *pclass, int gender, int refid,
int S_AddPlayerSound (const char *pclass, int gender, int refid, int lumpnum, bool fromskin) int S_AddPlayerSound (const char *pclass, int gender, int refid, int lumpnum, bool fromskin)
{ {
auto &S_sfx = soundEngine->GetSounds();
FString fakename; FString fakename;
int id; int id;
@ -728,7 +524,7 @@ int S_AddPlayerSound (const char *pclass, int gender, int refid, int lumpnum, bo
fakename += '"'; fakename += '"';
fakename += S_sfx[refid].name; fakename += S_sfx[refid].name;
id = S_AddSoundLump (fakename, lumpnum); id = soundEngine->AddSoundLump (fakename, lumpnum, CurrentPitchMask);
int classnum = S_AddPlayerClass (pclass); int classnum = S_AddPlayerClass (pclass);
int soundlist = S_AddPlayerGender (classnum, gender); int soundlist = S_AddPlayerGender (classnum, gender);
@ -752,6 +548,7 @@ int S_AddPlayerSoundExisting (const char *pclass, int gender, int refid,
int classnum = S_AddPlayerClass (pclass); int classnum = S_AddPlayerClass (pclass);
int soundlist = S_AddPlayerGender (classnum, gender); int soundlist = S_AddPlayerGender (classnum, gender);
auto &S_sfx = soundEngine->GetSounds();
PlayerSounds[soundlist].AddSound (S_sfx[refid].link, aliasto); PlayerSounds[soundlist].AddSound (S_sfx[refid].link, aliasto);
if (fromskin) S_SavePlayerSound(pclass, gender, refid, aliasto, true); if (fromskin) S_SavePlayerSound(pclass, gender, refid, aliasto, true);
@ -928,7 +725,7 @@ void FPlayerSoundHashTable::MarkUsed()
{ {
for (Entry *probe = Buckets[i]; probe != NULL; probe = probe->Next) for (Entry *probe = Buckets[i]; probe != NULL; probe = probe->Next)
{ {
S_sfx[probe->SfxID].bUsed = true; soundEngine->MarkUsed(probe->SfxID);
} }
} }
} }
@ -944,8 +741,9 @@ void FPlayerSoundHashTable::MarkUsed()
void S_ClearSoundData() void S_ClearSoundData()
{ {
S_StopAllChannels(); soundEngine->StopAllChannels();
S_UnloadAllSounds(); soundEngine->UnloadAllSounds();
auto &S_sfx = soundEngine->GetSounds();
S_sfx.Clear(); S_sfx.Clear();
Ambients.Clear(); Ambients.Clear();
while (MusicVolumes != NULL) while (MusicVolumes != NULL)
@ -954,7 +752,7 @@ void S_ClearSoundData()
MusicVolumes = me->Next; MusicVolumes = me->Next;
M_Free(me); M_Free(me);
} }
S_rnd.Clear(); soundEngine->ClearRandoms();
NumPlayerReserves = 0; NumPlayerReserves = 0;
PlayerClassesIsSorted = false; PlayerClassesIsSorted = false;
@ -977,6 +775,7 @@ void S_ClearSoundData()
void S_ParseSndInfo (bool redefine) void S_ParseSndInfo (bool redefine)
{ {
auto &S_sfx = soundEngine->GetSounds();
int lump; int lump;
if (!redefine) SavedPlayerSounds.Clear(); // clear skin sounds only for initial parsing. if (!redefine) SavedPlayerSounds.Clear(); // clear skin sounds only for initial parsing.
@ -1005,13 +804,7 @@ void S_ParseSndInfo (bool redefine)
} }
} }
S_RestorePlayerSounds(); S_RestorePlayerSounds();
S_HashSounds (); soundEngine->HashSounds ();
S_sfx.ShrinkToFit ();
if (S_rnd.Size() > 0)
{
S_rnd.ShrinkToFit ();
}
S_ShrinkPlayerSoundLists (); S_ShrinkPlayerSoundLists ();
@ -1028,13 +821,7 @@ void S_ParseSndInfo (bool redefine)
void S_AddLocalSndInfo(int lump) void S_AddLocalSndInfo(int lump)
{ {
S_AddSNDINFO(lump); S_AddSNDINFO(lump);
S_HashSounds (); soundEngine->HashSounds ();
S_sfx.ShrinkToFit ();
if (S_rnd.Size() > 0)
{
S_rnd.ShrinkToFit ();
}
S_ShrinkPlayerSoundLists (); S_ShrinkPlayerSoundLists ();
S_CheckIntegrity(); S_CheckIntegrity();
@ -1050,6 +837,7 @@ void S_AddLocalSndInfo(int lump)
static void S_AddSNDINFO (int lump) static void S_AddSNDINFO (int lump)
{ {
auto &S_sfx = soundEngine->GetSounds();
bool skipToEndIf; bool skipToEndIf;
TArray<uint32_t> list; TArray<uint32_t> list;
@ -1087,7 +875,7 @@ static void S_AddSNDINFO (int lump)
ambient->sound = 0; ambient->sound = 0;
sc.MustGetString (); sc.MustGetString ();
ambient->sound = FSoundID(S_FindSoundTentative(sc.String)); ambient->sound = FSoundID(soundEngine->FindSoundTentative(sc.String));
ambient->attenuation = 0; ambient->attenuation = 0;
sc.MustGetString (); sc.MustGetString ();
@ -1205,7 +993,7 @@ static void S_AddSNDINFO (int lump)
int gender, refid, targid; int gender, refid, targid;
S_ParsePlayerSoundCommon (sc, pclass, gender, refid); S_ParsePlayerSoundCommon (sc, pclass, gender, refid);
targid = S_FindSoundNoHash (sc.String); targid = soundEngine->FindSoundNoHash (sc.String);
if (!S_sfx[targid].bPlayerReserve) if (!S_sfx[targid].bPlayerReserve)
{ {
sc.ScriptError ("%s is not a player sound", sc.String); sc.ScriptError ("%s is not a player sound", sc.String);
@ -1235,7 +1023,7 @@ static void S_AddSNDINFO (int lump)
int soundnum; int soundnum;
S_ParsePlayerSoundCommon (sc, pclass, gender, refid); S_ParsePlayerSoundCommon (sc, pclass, gender, refid);
soundnum = S_FindSoundTentative (sc.String); soundnum = soundEngine->FindSoundTentative (sc.String);
S_AddPlayerSoundExisting (pclass, gender, refid, soundnum); S_AddPlayerSoundExisting (pclass, gender, refid, soundnum);
} }
break; break;
@ -1251,7 +1039,7 @@ static void S_AddSNDINFO (int lump)
{ {
sfxfrom = S_sfx[sfxfrom].link; sfxfrom = S_sfx[sfxfrom].link;
} }
S_sfx[sfxfrom].link = S_FindSoundTentative (sc.String); S_sfx[sfxfrom].link = soundEngine->FindSoundTentative (sc.String);
S_sfx[sfxfrom].NearLimit = -1; // Aliases must use the original sound's limit. S_sfx[sfxfrom].NearLimit = -1; // Aliases must use the original sound's limit.
} }
break; break;
@ -1261,7 +1049,7 @@ static void S_AddSNDINFO (int lump)
int sfx; int sfx;
sc.MustGetString (); sc.MustGetString ();
sfx = S_FindSoundTentative (sc.String); sfx = soundEngine->FindSoundTentative (sc.String);
sc.MustGetNumber (); sc.MustGetNumber ();
S_sfx[sfx].NearLimit = MIN(MAX(sc.Number, 0), 255); S_sfx[sfx].NearLimit = MIN(MAX(sc.Number, 0), 255);
if (sc.CheckFloat()) if (sc.CheckFloat())
@ -1276,7 +1064,7 @@ static void S_AddSNDINFO (int lump)
int sfx; int sfx;
sc.MustGetString (); sc.MustGetString ();
sfx = S_FindSoundTentative (sc.String); sfx = soundEngine->FindSoundTentative (sc.String);
S_sfx[sfx].bSingular = true; S_sfx[sfx].bSingular = true;
} }
break; break;
@ -1286,7 +1074,7 @@ static void S_AddSNDINFO (int lump)
int sfx; int sfx;
sc.MustGetString (); sc.MustGetString ();
sfx = S_FindSoundTentative (sc.String); sfx = soundEngine->FindSoundTentative (sc.String);
sc.MustGetNumber (); sc.MustGetNumber ();
S_sfx[sfx].PitchMask = (1 << clamp (sc.Number, 0, 7)) - 1; S_sfx[sfx].PitchMask = (1 << clamp (sc.Number, 0, 7)) - 1;
} }
@ -1303,7 +1091,7 @@ static void S_AddSNDINFO (int lump)
int sfx; int sfx;
sc.MustGetString(); sc.MustGetString();
sfx = S_FindSoundTentative(sc.String); sfx = soundEngine->FindSoundTentative(sc.String);
sc.MustGetFloat(); sc.MustGetFloat();
S_sfx[sfx].Volume = (float)sc.Float; S_sfx[sfx].Volume = (float)sc.Float;
} }
@ -1314,7 +1102,7 @@ static void S_AddSNDINFO (int lump)
int sfx; int sfx;
sc.MustGetString(); sc.MustGetString();
sfx = S_FindSoundTentative(sc.String); sfx = soundEngine->FindSoundTentative(sc.String);
sc.MustGetFloat(); sc.MustGetFloat();
S_sfx[sfx].Attenuation = (float)sc.Float; S_sfx[sfx].Attenuation = (float)sc.Float;
} }
@ -1331,11 +1119,11 @@ static void S_AddSNDINFO (int lump)
if (sc.Compare("*")) if (sc.Compare("*"))
{ {
sfx = -1; sfx = -1;
rolloff = &S_Rolloff; rolloff = &soundEngine->GlobalRolloff();
} }
else else
{ {
sfx = S_FindSoundTentative(sc.String); sfx = soundEngine->FindSoundTentative(sc.String);
rolloff = &S_sfx[sfx].Rolloff; rolloff = &S_sfx[sfx].Rolloff;
} }
type = ROLLOFF_Doom; type = ROLLOFF_Doom;
@ -1376,7 +1164,7 @@ static void S_AddSNDINFO (int lump)
sc.MustGetStringName ("{"); sc.MustGetStringName ("{");
while (sc.GetString () && !sc.Compare ("}")) while (sc.GetString () && !sc.Compare ("}"))
{ {
uint32_t sfxto = S_FindSoundTentative (sc.String); uint32_t sfxto = soundEngine->FindSoundTentative (sc.String);
if (sfxto == random.Owner) if (sfxto == random.Owner)
{ {
Printf("Definition of random sound '%s' refers to itself recursively.\n", sc.String); Printf("Definition of random sound '%s' refers to itself recursively.\n", sc.String);
@ -1391,13 +1179,7 @@ static void S_AddSNDINFO (int lump)
} }
else if (list.Size() > 1) else if (list.Size() > 1)
{ // Only add non-empty random lists { // Only add non-empty random lists
auto index = S_rnd.Reserve(1); soundEngine->AddRandomSound(Owner, list);
auto &random = S_rnd.Last();
random.Choices = std::move(list);
random.Owner = Owner;
S_sfx[Owner].link = index;
S_sfx[Owner].bRandomHeader = true;
S_sfx[Owner].NearLimit = -1;
} }
} }
break; break;
@ -1513,6 +1295,7 @@ static void S_AddBloodSFX (int lumpnum)
if (rawlump != -1) if (rawlump != -1)
{ {
auto &S_sfx = soundEngine->GetSounds();
const char *name = Wads.GetLumpFullName(lumpnum); const char *name = Wads.GetLumpFullName(lumpnum);
sfxnum = S_AddSound(name, rawlump); sfxnum = S_AddSound(name, rawlump);
if (sfx->Format < 5 || sfx->Format > 12) if (sfx->Format < 5 || sfx->Format > 12)
@ -1572,7 +1355,8 @@ static void S_ParsePlayerSoundCommon (FScanner &sc, FString &pclass, int &gender
sc.MustGetString (); sc.MustGetString ();
gender = D_GenderToInt (sc.String); gender = D_GenderToInt (sc.String);
sc.MustGetString (); sc.MustGetString ();
refid = S_FindSoundNoHash (sc.String); refid = soundEngine->FindSoundNoHash (sc.String);
auto &S_sfx = soundEngine->GetSounds();
if (refid != 0 && !S_sfx[refid].bPlayerReserve && !S_sfx[refid].bTentative) if (refid != 0 && !S_sfx[refid].bPlayerReserve && !S_sfx[refid].bTentative)
{ {
sc.ScriptError ("%s has already been used for a non-player sound.", sc.String); sc.ScriptError ("%s has already been used for a non-player sound.", sc.String);
@ -1734,6 +1518,7 @@ int S_LookupPlayerSound (const char *pclass, int gender, const char *name)
int S_LookupPlayerSound (const char *pclass, int gender, FSoundID refid) int S_LookupPlayerSound (const char *pclass, int gender, FSoundID refid)
{ {
auto &S_sfx = soundEngine->GetSounds();
if (!S_sfx[refid].bPlayerReserve) if (!S_sfx[refid].bPlayerReserve)
{ // Not a player sound, so just return this sound { // Not a player sound, so just return this sound
return refid; return refid;
@ -1744,6 +1529,7 @@ int S_LookupPlayerSound (const char *pclass, int gender, FSoundID refid)
static int S_LookupPlayerSound (int classidx, int gender, FSoundID refid) static int S_LookupPlayerSound (int classidx, int gender, FSoundID refid)
{ {
auto &S_sfx = soundEngine->GetSounds();
int ingender = gender; int ingender = gender;
if (classidx == -1) if (classidx == -1)
@ -1847,6 +1633,7 @@ bool S_AreSoundsEquivalent (AActor *actor, int id1, int id2)
{ {
sfxinfo_t *sfx; sfxinfo_t *sfx;
auto &S_sfx = soundEngine->GetSounds();
if (id1 == id2) if (id1 == id2)
{ {
return true; return true;
@ -1998,52 +1785,6 @@ void S_MarkPlayerSounds (AActor *player)
} }
} }
//==========================================================================
//
// CCMD soundlist
//
//==========================================================================
CCMD (soundlist)
{
char lumpname[9];
unsigned int i;
lumpname[8] = 0;
for (i = 0; i < S_sfx.Size (); i++)
{
const sfxinfo_t *sfx = &S_sfx[i];
if (sfx->bRandomHeader)
{
Printf ("%3d. %s -> #%d {", i, sfx->name.GetChars(), sfx->link);
const FRandomSoundList *list = &S_rnd[sfx->link];
for (auto &me : list->Choices)
{
Printf (" %s ", S_sfx[me].name.GetChars());
}
Printf ("}\n");
}
else if (sfx->bPlayerReserve)
{
Printf ("%3d. %s <<player sound %d>>\n", i, sfx->name.GetChars(), sfx->link);
}
else if (S_sfx[i].lumpnum != -1)
{
Wads.GetLumpName (lumpname, sfx->lumpnum);
Printf ("%3d. %s (%s)\n", i, sfx->name.GetChars(), lumpname);
}
else if (S_sfx[i].link != sfxinfo_t::NO_LINK)
{
Printf ("%3d. %s -> %s\n", i, sfx->name.GetChars(), S_sfx[sfx->link].name.GetChars());
}
else
{
Printf ("%3d. %s **not present**\n", i, sfx->name.GetChars());
}
Printf(" PitchMask = %d\n", sfx->PitchMask);
}
}
//========================================================================== //==========================================================================
// //
// CCMD soundlinks // CCMD soundlinks
@ -2052,6 +1793,7 @@ CCMD (soundlist)
CCMD (soundlinks) CCMD (soundlinks)
{ {
auto &S_sfx = soundEngine->GetSounds();
unsigned int i; unsigned int i;
for (i = 0; i < S_sfx.Size (); i++) for (i = 0; i < S_sfx.Size (); i++)
@ -2075,6 +1817,7 @@ CCMD (soundlinks)
CCMD (playersounds) CCMD (playersounds)
{ {
auto &S_sfx = soundEngine->GetSounds();
const char *reserveNames[256]; const char *reserveNames[256];
unsigned int i; unsigned int i;
int j, k, l; int j, k, l;
@ -2119,7 +1862,7 @@ DEFINE_ACTION_FUNCTION(AAmbientSound, MarkAmbientSounds)
FAmbientSound *ambient = Ambients.CheckKey(self->args[0]); FAmbientSound *ambient = Ambients.CheckKey(self->args[0]);
if (ambient != NULL) if (ambient != NULL)
{ {
ambient->sound.MarkUsed(); soundEngine->MarkUsed(ambient->sound);
} }
return 0; return 0;
} }
@ -2251,13 +1994,12 @@ DEFINE_ACTION_FUNCTION(AAmbientSound, Activate)
{ {
if ((amb->type & 3) == 0 && amb->periodmin == 0) if ((amb->type & 3) == 0 && amb->periodmin == 0)
{ {
int sndnum = S_FindSound(amb->sound); if (amb->sound == 0)
if (sndnum == 0)
{ {
self->Destroy (); self->Destroy ();
return 0; return 0;
} }
amb->periodmin = ::Scale(S_GetMSLength(sndnum), TICRATE, 1000); amb->periodmin = ::Scale(S_GetMSLength(amb->sound), TICRATE, 1000);
} }
self->special1 = 0; self->special1 = 0;
@ -2343,7 +2085,7 @@ DEFINE_ACTION_FUNCTION(DObject, MarkSound)
{ {
PARAM_PROLOGUE; PARAM_PROLOGUE;
PARAM_SOUND(sound_id); PARAM_SOUND(sound_id);
sound_id.MarkUsed(); soundEngine->MarkUsed(sound_id);
return 0; return 0;
} }

1399
src/sound/s_doomsound.cpp Normal file

File diff suppressed because it is too large Load diff

89
src/sound/s_doomsound.h Normal file
View file

@ -0,0 +1,89 @@
#pragma once
// Information about one playing sound.
struct sector_t;
struct FPolyObj;
struct FLevelLocals;
void S_Init();
void S_InitData();
void S_Start();
void S_Shutdown();
void S_UpdateSounds(AActor* listenactor);
void S_SetSoundPaused(int state);
void S_PrecacheLevel(FLevelLocals* l);
// Start sound for thing at <ent>
void S_Sound(int channel, FSoundID sfxid, float volume, float attenuation);
void S_SoundPitch(int channel, FSoundID sfxid, float volume, float attenuation, float pitch);
void S_Sound (AActor *ent, int channel, FSoundID sfxid, float volume, float attenuation);
void S_SoundMinMaxDist (AActor *ent, int channel, FSoundID sfxid, float volume, float mindist, float maxdist);
void S_Sound (const FPolyObj *poly, int channel, FSoundID sfxid, float volume, float attenuation);
void S_Sound (const sector_t *sec, int channel, FSoundID sfxid, float volume, float attenuation);
void S_Sound(FLevelLocals *Level, const DVector3 &pos, int channel, FSoundID sfxid, float volume, float attenuation);
void S_SoundPitchActor (AActor *ent, int channel, FSoundID sfxid, float volume, float attenuation, float pitch);
// [Nash] Used by ACS and DECORATE
void S_PlaySound(AActor *a, int chan, FSoundID sid, float vol, float atten, bool local);
void S_PlaySoundPitch(AActor *a, int chan, FSoundID sid, float vol, float atten, bool local, float pitch);
// Stops a sound emanating from one of an emitter's channels.
void S_StopSound (AActor *ent, int channel);
void S_StopSound (const sector_t *sec, int channel);
void S_StopSound (const FPolyObj *poly, int channel);
// Moves all sounds from one mobj to another
void S_RelinkSound (AActor *from, AActor *to);
// Is the sound playing on one of the emitter's channels?
bool S_GetSoundPlayingInfo (const AActor *actor, int sound_id);
bool S_GetSoundPlayingInfo (const sector_t *sector, int sound_id);
bool S_GetSoundPlayingInfo (const FPolyObj *poly, int sound_id);
bool S_IsActorPlayingSomething (AActor *actor, int channel, int sound_id);
// Change a playing sound's volume
void S_ChangeActorSoundVolume(AActor *actor, int channel, double volume);
// Change a playing sound's pitch
void S_ChangeActorSoundPitch(AActor *actor, int channel, double pitch);
// Stores/retrieves playing channel information in an archive.
void S_SerializeSounds(FSerializer &arc);
void A_PlaySound(AActor *self, int soundid, int channel, double volume, int looping, double attenuation, int local, double pitch);
static void S_SetListener(AActor *listenactor);
void S_SoundReset();
void S_ResumeSound(bool state);
void S_PauseSound(bool state1, bool state);
void S_NoiseDebug();
inline void S_StopSound(int chan)
{
soundEngine->StopSound(chan);
}
inline void S_StopAllChannels()
{
soundEngine->StopAllChannels();
}
inline const char* S_GetSoundName(FSoundID id)
{
return soundEngine->GetSoundName(id);
}
inline int S_FindSound(const char* logicalname)
{
return soundEngine->FindSound(logicalname);
}
inline int S_FindSoundByResID(int rid)
{
return soundEngine->FindSoundByResID(rid);
}

View file

@ -32,44 +32,13 @@
** **
*/ */
#include "doomtype.h" #include "s_soundinternal.h"
#include "s_sound.h"
#include "sc_man.h" #include "sc_man.h"
#include "cmdlib.h"
#include "templates.h" #include "templates.h"
#include "w_wad.h"
#include "i_system.h"
#include "m_misc.h" #include "m_misc.h"
#include "c_cvars.h"
#include "c_dispatch.h"
#include "vm.h"
#include "dobject.h"
#include "menu/menu.h"
FReverbField ReverbFields[] =
void InitReverbMenu();
REVERB_PROPERTIES SavedProperties;
ReverbContainer *CurrentEnv;
extern ReverbContainer *ForcedEnvironment;
// These are for internal use only and not supposed to be user-settable
CVAR(String, reverbedit_name, "", CVAR_NOSET);
CVAR(Int, reverbedit_id1, 0, CVAR_NOSET);
CVAR(Int, reverbedit_id2, 0, CVAR_NOSET);
CVAR(String, reverbsavename, "", 0);
struct FReverbField
{
int Min, Max;
float REVERB_PROPERTIES::*Float;
int REVERB_PROPERTIES::*Int;
unsigned int Flag;
};
static const FReverbField ReverbFields[] =
{ {
{ 0, 25, 0, &REVERB_PROPERTIES::Environment, 0 }, { 0, 25, 0, &REVERB_PROPERTIES::Environment, 0 },
{ 1000, 100000, &REVERB_PROPERTIES::EnvSize, 0, 0 }, { 1000, 100000, &REVERB_PROPERTIES::EnvSize, 0, 0 },
@ -110,8 +79,9 @@ static const FReverbField ReverbFields[] =
{ 0, 0, 0, 0, 7 } { 0, 0, 0, 0, 7 }
}; };
#define NUM_REVERB_FIELDS (int(countof(ReverbFields))) #define NUM_REVERB_FIELDS (int(countof(ReverbFields)))
int NumReverbs = NUM_REVERB_FIELDS;
static const char *ReverbFieldNames[NUM_REVERB_FIELDS+2] = const char *ReverbFieldNames[NUM_REVERB_FIELDS+2] =
{ {
"Environment", "Environment",
"EnvironmentSize", "EnvironmentSize",
@ -534,9 +504,8 @@ void S_AddEnvironment (ReverbContainer *settings)
} }
} }
static void ReadReverbDef (int lump) void S_ReadReverbDef (FScanner &sc)
{ {
FScanner sc;
const ReverbContainer *def; const ReverbContainer *def;
ReverbContainer *newenv; ReverbContainer *newenv;
REVERB_PROPERTIES props; REVERB_PROPERTIES props;
@ -545,10 +514,9 @@ static void ReadReverbDef (int lump)
bool inited[NUM_REVERB_FIELDS]; bool inited[NUM_REVERB_FIELDS];
uint8_t bools[32]; uint8_t bools[32];
sc.OpenLumpNum(lump);
while (sc.GetString ()) while (sc.GetString ())
{ {
name = copystring (sc.String); name = strdup (sc.String);
sc.MustGetNumber (); sc.MustGetNumber ();
id1 = sc.Number; id1 = sc.Number;
sc.MustGetNumber (); sc.MustGetNumber ();
@ -638,17 +606,6 @@ static void ReadReverbDef (int lump)
} }
} }
void S_ParseReverbDef ()
{
int lump, lastlump = 0;
while ((lump = Wads.FindLump ("REVERBS", &lastlump)) != -1)
{
ReadReverbDef (lump);
}
InitReverbMenu();
}
void S_UnloadReverbDef () void S_UnloadReverbDef ()
{ {
ReverbContainer *probe = Environments; ReverbContainer *probe = Environments;
@ -660,7 +617,7 @@ void S_UnloadReverbDef ()
if (!probe->Builtin) if (!probe->Builtin)
{ {
if (pNext != NULL) *pNext = probe->Next; if (pNext != NULL) *pNext = probe->Next;
delete[] const_cast<char *>(probe->Name); free(const_cast<char *>(probe->Name));
delete probe; delete probe;
} }
else else
@ -672,476 +629,3 @@ void S_UnloadReverbDef ()
Environments = &Off; Environments = &Off;
} }
CUSTOM_CVAR(Bool, eaxedit_test, false, CVAR_NOINITCALL)
{
if (self)
{
ForcedEnvironment = CurrentEnv;
}
else
{
ForcedEnvironment = nullptr;
}
}
struct EnvFlag
{
const char *Name;
int CheckboxControl;
unsigned int Flag;
};
inline int HIBYTE(int i)
{
return (i >> 8) & 255;
}
inline int LOBYTE(int i)
{
return i & 255;
}
uint16_t FirstFreeID(uint16_t base, bool builtin)
{
int tryCount = 0;
int priID = HIBYTE(base);
// If the original sound is built-in, start searching for a new
// primary ID at 30.
if (builtin)
{
for (priID = 30; priID < 256; ++priID)
{
if (S_FindEnvironment(priID << 8) == nullptr)
{
break;
}
}
if (priID == 256)
{ // Oh well.
priID = 30;
}
}
for (;;)
{
uint16_t lastID = Environments->ID;
const ReverbContainer *env = Environments->Next;
// Find the lowest-numbered free ID with the same primary ID as base
// If none are available, add 100 to base's primary ID and try again.
// If that fails, then the primary ID gets incremented
// by 1 until a match is found. If all the IDs searchable by this
// algorithm are in use, then you're in trouble.
while (env != nullptr)
{
if (HIBYTE(env->ID) > priID)
{
break;
}
if (HIBYTE(env->ID) == priID)
{
if (HIBYTE(lastID) == priID)
{
if (LOBYTE(env->ID) - LOBYTE(lastID) > 1)
{
return lastID + 1;
}
}
lastID = env->ID;
}
env = env->Next;
}
if (LOBYTE(lastID) == 255)
{
if (tryCount == 0)
{
base += 100 * 256;
tryCount = 1;
}
else
{
base += 256;
}
}
else if (builtin && lastID == 0)
{
return priID << 8;
}
else
{
return lastID + 1;
}
}
}
FString SuggestNewName(const ReverbContainer *env)
{
const ReverbContainer *probe = nullptr;
char text[32];
size_t len;
int number, numdigits;
strncpy(text, env->Name, 31);
text[31] = 0;
len = strlen(text);
while (text[len - 1] >= '0' && text[len - 1] <= '9')
{
len--;
}
number = atoi(text + len);
if (number < 1)
{
number = 1;
}
if (text[len - 1] != ' ' && len < 31)
{
text[len++] = ' ';
}
for (; number < 100000; ++number)
{
if (number < 10) numdigits = 1;
else if (number < 100) numdigits = 2;
else if (number < 1000) numdigits = 3;
else if (number < 10000)numdigits = 4;
else numdigits = 5;
if (len + numdigits > 31)
{
len = 31 - numdigits;
}
mysnprintf(text + len, countof(text) - len, "%d", number);
probe = Environments;
while (probe != nullptr)
{
if (stricmp(probe->Name, text) == 0)
break;
probe = probe->Next;
}
if (probe == nullptr)
{
break;
}
}
return text;
}
void ExportEnvironments(const char *filename, uint32_t count, const ReverbContainer **envs)
{
FString dest = M_GetDocumentsPath() + filename;
FileWriter *f = FileWriter::Open(dest);
if (f != nullptr)
{
for (uint32_t i = 0; i < count; ++i)
{
const ReverbContainer *env = envs[i];
const ReverbContainer *base;
size_t j;
if ((unsigned int)env->Properties.Environment < 26)
{
base = DefaultEnvironments[env->Properties.Environment];
}
else
{
base = nullptr;
}
f->Printf("\"%s\" %u %u\n{\n", env->Name, HIBYTE(env->ID), LOBYTE(env->ID));
for (j = 0; j < countof(ReverbFields); ++j)
{
const FReverbField *ctl = &ReverbFields[j];
const char *ctlName = ReverbFieldNames[j];
if (ctlName)
{
if (j == 0 ||
(ctl->Float && base->Properties.*ctl->Float != env->Properties.*ctl->Float) ||
(ctl->Int && base->Properties.*ctl->Int != env->Properties.*ctl->Int))
{
f->Printf("\t%s ", ctlName);
if (ctl->Float)
{
float v = env->Properties.*ctl->Float * 1000;
int vi = int(v >= 0.0 ? v + 0.5 : v - 0.5);
f->Printf("%d.%03d\n", vi / 1000, abs(vi % 1000));
}
else
{
f->Printf("%d\n", env->Properties.*ctl->Int);
}
}
else
{
if ((1 << ctl->Flag) & (env->Properties.Flags ^ base->Properties.Flags))
{
f->Printf("\t%s %s\n", ctlName, ctl->Flag & env->Properties.Flags ? "true" : "false");
}
}
}
}
f->Printf("}\n\n");
}
delete f;
}
else
{
M_StartMessage("Save failed", 1);
}
}
DEFINE_ACTION_FUNCTION(DReverbEdit, GetValue)
{
PARAM_PROLOGUE;
PARAM_INT(index);
float v = 0;
if (index >= 0 && index < (int)countof(ReverbFields))
{
auto rev = &ReverbFields[index];
if (rev->Int != nullptr)
{
v = float(CurrentEnv->Properties.*(rev->Int));
}
else if (rev->Float != nullptr)
{
v = CurrentEnv->Properties.*(rev->Float);
}
else
{
v = !!(CurrentEnv->Properties.Flags & (1 << int(rev->Flag)));
}
}
ACTION_RETURN_FLOAT(v);
return 1;
}
DEFINE_ACTION_FUNCTION(DReverbEdit, SetValue)
{
PARAM_PROLOGUE;
PARAM_INT(index);
PARAM_FLOAT(v);
if (index >= 0 && index < (int)countof(ReverbFields))
{
auto rev = &ReverbFields[index];
if (rev->Int != nullptr)
{
v = CurrentEnv->Properties.*(rev->Int) = clamp<int>(int(v), rev->Min, rev->Max);
}
else if (rev->Float != nullptr)
{
v = CurrentEnv->Properties.*(rev->Float) = clamp<float>(float(v), rev->Min / 1000.f, rev->Max / 1000.f);
}
else
{
if (v == 0) CurrentEnv->Properties.Flags &= ~(1 << int(rev->Flag));
else CurrentEnv->Properties.Flags |= (1 << int(rev->Flag));
}
}
ACTION_RETURN_FLOAT(v);
return 1;
}
DEFINE_ACTION_FUNCTION(DReverbEdit, GrayCheck)
{
PARAM_PROLOGUE;
ACTION_RETURN_BOOL(CurrentEnv->Builtin);
return 1;
}
DEFINE_ACTION_FUNCTION(DReverbEdit, GetSelectedEnvironment)
{
PARAM_PROLOGUE;
if (numret > 1)
{
numret = 2;
ret[1].SetInt(CurrentEnv ? CurrentEnv->ID : -1);
}
if (numret > 0)
{
ret[0].SetString(CurrentEnv ? CurrentEnv->Name : "");
}
return numret;
}
DEFINE_ACTION_FUNCTION(DReverbEdit, FillSelectMenu)
{
PARAM_PROLOGUE;
PARAM_STRING(ccmd);
PARAM_OBJECT(desc, DOptionMenuDescriptor);
desc->mItems.Clear();
for (auto env = Environments; env != nullptr; env = env->Next)
{
FStringf text("(%d, %d) %s", HIBYTE(env->ID), LOBYTE(env->ID), env->Name);
FStringf cmd("%s \"%s\"", ccmd.GetChars(), env->Name);
PClass *cls = PClass::FindClass("OptionMenuItemCommand");
if (cls != nullptr && cls->IsDescendantOf("OptionMenuItem"))
{
auto func = dyn_cast<PFunction>(cls->FindSymbol("Init", true));
if (func != nullptr)
{
DMenuItemBase *item = (DMenuItemBase*)cls->CreateNew();
VMValue params[] = { item, &text, FName(cmd).GetIndex(), false, true };
VMCall(func->Variants[0].Implementation, params, 5, nullptr, 0);
desc->mItems.Push((DMenuItemBase*)item);
}
}
}
return 0;
}
static TArray<std::pair<ReverbContainer*, bool>> SaveState;
DEFINE_ACTION_FUNCTION(DReverbEdit, FillSaveMenu)
{
PARAM_PROLOGUE;
PARAM_OBJECT(desc, DOptionMenuDescriptor);
desc->mItems.Resize(4);
SaveState.Clear();
for (auto env = Environments; env != nullptr; env = env->Next)
{
if (!env->Builtin)
{
int index = (int)SaveState.Push(std::make_pair(env, false));
FStringf text("(%d, %d) %s", HIBYTE(env->ID), LOBYTE(env->ID), env->Name);
PClass *cls = PClass::FindClass("OptionMenuItemReverbSaveSelect");
if (cls != nullptr && cls->IsDescendantOf("OptionMenuItem"))
{
auto func = dyn_cast<PFunction>(cls->FindSymbol("Init", true));
if (func != nullptr)
{
DMenuItemBase *item = (DMenuItemBase*)cls->CreateNew();
VMValue params[] = { item, &text, index, FName("OnOff").GetIndex() };
VMCall(func->Variants[0].Implementation, params, 4, nullptr, 0);
desc->mItems.Push((DMenuItemBase*)item);
}
}
}
}
return 0;
}
DEFINE_ACTION_FUNCTION(DReverbEdit, GetSaveSelection)
{
PARAM_PROLOGUE;
PARAM_INT(index);
bool res = false;
if ((unsigned)index <= SaveState.Size())
{
res = SaveState[index].second;
}
ACTION_RETURN_BOOL(res);
}
DEFINE_ACTION_FUNCTION(DReverbEdit, ToggleSaveSelection)
{
PARAM_PROLOGUE;
PARAM_INT(index);
if ((unsigned)index <= SaveState.Size())
{
SaveState[index].second = !SaveState[index].second;
}
return 0;
}
CCMD(savereverbs)
{
if (SaveState.Size() == 0) return;
TArray<const ReverbContainer*> toSave;
for (auto &p : SaveState)
{
if (p.second) toSave.Push(p.first);
}
ExportEnvironments(reverbsavename, toSave.Size(), &toSave[0]);
SaveState.Clear();
}
static void SelectEnvironment(const char *envname)
{
for (auto env = Environments; env != nullptr; env = env->Next)
{
if (!strcmp(env->Name, envname))
{
CurrentEnv = env;
SavedProperties = env->Properties;
if (eaxedit_test) ForcedEnvironment = env;
// Set up defaults for a new environment based on this one.
int newid = FirstFreeID(env->ID, env->Builtin);
UCVarValue cv;
cv.Int = HIBYTE(newid);
reverbedit_id1.ForceSet(cv, CVAR_Int);
cv.Int = LOBYTE(newid);
reverbedit_id2.ForceSet(cv, CVAR_Int);
FString selectname = SuggestNewName(env);
cv.String = selectname.GetChars();
reverbedit_name.ForceSet(cv, CVAR_String);
return;
}
}
}
void InitReverbMenu()
{
// Make sure that the editor's variables are properly initialized.
SelectEnvironment("Off");
}
CCMD(selectenvironment)
{
if (argv.argc() > 1)
{
auto str = argv[1];
SelectEnvironment(str);
}
else
InitReverbMenu();
}
CCMD(revertenvironment)
{
if (CurrentEnv != nullptr)
{
CurrentEnv->Properties = SavedProperties;
}
}
CCMD(createenvironment)
{
if (S_FindEnvironment(reverbedit_name))
{
M_StartMessage(FStringf("An environment with the name '%s' already exists", *reverbedit_name), 1);
return;
}
int id = (reverbedit_id1 << 8) + reverbedit_id2;
if (S_FindEnvironment(id))
{
M_StartMessage(FStringf("An environment with the ID (%d, %d) already exists", *reverbedit_id1, *reverbedit_id2), 1);
return;
}
auto newenv = new ReverbContainer;
newenv->Builtin = false;
newenv->ID = id;
newenv->Name = copystring(reverbedit_name);
newenv->Next = nullptr;
newenv->Properties = CurrentEnv->Properties;
S_AddEnvironment(newenv);
SelectEnvironment(newenv->Name);
}
CCMD(reverbedit)
{
C_DoCommand("openmenu reverbedit");
}

555
src/sound/s_reverbedit.cpp Normal file
View file

@ -0,0 +1,555 @@
/*
**
** reverb editor
**
**---------------------------------------------------------------------------
** Copyright 2005-2016 Randy Heit
** Copyright 2005-2017 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include "doomtype.h"
#include "s_sound.h"
#include "sc_man.h"
#include "cmdlib.h"
#include "templates.h"
#include "w_wad.h"
#include "i_system.h"
#include "m_misc.h"
#include "c_cvars.h"
#include "c_dispatch.h"
#include "vm.h"
#include "dobject.h"
#include "menu/menu.h"
void S_ReadReverbDef (FScanner &sc);
extern ReverbContainer *ForcedEnvironment;
ReverbContainer *CurrentEnv;
REVERB_PROPERTIES SavedProperties;
extern FReverbField ReverbFields[];
extern const char* ReverbFieldNames[];
extern int NumReverbs;
// These are for internal use only and not supposed to be user-settable
CVAR(String, reverbedit_name, "", CVAR_NOSET);
CVAR(Int, reverbedit_id1, 0, CVAR_NOSET);
CVAR(Int, reverbedit_id2, 0, CVAR_NOSET);
CVAR(String, reverbsavename, "", 0);
CUSTOM_CVAR(Bool, eaxedit_test, false, CVAR_NOINITCALL)
{
if (self)
{
ForcedEnvironment = CurrentEnv;
}
else
{
ForcedEnvironment = nullptr;
}
}
struct EnvFlag
{
const char *Name;
int CheckboxControl;
unsigned int Flag;
};
inline int HIBYTE(int i)
{
return (i >> 8) & 255;
}
inline int LOBYTE(int i)
{
return i & 255;
}
uint16_t FirstFreeID(uint16_t base, bool builtin)
{
int tryCount = 0;
int priID = HIBYTE(base);
// If the original sound is built-in, start searching for a new
// primary ID at 30.
if (builtin)
{
for (priID = 30; priID < 256; ++priID)
{
if (S_FindEnvironment(priID << 8) == nullptr)
{
break;
}
}
if (priID == 256)
{ // Oh well.
priID = 30;
}
}
for (;;)
{
uint16_t lastID = Environments->ID;
const ReverbContainer *env = Environments->Next;
// Find the lowest-numbered free ID with the same primary ID as base
// If none are available, add 100 to base's primary ID and try again.
// If that fails, then the primary ID gets incremented
// by 1 until a match is found. If all the IDs searchable by this
// algorithm are in use, then you're in trouble.
while (env != nullptr)
{
if (HIBYTE(env->ID) > priID)
{
break;
}
if (HIBYTE(env->ID) == priID)
{
if (HIBYTE(lastID) == priID)
{
if (LOBYTE(env->ID) - LOBYTE(lastID) > 1)
{
return lastID + 1;
}
}
lastID = env->ID;
}
env = env->Next;
}
if (LOBYTE(lastID) == 255)
{
if (tryCount == 0)
{
base += 100 * 256;
tryCount = 1;
}
else
{
base += 256;
}
}
else if (builtin && lastID == 0)
{
return priID << 8;
}
else
{
return lastID + 1;
}
}
}
FString SuggestNewName(const ReverbContainer *env)
{
const ReverbContainer *probe = nullptr;
char text[32];
size_t len;
int number, numdigits;
strncpy(text, env->Name, 31);
text[31] = 0;
len = strlen(text);
while (text[len - 1] >= '0' && text[len - 1] <= '9')
{
len--;
}
number = atoi(text + len);
if (number < 1)
{
number = 1;
}
if (text[len - 1] != ' ' && len < 31)
{
text[len++] = ' ';
}
for (; number < 100000; ++number)
{
if (number < 10) numdigits = 1;
else if (number < 100) numdigits = 2;
else if (number < 1000) numdigits = 3;
else if (number < 10000)numdigits = 4;
else numdigits = 5;
if (len + numdigits > 31)
{
len = 31 - numdigits;
}
mysnprintf(text + len, countof(text) - len, "%d", number);
probe = Environments;
while (probe != nullptr)
{
if (stricmp(probe->Name, text) == 0)
break;
probe = probe->Next;
}
if (probe == nullptr)
{
break;
}
}
return text;
}
void ExportEnvironments(const char *filename, uint32_t count, const ReverbContainer **envs)
{
FString dest = M_GetDocumentsPath() + filename;
FileWriter *f = FileWriter::Open(dest);
if (f != nullptr)
{
for (uint32_t i = 0; i < count; ++i)
{
const ReverbContainer *env = envs[i];
const ReverbContainer *base;
size_t j;
if ((unsigned int)env->Properties.Environment < 26)
{
base = DefaultEnvironments[env->Properties.Environment];
}
else
{
base = nullptr;
}
f->Printf("\"%s\" %u %u\n{\n", env->Name, HIBYTE(env->ID), LOBYTE(env->ID));
for (j = 0; j < NumReverbs; ++j)
{
const FReverbField *ctl = &ReverbFields[j];
const char *ctlName = ReverbFieldNames[j];
if (ctlName)
{
if (j == 0 ||
(ctl->Float && base->Properties.*ctl->Float != env->Properties.*ctl->Float) ||
(ctl->Int && base->Properties.*ctl->Int != env->Properties.*ctl->Int))
{
f->Printf("\t%s ", ctlName);
if (ctl->Float)
{
float v = env->Properties.*ctl->Float * 1000;
int vi = int(v >= 0.0 ? v + 0.5 : v - 0.5);
f->Printf("%d.%03d\n", vi / 1000, abs(vi % 1000));
}
else
{
f->Printf("%d\n", env->Properties.*ctl->Int);
}
}
else
{
if ((1 << ctl->Flag) & (env->Properties.Flags ^ base->Properties.Flags))
{
f->Printf("\t%s %s\n", ctlName, ctl->Flag & env->Properties.Flags ? "true" : "false");
}
}
}
}
f->Printf("}\n\n");
}
delete f;
}
else
{
M_StartMessage("Save failed", 1);
}
}
DEFINE_ACTION_FUNCTION(DReverbEdit, GetValue)
{
PARAM_PROLOGUE;
PARAM_INT(index);
float v = 0;
if (index >= 0 && index < NumReverbs)
{
auto rev = &ReverbFields[index];
if (rev->Int != nullptr)
{
v = float(CurrentEnv->Properties.*(rev->Int));
}
else if (rev->Float != nullptr)
{
v = CurrentEnv->Properties.*(rev->Float);
}
else
{
v = !!(CurrentEnv->Properties.Flags & (1 << int(rev->Flag)));
}
}
ACTION_RETURN_FLOAT(v);
return 1;
}
DEFINE_ACTION_FUNCTION(DReverbEdit, SetValue)
{
PARAM_PROLOGUE;
PARAM_INT(index);
PARAM_FLOAT(v);
if (index >= 0 && index < NumReverbs)
{
auto rev = &ReverbFields[index];
if (rev->Int != nullptr)
{
v = CurrentEnv->Properties.*(rev->Int) = clamp<int>(int(v), rev->Min, rev->Max);
}
else if (rev->Float != nullptr)
{
v = CurrentEnv->Properties.*(rev->Float) = clamp<float>(float(v), rev->Min / 1000.f, rev->Max / 1000.f);
}
else
{
if (v == 0) CurrentEnv->Properties.Flags &= ~(1 << int(rev->Flag));
else CurrentEnv->Properties.Flags |= (1 << int(rev->Flag));
}
}
ACTION_RETURN_FLOAT(v);
return 1;
}
DEFINE_ACTION_FUNCTION(DReverbEdit, GrayCheck)
{
PARAM_PROLOGUE;
ACTION_RETURN_BOOL(CurrentEnv->Builtin);
return 1;
}
DEFINE_ACTION_FUNCTION(DReverbEdit, GetSelectedEnvironment)
{
PARAM_PROLOGUE;
if (numret > 1)
{
numret = 2;
ret[1].SetInt(CurrentEnv ? CurrentEnv->ID : -1);
}
if (numret > 0)
{
ret[0].SetString(CurrentEnv ? CurrentEnv->Name : "");
}
return numret;
}
DEFINE_ACTION_FUNCTION(DReverbEdit, FillSelectMenu)
{
PARAM_PROLOGUE;
PARAM_STRING(ccmd);
PARAM_OBJECT(desc, DOptionMenuDescriptor);
desc->mItems.Clear();
for (auto env = Environments; env != nullptr; env = env->Next)
{
FStringf text("(%d, %d) %s", HIBYTE(env->ID), LOBYTE(env->ID), env->Name);
FStringf cmd("%s \"%s\"", ccmd.GetChars(), env->Name);
PClass *cls = PClass::FindClass("OptionMenuItemCommand");
if (cls != nullptr && cls->IsDescendantOf("OptionMenuItem"))
{
auto func = dyn_cast<PFunction>(cls->FindSymbol("Init", true));
if (func != nullptr)
{
DMenuItemBase *item = (DMenuItemBase*)cls->CreateNew();
VMValue params[] = { item, &text, FName(cmd).GetIndex(), false, true };
VMCall(func->Variants[0].Implementation, params, 5, nullptr, 0);
desc->mItems.Push((DMenuItemBase*)item);
}
}
}
return 0;
}
static TArray<std::pair<ReverbContainer*, bool>> SaveState;
DEFINE_ACTION_FUNCTION(DReverbEdit, FillSaveMenu)
{
PARAM_PROLOGUE;
PARAM_OBJECT(desc, DOptionMenuDescriptor);
desc->mItems.Resize(4);
SaveState.Clear();
for (auto env = Environments; env != nullptr; env = env->Next)
{
if (!env->Builtin)
{
int index = (int)SaveState.Push(std::make_pair(env, false));
FStringf text("(%d, %d) %s", HIBYTE(env->ID), LOBYTE(env->ID), env->Name);
PClass *cls = PClass::FindClass("OptionMenuItemReverbSaveSelect");
if (cls != nullptr && cls->IsDescendantOf("OptionMenuItem"))
{
auto func = dyn_cast<PFunction>(cls->FindSymbol("Init", true));
if (func != nullptr)
{
DMenuItemBase *item = (DMenuItemBase*)cls->CreateNew();
VMValue params[] = { item, &text, index, FName("OnOff").GetIndex() };
VMCall(func->Variants[0].Implementation, params, 4, nullptr, 0);
desc->mItems.Push((DMenuItemBase*)item);
}
}
}
}
return 0;
}
DEFINE_ACTION_FUNCTION(DReverbEdit, GetSaveSelection)
{
PARAM_PROLOGUE;
PARAM_INT(index);
bool res = false;
if ((unsigned)index <= SaveState.Size())
{
res = SaveState[index].second;
}
ACTION_RETURN_BOOL(res);
}
DEFINE_ACTION_FUNCTION(DReverbEdit, ToggleSaveSelection)
{
PARAM_PROLOGUE;
PARAM_INT(index);
if ((unsigned)index <= SaveState.Size())
{
SaveState[index].second = !SaveState[index].second;
}
return 0;
}
CCMD(savereverbs)
{
if (SaveState.Size() == 0) return;
TArray<const ReverbContainer*> toSave;
for (auto &p : SaveState)
{
if (p.second) toSave.Push(p.first);
}
ExportEnvironments(reverbsavename, toSave.Size(), &toSave[0]);
SaveState.Clear();
}
static void SelectEnvironment(const char *envname)
{
for (auto env = Environments; env != nullptr; env = env->Next)
{
if (!strcmp(env->Name, envname))
{
CurrentEnv = env;
SavedProperties = env->Properties;
if (eaxedit_test) ForcedEnvironment = env;
// Set up defaults for a new environment based on this one.
int newid = FirstFreeID(env->ID, env->Builtin);
UCVarValue cv;
cv.Int = HIBYTE(newid);
reverbedit_id1.ForceSet(cv, CVAR_Int);
cv.Int = LOBYTE(newid);
reverbedit_id2.ForceSet(cv, CVAR_Int);
FString selectname = SuggestNewName(env);
cv.String = selectname.GetChars();
reverbedit_name.ForceSet(cv, CVAR_String);
return;
}
}
}
void InitReverbMenu()
{
// Make sure that the editor's variables are properly initialized.
SelectEnvironment("Off");
}
CCMD(selectenvironment)
{
if (argv.argc() > 1)
{
auto str = argv[1];
SelectEnvironment(str);
}
else
InitReverbMenu();
}
CCMD(revertenvironment)
{
if (CurrentEnv != nullptr)
{
CurrentEnv->Properties = SavedProperties;
}
}
CCMD(createenvironment)
{
if (S_FindEnvironment(reverbedit_name))
{
M_StartMessage(FStringf("An environment with the name '%s' already exists", *reverbedit_name), 1);
return;
}
int id = (reverbedit_id1 << 8) + reverbedit_id2;
if (S_FindEnvironment(id))
{
M_StartMessage(FStringf("An environment with the ID (%d, %d) already exists", *reverbedit_id1, *reverbedit_id2), 1);
return;
}
auto newenv = new ReverbContainer;
newenv->Builtin = false;
newenv->ID = id;
newenv->Name = copystring(reverbedit_name);
newenv->Next = nullptr;
newenv->Properties = CurrentEnv->Properties;
S_AddEnvironment(newenv);
SelectEnvironment(newenv->Name);
}
CCMD(reverbedit)
{
C_DoCommand("openmenu reverbedit");
}
// This is here because it depends on Doom's resource management and is not universal.
void S_ParseReverbDef ()
{
int lump, lastlump = 0;
while ((lump = Wads.FindLump ("REVERBS", &lastlump)) != -1)
{
FScanner sc;
sc.OpenLumpNum(lump);
S_ReadReverbDef (sc);;
}
InitReverbMenu();
}

View file

@ -1433,13 +1433,13 @@ void SN_MarkPrecacheSounds(int sequence, seqtype_t type)
{ {
FSoundSequence *seq = Sequences[sequence]; FSoundSequence *seq = Sequences[sequence];
seq->StopSound.MarkUsed(); soundEngine->MarkUsed(seq->StopSound);
for (int i = 0; GetCommand(seq->Script[i]) != SS_CMD_END; ++i) for (int i = 0; GetCommand(seq->Script[i]) != SS_CMD_END; ++i)
{ {
int cmd = GetCommand(seq->Script[i]); int cmd = GetCommand(seq->Script[i]);
if (cmd == SS_CMD_PLAY || cmd == SS_CMD_PLAYREPEAT || cmd == SS_CMD_PLAYLOOP) if (cmd == SS_CMD_PLAY || cmd == SS_CMD_PLAYREPEAT || cmd == SS_CMD_PLAYLOOP)
{ {
FSoundID(GetData(seq->Script[i])).MarkUsed(); soundEngine->MarkUsed(GetData(seq->Script[i]));
} }
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -28,7 +28,6 @@
#ifndef __S_SOUND__ #ifndef __S_SOUND__
#define __S_SOUND__ #define __S_SOUND__
#include "doomtype.h"
#include "i_soundinternal.h" #include "i_soundinternal.h"
class AActor; class AActor;
@ -36,342 +35,37 @@ class FScanner;
class FSerializer; class FSerializer;
struct FLevelLocals; struct FLevelLocals;
// #include "s_soundinternal.h"
// SoundFX struct. #include "s_doomsound.h"
//
struct sfxinfo_t
{
// Next field is for use by the system sound interface.
// A non-null data means the sound has been loaded.
SoundHandle data;
// Also for the sound interface. Used for 3D positional
// sounds, may be the same as data.
SoundHandle data3d;
FString name; // [RH] Sound name defined in SNDINFO
int lumpnum; // lump number of sfx
unsigned int next, index; // [RH] For hashing
float Volume;
uint8_t PitchMask;
int16_t NearLimit; // 0 means unlimited
float LimitRange; // Range for sound limiting (squared for faster computations)
unsigned bRandomHeader:1;
unsigned bPlayerReserve:1;
unsigned bLoadRAW:1;
unsigned bPlayerCompat:1;
unsigned b16bit:1;
unsigned bUsed:1;
unsigned bSingular:1;
unsigned bTentative:1;
unsigned bPlayerSilent:1; // This player sound is intentionally silent.
int RawRate; // Sample rate to use when bLoadRAW is true
int LoopStart; // -1 means no specific loop defined
unsigned int link;
enum { NO_LINK = 0xffffffff };
FRolloffInfo Rolloff;
float Attenuation; // Multiplies the attenuation passed to S_Sound.
void MarkUsed(); // Marks this sound as used.
};
// Rolloff types
enum
{
ROLLOFF_Doom, // Linear rolloff with a logarithmic volume scale
ROLLOFF_Linear, // Linear rolloff with a linear volume scale
ROLLOFF_Log, // Logarithmic rolloff (standard hardware type)
ROLLOFF_Custom // Lookup volume from SNDCURVE
};
int S_FindSound (const char *logicalname);
// the complete set of sound effects
extern TArray<sfxinfo_t> S_sfx;
// An index into the S_sfx[] array.
class FSoundID
{
public:
FSoundID() = default;
FSoundID(int id)
{
ID = id;
}
FSoundID(const char *name)
{
ID = S_FindSound(name);
}
FSoundID(const FString &name)
{
ID = S_FindSound(name.GetChars());
}
FSoundID(const FSoundID &other) = default;
FSoundID &operator=(const FSoundID &other) = default;
FSoundID &operator=(const char *name)
{
ID = S_FindSound(name);
return *this;
}
FSoundID &operator=(const FString &name)
{
ID = S_FindSound(name.GetChars());
return *this;
}
bool operator !=(FSoundID other) const
{
return ID != other.ID;
}
bool operator !=(int other) const
{
return ID != other;
}
operator int() const
{
return ID;
}
operator FString() const
{
return ID ? S_sfx[ID].name : "";
}
operator const char *() const
{
return ID ? S_sfx[ID].name.GetChars() : NULL;
}
void MarkUsed() const
{
S_sfx[ID].MarkUsed();
}
private:
int ID;
protected:
enum EDummy { NoInit };
FSoundID(EDummy) {}
};
class FSoundIDNoInit : public FSoundID
{
public:
FSoundIDNoInit() : FSoundID(NoInit) {}
using FSoundID::operator=;
};
extern FRolloffInfo S_Rolloff;
extern TArray<uint8_t> S_SoundCurve;
// Information about one playing sound.
struct sector_t;
struct FPolyObj;
struct FSoundChan : public FISoundChannel
{
FSoundChan *NextChan; // Next channel in this list.
FSoundChan **PrevChan; // Previous channel in this list.
FSoundID SoundID; // Sound ID of playing sound.
FSoundID OrgID; // Sound ID of sound used to start this channel.
float Volume;
int16_t Pitch; // Pitch variation.
uint8_t EntChannel; // Actor's sound channel.
int8_t Priority;
int16_t NearLimit;
uint8_t SourceType;
float LimitRange;
union
{
AActor *Actor; // Used for position and velocity.
const sector_t *Sector; // Sector for area sounds.
const FPolyObj *Poly; // Polyobject sound source.
float Point[3]; // Sound is not attached to any source.
};
};
extern FSoundChan *Channels;
void S_ReturnChannel(FSoundChan *chan);
void S_EvictAllChannels();
void S_StopChannel(FSoundChan *chan);
void S_LinkChannel(FSoundChan *chan, FSoundChan **head);
void S_UnlinkChannel(FSoundChan *chan);
// Initializes sound stuff, including volume
// Sets channels, SFX and music volume,
// allocates channel buffer, sets S_sfx lookup.
//
void S_Init ();
void S_InitData ();
void S_Shutdown ();
// Per level startup code. // Per level startup code.
// Kills playing sounds at start of level and starts new music. // Kills playing sounds at start of level and starts new music.
// //
void S_Start ();
// Called after a level is loaded. Ensures that most sounds are loaded. // Called after a level is loaded. Ensures that most sounds are loaded.
void S_PrecacheLevel (FLevelLocals *l);
// Loads a sound, including any random sounds it might reference.
void S_CacheSound (sfxinfo_t *sfx);
// Start sound for thing at <ent>
void S_Sound (int channel, FSoundID sfxid, float volume, float attenuation);
void S_Sound (AActor *ent, int channel, FSoundID sfxid, float volume, float attenuation);
void S_SoundMinMaxDist (AActor *ent, int channel, FSoundID sfxid, float volume, float mindist, float maxdist);
void S_Sound (const FPolyObj *poly, int channel, FSoundID sfxid, float volume, float attenuation);
void S_Sound (const sector_t *sec, int channel, FSoundID sfxid, float volume, float attenuation);
void S_Sound(FLevelLocals *Level, const DVector3 &pos, int channel, FSoundID sfxid, float volume, float attenuation);
void S_SoundPitch (int channel, FSoundID sfxid, float volume, float attenuation, float pitch);
void S_SoundPitchActor (AActor *ent, int channel, FSoundID sfxid, float volume, float attenuation, float pitch);
// [Nash] Used by ACS and DECORATE
void S_PlaySound(AActor *a, int chan, FSoundID sid, float vol, float atten, bool local);
void S_PlaySoundPitch(AActor *a, int chan, FSoundID sid, float vol, float atten, bool local, float pitch);
// sound channels
// channel 0 never willingly overrides
// other channels (1-7) always override a playing sound on that channel
//
// CHAN_AUTO searches down from channel 7 until it finds a channel not in use
// CHAN_WEAPON is for weapons
// CHAN_VOICE is for oof, sight, or other voice sounds
// CHAN_ITEM is for small things and item pickup
// CHAN_BODY is for generic body sounds
// CHAN_PICKUP can optionally be set as a local sound only for "compatibility"
#define CHAN_AUTO 0
#define CHAN_WEAPON 1
#define CHAN_VOICE 2
#define CHAN_ITEM 3
#define CHAN_BODY 4
// Channel alias for sector sounds. These define how listener height is
// used when calculating 3D sound volume.
#define CHAN_FLOOR 1 // Sound comes from the floor.
#define CHAN_CEILING 2 // Sound comes from the ceiling.
#define CHAN_FULLHEIGHT 3 // Sound comes entire height of the sector.
#define CHAN_INTERIOR 4 // Sound comes height between floor and ceiling.
// modifier flags
#define CHAN_LISTENERZ 8
#define CHAN_MAYBE_LOCAL 16
#define CHAN_UI 32 // Do not record sound in savegames.
#define CHAN_NOPAUSE 64 // Do not pause this sound in menus.
#define CHAN_AREA 128 // Sound plays from all around. Only valid with sector sounds.
#define CHAN_LOOP 256
#define CHAN_PICKUP (CHAN_ITEM|CHAN_MAYBE_LOCAL)
#define CHAN_IS3D 1 // internal: Sound is 3D.
#define CHAN_EVICTED 2 // internal: Sound was evicted.
#define CHAN_FORGETTABLE 4 // internal: Forget channel data when sound stops.
#define CHAN_JUSTSTARTED 512 // internal: Sound has not been updated yet.
#define CHAN_ABSTIME 1024// internal: Start time is absolute and does not depend on current time.
#define CHAN_VIRTUAL 2048// internal: Channel is currently virtual
#define CHAN_NOSTOP 4096// only for A_PlaySound. Does not start if channel is playing something.
// sound attenuation values
#define ATTN_NONE 0.f // full volume the entire level
#define ATTN_NORM 1.f
#define ATTN_IDLE 1.001f
#define ATTN_STATIC 3.f // diminish very rapidly with distance
struct FSoundLoadBuffer; struct FSoundLoadBuffer;
int S_PickReplacement (int refid);
void S_CacheRandomSound (sfxinfo_t *sfx);
// Checks if a copy of this sound is already playing.
bool S_CheckSingular (int sound_id);
// Stops a sound emanating from one of an emitter's channels.
void S_StopSound (AActor *ent, int channel);
void S_StopSound (const sector_t *sec, int channel);
void S_StopSound (const FPolyObj *poly, int channel);
// Stops an origin-less sound from playing from this channel.
void S_StopSound (int channel);
// Stop sound for all channels
void S_StopAllChannels (void);
// Is the sound playing on one of the emitter's channels?
bool S_GetSoundPlayingInfo (const AActor *actor, int sound_id);
bool S_GetSoundPlayingInfo (const sector_t *sector, int sound_id);
bool S_GetSoundPlayingInfo (const FPolyObj *poly, int sound_id);
bool S_IsActorPlayingSomething (AActor *actor, int channel, int sound_id);
// Change a playing sound's volume
void S_ChangeSoundVolume(AActor *actor, int channel, double volume);
// Change a playing sound's pitch
void S_ChangeSoundPitch(AActor *actor, int channel, double pitch);
void S_SetPitch(FSoundChan *chan, float dpitch);
// Moves all sounds from one mobj to another
void S_RelinkSound (AActor *from, AActor *to);
// Stores/retrieves playing channel information in an archive.
void S_SerializeSounds(FSerializer &arc);
// Stop and resume music, during game PAUSE.
void S_PauseSound (bool notmusic, bool notsfx);
void S_ResumeSound (bool notsfx);
void S_SetSoundPaused (int state);
//
// Updates music & sounds
//
void S_UpdateSounds (AActor *listener);
void S_RestoreEvictedChannels();
// [RH] S_sfx "maintenance" routines // [RH] S_sfx "maintenance" routines
void S_ClearSoundData(); void S_ClearSoundData();
void S_ParseSndInfo (bool redefine); void S_ParseSndInfo (bool redefine);
void S_ParseReverbDef ();
void S_UnloadReverbDef ();
void S_HashSounds ();
int S_FindSoundNoHash (const char *logicalname);
bool S_AreSoundsEquivalent (AActor *actor, int id1, int id2); bool S_AreSoundsEquivalent (AActor *actor, int id1, int id2);
bool S_AreSoundsEquivalent (AActor *actor, const char *name1, const char *name2); bool S_AreSoundsEquivalent (AActor *actor, const char *name1, const char *name2);
int S_LookupPlayerSound (const char *playerclass, int gender, const char *logicalname); int S_LookupPlayerSound (const char *playerclass, int gender, const char *logicalname);
int S_LookupPlayerSound (const char *playerclass, int gender, FSoundID refid); int S_LookupPlayerSound (const char *playerclass, int gender, FSoundID refid);
int S_FindSkinnedSound (AActor *actor, FSoundID refid); int S_FindSkinnedSound (AActor *actor, FSoundID refid);
int S_FindSkinnedSoundEx (AActor *actor, const char *logicalname, const char *extendedname); int S_FindSkinnedSoundEx (AActor *actor, const char *logicalname, const char *extendedname);
int S_FindSoundByLump (int lump);
int S_AddSound (const char *logicalname, const char *lumpname, FScanner *sc=NULL); // Add sound by lumpname int S_AddSound (const char *logicalname, const char *lumpname, FScanner *sc=NULL); // Add sound by lumpname
int S_AddSoundLump (const char *logicalname, int lump); // Add sound by lump index
int S_AddPlayerSound (const char *playerclass, const int gender, int refid, const char *lumpname); int S_AddPlayerSound (const char *playerclass, const int gender, int refid, const char *lumpname);
int S_AddPlayerSound (const char *playerclass, const int gender, int refid, int lumpnum, bool fromskin=false); int S_AddPlayerSound (const char *playerclass, const int gender, int refid, int lumpnum, bool fromskin=false);
int S_AddPlayerSoundExisting (const char *playerclass, const int gender, int refid, int aliasto, bool fromskin=false); int S_AddPlayerSoundExisting (const char *playerclass, const int gender, int refid, int aliasto, bool fromskin=false);
void S_MarkPlayerSounds (AActor *player); void S_MarkPlayerSounds (AActor *player);
void S_ShrinkPlayerSoundLists (); void S_ShrinkPlayerSoundLists ();
void S_UnloadSound (sfxinfo_t *sfx);
sfxinfo_t *S_LoadSound(sfxinfo_t *sfx, FSoundLoadBuffer *pBuffer = nullptr);
unsigned int S_GetMSLength(FSoundID sound); unsigned int S_GetMSLength(FSoundID sound);
void A_PlaySound(AActor *self, int soundid, int channel, double volume, int looping, double attenuation, int local, double pitch);
// [RH] Prints sound debug info to the screen. // [RH] Prints sound debug info to the screen.
// Modelled after Hexen's noise cheat. // Modelled after Hexen's noise cheat.
void S_NoiseDebug ();
extern ReverbContainer *Environments;
extern ReverbContainer *DefaultEnvironments[26];
void S_SetEnvironment (const ReverbContainer *settings);
ReverbContainer *S_FindEnvironment (const char *name);
ReverbContainer *S_FindEnvironment (int id);
void S_AddEnvironment (ReverbContainer *settings);
void S_UnloadAllSounds();
void S_SoundReset();
#endif #endif

398
src/sound/s_soundinternal.h Normal file
View file

@ -0,0 +1,398 @@
#pragma once
#include "i_sound.h"
struct FRandomSoundList
{
TArray<uint32_t> Choices;
uint32_t Owner = 0;
};
extern int sfx_empty;
//
// SoundFX struct.
//
struct sfxinfo_t
{
// Next field is for use by the system sound interface.
// A non-null data means the sound has been loaded.
SoundHandle data;
// Also for the sound interface. Used for 3D positional
// sounds, may be the same as data.
SoundHandle data3d;
FString name; // [RH] Sound name defined in SNDINFO
int lumpnum; // lump number of sfx
unsigned int next, index; // [RH] For hashing
float Volume;
int ResourceId; // Resource ID as implemented by Blood. Not used by Doom but added for completeness.
uint8_t PitchMask;
int16_t NearLimit; // 0 means unlimited
float LimitRange; // Range for sound limiting (squared for faster computations)
unsigned bRandomHeader:1;
unsigned bLoadRAW:1;
unsigned b16bit:1;
unsigned bUsed:1;
unsigned bSingular:1;
unsigned bTentative:1;
unsigned bPlayerReserve : 1;
unsigned bPlayerCompat : 1;
unsigned bPlayerSilent:1; // This player sound is intentionally silent.
int RawRate; // Sample rate to use when bLoadRAW is true
int LoopStart; // -1 means no specific loop defined
unsigned int link;
enum { NO_LINK = 0xffffffff };
FRolloffInfo Rolloff;
float Attenuation; // Multiplies the attenuation passed to S_Sound.
void MarkUsed(); // Marks this sound as used.
};
// Rolloff types
enum
{
ROLLOFF_Doom, // Linear rolloff with a logarithmic volume scale
ROLLOFF_Linear, // Linear rolloff with a linear volume scale
ROLLOFF_Log, // Logarithmic rolloff (standard hardware type)
ROLLOFF_Custom // Lookup volume from SNDCURVE
};
int S_FindSound(const char *logicalname);
int S_FindSoundByResID(int snd_id);
// An index into the S_sfx[] array.
class FSoundID
{
public:
FSoundID() = default;
static FSoundID byResId(int ndx)
{
return FSoundID(S_FindSoundByResID(ndx));
}
FSoundID(int id)
{
ID = id;
}
FSoundID(const char *name)
{
ID = S_FindSound(name);
}
FSoundID(const FString &name)
{
ID = S_FindSound(name.GetChars());
}
FSoundID(const FSoundID &other) = default;
FSoundID &operator=(const FSoundID &other) = default;
FSoundID &operator=(const char *name)
{
ID = S_FindSound(name);
return *this;
}
FSoundID &operator=(const FString &name)
{
ID = S_FindSound(name.GetChars());
return *this;
}
bool operator !=(FSoundID other) const
{
return ID != other.ID;
}
bool operator !=(int other) const
{
return ID != other;
}
operator int() const
{
return ID;
}
private:
int ID;
protected:
enum EDummy { NoInit };
FSoundID(EDummy) {}
};
class FSoundIDNoInit : public FSoundID
{
public:
FSoundIDNoInit() : FSoundID(NoInit) {}
using FSoundID::operator=;
};
struct FSoundChan : public FISoundChannel
{
FSoundChan *NextChan; // Next channel in this list.
FSoundChan **PrevChan; // Previous channel in this list.
FSoundID SoundID; // Sound ID of playing sound.
FSoundID OrgID; // Sound ID of sound used to start this channel.
float Volume;
int16_t Pitch; // Pitch variation.
uint8_t EntChannel; // Actor's sound channel.
int8_t Priority;
int16_t NearLimit;
uint8_t SourceType;
float LimitRange;
union
{
const void *Source;
float Point[3]; // Sound is not attached to any source.
};
};
// sound channels
// channel 0 never willingly overrides
// other channels (1-7) always override a playing sound on that channel
//
// CHAN_AUTO searches down from channel 7 until it finds a channel not in use
// CHAN_WEAPON is for weapons
// CHAN_VOICE is for oof, sight, or other voice sounds
// CHAN_ITEM is for small things and item pickup
// CHAN_BODY is for generic body sounds
// CHAN_PICKUP can optionally be set as a local sound only for "compatibility"
enum
{
CHAN_AUTO = 0,
CHAN_WEAPON = 1,
CHAN_VOICE = 2,
CHAN_ITEM = 3,
CHAN_BODY = 4,
CHAN_5 = 5,
CHAN_6 = 6,
CHAN_7 = 7,
// Channel alias for sector sounds. These define how listener height is
// used when calculating 3D sound volume.
CHAN_FLOOR = 1, // Sound comes from the floor.
CHAN_CEILING = 2, // Sound comes from the ceiling.
CHAN_FULLHEIGHT = 3, // Sound comes entire height of the sector.
CHAN_INTERIOR = 4, // Sound comes height between floor and ceiling.
// modifier flags
CHAN_LISTENERZ = 8,
CHAN_MAYBE_LOCAL = 16,
CHAN_UI = 32, // Do not record sound in savegames.
CHAN_NOPAUSE = 64, // Do not pause this sound in menus.
CHAN_AREA = 128, // Sound plays from all around. Only valid with sector sounds.
CHAN_LOOP = 256,
CHAN_PICKUP = (CHAN_ITEM|CHAN_MAYBE_LOCAL),
CHAN_IS3D = 1, // internal: Sound is 3D.
CHAN_EVICTED = 2, // internal: Sound was evicted.
CHAN_FORGETTABLE = 4, // internal: Forget channel data when sound stops.
CHAN_JUSTSTARTED = 512, // internal: Sound has not been updated yet.
CHAN_ABSTIME = 1024, // internal: Start time is absolute and does not depend on current time.
CHAN_VIRTUAL = 2048, // internal: Channel is currently virtual
CHAN_NOSTOP = 4096, // only for A_PlaySound. Does not start if channel is playing something.
};
// sound attenuation values
#define ATTN_NONE 0.f // full volume the entire level
#define ATTN_NORM 1.f
#define ATTN_IDLE 1.001f
#define ATTN_STATIC 3.f // diminish very rapidly with distance
enum // This cannot be remain as this, but for now it has to suffice.
{
SOURCE_None, // Sound is always on top of the listener.
SOURCE_Actor, // Sound is coming from an actor.
SOURCE_Sector, // Sound is coming from a sector.
SOURCE_Polyobj, // Sound is coming from a polyobject.
SOURCE_Unattached, // Sound is not attached to any particular emitter.
};
extern ReverbContainer *Environments;
extern ReverbContainer *DefaultEnvironments[26];
void S_ParseReverbDef ();
void S_UnloadReverbDef ();
void S_SetEnvironment (const ReverbContainer *settings);
ReverbContainer *S_FindEnvironment (const char *name);
ReverbContainer *S_FindEnvironment (int id);
void S_AddEnvironment (ReverbContainer *settings);
class SoundEngine
{
protected:
bool SoundPaused = false; // whether sound is paused
int RestartEvictionsAt = 0; // do not restart evicted channels before this time
SoundListener listener{};
FSoundChan* Channels = nullptr;
FSoundChan* FreeChannels = nullptr;
// the complete set of sound effects
TArray<sfxinfo_t> S_sfx;
FRolloffInfo S_Rolloff;
TArray<uint8_t> S_SoundCurve;
TMap<int, int> ResIdMap;
TArray<FRandomSoundList> S_rnd;
private:
void LoadSound3D(sfxinfo_t* sfx, FSoundLoadBuffer* pBuffer);
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);
// This is the actual sound positioning logic which needs to be provided by the client.
virtual void CalcPosVel(int type, const void* source, const float pt[3], int channel, int chanflags, FVector3* pos, FVector3* vel) = 0;
// This can be overridden by the clent to provide some diagnostics. The default lets everything pass.
virtual bool ValidatePosVel(int sourcetype, const void* source, const FVector3& pos, const FVector3& vel) { return true; }
bool ValidatePosVel(const FSoundChan* const chan, const FVector3& pos, const FVector3& vel);
// Checks if a copy of this sound is already playing.
bool CheckSingular(int sound_id);
bool CheckSoundLimit(sfxinfo_t* sfx, const FVector3& pos, int near_limit, float limit_range, int sourcetype, const void* actor, int channel);
virtual TArray<uint8_t> ReadSound(int lumpnum) = 0;
public:
virtual ~SoundEngine() = default;
void EvictAllChannels();
void StopChannel(FSoundChan* chan);
sfxinfo_t* LoadSound(sfxinfo_t* sfx, FSoundLoadBuffer* pBuffer);
// Initializes sound stuff, including volume
// Sets channels, SFX and music volume,
// allocates channel buffer, sets S_sfx lookup.
//
void Init(TArray<uint8_t> &sndcurve);
void InitData();
void Shutdown();
void StopAllChannels(void);
void SetPitch(FSoundChan* chan, float dpitch);
FSoundChan* GetChannel(void* syschan);
void RestoreEvictedChannels();
void CalcPosVel(FSoundChan* chan, FVector3* pos, FVector3* vel);
// Loads a sound, including any random sounds it might reference.
void CacheSound(sfxinfo_t* sfx);
void CacheSound(int sfx) { CacheSound(&S_sfx[sfx]); }
void UnloadSound(sfxinfo_t* sfx);
void UpdateSounds(int time);
FSoundChan* StartSound(int sourcetype, const void* source,
const FVector3* pt, int channel, FSoundID sound_id, float volume, float attenuation, FRolloffInfo* rolloff = nullptr, float spitch = 0.0f);
// Stops an origin-less sound from playing from this channel.
void StopSound(int channel);
void StopSound(int sourcetype, const void* actor, int channel);
void RelinkSound(int sourcetype, const void* from, const void* to, const FVector3* optpos);
void ChangeSoundVolume(int sourcetype, const void* source, int channel, double dvolume);
void ChangeSoundPitch(int sourcetype, const void* source, int channel, double pitch);
bool IsSourcePlayingSomething(int sourcetype, const void* actor, int channel, int sound_id);
// Stop and resume music, during game PAUSE.
bool GetSoundPlayingInfo(int sourcetype, const void* source, int sound_id);
void UnloadAllSounds();
void Reset();
void MarkUsed(int num);
void CacheMarkedSounds();
TArray<FSoundChan*> AllActiveChannels();
void MarkAllUnused()
{
for (auto & s: S_sfx) s.bUsed = false;
}
bool isListener(const void* object) const
{
return object && listener.ListenerObject == object;
}
bool isPlayerReserve(int snd_id)
{
return S_sfx[snd_id].bPlayerReserve; // Later this needs to be abstracted out of the engine itself. Right now that cannot be done.
}
void SetListener(SoundListener& l)
{
listener = l;
}
void SetRestartTime(int time)
{
RestartEvictionsAt = time;
}
void SetPaused(bool on)
{
SoundPaused = on;
}
FSoundChan* GetChannels()
{
return Channels;
}
const char *GetSoundName(FSoundID id)
{
return id == 0 ? "" : S_sfx[id].name;
}
TArray<sfxinfo_t> &GetSounds() //Thio should only be used for constructing the sound list or for diagnostics code prinring information about the sound list.
{
return S_sfx;
}
FRolloffInfo& GlobalRolloff() // like GetSounds this is meant for sound list generators, not for gaining cheap access to the sound engine's innards.
{
return S_Rolloff;
}
FRandomSoundList *ResolveRandomSound(sfxinfo_t* sfx)
{
return &S_rnd[sfx->link];
}
void ClearRandoms()
{
S_rnd.Clear();
}
void ChannelVirtualChanged(FISoundChannel* ichan, bool is_virtual);
FString ListSoundChannels();
// Allow this to be overridden for special needs.
virtual float GetRolloff(const FRolloffInfo* rolloff, float distance);
virtual void ChannelEnded(FISoundChannel* ichan); // allows the client to do bookkeeping on the sound.
// Lookup utilities.
int FindSound(const char* logicalname);
int FindSoundByResID(int rid);
int FindSoundNoHash(const char* logicalname);
int FindSoundByLump(int lump);
int AddSoundLump(const char* logicalname, int lump, int CurrentPitchMask, int resid = -1);
int FindSoundTentative(const char* name);
void CacheRandomSound(sfxinfo_t* sfx);
unsigned int GetMSLength(FSoundID sound);
int PickReplacement(int refid);
void HashSounds();
void AddRandomSound(int Owner, TArray<uint32_t> list);
};
extern SoundEngine* soundEngine;
struct FReverbField
{
int Min, Max;
float REVERB_PROPERTIES::* Float;
int REVERB_PROPERTIES::* Int;
unsigned int Flag;
};

View file

@ -0,0 +1,5 @@
#pragma once
extern unsigned int MakeKey (const char *s);
extern unsigned int MakeKey (const char *s, size_t len);
extern unsigned int SuperFastHash (const char *data, size_t len);

View file

@ -436,6 +436,8 @@ class Actor : Thinker native
MarkSound(BounceSound); MarkSound(BounceSound);
MarkSound(WallBounceSound); MarkSound(WallBounceSound);
MarkSound(CrushPainSound); MarkSound(CrushPainSound);
MarkSound(HowlSound);
MarkSound(MeleeSound);
} }
bool IsPointerEqual(int ptr_select1, int ptr_select2) bool IsPointerEqual(int ptr_select1, int ptr_select2)