Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

EFX spawnarg for location entities #2

Draft
wants to merge 10 commits into
base: trunk
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ ipch/
Darkmod.log

ThirdParty/artefacts/

MayaImport.vcxproj.user
11 changes: 10 additions & 1 deletion game/PlayerView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,16 @@ void idPlayerView::SingleView( idUserInterface *hud, const renderView_t *view, b
// place the sound origin for the player
// TODO: Support overriding the location area so that reverb settings can be applied for listening thru doors?
idVec3 p = player->GetPrimaryListenerLoc(); // grayman #4882
gameSoundWorld->PlaceListener( p, view->viewaxis, player->entityNumber + 1, gameLocal.time, hud ? hud->State().GetString( "location" ) : "Undefined" ); // grayman #4882

const idLocationEntity* currentLocation = player->GetLocation();
idStr efxPreset;

// The map might not be using the location system
if (currentLocation != NULL) {
efxPreset = currentLocation->spawnArgs.GetString("efx_preset");
}

gameSoundWorld->PlaceListener( p, view->viewaxis, player->entityNumber + 1, gameLocal.time, hud ? hud->State().GetString( "location" ) : "Undefined", efxPreset ); // grayman #4882
// gameSoundWorld->PlaceListener(player->GetListenerLoc(), view->viewaxis, player->entityNumber + 1, gameLocal.time, hud ? hud->State().GetString("location") : "Undefined");

// hack the shake in at the very last moment, so it can't cause any consistency problems
Expand Down
4 changes: 4 additions & 0 deletions sound/efxlib.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,12 @@ class idEFXFile {
bool Reload();
bool IsAfterReload();

bool AddOrUpdatePreset(idStr areaName, idStr efxPreset, ALuint* effect);

private:
bool ReadEffectLegacy(idLexer &lexer, idSoundEffect *effect);
bool AddPreset(idStr token, idSoundEffect *effect, ALenum err);
bool GetEffect(idStr& name, idSoundEffect * soundEffect);
bool ReadEffectOpenAL(idLexer &lexer, idSoundEffect *effect);

//filename initially passed to LoadFile (or empty if LoadFile never called)
Expand Down
153 changes: 111 additions & 42 deletions sound/snd_efxfile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ static inline ALfloat _mB_to_gain(ALfloat millibels, ALfloat min, ALfloat max) {
}

idSoundEffect::idSoundEffect() :
effect(0) {
effect(0) {
}

idSoundEffect::~idSoundEffect() {
Expand Down Expand Up @@ -104,6 +104,19 @@ bool idEFXFile::FindEffect(idStr &name, ALuint *effect) {
return false;
}

bool idEFXFile::GetEffect(idStr& name, idSoundEffect *soundEffect) {
int i;

for (i = 0; i < effects.Num(); i++) {
if (effects[i]->name.Icmp(name) == 0) {
*soundEffect = *effects[i];
return true;
}
}

return false;
}

#define efxi(param, value) \
do { \
ALint _v = value; \
Expand Down Expand Up @@ -252,6 +265,98 @@ bool idEFXFile::ReadEffectLegacy(idLexer &src, idSoundEffect *effect) {
return true;
}

/*
===============
idEFXFile::AddOrUpdatePreset

Checks the internal list of location:sound effect mappings to see if a mapping exists for this location.
If it doesn't exist, create a new object and add to the list.
If it does exist, use the existing sound effect mapping.
In both cases, the EFX database gets updated with the current preset for the location
===============
*/
bool idEFXFile::AddOrUpdatePreset(idStr areaName, idStr efxPreset, ALuint* effect) {

idSoundEffect* soundEffect = new idSoundEffect;

const bool found = GetEffect(areaName, soundEffect);
ALenum err{};
bool ok;

if (!found) {

if (!soundEffect->alloc()) {
delete soundEffect;
Clear();
return false;
}

soundEffect->name = areaName;
effects.Append(soundEffect);
}

// update EFX database
ok = AddPreset(efxPreset, soundEffect, err);

if (!ok) {
return false;
}

// update effect - this is what's checked for change later
*effect = soundEffect->effect;

return true;
}

bool idEFXFile::AddPreset(idStr preset, idSoundEffect* effect, ALenum err) {

const EFXEAXREVERBPROPERTIES* props = NULL;
int k = 0;
for (k = 0; efxPresets[k].name[0]; k++)
if (efxPresets[k].name == preset) {
props = &efxPresets[k].props;
break;
}

// Reference the preset by index instead of name.
if (!props && idStr::IsNumeric(preset)) {
int idx = atoi(preset);
if (idx >= 0 && idx < k)
props = &efxPresets[idx].props;
}
if (!props) {
//src.Error("idEFXFile::ReadEffect: Unknown preset name %s", token.c_str());
return false;
}

efxf(AL_EAXREVERB_DENSITY, props->flDensity);
efxf(AL_EAXREVERB_DIFFUSION, props->flDiffusion);
efxf(AL_EAXREVERB_GAIN, props->flGain);
efxf(AL_EAXREVERB_GAINHF, props->flGainHF);
efxf(AL_EAXREVERB_GAINLF, props->flGainLF);
efxf(AL_EAXREVERB_DECAY_TIME, props->flDecayTime);
efxf(AL_EAXREVERB_DECAY_HFRATIO, props->flDecayHFRatio);
efxf(AL_EAXREVERB_DECAY_LFRATIO, props->flDecayLFRatio);
efxf(AL_EAXREVERB_REFLECTIONS_GAIN, props->flReflectionsGain);
efxf(AL_EAXREVERB_REFLECTIONS_DELAY, props->flReflectionsDelay);
efxfv(AL_EAXREVERB_REFLECTIONS_PAN, props->flReflectionsPan[0], props->flReflectionsPan[1], props->flReflectionsPan[2]);
efxf(AL_EAXREVERB_LATE_REVERB_GAIN, props->flLateReverbGain);
efxf(AL_EAXREVERB_LATE_REVERB_DELAY, props->flLateReverbDelay);
efxfv(AL_EAXREVERB_LATE_REVERB_PAN, props->flLateReverbPan[0], props->flLateReverbPan[1], props->flLateReverbPan[2]);
efxf(AL_EAXREVERB_ECHO_TIME, props->flEchoTime);
efxf(AL_EAXREVERB_ECHO_DEPTH, props->flEchoDepth);
efxf(AL_EAXREVERB_MODULATION_TIME, props->flModulationTime);
efxf(AL_EAXREVERB_MODULATION_DEPTH, props->flModulationDepth);
efxf(AL_EAXREVERB_AIR_ABSORPTION_GAINHF, props->flAirAbsorptionGainHF);
efxf(AL_EAXREVERB_HFREFERENCE, props->flHFReference);
efxf(AL_EAXREVERB_LFREFERENCE, props->flLFReference);
efxf(AL_EAXREVERB_ROOM_ROLLOFF_FACTOR, props->flRoomRolloffFactor);
efxi(AL_EAXREVERB_DECAY_HFLIMIT, props->iDecayHFLimit);

return true;

}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like missing return.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed


bool idEFXFile::ReadEffectOpenAL(idLexer &src, idSoundEffect *effect) {
idToken token;

Expand All @@ -267,7 +372,7 @@ bool idEFXFile::ReadEffectOpenAL(idLexer &src, idSoundEffect *effect) {
if (!src.ExpectTokenString("{"))
return false;

ALenum err;
ALenum err{};
alGetError();
common->Printf("Loading EFX effect for location '%s' (#%u)\n", name.c_str(), effect->effect);

Expand All @@ -288,47 +393,9 @@ bool idEFXFile::ReadEffectOpenAL(idLexer &src, idSoundEffect *effect) {
return false;
token.ToUpper();

const EFXEAXREVERBPROPERTIES *props = NULL;
int k = 0;
for (k = 0; efxPresets[k].name[0]; k++)
if (efxPresets[k].name == token) {
props = &efxPresets[k].props;
break;
}
if (!props && (token.type == TT_NUMBER)) {
int idx = token.GetIntValue();
if (idx >= 0 && idx < k)
props = &efxPresets[idx].props;
}
if (!props) {
src.Error("idEFXFile::ReadEffect: Unknown preset name %s", token.c_str());
if (!AddPreset(token, effect, err)) {
return false;
}

efxf(AL_EAXREVERB_DENSITY, props->flDensity);
efxf(AL_EAXREVERB_DIFFUSION, props->flDiffusion);
efxf(AL_EAXREVERB_GAIN, props->flGain);
efxf(AL_EAXREVERB_GAINHF, props->flGainHF);
efxf(AL_EAXREVERB_GAINLF, props->flGainLF);
efxf(AL_EAXREVERB_DECAY_TIME, props->flDecayTime);
efxf(AL_EAXREVERB_DECAY_HFRATIO, props->flDecayHFRatio);
efxf(AL_EAXREVERB_DECAY_LFRATIO, props->flDecayLFRatio);
efxf(AL_EAXREVERB_REFLECTIONS_GAIN, props->flReflectionsGain);
efxf(AL_EAXREVERB_REFLECTIONS_DELAY, props->flReflectionsDelay);
efxfv(AL_EAXREVERB_REFLECTIONS_PAN, props->flReflectionsPan[0], props->flReflectionsPan[1], props->flReflectionsPan[2]);
efxf(AL_EAXREVERB_LATE_REVERB_GAIN, props->flLateReverbGain);
efxf(AL_EAXREVERB_LATE_REVERB_DELAY, props->flLateReverbDelay);
efxfv(AL_EAXREVERB_LATE_REVERB_PAN, props->flLateReverbPan[0], props->flLateReverbPan[1], props->flLateReverbPan[2]);
efxf(AL_EAXREVERB_ECHO_TIME, props->flEchoTime);
efxf(AL_EAXREVERB_ECHO_DEPTH, props->flEchoDepth);
efxf(AL_EAXREVERB_MODULATION_TIME, props->flModulationTime);
efxf(AL_EAXREVERB_MODULATION_DEPTH, props->flModulationDepth);
efxf(AL_EAXREVERB_AIR_ABSORPTION_GAINHF, props->flAirAbsorptionGainHF);
efxf(AL_EAXREVERB_HFREFERENCE, props->flHFReference);
efxf(AL_EAXREVERB_LFREFERENCE, props->flLFReference);
efxf(AL_EAXREVERB_ROOM_ROLLOFF_FACTOR, props->flRoomRolloffFactor);
efxi(AL_EAXREVERB_DECAY_HFLIMIT, props->iDecayHFLimit);

} else if ( token == "DENSITY" ) {
efxf(AL_EAXREVERB_DENSITY, src.ParseFloat());
} else if ( token == "DIFFUSION" ) {
Expand Down Expand Up @@ -398,7 +465,9 @@ bool idEFXFile::LoadFile( const char *filename/*, bool OSPath*/ ) {
efxFilename = filename;
src.LoadFile( filename/*, OSPath*/ );
if ( !src.IsLoaded() ) {
return false;

// Just return true if file doesn't exist, as EFX can now be specified on location entities
return true;
}

if ( !src.ExpectTokenString( "Version" ) ) {
Expand Down
3 changes: 2 additions & 1 deletion sound/snd_local.h
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,7 @@ class idSoundWorldLocal : public idSoundWorld {

// where is the camera/microphone
// listenerId allows listener-private sounds to be added
virtual void PlaceListener( const idVec3 &origin, const idMat3 &axis, const int listenerId, const int gameTime, const idStr& areaName ) override;
virtual void PlaceListener( const idVec3 &origin, const idMat3 &axis, const int listenerId, const int gameTime, const idStr& areaName, const idStr& efxPreset) override;

// fade all sounds in the world with a given shader soundClass
// to is in Db (sigh), over is in seconds
Expand Down Expand Up @@ -618,6 +618,7 @@ class idSoundWorldLocal : public idSoundWorld {
idVec3 listenerQU; // position in "quake units"
int listenerArea;
idStr listenerAreaName;
idStr listenerAreaEfxPreset;
ALuint listenerEffect;
ALuint listenerSlot;
ALuint listenerFilter;
Expand Down
21 changes: 17 additions & 4 deletions sound/snd_world.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ void idSoundWorldLocal::ProcessDemoCommand( idDemoFile *readDemo ) {
readDemo->ReadInt( listenerId );
readDemo->ReadInt( gameTime );

PlaceListener( origin, axis, listenerId, gameTime, "" );
PlaceListener( origin, axis, listenerId, gameTime, "", "");
};
break;
case SCMD_ALLOC_EMITTER:
Expand Down Expand Up @@ -515,17 +515,29 @@ void idSoundWorldLocal::MixLoopInternal( int current44kHz, int numSpeakers, floa
soundSystemLocal.alAuxiliaryEffectSlotf(listenerSlot, AL_EFFECTSLOT_GAIN, gain);
}

// Look for effect based on area index (1, 2, etc.). Does anyone actually do this?
bool found = soundSystemLocal.EFXDatabase.FindEffect(s, &effect);

// Look for effect based on area (location) name
if (!found) {
s = listenerAreaName;
found = soundSystemLocal.EFXDatabase.FindEffect(s, &effect);

if (!listenerAreaEfxPreset.IsEmpty()) {
ALenum err;
found = soundSystemLocal.EFXDatabase.AddOrUpdatePreset(s, listenerAreaEfxPreset, &effect);
}
else {
found = soundSystemLocal.EFXDatabase.FindEffect(s, &effect);
}

}
if (!found) {
s = "default";
found = soundSystemLocal.EFXDatabase.FindEffect(s, &effect);
}

bool justReloaded = soundSystemLocal.EFXDatabase.IsAfterReload();

// only update if change in settings
if (listenerEffect != effect || justReloaded) {
common->Printf("Switching to EFX '%s' (#%u)\n", s.c_str(), effect);
Expand Down Expand Up @@ -1152,7 +1164,7 @@ idSoundWorldLocal::PlaceListener
===================
*/
void idSoundWorldLocal::PlaceListener( const idVec3& origin, const idMat3& axis,
const int listenerId, const int gameTime, const idStr& areaName ) {
const int listenerId, const int gameTime, const idStr& areaName, const idStr& efxPreset) {

int current44kHzTime;

Expand Down Expand Up @@ -1199,6 +1211,7 @@ void idSoundWorldLocal::PlaceListener( const idVec3& origin, const idMat3& axis,
listenerPos = origin * DOOM_TO_METERS; // meters
listenerAxis = axis;
listenerAreaName = areaName;
listenerAreaEfxPreset = efxPreset;

if ( rw ) {
listenerArea = rw->GetAreaAtPoint( listenerQU ); // where are we?
Expand Down Expand Up @@ -1573,7 +1586,7 @@ void idSoundWorldLocal::ReadFromSaveGame( idFile *savefile ) {
pause44kHz = currentSoundTime;

// place listener
PlaceListener( origin, axis, listenerId, gameTime, "Undefined" );
PlaceListener( origin, axis, listenerId, gameTime, "Undefined", "");

// make sure there are enough
// slots to read the saveGame in. We don't shrink the list
Expand Down
2 changes: 1 addition & 1 deletion sound/sound.h
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ class idSoundWorld {
// listenerId allows listener-private and antiPrivate sounds to be filtered
// gameTime is in msec, and is used to time sound queries and removals so that they are independent
// of any race conditions with the async update
virtual void PlaceListener( const idVec3 &origin, const idMat3 &axis, const int listenerId, const int gameTime, const idStr& areaName ) = 0;
virtual void PlaceListener( const idVec3 &origin, const idMat3 &axis, const int listenerId, const int gameTime, const idStr& areaName, const idStr& efxPreset ) = 0;

// fade all sounds in the world with a given shader soundClass
// to is in Db (sigh), over is in seconds
Expand Down
2 changes: 1 addition & 1 deletion tools/radiant/CamWnd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -950,7 +950,7 @@ void CCamWnd::Cam_Draw() {
// set the sound origin for both simple draw and rendered mode
// the editor uses opposite pitch convention
idMat3 axis = idAngles( -m_Camera.angles.pitch, m_Camera.angles.yaw, m_Camera.angles.roll ).ToMat3();
g_qeglobals.sw->PlaceListener( m_Camera.origin, axis, 0, Sys_Milliseconds(), "Undefined" );
g_qeglobals.sw->PlaceListener( m_Camera.origin, axis, 0, Sys_Milliseconds(), "Undefined", "");

if (renderMode) {
Cam_Render();
Expand Down