Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Restore EAX effects through OpenAL's EFX. #1000

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

Deledrius
Copy link
Member

This re-implements the supported EAX effects using OpenAL's EFX. Some features (such as occlusion effects) are currently unsupported by OpenAL and required conversion or local implementation.

Copy link
Member

@Hoikas Hoikas left a comment

Choose a reason for hiding this comment

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

These single byte string literals will be reinterpreted as UCS-2 on 3ds Max >= 2013, resulting in garbled UI strings.

Comment on lines +158 to +189
#define EAX_NUM_LEGACY_PRESETS 26
const char* EAX_LEGACY_PRESET_NAMES[EAX_NUM_LEGACY_PRESETS] =
{
"Generic",
"Padded Cell",
"Room",
"Bathroom",
"Living Room",
"Stone Room",
"Auditorium",
"Concert Hall",
"Cave",
"Arena",
"Hangar",
"Carpetted Hallway",
"Hallway",
"Stone Corridor",
"Alley",
"Forest",
"City",
"Mountains",
"Quarry",
"Plain",
"Parking Lot",
"Sewer Pipe",
"Underwater",
"Drugged",
"Dizzy",
"Psychotic"
};

EFXEAXREVERBPROPERTIES EAX_LEGACY_PRESETS[EAX_NUM_LEGACY_PRESETS] = {
Copy link
Member

@Hoikas Hoikas Oct 8, 2021

Choose a reason for hiding this comment

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

Suggested change
#define EAX_NUM_LEGACY_PRESETS 26
const char* EAX_LEGACY_PRESET_NAMES[EAX_NUM_LEGACY_PRESETS] =
{
"Generic",
"Padded Cell",
"Room",
"Bathroom",
"Living Room",
"Stone Room",
"Auditorium",
"Concert Hall",
"Cave",
"Arena",
"Hangar",
"Carpetted Hallway",
"Hallway",
"Stone Corridor",
"Alley",
"Forest",
"City",
"Mountains",
"Quarry",
"Plain",
"Parking Lot",
"Sewer Pipe",
"Underwater",
"Drugged",
"Dizzy",
"Psychotic"
};
EFXEAXREVERBPROPERTIES EAX_LEGACY_PRESETS[EAX_NUM_LEGACY_PRESETS] = {
const TCHAR* EAX_LEGACY_PRESET_NAMES[] =
{
_T("Generic"),
_T("Padded Cell"),
_T("Room"),
_T("Bathroom"),
_T("Living Room"),
_T("Stone Room"),
_T("Auditorium"),
_T("Concert Hall"),
_T("Cave"),
_T("Arena"),
_T("Hangar"),
_T("Carpeted Hallway"),
_T("Hallway"),
_T("Stone Corridor"),
_T("Alley"),
_T("Forest"),
_T("City"),
_T("Mountains"),
_T("Quarry"),
_T("Plain"),
_T("Parking Lot"),
_T("Sewer Pipe"),
_T("Underwater"),
_T("Drugged"),
_T("Dizzy"),
_T("Psychotic")
};
EFXEAXREVERBPROPERTIES EAX_LEGACY_PRESETS[] = {

/ sizeof( EAXLISTENERPROPERTIES )*/26 ; i++ )
ComboBox_AddString( comboBox, EAX30_ORIGINAL_PRESET_NAMES[ i ] );
#endif
for( int i = 0; i < EAX_NUM_LEGACY_PRESETS; i++ )
Copy link
Member

@Hoikas Hoikas Oct 8, 2021

Choose a reason for hiding this comment

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

Suggested change
for( int i = 0; i < EAX_NUM_LEGACY_PRESETS; i++ )
for( size_t i = 0; i < std::size(EAX_LEGACY_PRESET_NAMES); i++ )

Copy link
Member Author

Choose a reason for hiding this comment

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

That's a great suggestion. I wasn't aware I could do that!

Copy link
Member

Choose a reason for hiding this comment

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

Since you only use i to index EAX_LEGACY_PRESET_NAMES, this would be even better as a range-based loop.

{
if( !fInited )
if(!fInited)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if(!fInited)
if (!fInited)

static int oldTime = timeGetTime(); // Get starting time
int newTime;
EFXEAXREVERBPROPERTIES finalProps;
static auto oldTime = std::chrono::steady_clock::now(); // Get starting time
Copy link
Member

Choose a reason for hiding this comment

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

Should this be using something from hsTimer instead?

@@ -317,20 +239,16 @@ void plEAXListener::ProcessMods(const std::set<plEAXListenerMod*>& modArray )
if (myLog != nullptr)
myLog->Clear();

if( modArray.size() != fLastModCount )
if(modArray.size() != fLastModCount)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if(modArray.size() != fLastModCount)
if (modArray.size() != fLastModCount)

totalStrength = strength;
firstOne = false;
}
else
{
float scale = strength / ( totalStrength + strength );
EAX3ListenerInterpolate( &finalProps, mod->GetListenerProps(), scale, &finalProps, false );
//EAX3ListenerInterpolate( &finalProps, mod->GetListenerProps(), scale, &finalProps, false );
Copy link
Member

Choose a reason for hiding this comment

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

Commented out code

// change due to opt out(caching) feature.
if(bMorphing)
{
newTime = timeGetTime();
auto newTime = std::chrono::steady_clock::now();
Copy link
Member

Choose a reason for hiding this comment

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

hsTimer?

Comment on lines +214 to +239
s->WriteLE32((uint32_t)eaxListenerProps->ulEnvironment);
s->WriteLEFloat(eaxListenerProps->flEnvironmentSize);
s->WriteLEFloat(eaxListenerProps->flEnvironmentDiffusion);
s->WriteLE32((int32_t)eaxListenerProps->lRoom);
s->WriteLE32((int32_t)eaxListenerProps->lRoomHF);
s->WriteLE32((int32_t)eaxListenerProps->lRoomLF);
s->WriteLEFloat(eaxListenerProps->flDecayTime);
s->WriteLEFloat(eaxListenerProps->flDecayHFRatio);
s->WriteLEFloat(eaxListenerProps->flDecayLFRatio);
s->WriteLE32((int32_t)eaxListenerProps->lReflections);
s->WriteLEFloat(eaxListenerProps->flReflectionsDelay);
//s->WriteLEFloat( eaxListenerProps->vReflectionsPan; // early reflections panning vector
s->WriteLE32((int32_t)eaxListenerProps->lReverb); // late reverberation level relative to room effect
s->WriteLEFloat(eaxListenerProps->flReverbDelay);
//s->WriteLEFloat( eaxListenerProps->vReverbPan; // late reverberation panning vector
s->WriteLEFloat(eaxListenerProps->flEchoTime);
s->WriteLEFloat(eaxListenerProps->flEchoDepth);
s->WriteLEFloat(eaxListenerProps->flModulationTime);
s->WriteLEFloat(eaxListenerProps->flModulationDepth);
s->WriteLEFloat(eaxListenerProps->flAirAbsorptionHF);
s->WriteLEFloat(eaxListenerProps->flHFReference);
s->WriteLEFloat(eaxListenerProps->flLFReference);
s->WriteLEFloat(eaxListenerProps->flRoomRolloffFactor);
s->WriteLE32((uint32_t)eaxListenerProps->ulFlags);

delete eaxListenerProps;
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
s->WriteLE32((uint32_t)eaxListenerProps->ulEnvironment);
s->WriteLEFloat(eaxListenerProps->flEnvironmentSize);
s->WriteLEFloat(eaxListenerProps->flEnvironmentDiffusion);
s->WriteLE32((int32_t)eaxListenerProps->lRoom);
s->WriteLE32((int32_t)eaxListenerProps->lRoomHF);
s->WriteLE32((int32_t)eaxListenerProps->lRoomLF);
s->WriteLEFloat(eaxListenerProps->flDecayTime);
s->WriteLEFloat(eaxListenerProps->flDecayHFRatio);
s->WriteLEFloat(eaxListenerProps->flDecayLFRatio);
s->WriteLE32((int32_t)eaxListenerProps->lReflections);
s->WriteLEFloat(eaxListenerProps->flReflectionsDelay);
//s->WriteLEFloat( eaxListenerProps->vReflectionsPan; // early reflections panning vector
s->WriteLE32((int32_t)eaxListenerProps->lReverb); // late reverberation level relative to room effect
s->WriteLEFloat(eaxListenerProps->flReverbDelay);
//s->WriteLEFloat( eaxListenerProps->vReverbPan; // late reverberation panning vector
s->WriteLEFloat(eaxListenerProps->flEchoTime);
s->WriteLEFloat(eaxListenerProps->flEchoDepth);
s->WriteLEFloat(eaxListenerProps->flModulationTime);
s->WriteLEFloat(eaxListenerProps->flModulationDepth);
s->WriteLEFloat(eaxListenerProps->flAirAbsorptionHF);
s->WriteLEFloat(eaxListenerProps->flHFReference);
s->WriteLEFloat(eaxListenerProps->flLFReference);
s->WriteLEFloat(eaxListenerProps->flRoomRolloffFactor);
s->WriteLE32((uint32_t)eaxListenerProps->ulFlags);
delete eaxListenerProps;
s->WriteLE32((uint32_t)eaxListenerProps.ulEnvironment);
s->WriteLEFloat(eaxListenerProps.flEnvironmentSize);
s->WriteLEFloat(eaxListenerProps.flEnvironmentDiffusion);
s->WriteLE32((int32_t)eaxListenerProps.lRoom);
s->WriteLE32((int32_t)eaxListenerProps.lRoomHF);
s->WriteLE32((int32_t)eaxListenerProps.lRoomLF);
s->WriteLEFloat(eaxListenerProps.flDecayTime);
s->WriteLEFloat(eaxListenerProps.flDecayHFRatio);
s->WriteLEFloat(eaxListenerProps.flDecayLFRatio);
s->WriteLE32((int32_t)eaxListenerProps.lReflections);
s->WriteLEFloat(eaxListenerProps.flReflectionsDelay);
//s->WriteLEFloat( eaxListenerProps.vReflectionsPan; // early reflections panning vector
s->WriteLE32((int32_t)eaxListenerProps.lReverb); // late reverberation level relative to room effect
s->WriteLEFloat(eaxListenerProps.flReverbDelay);
//s->WriteLEFloat( eaxListenerProps.vReverbPan; // late reverberation panning vector
s->WriteLEFloat(eaxListenerProps.flEchoTime);
s->WriteLEFloat(eaxListenerProps.flEchoDepth);
s->WriteLEFloat(eaxListenerProps.flModulationTime);
s->WriteLEFloat(eaxListenerProps.flModulationDepth);
s->WriteLEFloat(eaxListenerProps.flAirAbsorptionHF);
s->WriteLEFloat(eaxListenerProps.flHFReference);
s->WriteLEFloat(eaxListenerProps.flLFReference);
s->WriteLEFloat(eaxListenerProps.flRoomRolloffFactor);
s->WriteLE32((uint32_t)eaxListenerProps.ulFlags);

}


void plEAXListenerMod::SetFromPreset( uint32_t preset )
void plEAXListenerMod::SetFromEFXPreset(EFXEAXREVERBPROPERTIES preset)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
void plEAXListenerMod::SetFromEFXPreset(EFXEAXREVERBPROPERTIES preset)
void plEAXListenerMod::SetFromEFXPreset(const EFXEAXREVERBPROPERTIES& preset)

EAXREVERBPROPERTIES * GetListenerProps() { return fListenerProps; }
void SetFromPreset( uint32_t preset );
EFXEAXREVERBPROPERTIES *GetListenerProps() { return fListenerProps; }
void SetFromEFXPreset(EFXEAXREVERBPROPERTIES preset);
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
void SetFromEFXPreset(EFXEAXREVERBPROPERTIES preset);
void SetFromEFXPreset(const EFXEAXREVERBPROPERTIES& preset);

Comment on lines +2996 to +2997
// Set params based on artist selections
EAXREVERBPROPERTIES *eaxProps = new EAXREVERBPROPERTIES;
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
// Set params based on artist selections
EAXREVERBPROPERTIES *eaxProps = new EAXREVERBPROPERTIES;
// Set params based on artist selections
EAXREVERBPROPERTIES eaxProps;

Comment on lines +3000 to +3026
eaxProps->flEnvironmentSize = fCompPB->GetFloat( (ParamID)kRefEnvironmentSize );
eaxProps->flEnvironmentDiffusion = fCompPB->GetFloat( (ParamID)kRefEnvironmentDiffusion );
eaxProps->lRoom = fCompPB->GetInt( (ParamID)kRefRoom );
eaxProps->lRoomHF = fCompPB->GetInt( (ParamID)kRefRoomHF );
eaxProps->lRoomLF = fCompPB->GetInt( (ParamID)kRefRoomLF );
eaxProps->flDecayTime = fCompPB->GetFloat( (ParamID)kRefDecayTime );
eaxProps->flDecayHFRatio = fCompPB->GetFloat( (ParamID)kRefDecayHFRatio );
eaxProps->flDecayLFRatio = fCompPB->GetFloat( (ParamID)kRefDecayLFRatio );
eaxProps->lReflections = fCompPB->GetInt( (ParamID)kRefReflections );
eaxProps->flReflectionsDelay = fCompPB->GetFloat( (ParamID)kRefReflectionsDelay );
//eaxProps->vReflectionsPan; // early reflections panning vector
eaxProps->lReverb = fCompPB->GetInt( (ParamID)kRefReverb ); // late reverberation level relative to room effect
eaxProps->flReverbDelay = fCompPB->GetFloat( (ParamID)kRefReverbDelay );
//eaxProps->vReverbPan; // late reverberation panning vector
eaxProps->flEchoTime = fCompPB->GetFloat( (ParamID)kRefEchoTime );
eaxProps->flEchoDepth = fCompPB->GetFloat( (ParamID)kRefEchoDepth );
eaxProps->flModulationTime = fCompPB->GetFloat( (ParamID)kRefModulationTime );
eaxProps->flModulationDepth = fCompPB->GetFloat( (ParamID)kRefModulationDepth );
eaxProps->flAirAbsorptionHF = fCompPB->GetFloat( (ParamID)kRefAirAbsorptionHF );
eaxProps->flHFReference = fCompPB->GetFloat( (ParamID)kRefHFReference );
eaxProps->flLFReference = fCompPB->GetFloat( (ParamID)kRefLFReference );
eaxProps->flRoomRolloffFactor = fCompPB->GetFloat( (ParamID)kRefRoomRolloffFactor );
eaxProps->ulFlags = fCompPB->GetInt( (ParamID)kRefFlags );

// Convert to EFX and store them
plEAXListenerMod::ConvertEAXToEFX(eaxProps, listener->GetListenerProps());
delete eaxProps;
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
eaxProps->flEnvironmentSize = fCompPB->GetFloat( (ParamID)kRefEnvironmentSize );
eaxProps->flEnvironmentDiffusion = fCompPB->GetFloat( (ParamID)kRefEnvironmentDiffusion );
eaxProps->lRoom = fCompPB->GetInt( (ParamID)kRefRoom );
eaxProps->lRoomHF = fCompPB->GetInt( (ParamID)kRefRoomHF );
eaxProps->lRoomLF = fCompPB->GetInt( (ParamID)kRefRoomLF );
eaxProps->flDecayTime = fCompPB->GetFloat( (ParamID)kRefDecayTime );
eaxProps->flDecayHFRatio = fCompPB->GetFloat( (ParamID)kRefDecayHFRatio );
eaxProps->flDecayLFRatio = fCompPB->GetFloat( (ParamID)kRefDecayLFRatio );
eaxProps->lReflections = fCompPB->GetInt( (ParamID)kRefReflections );
eaxProps->flReflectionsDelay = fCompPB->GetFloat( (ParamID)kRefReflectionsDelay );
//eaxProps->vReflectionsPan; // early reflections panning vector
eaxProps->lReverb = fCompPB->GetInt( (ParamID)kRefReverb ); // late reverberation level relative to room effect
eaxProps->flReverbDelay = fCompPB->GetFloat( (ParamID)kRefReverbDelay );
//eaxProps->vReverbPan; // late reverberation panning vector
eaxProps->flEchoTime = fCompPB->GetFloat( (ParamID)kRefEchoTime );
eaxProps->flEchoDepth = fCompPB->GetFloat( (ParamID)kRefEchoDepth );
eaxProps->flModulationTime = fCompPB->GetFloat( (ParamID)kRefModulationTime );
eaxProps->flModulationDepth = fCompPB->GetFloat( (ParamID)kRefModulationDepth );
eaxProps->flAirAbsorptionHF = fCompPB->GetFloat( (ParamID)kRefAirAbsorptionHF );
eaxProps->flHFReference = fCompPB->GetFloat( (ParamID)kRefHFReference );
eaxProps->flLFReference = fCompPB->GetFloat( (ParamID)kRefLFReference );
eaxProps->flRoomRolloffFactor = fCompPB->GetFloat( (ParamID)kRefRoomRolloffFactor );
eaxProps->ulFlags = fCompPB->GetInt( (ParamID)kRefFlags );
// Convert to EFX and store them
plEAXListenerMod::ConvertEAXToEFX(eaxProps, listener->GetListenerProps());
delete eaxProps;
eaxProps.flEnvironmentSize = fCompPB->GetFloat( (ParamID)kRefEnvironmentSize );
eaxProps.flEnvironmentDiffusion = fCompPB->GetFloat( (ParamID)kRefEnvironmentDiffusion );
eaxProps.lRoom = fCompPB->GetInt( (ParamID)kRefRoom );
eaxProps.lRoomHF = fCompPB->GetInt( (ParamID)kRefRoomHF );
eaxProps.lRoomLF = fCompPB->GetInt( (ParamID)kRefRoomLF );
eaxProps.flDecayTime = fCompPB->GetFloat( (ParamID)kRefDecayTime );
eaxProps.flDecayHFRatio = fCompPB->GetFloat( (ParamID)kRefDecayHFRatio );
eaxProps.flDecayLFRatio = fCompPB->GetFloat( (ParamID)kRefDecayLFRatio );
eaxProps.lReflections = fCompPB->GetInt( (ParamID)kRefReflections );
eaxProps.flReflectionsDelay = fCompPB->GetFloat( (ParamID)kRefReflectionsDelay );
//eaxProps.vReflectionsPan; // early reflections panning vector
eaxProps.lReverb = fCompPB->GetInt( (ParamID)kRefReverb ); // late reverberation level relative to room effect
eaxProps.flReverbDelay = fCompPB->GetFloat( (ParamID)kRefReverbDelay );
//eaxProps.vReverbPan; // late reverberation panning vector
eaxProps.flEchoTime = fCompPB->GetFloat( (ParamID)kRefEchoTime );
eaxProps.flEchoDepth = fCompPB->GetFloat( (ParamID)kRefEchoDepth );
eaxProps.flModulationTime = fCompPB->GetFloat( (ParamID)kRefModulationTime );
eaxProps.flModulationDepth = fCompPB->GetFloat( (ParamID)kRefModulationDepth );
eaxProps.flAirAbsorptionHF = fCompPB->GetFloat( (ParamID)kRefAirAbsorptionHF );
eaxProps.flHFReference = fCompPB->GetFloat( (ParamID)kRefHFReference );
eaxProps.flLFReference = fCompPB->GetFloat( (ParamID)kRefLFReference );
eaxProps.flRoomRolloffFactor = fCompPB->GetFloat( (ParamID)kRefRoomRolloffFactor );
eaxProps.ulFlags = fCompPB->GetInt( (ParamID)kRefFlags );
// Convert to EFX and store them
plEAXListenerMod::ConvertEAXToEFX(&eaxProps, listener->GetListenerProps());


settings->ClearDirtyParams();

// Do all the flags in one pass
#ifdef EAX_SDK_AVAILABLE
DWORD flags;
Copy link
Member

Choose a reason for hiding this comment

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

uint32_t flags because DWORD is Windows-specific (probably a few spots in this file that will need that sort of thing corrected. This is what's causing macOS/Linux CI to fail)

@patmauro
Copy link
Contributor

If there's any interest in dusting this one off again, I would love to help in any way I can, depending on what the current blockers may be. This feature in particular is very near and dear to me - URU has never quite felt like URU without it, and getting this functionality restored even partially would be a tremendously huge W. So again, please let me know if I can be of any assistance here; my C++ is a little rusty, but I'm certainly no stranger to reviewing scripts and running tests.

Here's a thought - on the front-end side, in addition to the simple change of "Enable EAX" to "Enable EFX" in the options menu (there doesn't really seem to be room in the GUI for a description more detailed than that, unfortunately), we'll probably want to replace that "EAX ADVANCED HD" graphic at the bottom of the audio menu with a more generic OpenAL one as well:
eax_to_openal

This would require a modification to the xoptionsguicomponents texture contained inside GUI_District_OptionsMenuGUI.prp - we don't have a source for this one (the version of this we have in the source files is from CC and is quite different), so as usual, the trick here would be figuring out how to modify this texture without introducing any new compression artifacts to the rest of the texture sheet. (Granted - this wouldn't be covered by this PR and would require a separate PR to moul-assets, but it seemed relevant to mention here.)

@Deledrius
Copy link
Member Author

Deledrius commented Jul 21, 2023

No dusting off necessary, I've been actively working on this.

Updating the in-game text and graphics will definitely be something we'll need. I'll let you know when I get close to that stage!

@patmauro
Copy link
Contributor

No dusting off necessary, I've been actively working on this.

Updating the in-game text and graphics will definitely be something we'll need. I'll let you know when I get close to that stage!

Sounds good. 🙂 In any case, the offer stands; happy to make myself available if you need an extra set of hands.

I may go ahead and look into a PR for that graphic in moul-assets unless there's any objection... seems like it might not be a bad idea to start ditching the user-facing EAX references anyway, regardless of the status of the EFX project. 🤔

@Deledrius
Copy link
Member Author

Sure, go ahead. We can replace that texture with a lossless one if it isn't already, so additional edits won't introduce any generational loss. I can't check on this at the moment, but feel free to start on a plan for it!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Cleanup sound to remove EAX dependencies
5 participants