Skip to content

Commit

Permalink
Restore EAX effects through OpenAL's EFX.
Browse files Browse the repository at this point in the history
  • Loading branch information
Deledrius committed Feb 21, 2025
1 parent dbc50fa commit b567a30
Show file tree
Hide file tree
Showing 15 changed files with 608 additions and 527 deletions.
139 changes: 97 additions & 42 deletions Sources/MaxPlugin/MaxComponent/plAudioComponents.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,15 +109,12 @@ You can contact Cyan Worlds, Inc. by email [email protected]

// EAX stuff
#include "plAudio/plEAXListenerMod.h"
#ifdef EAX_SDK_AVAILABLE
# include <eax-util.h>
# include <eaxlegacy.h>
#endif
#include "plAudio/plEAXStructures.h"

#include "plResMgr/plLocalization.h"
#include "plPhysical/plPhysicalSndGroup.h"

// EAX3 values which eax4 no longer defines, but we still need.
// EAX3 values which EAX4 no longer defines, but we still need.
// Single window material preset
#define EAX_MATERIAL_SINGLEWINDOW (-2800)
#define EAX_MATERIAL_SINGLEWINDOWLF 0.71f
Expand Down Expand Up @@ -158,6 +155,66 @@ You can contact Cyan Worlds, Inc. by email [email protected]
#define EAX_MATERIAL_CURTAINLF 0.15f
#define EAX_MATERIAL_CURTAINROOMRATIO 1.00f

#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] = {
EFX_REVERB_PRESET_GENERIC,
EFX_REVERB_PRESET_PADDEDCELL,
EFX_REVERB_PRESET_ROOM,
EFX_REVERB_PRESET_BATHROOM,
EFX_REVERB_PRESET_LIVINGROOM,
EFX_REVERB_PRESET_STONEROOM,
EFX_REVERB_PRESET_AUDITORIUM,
EFX_REVERB_PRESET_CONCERTHALL,
EFX_REVERB_PRESET_CAVE,
EFX_REVERB_PRESET_ARENA,
EFX_REVERB_PRESET_HANGAR,
EFX_REVERB_PRESET_CARPETEDHALLWAY,
EFX_REVERB_PRESET_HALLWAY,
EFX_REVERB_PRESET_STONECORRIDOR,
EFX_REVERB_PRESET_ALLEY,
EFX_REVERB_PRESET_FOREST,
EFX_REVERB_PRESET_CITY,
EFX_REVERB_PRESET_MOUNTAINS,
EFX_REVERB_PRESET_QUARRY,
EFX_REVERB_PRESET_PLAIN,
EFX_REVERB_PRESET_PARKINGLOT,
EFX_REVERB_PRESET_SEWERPIPE,
EFX_REVERB_PRESET_UNDERWATER,
EFX_REVERB_PRESET_DRUGGED,
EFX_REVERB_PRESET_DIZZY,
EFX_REVERB_PRESET_PSYCHOTIC
};

void DummyCodeIncludeFuncAudio() {}


Expand Down Expand Up @@ -2775,11 +2832,8 @@ class plEAXListenerDlgProc : public plSingleCompSelProc
HWND comboBox = GetDlgItem( hWnd, IDC_EAX_PRESET_COMBO );
ComboBox_ResetContent( comboBox );

#ifdef EAX_SDK_AVAILABLE
for( int i = 0; i < /*sizeof( EAX30_ORIGINAL_PRESETS )
/ sizeof( EAXLISTENERPROPERTIES )*/26 ; i++ )
ComboBox_AddString( comboBox, EAX30_ORIGINAL_PRESET_NAMES[ i ] );
#endif
for( int i = 0; i < EAX_NUM_LEGACY_PRESETS; i++ )
ComboBox_AddString(comboBox, EAX_LEGACY_PRESET_NAMES[i]);

ComboBox_SetCurSel( comboBox, pb->GetInt( (ParamID)plEAXListenerComponent::kRefPreset ) );

