mirror of
https://github.com/ZDoom/gzdoom-gles.git
synced 2024-11-28 15:02:39 +00:00
Merge branch 'soundsource_refactor'
This commit is contained in:
commit
298e29ffcc
30 changed files with 3122 additions and 2748 deletions
|
@ -878,7 +878,9 @@ set (PCH_SOURCES
|
|||
rendering/r_videoscale.cpp
|
||||
sound/s_advsound.cpp
|
||||
sound/s_environment.cpp
|
||||
sound/s_reverbedit.cpp
|
||||
sound/s_sndseq.cpp
|
||||
sound/s_doomsound.cpp
|
||||
sound/s_sound.cpp
|
||||
sound/s_music.cpp
|
||||
serializer.cpp
|
||||
|
|
|
@ -1134,6 +1134,11 @@ FString BuildString (int argc, FString *argv)
|
|||
//
|
||||
//===========================================================================
|
||||
|
||||
void FConsoleCommand::PrintCommand()
|
||||
{
|
||||
Printf("%s\n", m_Name);
|
||||
}
|
||||
|
||||
FString SubstituteAliasParams (FString &command, FCommandLine &args)
|
||||
{
|
||||
// Do substitution by replacing %x with the argument x.
|
||||
|
|
|
@ -34,7 +34,9 @@
|
|||
#ifndef __C_DISPATCH_H__
|
||||
#define __C_DISPATCH_H__
|
||||
|
||||
#include "doomtype.h"
|
||||
#include <stdint.h>
|
||||
#include "tarray.h"
|
||||
#include "zstring.h"
|
||||
|
||||
class FConfigFile;
|
||||
|
||||
|
@ -63,7 +65,7 @@ struct FExecList
|
|||
TArray<FString> Commands;
|
||||
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 AddPullins(TArray<FString> &wads) const;
|
||||
};
|
||||
|
@ -107,7 +109,7 @@ public:
|
|||
FConsoleCommand (const char *name, CCmdRun RunFunc);
|
||||
virtual ~FConsoleCommand ();
|
||||
virtual bool IsAlias ();
|
||||
void PrintCommand () { Printf ("%s\n", m_Name); }
|
||||
void PrintCommand();
|
||||
|
||||
virtual void Run (FCommandLine &args, AActor *instigator, int key);
|
||||
static FConsoleCommand* FindByName (const char* name);
|
||||
|
@ -208,9 +210,7 @@ extern bool ParsingKeyConf, UnsafeExecutionContext;
|
|||
void ResetButtonTriggers (); // Call ResetTriggers for all buttons
|
||||
void ResetButtonStates (); // Same as above, but also clear bDown
|
||||
|
||||
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);
|
||||
#include "superfasthash.h"
|
||||
|
||||
void execLogfile(const char *fn, bool append = false);
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
|
||||
#include "c_dispatch.h"
|
||||
#include "c_cvars.h"
|
||||
#include "doomtype.h"
|
||||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
#ifndef __V_TEXT_H__
|
||||
#define __V_TEXT_H__
|
||||
|
||||
#include "doomtype.h"
|
||||
#include "v_font.h"
|
||||
|
||||
struct FBrokenLines
|
||||
|
|
|
@ -364,7 +364,7 @@ static FSoundID T_FindSound(const char * name)
|
|||
}
|
||||
|
||||
int id = S_AddSound(name, buffer);
|
||||
S_HashSounds();
|
||||
soundEngine->HashSounds();
|
||||
return FSoundID(id);
|
||||
}
|
||||
|
||||
|
|
|
@ -4387,11 +4387,11 @@ int DLevelScript::GetActorProperty (int tid, int property)
|
|||
return 0;
|
||||
}
|
||||
|
||||
case APROP_SeeSound: return GlobalACSStrings.AddString(actor->SeeSound);
|
||||
case APROP_AttackSound: return GlobalACSStrings.AddString(actor->AttackSound);
|
||||
case APROP_PainSound: return GlobalACSStrings.AddString(actor->PainSound);
|
||||
case APROP_DeathSound: return GlobalACSStrings.AddString(actor->DeathSound);
|
||||
case APROP_ActiveSound: return GlobalACSStrings.AddString(actor->ActiveSound);
|
||||
case APROP_SeeSound: return GlobalACSStrings.AddString(S_GetSoundName(actor->SeeSound));
|
||||
case APROP_AttackSound: return GlobalACSStrings.AddString(S_GetSoundName(actor->AttackSound));
|
||||
case APROP_PainSound: return GlobalACSStrings.AddString(S_GetSoundName(actor->PainSound));
|
||||
case APROP_DeathSound: return GlobalACSStrings.AddString(S_GetSoundName(actor->DeathSound));
|
||||
case APROP_ActiveSound: return GlobalACSStrings.AddString(S_GetSoundName(actor->ActiveSound));
|
||||
case APROP_Species: return GlobalACSStrings.AddString(actor->GetSpecies());
|
||||
case APROP_NameTag: return GlobalACSStrings.AddString(actor->GetTag());
|
||||
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
|
||||
// heavy-duty, so make the check here.
|
||||
case APROP_SeeSound: string = actor->SeeSound; break;
|
||||
case APROP_AttackSound: string = actor->AttackSound; break;
|
||||
case APROP_PainSound: string = actor->PainSound; break;
|
||||
case APROP_DeathSound: string = actor->DeathSound; break;
|
||||
case APROP_ActiveSound: string = actor->ActiveSound; break;
|
||||
case APROP_SeeSound: string = S_GetSoundName(actor->SeeSound); break;
|
||||
case APROP_AttackSound: string = S_GetSoundName(actor->AttackSound); break;
|
||||
case APROP_PainSound: string = S_GetSoundName(actor->PainSound); break;
|
||||
case APROP_DeathSound: string = S_GetSoundName(actor->DeathSound); break;
|
||||
case APROP_ActiveSound: string = S_GetSoundName(actor->ActiveSound); break;
|
||||
case APROP_Species: string = actor->GetSpecies(); break;
|
||||
case APROP_NameTag: string = actor->GetTag(); break;
|
||||
case APROP_DamageType: string = actor->DamageType; break;
|
||||
|
@ -5265,7 +5265,7 @@ int DLevelScript::SwapActorTeleFog(AActor *activator, int tid)
|
|||
}
|
||||
else if (rettype == TypeSound)
|
||||
{
|
||||
retval = GlobalACSStrings.AddString(FSoundID(retval));
|
||||
retval = GlobalACSStrings.AddString(S_GetSoundName(FSoundID(retval)));
|
||||
}
|
||||
}
|
||||
else if (rettype == TypeFloat64)
|
||||
|
@ -5953,7 +5953,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
|
|||
|
||||
if (args[0] == 0)
|
||||
{
|
||||
S_ChangeSoundVolume(activator, chan, volume);
|
||||
S_ChangeActorSoundVolume(activator, chan, volume);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -5962,7 +5962,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
|
|||
|
||||
while ((spot = it.Next()) != NULL)
|
||||
{
|
||||
S_ChangeSoundVolume(spot, chan, volume);
|
||||
S_ChangeActorSoundVolume(spot, chan, volume);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "templates.h"
|
||||
#include "c_cvars.h"
|
||||
#include "w_wad.h"
|
||||
#include "doomtype.h"
|
||||
#ifdef _DEBUG
|
||||
#include "c_dispatch.h"
|
||||
#endif
|
||||
|
|
|
@ -731,7 +731,7 @@ void R_InitSkins (void)
|
|||
}
|
||||
else
|
||||
{
|
||||
int sndref = S_FindSoundNoHash (key);
|
||||
int sndref = soundEngine->FindSoundNoHash (key);
|
||||
if (sndref != 0)
|
||||
{
|
||||
S_AddPlayerSound (Skins[i].Name, Skins[i].gender, sndref, lump, true);
|
||||
|
@ -911,7 +911,7 @@ void R_InitSkins (void)
|
|||
|
||||
if (Skins.Size() > PlayerClasses.Size ())
|
||||
{ // The sound table may have changed, so rehash it.
|
||||
S_HashSounds ();
|
||||
soundEngine->HashSounds ();
|
||||
S_ShrinkPlayerSoundLists ();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1243,7 +1243,7 @@ FxExpression *FxStringCast::Resolve(FCompileContext &ctx)
|
|||
if (basex->isConstant())
|
||||
{
|
||||
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;
|
||||
return x;
|
||||
}
|
||||
|
|
|
@ -1184,7 +1184,7 @@ PSound::PSound()
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 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 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 CastTID2S(FString *a, int b) { auto tex = TexMan.GetTexture(*(FTextureID*)&b); *a = (tex == nullptr) ? "(null)" : tex->GetName().GetChars(); }
|
||||
|
||||
|
|
|
@ -1837,7 +1837,7 @@ static void DoCast(const VMRegisters ®, const VMFrame *f, int a, int b, int c
|
|||
|
||||
case CAST_So2S:
|
||||
ASSERTS(a); ASSERTD(b);
|
||||
reg.s[a] = S_sfx[reg.d[b]].name;
|
||||
reg.s[a] = S_GetSoundName(reg.d[b]);
|
||||
break;
|
||||
|
||||
case CAST_SID2S:
|
||||
|
|
|
@ -142,21 +142,21 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_StopSound, NativeStopSound)
|
|||
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_INT(channel);
|
||||
PARAM_FLOAT(pitch);
|
||||
S_ChangeSoundPitch(self, channel, pitch);
|
||||
S_ChangeActorSoundPitch(self, channel, pitch);
|
||||
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_INT(channel);
|
||||
PARAM_FLOAT(volume);
|
||||
S_ChangeSoundVolume(self, channel, volume);
|
||||
S_ChangeActorSoundVolume(self, channel, volume);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1663,7 +1663,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FSoundID &sid, FSoundI
|
|||
if (!arc.w->inObject() || def == nullptr || sid != *def)
|
||||
{
|
||||
arc.WriteKey(key);
|
||||
const char *sn = (const char*)sid;
|
||||
const char *sn = S_GetSoundName(sid);
|
||||
if (sn != nullptr) arc.w->String(sn);
|
||||
else arc.w->Null();
|
||||
}
|
||||
|
|
|
@ -35,8 +35,6 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "doomtype.h"
|
||||
|
||||
#include "oalsound.h"
|
||||
|
||||
#include "i_module.h"
|
||||
|
@ -49,9 +47,9 @@
|
|||
#include "v_text.h"
|
||||
#include "c_cvars.h"
|
||||
#include "stats.h"
|
||||
#include "s_music.h"
|
||||
#include "zmusic/zmusic.h"
|
||||
|
||||
|
||||
EXTERN_CVAR (Float, snd_sfxvolume)
|
||||
EXTERN_CVAR (Float, snd_musicvolume)
|
||||
CVAR (Int, snd_samplerate, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
|
@ -260,20 +258,12 @@ void I_InitSound ()
|
|||
return;
|
||||
}
|
||||
|
||||
#ifndef NO_OPENAL
|
||||
// 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
|
||||
|
||||
// Keep it simple: let everything except "null" init the sound.
|
||||
if (stricmp(snd_backend, "null") == 0)
|
||||
{
|
||||
GSnd = new NullSoundRenderer;
|
||||
}
|
||||
else if(stricmp(snd_backend, "openal") == 0)
|
||||
else
|
||||
{
|
||||
#ifndef NO_OPENAL
|
||||
if (IsOpenALPresent())
|
||||
|
@ -282,11 +272,6 @@ void I_InitSound ()
|
|||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf (TEXTCOLOR_RED"%s: Unknown sound system specified\n", *snd_backend);
|
||||
snd_backend = "null";
|
||||
}
|
||||
if (!GSnd || !GSnd->IsValid ())
|
||||
{
|
||||
I_CloseSound();
|
||||
|
@ -300,8 +285,8 @@ void I_InitSound ()
|
|||
|
||||
void I_CloseSound ()
|
||||
{
|
||||
// Free all loaded samples
|
||||
S_UnloadAllSounds();
|
||||
// Free all loaded samples. Beware that the sound engine may already have been deleted.
|
||||
if (soundEngine) soundEngine->UnloadAllSounds();
|
||||
|
||||
delete GSnd;
|
||||
GSnd = NULL;
|
||||
|
|
|
@ -174,11 +174,7 @@ extern bool nosfx;
|
|||
extern bool nosound;
|
||||
|
||||
void I_InitSound ();
|
||||
|
||||
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);
|
||||
void I_CloseSound();
|
||||
|
||||
extern ReverbContainer *DefaultEnvironments[26];
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "doomtype.h"
|
||||
#include "vectors.h"
|
||||
#include "tarray.h"
|
||||
#include "zmusic/sounddecoder.h"
|
||||
|
@ -77,6 +76,7 @@ struct SoundListener
|
|||
bool underwater;
|
||||
bool valid;
|
||||
ReverbContainer *Environment;
|
||||
void* ListenerObject;
|
||||
};
|
||||
|
||||
// Default rolloff information.
|
||||
|
@ -121,4 +121,5 @@ class SoundStream;
|
|||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -35,17 +35,18 @@
|
|||
#include <functional>
|
||||
#include <chrono>
|
||||
|
||||
#include "doomstat.h"
|
||||
#include "c_cvars.h"
|
||||
#include "templates.h"
|
||||
#include "oalsound.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "v_text.h"
|
||||
#include "i_module.h"
|
||||
#include "cmdlib.h"
|
||||
#include "menu/menu.h"
|
||||
#include "m_fixed.h"
|
||||
#include "zmusic/sounddecoder.h"
|
||||
#include "filereadermusicinterface.h"
|
||||
|
||||
|
||||
const char *GetSampleTypeName(SampleType type);
|
||||
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;
|
||||
|
||||
|
@ -544,22 +493,7 @@ static size_t GetChannelCount(ChannelConfig chans)
|
|||
|
||||
static float GetRolloff(const FRolloffInfo *rolloff, float distance)
|
||||
{
|
||||
if(distance <= rolloff->MinDistance)
|
||||
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;
|
||||
return soundEngine->GetRolloff(rolloff, distance);
|
||||
}
|
||||
|
||||
ALCdevice *OpenALSoundRenderer::InitDevice()
|
||||
|
@ -983,7 +917,7 @@ void OpenALSoundRenderer::SetSfxVolume(float volume)
|
|||
{
|
||||
SfxVolume = volume;
|
||||
|
||||
FSoundChan *schan = Channels;
|
||||
FSoundChan *schan = soundEngine->GetChannels();
|
||||
while(schan)
|
||||
{
|
||||
if(schan->SysChannel != NULL)
|
||||
|
@ -1359,7 +1293,7 @@ void OpenALSoundRenderer::UnloadSound(SoundHandle sfx)
|
|||
return;
|
||||
|
||||
ALuint buffer = GET_PTRID(sfx.data);
|
||||
FSoundChan *schan = Channels;
|
||||
FSoundChan *schan = soundEngine->GetChannels();
|
||||
while(schan)
|
||||
{
|
||||
if(schan->SysChannel)
|
||||
|
@ -1495,7 +1429,7 @@ FISoundChannel *OpenALSoundRenderer::StartSound(SoundHandle sfx, float vol, int
|
|||
FreeSfx.Pop();
|
||||
|
||||
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);
|
||||
|
||||
chan->Rolloff.RolloffType = ROLLOFF_Log;
|
||||
|
@ -1706,7 +1640,7 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener
|
|||
FreeSfx.Pop();
|
||||
|
||||
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);
|
||||
|
||||
chan->Rolloff = *rolloff;
|
||||
|
@ -1765,7 +1699,7 @@ void OpenALSoundRenderer::StopChannel(FISoundChannel *chan)
|
|||
|
||||
ALuint source = GET_PTRID(chan->SysChannel);
|
||||
// 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;
|
||||
alGetSourcei(source, AL_SOURCE_STATE, &state);
|
||||
|
@ -1789,7 +1723,7 @@ void OpenALSoundRenderer::ForceStopChannel(FISoundChannel *chan)
|
|||
ALuint source = GET_PTRID(chan->SysChannel);
|
||||
if(!source) return;
|
||||
|
||||
S_ChannelEnded(chan);
|
||||
soundEngine->ChannelEnded(chan);
|
||||
FreeSource(source);
|
||||
}
|
||||
|
||||
|
@ -2009,7 +1943,7 @@ void OpenALSoundRenderer::UpdateListener(SoundListener *listener)
|
|||
alFilterf(EnvFilters[1], AL_LOWPASS_GAINHF, 1.f);
|
||||
|
||||
// Apply the updated filters on the sources
|
||||
FSoundChan *schan = Channels;
|
||||
FSoundChan *schan = soundEngine->GetChannels();
|
||||
while (schan)
|
||||
{
|
||||
ALuint source = GET_PTRID(schan->SysChannel);
|
||||
|
@ -2022,7 +1956,7 @@ void OpenALSoundRenderer::UpdateListener(SoundListener *listener)
|
|||
}
|
||||
}
|
||||
|
||||
FSoundChan *schan = Channels;
|
||||
FSoundChan *schan = soundEngine->GetChannels();
|
||||
while (schan)
|
||||
{
|
||||
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_GAINHF, 1.f);
|
||||
|
||||
FSoundChan *schan = Channels;
|
||||
FSoundChan *schan = soundEngine->GetChannels();
|
||||
while (schan)
|
||||
{
|
||||
ALuint source = GET_PTRID(schan->SysChannel);
|
||||
|
@ -2060,7 +1994,7 @@ void OpenALSoundRenderer::UpdateListener(SoundListener *listener)
|
|||
}
|
||||
}
|
||||
|
||||
FSoundChan *schan = Channels;
|
||||
FSoundChan *schan = soundEngine->GetChannels();
|
||||
while (schan)
|
||||
{
|
||||
ALuint source = GET_PTRID(schan->SysChannel);
|
||||
|
@ -2236,7 +2170,7 @@ void OpenALSoundRenderer::PurgeStoppedSources()
|
|||
if(state == AL_INITIAL || state == AL_PLAYING || state == AL_PAUSED)
|
||||
continue;
|
||||
|
||||
FSoundChan *schan = Channels;
|
||||
FSoundChan *schan = soundEngine->GetChannels();
|
||||
while(schan)
|
||||
{
|
||||
if(schan->SysChannel != NULL && src == GET_PTRID(schan->SysChannel))
|
||||
|
@ -2358,7 +2292,7 @@ void OpenALSoundRenderer::LoadReverb(const ReverbContainer *env)
|
|||
|
||||
FSoundChan *OpenALSoundRenderer::FindLowestChannel()
|
||||
{
|
||||
FSoundChan *schan = Channels;
|
||||
FSoundChan *schan = soundEngine->GetChannels();
|
||||
FSoundChan *lowest = NULL;
|
||||
while(schan)
|
||||
{
|
||||
|
@ -2374,4 +2308,60 @@ FSoundChan *OpenALSoundRenderer::FindLowestChannel()
|
|||
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
|
||||
|
|
|
@ -61,12 +61,6 @@
|
|||
|
||||
// TYPES -------------------------------------------------------------------
|
||||
|
||||
struct FRandomSoundList
|
||||
{
|
||||
TArray<uint32_t> Choices;
|
||||
uint32_t Owner = 0;
|
||||
};
|
||||
|
||||
struct FPlayerClassLookup
|
||||
{
|
||||
FString Name;
|
||||
|
@ -200,11 +194,9 @@ static int S_AddSound (const char *logicalname, int lumpnum, FScanner *sc=NULL);
|
|||
|
||||
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
|
||||
|
||||
extern int sfx_empty;
|
||||
|
||||
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
||||
|
||||
TArray<sfxinfo_t> S_sfx (128);
|
||||
//TArray<sfxinfo_t> S_sfx (128);
|
||||
TMap<int, FString> HexenMusic;
|
||||
|
||||
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
||||
|
@ -239,7 +231,6 @@ static const char *SICommandStrings[] =
|
|||
NULL
|
||||
};
|
||||
|
||||
static TArray<FRandomSoundList> S_rnd;
|
||||
static FMusicVolume *MusicVolumes;
|
||||
static TArray<FSavedPlayerSoundInfo> SavedPlayerSounds;
|
||||
|
||||
|
@ -255,8 +246,6 @@ static int DefPlayerClass;
|
|||
|
||||
static uint8_t CurrentPitchMask;
|
||||
|
||||
static FRandom pr_randsound ("RandSound");
|
||||
|
||||
// CODE --------------------------------------------------------------------
|
||||
|
||||
//==========================================================================
|
||||
|
@ -281,36 +270,6 @@ float S_GetMusicVolume (const char *music)
|
|||
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
|
||||
|
@ -320,6 +279,7 @@ void S_HashSounds ()
|
|||
|
||||
static bool S_CheckSound(sfxinfo_t *startsfx, sfxinfo_t *sfx, TArray<sfxinfo_t *> &chain)
|
||||
{
|
||||
auto &S_sfx = soundEngine->GetSounds();
|
||||
sfxinfo_t *me = sfx;
|
||||
bool success = true;
|
||||
unsigned siz = chain.Size();
|
||||
|
@ -339,7 +299,7 @@ static bool S_CheckSound(sfxinfo_t *startsfx, sfxinfo_t *sfx, TArray<sfxinfo_t *
|
|||
|
||||
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)
|
||||
{
|
||||
auto rsfx = &S_sfx[list->Choices[i]];
|
||||
|
@ -385,6 +345,7 @@ void S_CheckIntegrity()
|
|||
TArray<sfxinfo_t *> chain;
|
||||
TArray<bool> broken;
|
||||
|
||||
auto &S_sfx = soundEngine->GetSounds();
|
||||
broken.Resize(S_sfx.Size());
|
||||
memset(&broken[0], 0, sizeof(bool)*S_sfx.Size());
|
||||
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
|
||||
//
|
||||
// Returns duration of sound
|
||||
// This cannot be made a sound engine function due to the player sounds.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
unsigned int S_GetMSLength(FSoundID sound)
|
||||
{
|
||||
auto &S_sfx = soundEngine->GetSounds();
|
||||
if ((unsigned int)sound >= S_sfx.Size())
|
||||
{
|
||||
return 0;
|
||||
|
@ -453,7 +398,7 @@ unsigned int S_GetMSLength(FSoundID sound)
|
|||
// I think the longest one makes more sense.
|
||||
|
||||
int length = 0;
|
||||
const FRandomSoundList *list = &S_rnd[sfx->link];
|
||||
const FRandomSoundList* list = soundEngine->ResolveRandomSound(sfx);
|
||||
|
||||
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);
|
||||
else return 0;
|
||||
}
|
||||
|
@ -481,157 +426,6 @@ DEFINE_ACTION_FUNCTION(DObject,S_GetLength)
|
|||
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
|
||||
|
@ -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)
|
||||
{
|
||||
auto &S_sfx = soundEngine->GetSounds();
|
||||
int sfxid;
|
||||
|
||||
sfxid = S_FindSoundNoHash (logicalname);
|
||||
sfxid = soundEngine->FindSoundNoHash (logicalname);
|
||||
|
||||
if (sfxid > 0)
|
||||
{ // 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)
|
||||
{
|
||||
FRandomSoundList *rnd = &S_rnd[sfx->link];
|
||||
FRandomSoundList* rnd = soundEngine->ResolveRandomSound(sfx);
|
||||
rnd->Choices.Reset();
|
||||
rnd->Owner = 0;
|
||||
}
|
||||
|
@ -691,7 +486,7 @@ static int S_AddSound (const char *logicalname, int lumpnum, FScanner *sc)
|
|||
}
|
||||
else
|
||||
{ // Otherwise, create a new definition.
|
||||
sfxid = S_AddSoundLump (logicalname, lumpnum);
|
||||
sfxid = soundEngine->AddSoundLump (logicalname, lumpnum, CurrentPitchMask);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
auto &S_sfx = soundEngine->GetSounds();
|
||||
FString fakename;
|
||||
int id;
|
||||
|
||||
|
@ -728,7 +524,7 @@ int S_AddPlayerSound (const char *pclass, int gender, int refid, int lumpnum, bo
|
|||
fakename += '"';
|
||||
fakename += S_sfx[refid].name;
|
||||
|
||||
id = S_AddSoundLump (fakename, lumpnum);
|
||||
id = soundEngine->AddSoundLump (fakename, lumpnum, CurrentPitchMask);
|
||||
int classnum = S_AddPlayerClass (pclass);
|
||||
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 soundlist = S_AddPlayerGender (classnum, gender);
|
||||
|
||||
auto &S_sfx = soundEngine->GetSounds();
|
||||
PlayerSounds[soundlist].AddSound (S_sfx[refid].link, aliasto);
|
||||
|
||||
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)
|
||||
{
|
||||
S_sfx[probe->SfxID].bUsed = true;
|
||||
soundEngine->MarkUsed(probe->SfxID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -944,8 +741,9 @@ void FPlayerSoundHashTable::MarkUsed()
|
|||
|
||||
void S_ClearSoundData()
|
||||
{
|
||||
S_StopAllChannels();
|
||||
S_UnloadAllSounds();
|
||||
soundEngine->StopAllChannels();
|
||||
soundEngine->UnloadAllSounds();
|
||||
auto &S_sfx = soundEngine->GetSounds();
|
||||
S_sfx.Clear();
|
||||
Ambients.Clear();
|
||||
while (MusicVolumes != NULL)
|
||||
|
@ -954,7 +752,7 @@ void S_ClearSoundData()
|
|||
MusicVolumes = me->Next;
|
||||
M_Free(me);
|
||||
}
|
||||
S_rnd.Clear();
|
||||
soundEngine->ClearRandoms();
|
||||
|
||||
NumPlayerReserves = 0;
|
||||
PlayerClassesIsSorted = false;
|
||||
|
@ -977,6 +775,7 @@ void S_ClearSoundData()
|
|||
|
||||
void S_ParseSndInfo (bool redefine)
|
||||
{
|
||||
auto &S_sfx = soundEngine->GetSounds();
|
||||
int lump;
|
||||
|
||||
if (!redefine) SavedPlayerSounds.Clear(); // clear skin sounds only for initial parsing.
|
||||
|
@ -1005,13 +804,7 @@ void S_ParseSndInfo (bool redefine)
|
|||
}
|
||||
}
|
||||
S_RestorePlayerSounds();
|
||||
S_HashSounds ();
|
||||
S_sfx.ShrinkToFit ();
|
||||
|
||||
if (S_rnd.Size() > 0)
|
||||
{
|
||||
S_rnd.ShrinkToFit ();
|
||||
}
|
||||
soundEngine->HashSounds ();
|
||||
|
||||
S_ShrinkPlayerSoundLists ();
|
||||
|
||||
|
@ -1028,13 +821,7 @@ void S_ParseSndInfo (bool redefine)
|
|||
void S_AddLocalSndInfo(int lump)
|
||||
{
|
||||
S_AddSNDINFO(lump);
|
||||
S_HashSounds ();
|
||||
S_sfx.ShrinkToFit ();
|
||||
|
||||
if (S_rnd.Size() > 0)
|
||||
{
|
||||
S_rnd.ShrinkToFit ();
|
||||
}
|
||||
soundEngine->HashSounds ();
|
||||
|
||||
S_ShrinkPlayerSoundLists ();
|
||||
S_CheckIntegrity();
|
||||
|
@ -1050,6 +837,7 @@ void S_AddLocalSndInfo(int lump)
|
|||
|
||||
static void S_AddSNDINFO (int lump)
|
||||
{
|
||||
auto &S_sfx = soundEngine->GetSounds();
|
||||
bool skipToEndIf;
|
||||
TArray<uint32_t> list;
|
||||
|
||||
|
@ -1087,7 +875,7 @@ static void S_AddSNDINFO (int lump)
|
|||
ambient->sound = 0;
|
||||
|
||||
sc.MustGetString ();
|
||||
ambient->sound = FSoundID(S_FindSoundTentative(sc.String));
|
||||
ambient->sound = FSoundID(soundEngine->FindSoundTentative(sc.String));
|
||||
ambient->attenuation = 0;
|
||||
|
||||
sc.MustGetString ();
|
||||
|
@ -1205,7 +993,7 @@ static void S_AddSNDINFO (int lump)
|
|||
int gender, refid, targid;
|
||||
|
||||
S_ParsePlayerSoundCommon (sc, pclass, gender, refid);
|
||||
targid = S_FindSoundNoHash (sc.String);
|
||||
targid = soundEngine->FindSoundNoHash (sc.String);
|
||||
if (!S_sfx[targid].bPlayerReserve)
|
||||
{
|
||||
sc.ScriptError ("%s is not a player sound", sc.String);
|
||||
|
@ -1235,7 +1023,7 @@ static void S_AddSNDINFO (int lump)
|
|||
int soundnum;
|
||||
|
||||
S_ParsePlayerSoundCommon (sc, pclass, gender, refid);
|
||||
soundnum = S_FindSoundTentative (sc.String);
|
||||
soundnum = soundEngine->FindSoundTentative (sc.String);
|
||||
S_AddPlayerSoundExisting (pclass, gender, refid, soundnum);
|
||||
}
|
||||
break;
|
||||
|
@ -1251,7 +1039,7 @@ static void S_AddSNDINFO (int lump)
|
|||
{
|
||||
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.
|
||||
}
|
||||
break;
|
||||
|
@ -1261,7 +1049,7 @@ static void S_AddSNDINFO (int lump)
|
|||
int sfx;
|
||||
|
||||
sc.MustGetString ();
|
||||
sfx = S_FindSoundTentative (sc.String);
|
||||
sfx = soundEngine->FindSoundTentative (sc.String);
|
||||
sc.MustGetNumber ();
|
||||
S_sfx[sfx].NearLimit = MIN(MAX(sc.Number, 0), 255);
|
||||
if (sc.CheckFloat())
|
||||
|
@ -1276,7 +1064,7 @@ static void S_AddSNDINFO (int lump)
|
|||
int sfx;
|
||||
|
||||
sc.MustGetString ();
|
||||
sfx = S_FindSoundTentative (sc.String);
|
||||
sfx = soundEngine->FindSoundTentative (sc.String);
|
||||
S_sfx[sfx].bSingular = true;
|
||||
}
|
||||
break;
|
||||
|
@ -1286,7 +1074,7 @@ static void S_AddSNDINFO (int lump)
|
|||
int sfx;
|
||||
|
||||
sc.MustGetString ();
|
||||
sfx = S_FindSoundTentative (sc.String);
|
||||
sfx = soundEngine->FindSoundTentative (sc.String);
|
||||
sc.MustGetNumber ();
|
||||
S_sfx[sfx].PitchMask = (1 << clamp (sc.Number, 0, 7)) - 1;
|
||||
}
|
||||
|
@ -1303,7 +1091,7 @@ static void S_AddSNDINFO (int lump)
|
|||
int sfx;
|
||||
|
||||
sc.MustGetString();
|
||||
sfx = S_FindSoundTentative(sc.String);
|
||||
sfx = soundEngine->FindSoundTentative(sc.String);
|
||||
sc.MustGetFloat();
|
||||
S_sfx[sfx].Volume = (float)sc.Float;
|
||||
}
|
||||
|
@ -1314,7 +1102,7 @@ static void S_AddSNDINFO (int lump)
|
|||
int sfx;
|
||||
|
||||
sc.MustGetString();
|
||||
sfx = S_FindSoundTentative(sc.String);
|
||||
sfx = soundEngine->FindSoundTentative(sc.String);
|
||||
sc.MustGetFloat();
|
||||
S_sfx[sfx].Attenuation = (float)sc.Float;
|
||||
}
|
||||
|
@ -1331,11 +1119,11 @@ static void S_AddSNDINFO (int lump)
|
|||
if (sc.Compare("*"))
|
||||
{
|
||||
sfx = -1;
|
||||
rolloff = &S_Rolloff;
|
||||
rolloff = &soundEngine->GlobalRolloff();
|
||||
}
|
||||
else
|
||||
{
|
||||
sfx = S_FindSoundTentative(sc.String);
|
||||
sfx = soundEngine->FindSoundTentative(sc.String);
|
||||
rolloff = &S_sfx[sfx].Rolloff;
|
||||
}
|
||||
type = ROLLOFF_Doom;
|
||||
|
@ -1376,7 +1164,7 @@ static void S_AddSNDINFO (int lump)
|
|||
sc.MustGetStringName ("{");
|
||||
while (sc.GetString () && !sc.Compare ("}"))
|
||||
{
|
||||
uint32_t sfxto = S_FindSoundTentative (sc.String);
|
||||
uint32_t sfxto = soundEngine->FindSoundTentative (sc.String);
|
||||
if (sfxto == random.Owner)
|
||||
{
|
||||
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)
|
||||
{ // Only add non-empty random lists
|
||||
auto index = S_rnd.Reserve(1);
|
||||
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;
|
||||
soundEngine->AddRandomSound(Owner, list);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1513,6 +1295,7 @@ static void S_AddBloodSFX (int lumpnum)
|
|||
|
||||
if (rawlump != -1)
|
||||
{
|
||||
auto &S_sfx = soundEngine->GetSounds();
|
||||
const char *name = Wads.GetLumpFullName(lumpnum);
|
||||
sfxnum = S_AddSound(name, rawlump);
|
||||
if (sfx->Format < 5 || sfx->Format > 12)
|
||||
|
@ -1572,7 +1355,8 @@ static void S_ParsePlayerSoundCommon (FScanner &sc, FString &pclass, int &gender
|
|||
sc.MustGetString ();
|
||||
gender = D_GenderToInt (sc.String);
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
auto &S_sfx = soundEngine->GetSounds();
|
||||
if (!S_sfx[refid].bPlayerReserve)
|
||||
{ // Not a player sound, so just return this sound
|
||||
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)
|
||||
{
|
||||
auto &S_sfx = soundEngine->GetSounds();
|
||||
int ingender = gender;
|
||||
|
||||
if (classidx == -1)
|
||||
|
@ -1847,6 +1633,7 @@ bool S_AreSoundsEquivalent (AActor *actor, int id1, int id2)
|
|||
{
|
||||
sfxinfo_t *sfx;
|
||||
|
||||
auto &S_sfx = soundEngine->GetSounds();
|
||||
if (id1 == id2)
|
||||
{
|
||||
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
|
||||
|
@ -2052,6 +1793,7 @@ CCMD (soundlist)
|
|||
|
||||
CCMD (soundlinks)
|
||||
{
|
||||
auto &S_sfx = soundEngine->GetSounds();
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < S_sfx.Size (); i++)
|
||||
|
@ -2075,6 +1817,7 @@ CCMD (soundlinks)
|
|||
|
||||
CCMD (playersounds)
|
||||
{
|
||||
auto &S_sfx = soundEngine->GetSounds();
|
||||
const char *reserveNames[256];
|
||||
unsigned int i;
|
||||
int j, k, l;
|
||||
|
@ -2119,7 +1862,7 @@ DEFINE_ACTION_FUNCTION(AAmbientSound, MarkAmbientSounds)
|
|||
FAmbientSound *ambient = Ambients.CheckKey(self->args[0]);
|
||||
if (ambient != NULL)
|
||||
{
|
||||
ambient->sound.MarkUsed();
|
||||
soundEngine->MarkUsed(ambient->sound);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -2251,13 +1994,12 @@ DEFINE_ACTION_FUNCTION(AAmbientSound, Activate)
|
|||
{
|
||||
if ((amb->type & 3) == 0 && amb->periodmin == 0)
|
||||
{
|
||||
int sndnum = S_FindSound(amb->sound);
|
||||
if (sndnum == 0)
|
||||
if (amb->sound == 0)
|
||||
{
|
||||
self->Destroy ();
|
||||
return 0;
|
||||
}
|
||||
amb->periodmin = ::Scale(S_GetMSLength(sndnum), TICRATE, 1000);
|
||||
amb->periodmin = ::Scale(S_GetMSLength(amb->sound), TICRATE, 1000);
|
||||
}
|
||||
|
||||
self->special1 = 0;
|
||||
|
@ -2343,7 +2085,7 @@ DEFINE_ACTION_FUNCTION(DObject, MarkSound)
|
|||
{
|
||||
PARAM_PROLOGUE;
|
||||
PARAM_SOUND(sound_id);
|
||||
sound_id.MarkUsed();
|
||||
soundEngine->MarkUsed(sound_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
1399
src/sound/s_doomsound.cpp
Normal file
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
89
src/sound/s_doomsound.h
Normal 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);
|
||||
}
|
|
@ -32,44 +32,13 @@
|
|||
**
|
||||
*/
|
||||
|
||||
#include "doomtype.h"
|
||||
#include "s_sound.h"
|
||||
#include "s_soundinternal.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 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[] =
|
||||
FReverbField ReverbFields[] =
|
||||
{
|
||||
{ 0, 25, 0, &REVERB_PROPERTIES::Environment, 0 },
|
||||
{ 1000, 100000, &REVERB_PROPERTIES::EnvSize, 0, 0 },
|
||||
|
@ -110,8 +79,9 @@ static const FReverbField ReverbFields[] =
|
|||
{ 0, 0, 0, 0, 7 }
|
||||
};
|
||||
#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",
|
||||
"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;
|
||||
ReverbContainer *newenv;
|
||||
REVERB_PROPERTIES props;
|
||||
|
@ -545,10 +514,9 @@ static void ReadReverbDef (int lump)
|
|||
bool inited[NUM_REVERB_FIELDS];
|
||||
uint8_t bools[32];
|
||||
|
||||
sc.OpenLumpNum(lump);
|
||||
while (sc.GetString ())
|
||||
{
|
||||
name = copystring (sc.String);
|
||||
name = strdup (sc.String);
|
||||
sc.MustGetNumber ();
|
||||
id1 = sc.Number;
|
||||
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 ()
|
||||
{
|
||||
ReverbContainer *probe = Environments;
|
||||
|
@ -660,7 +617,7 @@ void S_UnloadReverbDef ()
|
|||
if (!probe->Builtin)
|
||||
{
|
||||
if (pNext != NULL) *pNext = probe->Next;
|
||||
delete[] const_cast<char *>(probe->Name);
|
||||
free(const_cast<char *>(probe->Name));
|
||||
delete probe;
|
||||
}
|
||||
else
|
||||
|
@ -672,476 +629,3 @@ void S_UnloadReverbDef ()
|
|||
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
555
src/sound/s_reverbedit.cpp
Normal 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();
|
||||
}
|
||||
|
|
@ -1433,13 +1433,13 @@ void SN_MarkPrecacheSounds(int sequence, seqtype_t type)
|
|||
{
|
||||
FSoundSequence *seq = Sequences[sequence];
|
||||
|
||||
seq->StopSound.MarkUsed();
|
||||
soundEngine->MarkUsed(seq->StopSound);
|
||||
for (int i = 0; GetCommand(seq->Script[i]) != SS_CMD_END; ++i)
|
||||
{
|
||||
int cmd = GetCommand(seq->Script[i]);
|
||||
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
|
@ -28,7 +28,6 @@
|
|||
#ifndef __S_SOUND__
|
||||
#define __S_SOUND__
|
||||
|
||||
#include "doomtype.h"
|
||||
#include "i_soundinternal.h"
|
||||
|
||||
class AActor;
|
||||
|
@ -36,342 +35,37 @@ class FScanner;
|
|||
class FSerializer;
|
||||
struct FLevelLocals;
|
||||
|
||||
//
|
||||
// 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;
|
||||
|
||||
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 ();
|
||||
#include "s_soundinternal.h"
|
||||
#include "s_doomsound.h"
|
||||
|
||||
// Per level startup code.
|
||||
// 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.
|
||||
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;
|
||||
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
|
||||
void S_ClearSoundData();
|
||||
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, 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, FSoundID refid);
|
||||
int S_FindSkinnedSound (AActor *actor, FSoundID refid);
|
||||
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_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, int lumpnum, 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_ShrinkPlayerSoundLists ();
|
||||
void S_UnloadSound (sfxinfo_t *sfx);
|
||||
sfxinfo_t *S_LoadSound(sfxinfo_t *sfx, FSoundLoadBuffer *pBuffer = nullptr);
|
||||
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.
|
||||
// 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
|
||||
|
|
398
src/sound/s_soundinternal.h
Normal file
398
src/sound/s_soundinternal.h
Normal 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;
|
||||
};
|
||||
|
||||
|
5
src/utility/superfasthash.h
Normal file
5
src/utility/superfasthash.h
Normal 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);
|
|
@ -436,6 +436,8 @@ class Actor : Thinker native
|
|||
MarkSound(BounceSound);
|
||||
MarkSound(WallBounceSound);
|
||||
MarkSound(CrushPainSound);
|
||||
MarkSound(HowlSound);
|
||||
MarkSound(MeleeSound);
|
||||
}
|
||||
|
||||
bool IsPointerEqual(int ptr_select1, int ptr_select2)
|
||||
|
|
Loading…
Reference in a new issue