Expand Down Expand Up @@ -2914,42 +2968,43 @@ bool plEAXListenerComponent::Convert(plMaxNode *node, plErrorMsg *errMsg)
// Add the soft region
hsgResMgr::ResMgr()->AddViaNotify( softKey, new plGenRefMsg( listener->GetKey(), plRefMsg::kOnCreate, 0, plEAXListenerMod::kRefSoftRegion ), plRefFlags::kActiveRef );

#ifdef EAX_SDK_AVAILABLE
// Set up the parameters of the listener mod
EAXLISTENERPROPERTIES *listenerProps = listener->GetListenerProps();
if( fCompPB->GetInt( (ParamID)kRefWhichSettings ) == 0 )
{
if(fCompPB->GetInt( (ParamID)kRefWhichSettings ) == 0) {
// Set params based on a preset
listener->SetFromPreset( fCompPB->GetInt( (ParamID)kRefPreset ) );
}
else
{
listener->SetFromEFXPreset(EAX_LEGACY_PRESETS[fCompPB->GetInt((ParamID)kRefPreset)]);
} else {
// Set params based on artist selections
EAXREVERBPROPERTIES *eaxProps = new EAXREVERBPROPERTIES;

// Get the raw params
listenerProps->flEnvironmentSize = fCompPB->GetFloat( (ParamID)kRefEnvironmentSize );
listenerProps->flEnvironmentDiffusion = fCompPB->GetFloat( (ParamID)kRefEnvironmentDiffusion );
listenerProps->lRoom = fCompPB->GetInt( (ParamID)kRefRoom );
listenerProps->lRoomHF = fCompPB->GetInt( (ParamID)kRefRoomHF );
listenerProps->lRoomLF = fCompPB->GetInt( (ParamID)kRefRoomLF );
listenerProps->flDecayTime = fCompPB->GetFloat( (ParamID)kRefDecayTime );
listenerProps->flDecayHFRatio = fCompPB->GetFloat( (ParamID)kRefDecayHFRatio );
listenerProps->flDecayLFRatio = fCompPB->GetFloat( (ParamID)kRefDecayLFRatio );
listenerProps->lReflections = fCompPB->GetInt( (ParamID)kRefReflections );
listenerProps->flReflectionsDelay = fCompPB->GetFloat( (ParamID)kRefReflectionsDelay );
//listenerProps->vReflectionsPan; // early reflections panning vector
listenerProps->lReverb = fCompPB->GetInt( (ParamID)kRefReverb ); // late reverberation level relative to room effect
listenerProps->flReverbDelay = fCompPB->GetFloat( (ParamID)kRefReverbDelay );
//listenerProps->vReverbPan; // late reverberation panning vector
listenerProps->flEchoTime = fCompPB->GetFloat( (ParamID)kRefEchoTime );
listenerProps->flEchoDepth = fCompPB->GetFloat( (ParamID)kRefEchoDepth );
listenerProps->flModulationTime = fCompPB->GetFloat( (ParamID)kRefModulationTime );
listenerProps->flModulationDepth = fCompPB->GetFloat( (ParamID)kRefModulationDepth );
listenerProps->flAirAbsorptionHF = fCompPB->GetFloat( (ParamID)kRefAirAbsorptionHF );
listenerProps->flHFReference = fCompPB->GetFloat( (ParamID)kRefHFReference );
listenerProps->flLFReference = fCompPB->GetFloat( (ParamID)kRefLFReference );
listenerProps->flRoomRolloffFactor = fCompPB->GetFloat( (ParamID)kRefRoomRolloffFactor );
listenerProps->ulFlags = fCompPB->GetInt( (ParamID)kRefFlags );
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;
}
#endif

return true;
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/Plasma/Apps/plClient/plClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2103,7 +2103,7 @@ void plClient::IWriteDefaultAudioSettings(const plFileName& destFile)
{
std::unique_ptr<hsStream> stream = plEncryptedStream::OpenEncryptedFileWrite(destFile);
WriteBool(stream.get(), "Audio.Initialize", true);
WriteBool(stream.get(), "Audio.UseEAX", false);
WriteBool(stream.get(), "Audio.UseEAX", true);
WriteInt(stream.get(), "Audio.SetPriorityCutoff", 6);
WriteInt(stream.get(), "Audio.MuteAll", false);
WriteInt(stream.get(), "Audio.SetChannelVolume SoundFX", 1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ PF_CONSOLE_CMD(Audio, Enable, "bool on", "Switch Audio on or off at runtime")
plgAudioSys::Activate( on );
}

PF_CONSOLE_CMD(Audio, UseEAX, "bool on", "Enable EAX sound acceleration (requires hardware acceleration)")
PF_CONSOLE_CMD(Audio, UseEAX, "bool on", "Enable EFX environmental sound")
{
bool on = params[0];
plgAudioSys::EnableEAX( on );
Expand Down
2 changes: 1 addition & 1 deletion Sources/Plasma/FeatureLib/pfPython/pyAudioControl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ void pyAudioControl::SetTwoStageLOD(bool state)
plSound::SetLoadFromDiskOnDemand(!state);
}

// Enable EAX sound acceleration (requires hardware acceleration)
// Enable EFX environmental sound
void pyAudioControl::UseEAXAcceleration(bool state)
{
plgAudioSys::EnableEAX(state);
Expand Down
6 changes: 3 additions & 3 deletions Sources/Plasma/FeatureLib/pfPython/pyAudioControlGlue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -409,9 +409,9 @@ PYTHON_START_METHODS_TABLE(ptAudioControl)
PYTHON_METHOD(ptAudioControl, setLoadOnDemand, "Params: state\nEnables or disables the load on demand for sounds."),
PYTHON_METHOD(ptAudioControl, setTwoStageLOD, "Params: state\nEnables or disables two-stage LOD, where sounds can be loaded into RAM but not into sound buffers.\n"
"...Less of a performance hit, harder on memory."),
PYTHON_METHOD(ptAudioControl, useEAXAcceleration, "Params: state\nEnables or disables EAX sound acceleration (requires hardware acceleration)."),
PYTHON_METHOD_NOARGS(ptAudioControl, isUsingEAXAcceleration, "Is EAX sound acceleration enabled? Returns 1 if true otherwise returns 0."),
PYTHON_METHOD_NOARGS(ptAudioControl, isEAXSupported, "Is EAX acceleration supported by the current device?"),
PYTHON_METHOD(ptAudioControl, useEAXAcceleration, "Params: state\nEnables or disables EFX environmental sound."),
PYTHON_METHOD_NOARGS(ptAudioControl, isUsingEAXAcceleration, "Is EFX environmental sound enabled? Returns 1 if true otherwise returns 0."),
PYTHON_METHOD_NOARGS(ptAudioControl, isEAXSupported, "Is EFX environmental sound supported by the current device?"),
PYTHON_BASIC_METHOD(ptAudioControl, muteAll, "Mutes all sounds."),
PYTHON_BASIC_METHOD(ptAudioControl, unmuteAll, "Unmutes all sounds."),
PYTHON_METHOD_NOARGS(ptAudioControl, isMuted, "Are all sounds muted? Returns 1 if true otherwise returns 0."),
Expand Down
3 changes: 3 additions & 0 deletions Sources/Plasma/PubUtilLib/plAudio/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -68,5 +68,8 @@ target_link_libraries(plAudio
pnFactory
)

target_compile_definitions(plAudio
PRIVATE AL_ALEXT_PROTOTYPES)

source_group("Source Files" FILES ${plAudio_SOURCES})
source_group("Header Files" FILES ${plAudio_HEADERS})
25 changes: 14 additions & 11 deletions Sources/Plasma/PubUtilLib/plAudio/plAudioSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,7 @@ You can contact Cyan Worlds, Inc. by email [email protected]
*==LICENSE==*/
#include "HeadSpin.h"
#include <al.h>
#ifdef USE_EFX
# include <efx.h>
#endif
#ifdef EAX_SDK_AVAILABLE
# include <eax.h>
#endif
#include <efx.h>
#include <memory>
#include <array>

Expand Down Expand Up @@ -245,6 +240,7 @@ bool plAudioSystem::Init()
plStatusLog::AddLineSF("audio.log", "OpenAL version: {}", alGetString(AL_VERSION));
plStatusLog::AddLineSF("audio.log", "OpenAL renderer: {}", alGetString(AL_RENDERER));
plStatusLog::AddLineSF("audio.log", "OpenAL extensions: {}", alGetString(AL_EXTENSIONS));
plStatusLog::AddLineSF("audio.log", "OpenAL context extensions: {}", alcGetString(fPlaybackDevice, ALC_EXTENSIONS));
plStatusLog::AddLineS("audio.log", plStatusLog::kGreen, "ASYS: Detecting caps...");

// Detect maximum number of voices that can be created.
Expand All @@ -264,15 +260,22 @@ bool plAudioSystem::Init()
plStatusLog::AddLineSF("audio.log", "Max Number of sources: {}", fMaxNumSources);
SetMaxNumberOfActiveSounds();

// TODO: Detect EAX support. Not adding this in now until the replacement is implemented.
// Detect EFX support.
if (alcIsExtensionPresent(alcGetContextsDevice(alcGetCurrentContext()), "ALC_EXT_EFX"))
fEAXSupported = true;

// Attempt to init the EFX listener.
if (fEAXSupported && plgAudioSys::fEnableEAX) {
ALCint iVerMajor, iVerMinor;
alcGetIntegerv(fPlaybackDevice, ALC_EFX_MAJOR_VERSION, 1, &iVerMajor);
alcGetIntegerv(fPlaybackDevice, ALC_EFX_MAJOR_VERSION, 1, &iVerMinor);
plStatusLog::AddLineSF("audio.log", "ASYS: EFX v{}.{} available.", iVerMajor, iVerMinor);

// attempt to init the EAX listener.
if (plgAudioSys::fEnableEAX) {
fUsingEAX = plEAXListener::GetInstance().Init();
if (fUsingEAX)
plStatusLog::AddLineS("audio.log", plStatusLog::kGreen, "ASYS: EAX support detected and enabled.");
plStatusLog::AddLineS("audio.log", plStatusLog::kGreen, "ASYS: EFX support detected and enabled.");
else
plStatusLog::AddLineS("audio.log", plStatusLog::kRed, "ASYS: EAX support NOT detected. EAX effects disabled.");
plStatusLog::AddLineS("audio.log", plStatusLog::kRed, "ASYS: Unable to initialize environmental audio. EFX effects disabled.");
} else {
fUsingEAX = false;
}
Expand Down
6 changes: 0 additions & 6 deletions Sources/Plasma/PubUtilLib/plAudio/plAudioSystem_Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,6 @@ You can contact Cyan Worlds, Inc. by email [email protected]
#include "HeadSpin.h"
#include <al.h>
#include <alc.h>
#ifdef USE_EFX
# include <efx.h>
#endif
#ifdef EAX_SDK_AVAILABLE
# include <eax.h>
#endif
#include <memory>
#include <set>
#include <vector>
Expand Down
19 changes: 13 additions & 6 deletions Sources/Plasma/PubUtilLib/plAudio/plDSoundBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ You can contact Cyan Worlds, Inc. by email [email protected]
#include "HeadSpin.h"
#include "hsThread.h"
#include "plDSoundBuffer.h"
#include <al.h>

#include "plgDispatch.h"
#include "plAudioSystem.h"
Expand All @@ -59,9 +58,10 @@ You can contact Cyan Worlds, Inc. by email [email protected]
#include "plEAXEffects.h"

#include "plProfile.h"

#include "plStatusLog/plStatusLog.h"

#include <al.h>

uint32_t plDSoundBuffer::fNumBuffers = 0;
plProfile_CreateCounterNoReset( "Playing", "Sound", SoundPlaying );
plProfile_CreateCounterNoReset( "Allocated", "Sound", NumAllocated );
Expand Down Expand Up @@ -193,6 +193,8 @@ bool plDSoundBuffer::FillBuffer(void *data, unsigned bytes, plWAVHeader *header)

// Just make it quiet for now
SetScalarVolume(0);

alSource3i(source, AL_AUXILIARY_SEND_FILTER, 1, 0, AL_FILTER_NULL);

alSourcef(source, AL_ROLLOFF_FACTOR, 0.3048f);
alGetError();
Expand Down Expand Up @@ -265,7 +267,8 @@ bool plDSoundBuffer::SetupStreamingSource(plAudioFileReader *stream)
}
alSourcei(source, AL_BUFFER, 0);
SetScalarVolume(0);


alSource3i(source, AL_AUXILIARY_SEND_FILTER, 1, 0, AL_FILTER_NULL);

alSourcef(source, AL_ROLLOFF_FACTOR, 0.3048f);
error = alGetError();
Expand Down Expand Up @@ -331,7 +334,9 @@ bool plDSoundBuffer::SetupStreamingSource(void *data, unsigned bytes)
}
alSourcei(source, AL_BUFFER, 0);
SetScalarVolume(0);


alSource3i(source, AL_AUXILIARY_SEND_FILTER, 1, 0, AL_FILTER_NULL);

alSourcef(source, AL_ROLLOFF_FACTOR, 0.3048f);
error = alGetError();
if( error != AL_NO_ERROR )
Expand Down Expand Up @@ -489,6 +494,8 @@ bool plDSoundBuffer::SetupVoiceSource()
}

SetScalarVolume(0);

alSource3i(source, AL_AUXILIARY_SEND_FILTER, 1, 0, AL_FILTER_NULL);

alSourcef(source, AL_ROLLOFF_FACTOR, 0.3048f);
error = alGetError();
Expand All @@ -510,7 +517,7 @@ void plDSoundBuffer::UnQueueVoiceBuffers()
unsigned buffersProcessed = BuffersProcessed();
if(buffersProcessed)
plStatusLog::AddLineSF("audio.log", "unqueuing buffers {}", buffersProcessed);
for(int i = 0; i < buffersProcessed; i++)
for(uint32_t i = 0; i < buffersProcessed; i++)
{
ALuint unQueued;
alSourceUnqueueBuffers( source, 1, &unQueued );
Expand All @@ -532,7 +539,7 @@ bool plDSoundBuffer::VoiceFillBuffer(const void *data, size_t bytes, unsigned bu
return false;

ALenum error;
unsigned int size = bytes < STREAM_BUFFER_SIZE ? bytes : STREAM_BUFFER_SIZE;
size_t size = bytes < STREAM_BUFFER_SIZE ? bytes : STREAM_BUFFER_SIZE;

ALenum format = IGetALFormat(fBufferDesc->fBitsPerSample, fBufferDesc->fNumChannels);
alBufferData(bufferId, format, data, size, fBufferDesc->fNumSamplesPerSec);
Expand Down
8 changes: 3 additions & 5 deletions Sources/Plasma/PubUtilLib/plAudio/plDSoundBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ You can contact Cyan Worlds, Inc. by email [email protected]
Mead, WA 99021
*==LICENSE==*/

//////////////////////////////////////////////////////////////////////////////
// //
// plDSoundBuffer - Simple wrapper class for a DirectSound buffer. //
Expand All @@ -56,15 +57,12 @@ You can contact Cyan Worlds, Inc. by email [email protected]
#define STREAMING_BUFFERS 16
#define STREAM_BUFFER_SIZE 4608*4

//#define VOICE_BUFFERS 4
//#define VOICE_BUFFER_SIZE 4608

class plWAVHeader;
class plAudioFileReader;


// Ported to OpenAL from DirectSound May 2006. Idealy the openal sources would be seperate from this class.
// OpenAl sound buffer, and source.
// Ported to OpenAL from DirectSound May 2006. Ideally the OpenAL sources would be separate from this class.
// OpenAL sound buffer, and source.
class plDSoundBuffer
{
public:
Expand Down
Loading

0 comments on commit b567a30

Please sign in to comment.