aboutsummaryrefslogtreecommitdiffstats
path: root/al/eax
diff options
context:
space:
mode:
Diffstat (limited to 'al/eax')
-rw-r--r--al/eax/api.cpp1213
-rw-r--r--al/eax/api.h1557
-rw-r--r--al/eax/eax_call.cpp323
-rw-r--r--al/eax/eax_call.h117
-rw-r--r--al/eax/effect.cpp3
-rw-r--r--al/eax/effect.h44
-rw-r--r--al/eax/exception.cpp62
-rw-r--r--al/eax/exception.h25
-rw-r--r--al/eax/fx_slot_index.cpp71
-rw-r--r--al/eax/fx_slot_index.h41
-rw-r--r--al/eax/fx_slots.cpp83
-rw-r--r--al/eax/fx_slots.h53
-rw-r--r--al/eax/globals.cpp21
-rw-r--r--al/eax/globals.h22
-rw-r--r--al/eax/utils.cpp36
-rw-r--r--al/eax/utils.h132
-rw-r--r--al/eax/x_ram.cpp3
-rw-r--r--al/eax/x_ram.h38
18 files changed, 3844 insertions, 0 deletions
diff --git a/al/eax/api.cpp b/al/eax/api.cpp
new file mode 100644
index 00000000..f859a1c4
--- /dev/null
+++ b/al/eax/api.cpp
@@ -0,0 +1,1213 @@
+//
+// EAX API.
+//
+// Based on headers `eax[2-5].h` included in Doom 3 source code:
+// https://github.com/id-Software/DOOM-3/tree/master/neo/openal/include
+//
+
+#include "config.h"
+
+#include <algorithm>
+
+#include "api.h"
+
+
+const GUID DSPROPSETID_EAX_ReverbProperties =
+{
+ 0x4A4E6FC1,
+ 0xC341,
+ 0x11D1,
+ {0xB7, 0x3A, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}
+};
+
+const GUID DSPROPSETID_EAXBUFFER_ReverbProperties =
+{
+ 0x4A4E6FC0,
+ 0xC341,
+ 0x11D1,
+ {0xB7, 0x3A, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}
+};
+
+const GUID DSPROPSETID_EAX20_ListenerProperties =
+{
+ 0x306A6A8,
+ 0xB224,
+ 0x11D2,
+ {0x99, 0xE5, 0x00, 0x00, 0xE8, 0xD8, 0xC7, 0x22}
+};
+
+const GUID DSPROPSETID_EAX20_BufferProperties =
+{
+ 0x306A6A7,
+ 0xB224,
+ 0x11D2,
+ {0x99, 0xE5, 0x00, 0x00, 0xE8, 0xD8, 0xC7, 0x22}
+};
+
+const GUID DSPROPSETID_EAX30_ListenerProperties =
+{
+ 0xA8FA6882,
+ 0xB476,
+ 0x11D3,
+ {0xBD, 0xB9, 0x00, 0xC0, 0xF0, 0x2D, 0xDF, 0x87}
+};
+
+const GUID DSPROPSETID_EAX30_BufferProperties =
+{
+ 0xA8FA6881,
+ 0xB476,
+ 0x11D3,
+ {0xBD, 0xB9, 0x00, 0xC0, 0xF0, 0x2D, 0xDF, 0x87}
+};
+
+const GUID EAX_NULL_GUID =
+{
+ 0x00000000,
+ 0x0000,
+ 0x0000,
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+};
+
+const GUID EAX_PrimaryFXSlotID =
+{
+ 0xF317866D,
+ 0x924C,
+ 0x450C,
+ {0x86, 0x1B, 0xE6, 0xDA, 0xA2, 0x5E, 0x7C, 0x20}
+};
+
+const GUID EAXPROPERTYID_EAX40_Context =
+{
+ 0x1D4870AD,
+ 0xDEF,
+ 0x43C0,
+ {0xA4, 0xC, 0x52, 0x36, 0x32, 0x29, 0x63, 0x42}
+};
+
+const GUID EAXPROPERTYID_EAX50_Context =
+{
+ 0x57E13437,
+ 0xB932,
+ 0x4AB2,
+ {0xB8, 0xBD, 0x52, 0x66, 0xC1, 0xA8, 0x87, 0xEE}
+};
+
+const GUID EAXPROPERTYID_EAX40_FXSlot0 =
+{
+ 0xC4D79F1E,
+ 0xF1AC,
+ 0x436B,
+ {0xA8, 0x1D, 0xA7, 0x38, 0xE7, 0x04, 0x54, 0x69}
+};
+
+const GUID EAXPROPERTYID_EAX50_FXSlot0 =
+{
+ 0x91F9590F,
+ 0xC388,
+ 0x407A,
+ {0x84, 0xB0, 0x1B, 0xAE, 0xE, 0xF7, 0x1A, 0xBC}
+};
+
+const GUID EAXPROPERTYID_EAX40_FXSlot1 =
+{
+ 0x8C00E96,
+ 0x74BE,
+ 0x4491,
+ {0x93, 0xAA, 0xE8, 0xAD, 0x35, 0xA4, 0x91, 0x17}
+};
+
+const GUID EAXPROPERTYID_EAX50_FXSlot1 =
+{
+ 0x8F5F7ACA,
+ 0x9608,
+ 0x4965,
+ {0x81, 0x37, 0x82, 0x13, 0xC7, 0xB9, 0xD9, 0xDE}
+};
+
+const GUID EAXPROPERTYID_EAX40_FXSlot2 =
+{
+ 0x1D433B88,
+ 0xF0F6,
+ 0x4637,
+ {0x91, 0x9F, 0x60, 0xE7, 0xE0, 0x6B, 0x5E, 0xDD}
+};
+
+const GUID EAXPROPERTYID_EAX50_FXSlot2 =
+{
+ 0x3C0F5252,
+ 0x9834,
+ 0x46F0,
+ {0xA1, 0xD8, 0x5B, 0x95, 0xC4, 0xA0, 0xA, 0x30}
+};
+
+const GUID EAXPROPERTYID_EAX40_FXSlot3 =
+{
+ 0xEFFF08EA,
+ 0xC7D8,
+ 0x44AB,
+ {0x93, 0xAD, 0x6D, 0xBD, 0x5F, 0x91, 0x00, 0x64}
+};
+
+const GUID EAXPROPERTYID_EAX50_FXSlot3 =
+{
+ 0xE2EB0EAA,
+ 0xE806,
+ 0x45E7,
+ {0x9F, 0x86, 0x06, 0xC1, 0x57, 0x1A, 0x6F, 0xA3}
+};
+
+const GUID EAXPROPERTYID_EAX40_Source =
+{
+ 0x1B86B823,
+ 0x22DF,
+ 0x4EAE,
+ {0x8B, 0x3C, 0x12, 0x78, 0xCE, 0x54, 0x42, 0x27}
+};
+
+const GUID EAXPROPERTYID_EAX50_Source =
+{
+ 0x5EDF82F0,
+ 0x24A7,
+ 0x4F38,
+ {0x8E, 0x64, 0x2F, 0x09, 0xCA, 0x05, 0xDE, 0xE1}
+};
+
+const GUID EAX_REVERB_EFFECT =
+{
+ 0xCF95C8F,
+ 0xA3CC,
+ 0x4849,
+ {0xB0, 0xB6, 0x83, 0x2E, 0xCC, 0x18, 0x22, 0xDF}
+};
+
+const GUID EAX_AGCCOMPRESSOR_EFFECT =
+{
+ 0xBFB7A01E,
+ 0x7825,
+ 0x4039,
+ {0x92, 0x7F, 0x03, 0xAA, 0xBD, 0xA0, 0xC5, 0x60}
+};
+
+const GUID EAX_AUTOWAH_EFFECT =
+{
+ 0xEC3130C0,
+ 0xAC7A,
+ 0x11D2,
+ {0x88, 0xDD, 0x00, 0xA0, 0x24, 0xD1, 0x3C, 0xE1}
+};
+
+const GUID EAX_CHORUS_EFFECT =
+{
+ 0xDE6D6FE0,
+ 0xAC79,
+ 0x11D2,
+ {0x88, 0xDD, 0x00, 0xA0, 0x24, 0xD1, 0x3C, 0xE1}
+};
+
+const GUID EAX_DISTORTION_EFFECT =
+{
+ 0x975A4CE0,
+ 0xAC7E,
+ 0x11D2,
+ {0x88, 0xDD, 0x00, 0xA0, 0x24, 0xD1, 0x3C, 0xE1}
+};
+
+const GUID EAX_ECHO_EFFECT =
+{
+ 0xE9F1BC0,
+ 0xAC82,
+ 0x11D2,
+ {0x88, 0xDD, 0x00, 0xA0, 0x24, 0xD1, 0x3C, 0xE1}
+};
+
+const GUID EAX_EQUALIZER_EFFECT =
+{
+ 0x65F94CE0,
+ 0x9793,
+ 0x11D3,
+ {0x93, 0x9D, 0x00, 0xC0, 0xF0, 0x2D, 0xD6, 0xF0}
+};
+
+const GUID EAX_FLANGER_EFFECT =
+{
+ 0xA70007C0,
+ 0x7D2,
+ 0x11D3,
+ {0x9B, 0x1E, 0x00, 0xA0, 0x24, 0xD1, 0x3C, 0xE1}
+};
+
+const GUID EAX_FREQUENCYSHIFTER_EFFECT =
+{
+ 0xDC3E1880,
+ 0x9212,
+ 0x11D3,
+ {0x93, 0x9D, 0x00, 0xC0, 0xF0, 0x2D, 0xD6, 0xF0}
+};
+
+const GUID EAX_VOCALMORPHER_EFFECT =
+{
+ 0xE41CF10C,
+ 0x3383,
+ 0x11D2,
+ {0x88, 0xDD, 0x00, 0xA0, 0x24, 0xD1, 0x3C, 0xE1}
+};
+
+const GUID EAX_PITCHSHIFTER_EFFECT =
+{
+ 0xE7905100,
+ 0xAFB2,
+ 0x11D2,
+ {0x88, 0xDD, 0x00, 0xA0, 0x24, 0xD1, 0x3C, 0xE1}
+};
+
+const GUID EAX_RINGMODULATOR_EFFECT =
+{
+ 0xB89FE60,
+ 0xAFB5,
+ 0x11D2,
+ {0x88, 0xDD, 0x00, 0xA0, 0x24, 0xD1, 0x3C, 0xE1}
+};
+
+
+bool operator==(
+ const EAX40CONTEXTPROPERTIES& lhs,
+ const EAX40CONTEXTPROPERTIES& rhs) noexcept
+{
+ return
+ lhs.guidPrimaryFXSlotID == rhs.guidPrimaryFXSlotID &&
+ lhs.flDistanceFactor == rhs.flDistanceFactor &&
+ lhs.flAirAbsorptionHF == rhs.flAirAbsorptionHF &&
+ lhs.flHFReference == rhs.flHFReference;
+}
+
+bool operator==(
+ const EAX50CONTEXTPROPERTIES& lhs,
+ const EAX50CONTEXTPROPERTIES& rhs) noexcept
+{
+ return
+ static_cast<const EAX40CONTEXTPROPERTIES&>(lhs) == static_cast<const EAX40CONTEXTPROPERTIES&>(rhs) &&
+ lhs.flMacroFXFactor == rhs.flMacroFXFactor;
+}
+
+
+const GUID EAXCONTEXT_DEFAULTPRIMARYFXSLOTID = EAXPROPERTYID_EAX40_FXSlot0;
+
+bool operator==(
+ const EAX40FXSLOTPROPERTIES& lhs,
+ const EAX40FXSLOTPROPERTIES& rhs) noexcept
+{
+ return
+ lhs.guidLoadEffect == rhs.guidLoadEffect &&
+ lhs.lVolume == rhs.lVolume &&
+ lhs.lLock == rhs.lLock &&
+ lhs.ulFlags == rhs.ulFlags;
+}
+
+bool operator==(
+ const EAX50FXSLOTPROPERTIES& lhs,
+ const EAX50FXSLOTPROPERTIES& rhs) noexcept
+{
+ return
+ static_cast<const EAX40FXSLOTPROPERTIES&>(lhs) == static_cast<const EAX40FXSLOTPROPERTIES&>(rhs) &&
+ lhs.lOcclusion == rhs.lOcclusion &&
+ lhs.flOcclusionLFRatio == rhs.flOcclusionLFRatio;
+}
+
+const EAX50ACTIVEFXSLOTS EAX40SOURCE_DEFAULTACTIVEFXSLOTID = EAX50ACTIVEFXSLOTS
+{{
+ EAX_NULL_GUID,
+ EAXPROPERTYID_EAX40_FXSlot0,
+}};
+
+bool operator==(
+ const EAX50ACTIVEFXSLOTS& lhs,
+ const EAX50ACTIVEFXSLOTS& rhs) noexcept
+{
+ return std::equal(
+ std::cbegin(lhs.guidActiveFXSlots),
+ std::cend(lhs.guidActiveFXSlots),
+ std::begin(rhs.guidActiveFXSlots));
+}
+
+bool operator!=(
+ const EAX50ACTIVEFXSLOTS& lhs,
+ const EAX50ACTIVEFXSLOTS& rhs) noexcept
+{
+ return !(lhs == rhs);
+}
+
+
+const EAX50ACTIVEFXSLOTS EAX50SOURCE_3DDEFAULTACTIVEFXSLOTID = EAX50ACTIVEFXSLOTS
+{{
+ EAX_NULL_GUID,
+ EAX_PrimaryFXSlotID,
+ EAX_NULL_GUID,
+ EAX_NULL_GUID,
+}};
+
+
+const EAX50ACTIVEFXSLOTS EAX50SOURCE_2DDEFAULTACTIVEFXSLOTID = EAX50ACTIVEFXSLOTS
+{{
+ EAX_NULL_GUID,
+ EAX_NULL_GUID,
+ EAX_NULL_GUID,
+ EAX_NULL_GUID,
+}};
+
+bool operator==(
+ const EAXREVERBPROPERTIES& lhs,
+ const EAXREVERBPROPERTIES& rhs) noexcept
+{
+ return
+ lhs.ulEnvironment == rhs.ulEnvironment &&
+ lhs.flEnvironmentSize == rhs.flEnvironmentSize &&
+ lhs.flEnvironmentDiffusion == rhs.flEnvironmentDiffusion &&
+ lhs.lRoom == rhs.lRoom &&
+ lhs.lRoomHF == rhs.lRoomHF &&
+ lhs.lRoomLF == rhs.lRoomLF &&
+ lhs.flDecayTime == rhs.flDecayTime &&
+ lhs.flDecayHFRatio == rhs.flDecayHFRatio &&
+ lhs.flDecayLFRatio == rhs.flDecayLFRatio &&
+ lhs.lReflections == rhs.lReflections &&
+ lhs.flReflectionsDelay == rhs.flReflectionsDelay &&
+ lhs.vReflectionsPan == rhs.vReflectionsPan &&
+ lhs.lReverb == rhs.lReverb &&
+ lhs.flReverbDelay == rhs.flReverbDelay &&
+ lhs.vReverbPan == rhs.vReverbPan &&
+ lhs.flEchoTime == rhs.flEchoTime &&
+ lhs.flEchoDepth == rhs.flEchoDepth &&
+ lhs.flModulationTime == rhs.flModulationTime &&
+ lhs.flModulationDepth == rhs.flModulationDepth &&
+ lhs.flAirAbsorptionHF == rhs.flAirAbsorptionHF &&
+ lhs.flHFReference == rhs.flHFReference &&
+ lhs.flLFReference == rhs.flLFReference &&
+ lhs.flRoomRolloffFactor == rhs.flRoomRolloffFactor &&
+ lhs.ulFlags == rhs.ulFlags;
+}
+
+bool operator!=(
+ const EAXREVERBPROPERTIES& lhs,
+ const EAXREVERBPROPERTIES& rhs) noexcept
+{
+ return !(lhs == rhs);
+}
+
+
+namespace {
+
+constexpr EAXREVERBPROPERTIES EAXREVERB_PRESET_GENERIC =
+{
+ EAXREVERB_DEFAULTENVIRONMENT,
+ EAXREVERB_DEFAULTENVIRONMENTSIZE,
+ EAXREVERB_DEFAULTENVIRONMENTDIFFUSION,
+ EAXREVERB_DEFAULTROOM,
+ EAXREVERB_DEFAULTROOMHF,
+ EAXREVERB_DEFAULTROOMLF,
+ EAXREVERB_DEFAULTDECAYTIME,
+ EAXREVERB_DEFAULTDECAYHFRATIO,
+ EAXREVERB_DEFAULTDECAYLFRATIO,
+ EAXREVERB_DEFAULTREFLECTIONS,
+ EAXREVERB_DEFAULTREFLECTIONSDELAY,
+ EAXREVERB_DEFAULTREFLECTIONSPAN,
+ EAXREVERB_DEFAULTREVERB,
+ EAXREVERB_DEFAULTREVERBDELAY,
+ EAXREVERB_DEFAULTREVERBPAN,
+ EAXREVERB_DEFAULTECHOTIME,
+ EAXREVERB_DEFAULTECHODEPTH,
+ EAXREVERB_DEFAULTMODULATIONTIME,
+ EAXREVERB_DEFAULTMODULATIONDEPTH,
+ EAXREVERB_DEFAULTAIRABSORPTIONHF,
+ EAXREVERB_DEFAULTHFREFERENCE,
+ EAXREVERB_DEFAULTLFREFERENCE,
+ EAXREVERB_DEFAULTROOMROLLOFFFACTOR,
+ EAXREVERB_DEFAULTFLAGS,
+};
+
+constexpr EAXREVERBPROPERTIES EAXREVERB_PRESET_PADDEDCELL =
+{
+ EAX_ENVIRONMENT_PADDEDCELL,
+ 1.4F,
+ 1.0F,
+ -1'000L,
+ -6'000L,
+ 0L,
+ 0.17F,
+ 0.10F,
+ 1.0F,
+ -1'204L,
+ 0.001F,
+ EAXVECTOR{},
+ 207L,
+ 0.002F,
+ EAXVECTOR{},
+ 0.250F,
+ 0.0F,
+ 0.250F,
+ 0.0F,
+ -5.0F,
+ 5'000.0F,
+ 250.0F,
+ 0.0F,
+ 0x3FUL,
+};
+
+constexpr EAXREVERBPROPERTIES EAXREVERB_PRESET_ROOM =
+{
+ EAX_ENVIRONMENT_ROOM,
+ 1.9F,
+ 1.0F,
+ -1'000L,
+ -454L,
+ 0L,
+ 0.40F,
+ 0.83F,
+ 1.0F,
+ -1'646L,
+ 0.002F,
+ EAXVECTOR{},
+ 53L,
+ 0.003F,
+ EAXVECTOR{},
+ 0.250F,
+ 0.0F,
+ 0.250F,
+ 0.0F,
+ -5.0F,
+ 5'000.0F,
+ 250.0F,
+ 0.0F,
+ 0x3FUL,
+};
+
+constexpr EAXREVERBPROPERTIES EAXREVERB_PRESET_BATHROOM =
+{
+ EAX_ENVIRONMENT_BATHROOM,
+ 1.4F,
+ 1.0F,
+ -1'000L,
+ -1'200L,
+ 0L,
+ 1.49F,
+ 0.54F,
+ 1.0F,
+ -370L,
+ 0.007F,
+ EAXVECTOR{},
+ 1'030L,
+ 0.011F,
+ EAXVECTOR{},
+ 0.250F,
+ 0.0F,
+ 0.250F,
+ 0.0F,
+ -5.0F,
+ 5'000.0F,
+ 250.0F,
+ 0.0F,
+ 0x3FUL,
+};
+
+constexpr EAXREVERBPROPERTIES EAXREVERB_PRESET_LIVINGROOM =
+{
+ EAX_ENVIRONMENT_LIVINGROOM,
+ 2.5F,
+ 1.0F,
+ -1'000L,
+ -6'000L,
+ 0L,
+ 0.50F,
+ 0.10F,
+ 1.0F,
+ -1'376,
+ 0.003F,
+ EAXVECTOR{},
+ -1'104L,
+ 0.004F,
+ EAXVECTOR{},
+ 0.250F,
+ 0.0F,
+ 0.250F,
+ 0.0F,
+ -5.0F,
+ 5'000.0F,
+ 250.0F,
+ 0.0F,
+ 0x3FUL,
+};
+
+constexpr EAXREVERBPROPERTIES EAXREVERB_PRESET_STONEROOM =
+{
+ EAX_ENVIRONMENT_STONEROOM,
+ 11.6F,
+ 1.0F,
+ -1'000L,
+ -300L,
+ 0L,
+ 2.31F,
+ 0.64F,
+ 1.0F,
+ -711L,
+ 0.012F,
+ EAXVECTOR{},
+ 83L,
+ 0.017F,
+ EAXVECTOR{},
+ 0.250F,
+ 0.0F,
+ 0.250F,
+ 0.0F,
+ -5.0F,
+ 5'000.0F,
+ 250.0F,
+ 0.0F,
+ 0x3FUL,
+};
+
+constexpr EAXREVERBPROPERTIES EAXREVERB_PRESET_AUDITORIUM =
+{
+ EAX_ENVIRONMENT_AUDITORIUM,
+ 21.6F,
+ 1.0F,
+ -1'000L,
+ -476L,
+ 0L,
+ 4.32F,
+ 0.59F,
+ 1.0F,
+ -789L,
+ 0.020F,
+ EAXVECTOR{},
+ -289L,
+ 0.030F,
+ EAXVECTOR{},
+ 0.250F,
+ 0.0F,
+ 0.250F,
+ 0.0F,
+ -5.0F,
+ 5'000.0F,
+ 250.0F,
+ 0.0F,
+ 0x3FUL,
+};
+
+constexpr EAXREVERBPROPERTIES EAXREVERB_PRESET_CONCERTHALL =
+{
+ EAX_ENVIRONMENT_CONCERTHALL,
+ 19.6F,
+ 1.0F,
+ -1'000L,
+ -500L,
+ 0L,
+ 3.92F,
+ 0.70F,
+ 1.0F,
+ -1'230L,
+ 0.020F,
+ EAXVECTOR{},
+ -2L,
+ 0.029F,
+ EAXVECTOR{},
+ 0.250F,
+ 0.0F,
+ 0.250F,
+ 0.0F,
+ -5.0F,
+ 5'000.0F,
+ 250.0F,
+ 0.0F,
+ 0x3FUL,
+};
+
+constexpr EAXREVERBPROPERTIES EAXREVERB_PRESET_CAVE =
+{
+ EAX_ENVIRONMENT_CAVE,
+ 14.6F,
+ 1.0F,
+ -1'000L,
+ 0L,
+ 0L,
+ 2.91F,
+ 1.30F,
+ 1.0F,
+ -602L,
+ 0.015F,
+ EAXVECTOR{},
+ -302L,
+ 0.022F,
+ EAXVECTOR{},
+ 0.250F,
+ 0.0F,
+ 0.250F,
+ 0.0F,
+ -5.0F,
+ 5'000.0F,
+ 250.0F,
+ 0.0F,
+ 0x1FUL,
+};
+
+constexpr EAXREVERBPROPERTIES EAXREVERB_PRESET_ARENA =
+{
+ EAX_ENVIRONMENT_ARENA,
+ 36.2F,
+ 1.0F,
+ -1'000L,
+ -698L,
+ 0L,
+ 7.24F,
+ 0.33F,
+ 1.0F,
+ -1'166L,
+ 0.020F,
+ EAXVECTOR{},
+ 16L,
+ 0.030F,
+ EAXVECTOR{},
+ 0.250F,
+ 0.0F,
+ 0.250F,
+ 0.0F,
+ -5.0F,
+ 5'000.0F,
+ 250.0F,
+ 0.0F,
+ 0x3FUL,
+};
+
+constexpr EAXREVERBPROPERTIES EAXREVERB_PRESET_HANGAR =
+{
+ EAX_ENVIRONMENT_HANGAR,
+ 50.3F,
+ 1.0F,
+ -1'000L,
+ -1'000L,
+ 0L,
+ 10.05F,
+ 0.23F,
+ 1.0F,
+ -602L,
+ 0.020F,
+ EAXVECTOR{},
+ 198L,
+ 0.030F,
+ EAXVECTOR{},
+ 0.250F,
+ 0.0F,
+ 0.250F,
+ 0.0F,
+ -5.0F,
+ 5'000.0F,
+ 250.0F,
+ 0.0F,
+ 0x3FUL,
+};
+
+constexpr EAXREVERBPROPERTIES EAXREVERB_PRESET_CARPETTEDHALLWAY =
+{
+ EAX_ENVIRONMENT_CARPETEDHALLWAY,
+ 1.9F,
+ 1.0F,
+ -1'000L,
+ -4'000L,
+ 0L,
+ 0.30F,
+ 0.10F,
+ 1.0F,
+ -1'831L,
+ 0.002F,
+ EAXVECTOR{},
+ -1'630L,
+ 0.030F,
+ EAXVECTOR{},
+ 0.250F,
+ 0.0F,
+ 0.250F,
+ 0.0F,
+ -5.0F,
+ 5'000.0F,
+ 250.0F,
+ 0.0F,
+ 0x3FUL,
+};
+
+constexpr EAXREVERBPROPERTIES EAXREVERB_PRESET_HALLWAY =
+{
+ EAX_ENVIRONMENT_HALLWAY,
+ 1.8F,
+ 1.0F,
+ -1'000L,
+ -300L,
+ 0L,
+ 1.49F,
+ 0.59F,
+ 1.0F,
+ -1'219L,
+ 0.007F,
+ EAXVECTOR{},
+ 441L,
+ 0.011F,
+ EAXVECTOR{},
+ 0.250F,
+ 0.0F,
+ 0.250F,
+ 0.0F,
+ -5.0F,
+ 5'000.0F,
+ 250.0F,
+ 0.0F,
+ 0x3FUL,
+};
+
+constexpr EAXREVERBPROPERTIES EAXREVERB_PRESET_STONECORRIDOR =
+{
+ EAX_ENVIRONMENT_STONECORRIDOR,
+ 13.5F,
+ 1.0F,
+ -1'000L,
+ -237L,
+ 0L,
+ 2.70F,
+ 0.79F,
+ 1.0F,
+ -1'214L,
+ 0.013F,
+ EAXVECTOR{},
+ 395L,
+ 0.020F,
+ EAXVECTOR{},
+ 0.250F,
+ 0.0F,
+ 0.250F,
+ 0.0F,
+ -5.0F,
+ 5'000.0F,
+ 250.0F,
+ 0.0F,
+ 0x3FUL,
+};
+
+constexpr EAXREVERBPROPERTIES EAXREVERB_PRESET_ALLEY =
+{
+ EAX_ENVIRONMENT_ALLEY,
+ 7.5F,
+ 0.300F,
+ -1'000L,
+ -270L,
+ 0L,
+ 1.49F,
+ 0.86F,
+ 1.0F,
+ -1'204L,
+ 0.007F,
+ EAXVECTOR{},
+ -4L,
+ 0.011F,
+ EAXVECTOR{},
+ 0.125F,
+ 0.950F,
+ 0.250F,
+ 0.0F,
+ -5.0F,
+ 5'000.0F,
+ 250.0F,
+ 0.0F,
+ 0x3FUL,
+};
+
+constexpr EAXREVERBPROPERTIES EAXREVERB_PRESET_FOREST =
+{
+ EAX_ENVIRONMENT_FOREST,
+ 38.0F,
+ 0.300F,
+ -1'000L,
+ -3'300L,
+ 0L,
+ 1.49F,
+ 0.54F,
+ 1.0F,
+ -2'560L,
+ 0.162F,
+ EAXVECTOR{},
+ -229L,
+ 0.088F,
+ EAXVECTOR{},
+ 0.125F,
+ 1.0F,
+ 0.250F,
+ 0.0F,
+ -5.0F,
+ 5'000.0F,
+ 250.0F,
+ 0.0F,
+ 0x3FUL,
+};
+
+constexpr EAXREVERBPROPERTIES EAXREVERB_PRESET_CITY =
+{
+ EAX_ENVIRONMENT_CITY,
+ 7.5F,
+ 0.500F,
+ -1'000L,
+ -800L,
+ 0L,
+ 1.49F,
+ 0.67F,
+ 1.0F,
+ -2'273L,
+ 0.007F,
+ EAXVECTOR{},
+ -1'691L,
+ 0.011F,
+ EAXVECTOR{},
+ 0.250F,
+ 0.0F,
+ 0.250F,
+ 0.0F,
+ -5.0F,
+ 5'000.0F,
+ 250.0F,
+ 0.0F,
+ 0x3FUL,
+};
+
+constexpr EAXREVERBPROPERTIES EAXREVERB_PRESET_MOUNTAINS =
+{
+ EAX_ENVIRONMENT_MOUNTAINS,
+ 100.0F,
+ 0.270F,
+ -1'000L,
+ -2'500L,
+ 0L,
+ 1.49F,
+ 0.21F,
+ 1.0F,
+ -2'780L,
+ 0.300F,
+ EAXVECTOR{},
+ -1'434L,
+ 0.100F,
+ EAXVECTOR{},
+ 0.250F,
+ 1.0F,
+ 0.250F,
+ 0.0F,
+ -5.0F,
+ 5'000.0F,
+ 250.0F,
+ 0.0F,
+ 0x1FUL,
+};
+
+constexpr EAXREVERBPROPERTIES EAXREVERB_PRESET_QUARRY =
+{
+ EAX_ENVIRONMENT_QUARRY,
+ 17.5F,
+ 1.0F,
+ -1'000L,
+ -1'000L,
+ 0L,
+ 1.49F,
+ 0.83F,
+ 1.0F,
+ -10'000L,
+ 0.061F,
+ EAXVECTOR{},
+ 500L,
+ 0.025F,
+ EAXVECTOR{},
+ 0.125F,
+ 0.700F,
+ 0.250F,
+ 0.0F,
+ -5.0F,
+ 5'000.0F,
+ 250.0F,
+ 0.0F,
+ 0x3FUL,
+};
+
+constexpr EAXREVERBPROPERTIES EAXREVERB_PRESET_PLAIN =
+{
+ EAX_ENVIRONMENT_PLAIN,
+ 42.5F,
+ 0.210F,
+ -1'000L,
+ -2'000L,
+ 0L,
+ 1.49F,
+ 0.50F,
+ 1.0F,
+ -2'466L,
+ 0.179F,
+ EAXVECTOR{},
+ -1'926L,
+ 0.100F,
+ EAXVECTOR{},
+ 0.250F,
+ 1.0F,
+ 0.250F,
+ 0.0F,
+ -5.0F,
+ 5'000.0F,
+ 250.0F,
+ 0.0F,
+ 0x3FUL,
+};
+
+constexpr EAXREVERBPROPERTIES EAXREVERB_PRESET_PARKINGLOT =
+{
+ EAX_ENVIRONMENT_PARKINGLOT,
+ 8.3F,
+ 1.0F,
+ -1'000L,
+ 0L,
+ 0L,
+ 1.65F,
+ 1.50F,
+ 1.0F,
+ -1'363L,
+ 0.008F,
+ EAXVECTOR{},
+ -1'153L,
+ 0.012F,
+ EAXVECTOR{},
+ 0.250F,
+ 0.0F,
+ 0.250F,
+ 0.0F,
+ -5.0F,
+ 5'000.0F,
+ 250.0F,
+ 0.0F,
+ 0x1FUL,
+};
+
+constexpr EAXREVERBPROPERTIES EAXREVERB_PRESET_SEWERPIPE =
+{
+ EAX_ENVIRONMENT_SEWERPIPE,
+ 1.7F,
+ 0.800F,
+ -1'000L,
+ -1'000L,
+ 0L,
+ 2.81F,
+ 0.14F,
+ 1.0F,
+ 429L,
+ 0.014F,
+ EAXVECTOR{},
+ 1'023L,
+ 0.021F,
+ EAXVECTOR{},
+ 0.250F,
+ 0.0F,
+ 0.250F,
+ 0.0F,
+ -5.0F,
+ 5'000.0F,
+ 250.0F,
+ 0.0F,
+ 0x3FUL,
+};
+
+constexpr EAXREVERBPROPERTIES EAXREVERB_PRESET_UNDERWATER =
+{
+ EAX_ENVIRONMENT_UNDERWATER,
+ 1.8F,
+ 1.0F,
+ -1'000L,
+ -4'000L,
+ 0L,
+ 1.49F,
+ 0.10F,
+ 1.0F,
+ -449L,
+ 0.007F,
+ EAXVECTOR{},
+ 1'700L,
+ 0.011F,
+ EAXVECTOR{},
+ 0.250F,
+ 0.0F,
+ 1.180F,
+ 0.348F,
+ -5.0F,
+ 5'000.0F,
+ 250.0F,
+ 0.0F,
+ 0x3FUL,
+};
+
+constexpr EAXREVERBPROPERTIES EAXREVERB_PRESET_DRUGGED =
+{
+ EAX_ENVIRONMENT_DRUGGED,
+ 1.9F,
+ 0.500F,
+ -1'000L,
+ 0L,
+ 0L,
+ 8.39F,
+ 1.39F,
+ 1.0F,
+ -115L,
+ 0.002F,
+ EAXVECTOR{},
+ 985L,
+ 0.030F,
+ EAXVECTOR{},
+ 0.250F,
+ 0.0F,
+ 0.250F,
+ 1.0F,
+ -5.0F,
+ 5'000.0F,
+ 250.0F,
+ 0.0F,
+ 0x1FUL,
+};
+
+constexpr EAXREVERBPROPERTIES EAXREVERB_PRESET_DIZZY =
+{
+ EAX_ENVIRONMENT_DIZZY,
+ 1.8F,
+ 0.600F,
+ -1'000L,
+ -400L,
+ 0L,
+ 17.23F,
+ 0.56F,
+ 1.0F,
+ -1'713L,
+ 0.020F,
+ EAXVECTOR{},
+ -613L,
+ 0.030F,
+ EAXVECTOR{},
+ 0.250F,
+ 1.0F,
+ 0.810F,
+ 0.310F,
+ -5.0F,
+ 5'000.0F,
+ 250.0F,
+ 0.0F,
+ 0x1FUL,
+};
+
+constexpr EAXREVERBPROPERTIES EAXREVERB_PRESET_PSYCHOTIC =
+{
+ EAX_ENVIRONMENT_PSYCHOTIC,
+ 1.0F,
+ 0.500F,
+ -1'000L,
+ -151L,
+ 0L,
+ 7.56F,
+ 0.91F,
+ 1.0F,
+ -626L,
+ 0.020F,
+ EAXVECTOR{},
+ 774L,
+ 0.030F,
+ EAXVECTOR{},
+ 0.250F,
+ 0.0F,
+ 4.0F,
+ 1.0F,
+ -5.0F,
+ 5'000.0F,
+ 250.0F,
+ 0.0F,
+ 0x1FUL,
+};
+
+} // namespace
+
+const EaxReverbPresets EAXREVERB_PRESETS{{
+ EAXREVERB_PRESET_GENERIC,
+ EAXREVERB_PRESET_PADDEDCELL,
+ EAXREVERB_PRESET_ROOM,
+ EAXREVERB_PRESET_BATHROOM,
+ EAXREVERB_PRESET_LIVINGROOM,
+ EAXREVERB_PRESET_STONEROOM,
+ EAXREVERB_PRESET_AUDITORIUM,
+ EAXREVERB_PRESET_CONCERTHALL,
+ EAXREVERB_PRESET_CAVE,
+ EAXREVERB_PRESET_ARENA,
+ EAXREVERB_PRESET_HANGAR,
+ EAXREVERB_PRESET_CARPETTEDHALLWAY,
+ EAXREVERB_PRESET_HALLWAY,
+ EAXREVERB_PRESET_STONECORRIDOR,
+ EAXREVERB_PRESET_ALLEY,
+ EAXREVERB_PRESET_FOREST,
+ EAXREVERB_PRESET_CITY,
+ EAXREVERB_PRESET_MOUNTAINS,
+ EAXREVERB_PRESET_QUARRY,
+ EAXREVERB_PRESET_PLAIN,
+ EAXREVERB_PRESET_PARKINGLOT,
+ EAXREVERB_PRESET_SEWERPIPE,
+ EAXREVERB_PRESET_UNDERWATER,
+ EAXREVERB_PRESET_DRUGGED,
+ EAXREVERB_PRESET_DIZZY,
+ EAXREVERB_PRESET_PSYCHOTIC,
+}};
+
+namespace {
+constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_GENERIC = {EAX_ENVIRONMENT_GENERIC, 0.5F, 1.493F, 0.5F};
+constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_PADDEDCELL = {EAX_ENVIRONMENT_PADDEDCELL, 0.25F, 0.1F, 0.0F};
+constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_ROOM = {EAX_ENVIRONMENT_ROOM, 0.417F, 0.4F, 0.666F};
+constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_BATHROOM = {EAX_ENVIRONMENT_BATHROOM, 0.653F, 1.499F, 0.166F};
+constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_LIVINGROOM = {EAX_ENVIRONMENT_LIVINGROOM, 0.208F, 0.478F, 0.0F};
+constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_STONEROOM = {EAX_ENVIRONMENT_STONEROOM, 0.5F, 2.309F, 0.888F};
+constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_AUDITORIUM = {EAX_ENVIRONMENT_AUDITORIUM, 0.403F, 4.279F, 0.5F};
+constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_CONCERTHALL = {EAX_ENVIRONMENT_CONCERTHALL, 0.5F, 3.961F, 0.5F};
+constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_CAVE = {EAX_ENVIRONMENT_CAVE, 0.5F, 2.886F, 1.304F};
+constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_ARENA = {EAX_ENVIRONMENT_ARENA, 0.361F, 7.284F, 0.332F};
+constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_HANGAR = {EAX_ENVIRONMENT_HANGAR, 0.5F, 10.0F, 0.3F};
+constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_CARPETTEDHALLWAY = {EAX_ENVIRONMENT_CARPETEDHALLWAY, 0.153F, 0.259F, 2.0F};
+constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_HALLWAY = {EAX_ENVIRONMENT_HALLWAY, 0.361F, 1.493F, 0.0F};
+constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_STONECORRIDOR = {EAX_ENVIRONMENT_STONECORRIDOR, 0.444F, 2.697F, 0.638F};
+constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_ALLEY = {EAX_ENVIRONMENT_ALLEY, 0.25F, 1.752F, 0.776F};
+constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_FOREST = {EAX_ENVIRONMENT_FOREST, 0.111F, 3.145F, 0.472F};
+constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_CITY = {EAX_ENVIRONMENT_CITY, 0.111F, 2.767F, 0.224F};
+constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_MOUNTAINS = {EAX_ENVIRONMENT_MOUNTAINS, 0.194F, 7.841F, 0.472F};
+constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_QUARRY = {EAX_ENVIRONMENT_QUARRY, 1.0F, 1.499F, 0.5F};
+constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_PLAIN = {EAX_ENVIRONMENT_PLAIN, 0.097F, 2.767F, 0.224F};
+constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_PARKINGLOT = {EAX_ENVIRONMENT_PARKINGLOT, 0.208F, 1.652F, 1.5F};
+constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_SEWERPIPE = {EAX_ENVIRONMENT_SEWERPIPE, 0.652F, 2.886F, 0.25F};
+constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_UNDERWATER = {EAX_ENVIRONMENT_UNDERWATER, 1.0F, 1.499F, 0.0F};
+constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_DRUGGED = {EAX_ENVIRONMENT_DRUGGED, 0.875F, 8.392F, 1.388F};
+constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_DIZZY = {EAX_ENVIRONMENT_DIZZY, 0.139F, 17.234F, 0.666F};
+constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_PSYCHOTIC = {EAX_ENVIRONMENT_PSYCHOTIC, 0.486F, 7.563F, 0.806F};
+} // namespace
+
+const Eax1ReverbPresets EAX1REVERB_PRESETS{{
+ EAX1REVERB_PRESET_GENERIC,
+ EAX1REVERB_PRESET_PADDEDCELL,
+ EAX1REVERB_PRESET_ROOM,
+ EAX1REVERB_PRESET_BATHROOM,
+ EAX1REVERB_PRESET_LIVINGROOM,
+ EAX1REVERB_PRESET_STONEROOM,
+ EAX1REVERB_PRESET_AUDITORIUM,
+ EAX1REVERB_PRESET_CONCERTHALL,
+ EAX1REVERB_PRESET_CAVE,
+ EAX1REVERB_PRESET_ARENA,
+ EAX1REVERB_PRESET_HANGAR,
+ EAX1REVERB_PRESET_CARPETTEDHALLWAY,
+ EAX1REVERB_PRESET_HALLWAY,
+ EAX1REVERB_PRESET_STONECORRIDOR,
+ EAX1REVERB_PRESET_ALLEY,
+ EAX1REVERB_PRESET_FOREST,
+ EAX1REVERB_PRESET_CITY,
+ EAX1REVERB_PRESET_MOUNTAINS,
+ EAX1REVERB_PRESET_QUARRY,
+ EAX1REVERB_PRESET_PLAIN,
+ EAX1REVERB_PRESET_PARKINGLOT,
+ EAX1REVERB_PRESET_SEWERPIPE,
+ EAX1REVERB_PRESET_UNDERWATER,
+ EAX1REVERB_PRESET_DRUGGED,
+ EAX1REVERB_PRESET_DIZZY,
+ EAX1REVERB_PRESET_PSYCHOTIC,
+}};
diff --git a/al/eax/api.h b/al/eax/api.h
new file mode 100644
index 00000000..d0737d1d
--- /dev/null
+++ b/al/eax/api.h
@@ -0,0 +1,1557 @@
+#ifndef EAX_API_INCLUDED
+#define EAX_API_INCLUDED
+
+
+//
+// EAX API.
+//
+// Based on headers `eax[2-5].h` included in Doom 3 source code:
+// https://github.com/id-Software/DOOM-3/tree/master/neo/openal/include
+//
+
+
+#include <cfloat>
+#include <cstdint>
+#include <cstring>
+
+#include <array>
+
+#include "AL/al.h"
+
+
+#ifndef GUID_DEFINED
+#define GUID_DEFINED
+typedef struct _GUID
+{
+ std::uint32_t Data1;
+ std::uint16_t Data2;
+ std::uint16_t Data3;
+ std::uint8_t Data4[8];
+} GUID;
+
+inline bool operator==(const GUID& lhs, const GUID& rhs) noexcept
+{
+ return std::memcmp(&lhs, &rhs, sizeof(GUID)) == 0;
+}
+
+inline bool operator!=(const GUID& lhs, const GUID& rhs) noexcept
+{
+ return !(lhs == rhs);
+}
+#endif // GUID_DEFINED
+
+
+extern const GUID DSPROPSETID_EAX_ReverbProperties;
+
+enum DSPROPERTY_EAX_REVERBPROPERTY : unsigned int
+{
+ DSPROPERTY_EAX_ALL,
+ DSPROPERTY_EAX_ENVIRONMENT,
+ DSPROPERTY_EAX_VOLUME,
+ DSPROPERTY_EAX_DECAYTIME,
+ DSPROPERTY_EAX_DAMPING,
+}; // DSPROPERTY_EAX_REVERBPROPERTY
+
+struct EAX_REVERBPROPERTIES
+{
+ unsigned long environment;
+ float fVolume;
+ float fDecayTime_sec;
+ float fDamping;
+}; // EAX_REVERBPROPERTIES
+
+inline bool operator==(const EAX_REVERBPROPERTIES& lhs, const EAX_REVERBPROPERTIES& rhs) noexcept
+{
+ return std::memcmp(&lhs, &rhs, sizeof(EAX_REVERBPROPERTIES)) == 0;
+}
+
+extern const GUID DSPROPSETID_EAXBUFFER_ReverbProperties;
+
+enum DSPROPERTY_EAXBUFFER_REVERBPROPERTY : unsigned int
+{
+ DSPROPERTY_EAXBUFFER_ALL,
+ DSPROPERTY_EAXBUFFER_REVERBMIX,
+}; // DSPROPERTY_EAXBUFFER_REVERBPROPERTY
+
+struct EAXBUFFER_REVERBPROPERTIES
+{
+ float fMix;
+};
+
+inline bool operator==(const EAXBUFFER_REVERBPROPERTIES& lhs, const EAXBUFFER_REVERBPROPERTIES& rhs) noexcept
+{
+ return lhs.fMix == rhs.fMix;
+}
+
+constexpr auto EAX_BUFFER_MINREVERBMIX = 0.0F;
+constexpr auto EAX_BUFFER_MAXREVERBMIX = 1.0F;
+constexpr auto EAX_REVERBMIX_USEDISTANCE = -1.0F;
+
+
+extern const GUID DSPROPSETID_EAX20_ListenerProperties;
+
+enum DSPROPERTY_EAX20_LISTENERPROPERTY :
+ unsigned int
+{
+ DSPROPERTY_EAX20LISTENER_NONE,
+ DSPROPERTY_EAX20LISTENER_ALLPARAMETERS,
+ DSPROPERTY_EAX20LISTENER_ROOM,
+ DSPROPERTY_EAX20LISTENER_ROOMHF,
+ DSPROPERTY_EAX20LISTENER_ROOMROLLOFFFACTOR,
+ DSPROPERTY_EAX20LISTENER_DECAYTIME,
+ DSPROPERTY_EAX20LISTENER_DECAYHFRATIO,
+ DSPROPERTY_EAX20LISTENER_REFLECTIONS,
+ DSPROPERTY_EAX20LISTENER_REFLECTIONSDELAY,
+ DSPROPERTY_EAX20LISTENER_REVERB,
+ DSPROPERTY_EAX20LISTENER_REVERBDELAY,
+ DSPROPERTY_EAX20LISTENER_ENVIRONMENT,
+ DSPROPERTY_EAX20LISTENER_ENVIRONMENTSIZE,
+ DSPROPERTY_EAX20LISTENER_ENVIRONMENTDIFFUSION,
+ DSPROPERTY_EAX20LISTENER_AIRABSORPTIONHF,
+ DSPROPERTY_EAX20LISTENER_FLAGS
+}; // DSPROPERTY_EAX20_LISTENERPROPERTY
+
+struct EAX20LISTENERPROPERTIES
+{
+ long lRoom; // room effect level at low frequencies
+ long lRoomHF; // room effect high-frequency level re. low frequency level
+ float flRoomRolloffFactor; // like DS3D flRolloffFactor but for room effect
+ float flDecayTime; // reverberation decay time at low frequencies
+ float flDecayHFRatio; // high-frequency to low-frequency decay time ratio
+ long lReflections; // early reflections level relative to room effect
+ float flReflectionsDelay; // initial reflection delay time
+ long lReverb; // late reverberation level relative to room effect
+ float flReverbDelay; // late reverberation delay time relative to initial reflection
+ unsigned long dwEnvironment; // sets all listener properties
+ float flEnvironmentSize; // environment size in meters
+ float flEnvironmentDiffusion; // environment diffusion
+ float flAirAbsorptionHF; // change in level per meter at 5 kHz
+ unsigned long dwFlags; // modifies the behavior of properties
+}; // EAX20LISTENERPROPERTIES
+
+
+extern const GUID DSPROPSETID_EAX20_BufferProperties;
+
+
+enum DSPROPERTY_EAX20_BUFFERPROPERTY :
+ unsigned int
+{
+ DSPROPERTY_EAX20BUFFER_NONE,
+ DSPROPERTY_EAX20BUFFER_ALLPARAMETERS,
+ DSPROPERTY_EAX20BUFFER_DIRECT,
+ DSPROPERTY_EAX20BUFFER_DIRECTHF,
+ DSPROPERTY_EAX20BUFFER_ROOM,
+ DSPROPERTY_EAX20BUFFER_ROOMHF,
+ DSPROPERTY_EAX20BUFFER_ROOMROLLOFFFACTOR,
+ DSPROPERTY_EAX20BUFFER_OBSTRUCTION,
+ DSPROPERTY_EAX20BUFFER_OBSTRUCTIONLFRATIO,
+ DSPROPERTY_EAX20BUFFER_OCCLUSION,
+ DSPROPERTY_EAX20BUFFER_OCCLUSIONLFRATIO,
+ DSPROPERTY_EAX20BUFFER_OCCLUSIONROOMRATIO,
+ DSPROPERTY_EAX20BUFFER_OUTSIDEVOLUMEHF,
+ DSPROPERTY_EAX20BUFFER_AIRABSORPTIONFACTOR,
+ DSPROPERTY_EAX20BUFFER_FLAGS
+}; // DSPROPERTY_EAX20_BUFFERPROPERTY
+
+
+struct EAX20BUFFERPROPERTIES
+{
+ long lDirect; // direct path level
+ long lDirectHF; // direct path level at high frequencies
+ long lRoom; // room effect level
+ long lRoomHF; // room effect level at high frequencies
+ float flRoomRolloffFactor; // like DS3D flRolloffFactor but for room effect
+ long lObstruction; // main obstruction control (attenuation at high frequencies)
+ float flObstructionLFRatio; // obstruction low-frequency level re. main control
+ long lOcclusion; // main occlusion control (attenuation at high frequencies)
+ float flOcclusionLFRatio; // occlusion low-frequency level re. main control
+ float flOcclusionRoomRatio; // occlusion room effect level re. main control
+ long lOutsideVolumeHF; // outside sound cone level at high frequencies
+ float flAirAbsorptionFactor; // multiplies DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF
+ unsigned long dwFlags; // modifies the behavior of properties
+}; // EAX20BUFFERPROPERTIES
+
+
+extern const GUID DSPROPSETID_EAX30_ListenerProperties;
+
+extern const GUID DSPROPSETID_EAX30_BufferProperties;
+
+
+constexpr auto EAX_MAX_FXSLOTS = 4;
+
+constexpr auto EAX40_MAX_ACTIVE_FXSLOTS = 2;
+constexpr auto EAX50_MAX_ACTIVE_FXSLOTS = 4;
+
+
+constexpr auto EAX_OK = 0L;
+constexpr auto EAXERR_INVALID_OPERATION = -1L;
+constexpr auto EAXERR_INVALID_VALUE = -2L;
+constexpr auto EAXERR_NO_EFFECT_LOADED = -3L;
+constexpr auto EAXERR_UNKNOWN_EFFECT = -4L;
+constexpr auto EAXERR_INCOMPATIBLE_SOURCE_TYPE = -5L;
+constexpr auto EAXERR_INCOMPATIBLE_EAX_VERSION = -6L;
+
+
+extern const GUID EAX_NULL_GUID;
+
+extern const GUID EAX_PrimaryFXSlotID;
+
+
+struct EAXVECTOR
+{
+ float x;
+ float y;
+ float z;
+}; // EAXVECTOR
+
+inline bool operator==(const EAXVECTOR& lhs, const EAXVECTOR& rhs) noexcept
+{ return std::memcmp(&lhs, &rhs, sizeof(EAXVECTOR)) == 0; }
+
+inline bool operator!=(const EAXVECTOR& lhs, const EAXVECTOR& rhs) noexcept
+{ return !(lhs == rhs); }
+
+
+extern const GUID EAXPROPERTYID_EAX40_Context;
+
+extern const GUID EAXPROPERTYID_EAX50_Context;
+
+// EAX50
+enum :
+ unsigned long
+{
+ HEADPHONES = 0,
+ SPEAKERS_2,
+ SPEAKERS_4,
+ SPEAKERS_5, // 5.1 speakers
+ SPEAKERS_6, // 6.1 speakers
+ SPEAKERS_7, // 7.1 speakers
+};
+
+// EAX50
+enum :
+ unsigned long
+{
+ EAX_40 = 5, // EAX 4.0
+ EAX_50 = 6, // EAX 5.0
+};
+
+constexpr auto EAXCONTEXT_MINEAXSESSION = EAX_40;
+constexpr auto EAXCONTEXT_MAXEAXSESSION = EAX_50;
+constexpr auto EAXCONTEXT_DEFAULTEAXSESSION = EAX_40;
+
+constexpr auto EAXCONTEXT_MINMAXACTIVESENDS = 2UL;
+constexpr auto EAXCONTEXT_MAXMAXACTIVESENDS = 4UL;
+constexpr auto EAXCONTEXT_DEFAULTMAXACTIVESENDS = 2UL;
+
+// EAX50
+struct EAXSESSIONPROPERTIES
+{
+ unsigned long ulEAXVersion;
+ unsigned long ulMaxActiveSends;
+}; // EAXSESSIONPROPERTIES
+
+enum EAXCONTEXT_PROPERTY :
+ unsigned int
+{
+ EAXCONTEXT_NONE = 0,
+ EAXCONTEXT_ALLPARAMETERS,
+ EAXCONTEXT_PRIMARYFXSLOTID,
+ EAXCONTEXT_DISTANCEFACTOR,
+ EAXCONTEXT_AIRABSORPTIONHF,
+ EAXCONTEXT_HFREFERENCE,
+ EAXCONTEXT_LASTERROR,
+
+ // EAX50
+ EAXCONTEXT_SPEAKERCONFIG,
+ EAXCONTEXT_EAXSESSION,
+ EAXCONTEXT_MACROFXFACTOR,
+}; // EAXCONTEXT_PROPERTY
+
+struct EAX40CONTEXTPROPERTIES
+{
+ GUID guidPrimaryFXSlotID;
+ float flDistanceFactor;
+ float flAirAbsorptionHF;
+ float flHFReference;
+}; // EAX40CONTEXTPROPERTIES
+
+struct EAX50CONTEXTPROPERTIES :
+ public EAX40CONTEXTPROPERTIES
+{
+ float flMacroFXFactor;
+}; // EAX40CONTEXTPROPERTIES
+
+
+bool operator==(
+ const EAX40CONTEXTPROPERTIES& lhs,
+ const EAX40CONTEXTPROPERTIES& rhs) noexcept;
+
+bool operator==(
+ const EAX50CONTEXTPROPERTIES& lhs,
+ const EAX50CONTEXTPROPERTIES& rhs) noexcept;
+
+
+constexpr auto EAXCONTEXT_MINDISTANCEFACTOR = FLT_MIN;
+constexpr auto EAXCONTEXT_MAXDISTANCEFACTOR = FLT_MAX;
+constexpr auto EAXCONTEXT_DEFAULTDISTANCEFACTOR = 1.0F;
+
+constexpr auto EAXCONTEXT_MINAIRABSORPTIONHF = -100.0F;
+constexpr auto EAXCONTEXT_MAXAIRABSORPTIONHF = 0.0F;
+constexpr auto EAXCONTEXT_DEFAULTAIRABSORPTIONHF = -5.0F;
+
+constexpr auto EAXCONTEXT_MINHFREFERENCE = 1000.0F;
+constexpr auto EAXCONTEXT_MAXHFREFERENCE = 20000.0F;
+constexpr auto EAXCONTEXT_DEFAULTHFREFERENCE = 5000.0F;
+
+constexpr auto EAXCONTEXT_MINMACROFXFACTOR = 0.0F;
+constexpr auto EAXCONTEXT_MAXMACROFXFACTOR = 1.0F;
+constexpr auto EAXCONTEXT_DEFAULTMACROFXFACTOR = 0.0F;
+
+
+extern const GUID EAXPROPERTYID_EAX40_FXSlot0;
+
+extern const GUID EAXPROPERTYID_EAX50_FXSlot0;
+
+extern const GUID EAXPROPERTYID_EAX40_FXSlot1;
+
+extern const GUID EAXPROPERTYID_EAX50_FXSlot1;
+
+extern const GUID EAXPROPERTYID_EAX40_FXSlot2;
+
+extern const GUID EAXPROPERTYID_EAX50_FXSlot2;
+
+extern const GUID EAXPROPERTYID_EAX40_FXSlot3;
+
+extern const GUID EAXPROPERTYID_EAX50_FXSlot3;
+
+extern const GUID EAXCONTEXT_DEFAULTPRIMARYFXSLOTID;
+
+enum EAXFXSLOT_PROPERTY :
+ unsigned int
+{
+ EAXFXSLOT_PARAMETER = 0,
+
+ EAXFXSLOT_NONE = 0x10000,
+ EAXFXSLOT_ALLPARAMETERS,
+ EAXFXSLOT_LOADEFFECT,
+ EAXFXSLOT_VOLUME,
+ EAXFXSLOT_LOCK,
+ EAXFXSLOT_FLAGS,
+
+ // EAX50
+ EAXFXSLOT_OCCLUSION,
+ EAXFXSLOT_OCCLUSIONLFRATIO,
+}; // EAXFXSLOT_PROPERTY
+
+constexpr auto EAXFXSLOTFLAGS_ENVIRONMENT = 0x00000001UL;
+// EAX50
+constexpr auto EAXFXSLOTFLAGS_UPMIX = 0x00000002UL;
+
+constexpr auto EAX40FXSLOTFLAGS_RESERVED = 0xFFFFFFFEUL; // reserved future use
+constexpr auto EAX50FXSLOTFLAGS_RESERVED = 0xFFFFFFFCUL; // reserved future use
+
+
+constexpr auto EAXFXSLOT_MINVOLUME = -10'000L;
+constexpr auto EAXFXSLOT_MAXVOLUME = 0L;
+constexpr auto EAXFXSLOT_DEFAULTVOLUME = 0L;
+
+constexpr auto EAXFXSLOT_MINLOCK = 0L;
+constexpr auto EAXFXSLOT_MAXLOCK = 1L;
+
+enum :
+ long
+{
+ EAXFXSLOT_UNLOCKED = 0,
+ EAXFXSLOT_LOCKED = 1
+};
+
+constexpr auto EAXFXSLOT_MINOCCLUSION = -10'000L;
+constexpr auto EAXFXSLOT_MAXOCCLUSION = 0L;
+constexpr auto EAXFXSLOT_DEFAULTOCCLUSION = 0L;
+
+constexpr auto EAXFXSLOT_MINOCCLUSIONLFRATIO = 0.0F;
+constexpr auto EAXFXSLOT_MAXOCCLUSIONLFRATIO = 1.0F;
+constexpr auto EAXFXSLOT_DEFAULTOCCLUSIONLFRATIO = 0.25F;
+
+constexpr auto EAX40FXSLOT_DEFAULTFLAGS = EAXFXSLOTFLAGS_ENVIRONMENT;
+
+constexpr auto EAX50FXSLOT_DEFAULTFLAGS =
+ EAXFXSLOTFLAGS_ENVIRONMENT |
+ EAXFXSLOTFLAGS_UPMIX; // ignored for reverb;
+
+struct EAX40FXSLOTPROPERTIES
+{
+ GUID guidLoadEffect;
+ long lVolume;
+ long lLock;
+ unsigned long ulFlags;
+}; // EAX40FXSLOTPROPERTIES
+
+struct EAX50FXSLOTPROPERTIES :
+ public EAX40FXSLOTPROPERTIES
+{
+ long lOcclusion;
+ float flOcclusionLFRatio;
+}; // EAX50FXSLOTPROPERTIES
+
+bool operator==(
+ const EAX40FXSLOTPROPERTIES& lhs,
+ const EAX40FXSLOTPROPERTIES& rhs) noexcept;
+
+bool operator==(
+ const EAX50FXSLOTPROPERTIES& lhs,
+ const EAX50FXSLOTPROPERTIES& rhs) noexcept;
+
+extern const GUID EAXPROPERTYID_EAX40_Source;
+
+extern const GUID EAXPROPERTYID_EAX50_Source;
+
+// Source object properties
+enum EAXSOURCE_PROPERTY :
+ unsigned int
+{
+ // EAX30
+
+ EAXSOURCE_NONE,
+ EAXSOURCE_ALLPARAMETERS,
+ EAXSOURCE_OBSTRUCTIONPARAMETERS,
+ EAXSOURCE_OCCLUSIONPARAMETERS,
+ EAXSOURCE_EXCLUSIONPARAMETERS,
+ EAXSOURCE_DIRECT,
+ EAXSOURCE_DIRECTHF,
+ EAXSOURCE_ROOM,
+ EAXSOURCE_ROOMHF,
+ EAXSOURCE_OBSTRUCTION,
+ EAXSOURCE_OBSTRUCTIONLFRATIO,
+ EAXSOURCE_OCCLUSION,
+ EAXSOURCE_OCCLUSIONLFRATIO,
+ EAXSOURCE_OCCLUSIONROOMRATIO,
+ EAXSOURCE_OCCLUSIONDIRECTRATIO,
+ EAXSOURCE_EXCLUSION,
+ EAXSOURCE_EXCLUSIONLFRATIO,
+ EAXSOURCE_OUTSIDEVOLUMEHF,
+ EAXSOURCE_DOPPLERFACTOR,
+ EAXSOURCE_ROLLOFFFACTOR,
+ EAXSOURCE_ROOMROLLOFFFACTOR,
+ EAXSOURCE_AIRABSORPTIONFACTOR,
+ EAXSOURCE_FLAGS,
+
+ // EAX40
+
+ EAXSOURCE_SENDPARAMETERS,
+ EAXSOURCE_ALLSENDPARAMETERS,
+ EAXSOURCE_OCCLUSIONSENDPARAMETERS,
+ EAXSOURCE_EXCLUSIONSENDPARAMETERS,
+ EAXSOURCE_ACTIVEFXSLOTID,
+
+ // EAX50
+
+ EAXSOURCE_MACROFXFACTOR,
+ EAXSOURCE_SPEAKERLEVELS,
+ EAXSOURCE_ALL2DPARAMETERS,
+}; // EAXSOURCE_PROPERTY
+
+
+constexpr auto EAXSOURCEFLAGS_DIRECTHFAUTO = 0x00000001UL; // relates to EAXSOURCE_DIRECTHF
+constexpr auto EAXSOURCEFLAGS_ROOMAUTO = 0x00000002UL; // relates to EAXSOURCE_ROOM
+constexpr auto EAXSOURCEFLAGS_ROOMHFAUTO = 0x00000004UL; // relates to EAXSOURCE_ROOMHF
+// EAX50
+constexpr auto EAXSOURCEFLAGS_3DELEVATIONFILTER = 0x00000008UL;
+// EAX50
+constexpr auto EAXSOURCEFLAGS_UPMIX = 0x00000010UL;
+// EAX50
+constexpr auto EAXSOURCEFLAGS_APPLYSPEAKERLEVELS = 0x00000020UL;
+
+constexpr auto EAX20SOURCEFLAGS_RESERVED = 0xFFFFFFF8UL; // reserved future use
+constexpr auto EAX50SOURCEFLAGS_RESERVED = 0xFFFFFFC0UL; // reserved future use
+
+
+constexpr auto EAXSOURCE_MINSEND = -10'000L;
+constexpr auto EAXSOURCE_MAXSEND = 0L;
+constexpr auto EAXSOURCE_DEFAULTSEND = 0L;
+
+constexpr auto EAXSOURCE_MINSENDHF = -10'000L;
+constexpr auto EAXSOURCE_MAXSENDHF = 0L;
+constexpr auto EAXSOURCE_DEFAULTSENDHF = 0L;
+
+constexpr auto EAXSOURCE_MINDIRECT = -10'000L;
+constexpr auto EAXSOURCE_MAXDIRECT = 1'000L;
+constexpr auto EAXSOURCE_DEFAULTDIRECT = 0L;
+
+constexpr auto EAXSOURCE_MINDIRECTHF = -10'000L;
+constexpr auto EAXSOURCE_MAXDIRECTHF = 0L;
+constexpr auto EAXSOURCE_DEFAULTDIRECTHF = 0L;
+
+constexpr auto EAXSOURCE_MINROOM = -10'000L;
+constexpr auto EAXSOURCE_MAXROOM = 1'000L;
+constexpr auto EAXSOURCE_DEFAULTROOM = 0L;
+
+constexpr auto EAXSOURCE_MINROOMHF = -10'000L;
+constexpr auto EAXSOURCE_MAXROOMHF = 0L;
+constexpr auto EAXSOURCE_DEFAULTROOMHF = 0L;
+
+constexpr auto EAXSOURCE_MINOBSTRUCTION = -10'000L;
+constexpr auto EAXSOURCE_MAXOBSTRUCTION = 0L;
+constexpr auto EAXSOURCE_DEFAULTOBSTRUCTION = 0L;
+
+constexpr auto EAXSOURCE_MINOBSTRUCTIONLFRATIO = 0.0F;
+constexpr auto EAXSOURCE_MAXOBSTRUCTIONLFRATIO = 1.0F;
+constexpr auto EAXSOURCE_DEFAULTOBSTRUCTIONLFRATIO = 0.0F;
+
+constexpr auto EAXSOURCE_MINOCCLUSION = -10'000L;
+constexpr auto EAXSOURCE_MAXOCCLUSION = 0L;
+constexpr auto EAXSOURCE_DEFAULTOCCLUSION = 0L;
+
+constexpr auto EAXSOURCE_MINOCCLUSIONLFRATIO = 0.0F;
+constexpr auto EAXSOURCE_MAXOCCLUSIONLFRATIO = 1.0F;
+constexpr auto EAXSOURCE_DEFAULTOCCLUSIONLFRATIO = 0.25F;
+
+constexpr auto EAXSOURCE_MINOCCLUSIONROOMRATIO = 0.0F;
+constexpr auto EAXSOURCE_MAXOCCLUSIONROOMRATIO = 10.0F;
+constexpr auto EAXSOURCE_DEFAULTOCCLUSIONROOMRATIO = 1.5F;
+
+constexpr auto EAXSOURCE_MINOCCLUSIONDIRECTRATIO = 0.0F;
+constexpr auto EAXSOURCE_MAXOCCLUSIONDIRECTRATIO = 10.0F;
+constexpr auto EAXSOURCE_DEFAULTOCCLUSIONDIRECTRATIO = 1.0F;
+
+constexpr auto EAXSOURCE_MINEXCLUSION = -10'000L;
+constexpr auto EAXSOURCE_MAXEXCLUSION = 0L;
+constexpr auto EAXSOURCE_DEFAULTEXCLUSION = 0L;
+
+constexpr auto EAXSOURCE_MINEXCLUSIONLFRATIO = 0.0F;
+constexpr auto EAXSOURCE_MAXEXCLUSIONLFRATIO = 1.0F;
+constexpr auto EAXSOURCE_DEFAULTEXCLUSIONLFRATIO = 1.0F;
+
+constexpr auto EAXSOURCE_MINOUTSIDEVOLUMEHF = -10'000L;
+constexpr auto EAXSOURCE_MAXOUTSIDEVOLUMEHF = 0L;
+constexpr auto EAXSOURCE_DEFAULTOUTSIDEVOLUMEHF = 0L;
+
+constexpr auto EAXSOURCE_MINDOPPLERFACTOR = 0.0F;
+constexpr auto EAXSOURCE_MAXDOPPLERFACTOR = 10.0F;
+constexpr auto EAXSOURCE_DEFAULTDOPPLERFACTOR = 1.0F;
+
+constexpr auto EAXSOURCE_MINROLLOFFFACTOR = 0.0F;
+constexpr auto EAXSOURCE_MAXROLLOFFFACTOR = 10.0F;
+constexpr auto EAXSOURCE_DEFAULTROLLOFFFACTOR = 0.0F;
+
+constexpr auto EAXSOURCE_MINROOMROLLOFFFACTOR = 0.0F;
+constexpr auto EAXSOURCE_MAXROOMROLLOFFFACTOR = 10.0F;
+constexpr auto EAXSOURCE_DEFAULTROOMROLLOFFFACTOR = 0.0F;
+
+constexpr auto EAXSOURCE_MINAIRABSORPTIONFACTOR = 0.0F;
+constexpr auto EAXSOURCE_MAXAIRABSORPTIONFACTOR = 10.0F;
+constexpr auto EAXSOURCE_DEFAULTAIRABSORPTIONFACTOR = 0.0F;
+
+// EAX50
+
+constexpr auto EAXSOURCE_MINMACROFXFACTOR = 0.0F;
+constexpr auto EAXSOURCE_MAXMACROFXFACTOR = 1.0F;
+constexpr auto EAXSOURCE_DEFAULTMACROFXFACTOR = 1.0F;
+
+// EAX50
+
+constexpr auto EAXSOURCE_MINSPEAKERLEVEL = -10'000L;
+constexpr auto EAXSOURCE_MAXSPEAKERLEVEL = 0L;
+constexpr auto EAXSOURCE_DEFAULTSPEAKERLEVEL = -10'000L;
+
+constexpr auto EAXSOURCE_DEFAULTFLAGS =
+ EAXSOURCEFLAGS_DIRECTHFAUTO |
+ EAXSOURCEFLAGS_ROOMAUTO |
+ EAXSOURCEFLAGS_ROOMHFAUTO;
+
+enum :
+ long
+{
+ EAXSPEAKER_FRONT_LEFT = 1,
+ EAXSPEAKER_FRONT_CENTER = 2,
+ EAXSPEAKER_FRONT_RIGHT = 3,
+ EAXSPEAKER_SIDE_RIGHT = 4,
+ EAXSPEAKER_REAR_RIGHT = 5,
+ EAXSPEAKER_REAR_CENTER = 6,
+ EAXSPEAKER_REAR_LEFT = 7,
+ EAXSPEAKER_SIDE_LEFT = 8,
+ EAXSPEAKER_LOW_FREQUENCY = 9
+};
+
+// EAXSOURCEFLAGS_DIRECTHFAUTO, EAXSOURCEFLAGS_ROOMAUTO and EAXSOURCEFLAGS_ROOMHFAUTO are ignored for 2D sources
+// EAXSOURCEFLAGS_UPMIX is ignored for 3D sources
+constexpr auto EAX50SOURCE_DEFAULTFLAGS =
+ EAXSOURCEFLAGS_DIRECTHFAUTO |
+ EAXSOURCEFLAGS_ROOMAUTO |
+ EAXSOURCEFLAGS_ROOMHFAUTO |
+ EAXSOURCEFLAGS_UPMIX;
+
+struct EAX30SOURCEPROPERTIES
+{
+ long lDirect; // direct path level (at low and mid frequencies)
+ long lDirectHF; // relative direct path level at high frequencies
+ long lRoom; // room effect level (at low and mid frequencies)
+ long lRoomHF; // relative room effect level at high frequencies
+ long lObstruction; // main obstruction control (attenuation at high frequencies)
+ float flObstructionLFRatio; // obstruction low-frequency level re. main control
+ long lOcclusion; // main occlusion control (attenuation at high frequencies)
+ float flOcclusionLFRatio; // occlusion low-frequency level re. main control
+ float flOcclusionRoomRatio; // relative occlusion control for room effect
+ float flOcclusionDirectRatio; // relative occlusion control for direct path
+ long lExclusion; // main exlusion control (attenuation at high frequencies)
+ float flExclusionLFRatio; // exclusion low-frequency level re. main control
+ long lOutsideVolumeHF; // outside sound cone level at high frequencies
+ float flDopplerFactor; // like DS3D flDopplerFactor but per source
+ float flRolloffFactor; // like DS3D flRolloffFactor but per source
+ float flRoomRolloffFactor; // like DS3D flRolloffFactor but for room effect
+ float flAirAbsorptionFactor; // multiplies EAXREVERB_AIRABSORPTIONHF
+ unsigned long ulFlags; // modifies the behavior of properties
+}; // EAX30SOURCEPROPERTIES
+
+struct EAX50SOURCEPROPERTIES :
+ public EAX30SOURCEPROPERTIES
+{
+ float flMacroFXFactor;
+}; // EAX50SOURCEPROPERTIES
+
+struct EAXSOURCEALLSENDPROPERTIES
+{
+ GUID guidReceivingFXSlotID;
+ long lSend; // send level (at low and mid frequencies)
+ long lSendHF; // relative send level at high frequencies
+ long lOcclusion;
+ float flOcclusionLFRatio;
+ float flOcclusionRoomRatio;
+ float flOcclusionDirectRatio;
+ long lExclusion;
+ float flExclusionLFRatio;
+}; // EAXSOURCEALLSENDPROPERTIES
+
+struct EAXSOURCE2DPROPERTIES
+{
+ long lDirect; // direct path level (at low and mid frequencies)
+ long lDirectHF; // relative direct path level at high frequencies
+ long lRoom; // room effect level (at low and mid frequencies)
+ long lRoomHF; // relative room effect level at high frequencies
+ unsigned long ulFlags; // modifies the behavior of properties
+}; // EAXSOURCE2DPROPERTIES
+
+struct EAXSPEAKERLEVELPROPERTIES
+{
+ long lSpeakerID;
+ long lLevel;
+}; // EAXSPEAKERLEVELPROPERTIES
+
+struct EAX40ACTIVEFXSLOTS
+{
+ GUID guidActiveFXSlots[EAX40_MAX_ACTIVE_FXSLOTS];
+}; // EAX40ACTIVEFXSLOTS
+
+struct EAX50ACTIVEFXSLOTS
+{
+ GUID guidActiveFXSlots[EAX50_MAX_ACTIVE_FXSLOTS];
+}; // EAX50ACTIVEFXSLOTS
+
+bool operator==(
+ const EAX50ACTIVEFXSLOTS& lhs,
+ const EAX50ACTIVEFXSLOTS& rhs) noexcept;
+
+bool operator!=(
+ const EAX50ACTIVEFXSLOTS& lhs,
+ const EAX50ACTIVEFXSLOTS& rhs) noexcept;
+
+// Use this structure for EAXSOURCE_OBSTRUCTIONPARAMETERS property.
+struct EAXOBSTRUCTIONPROPERTIES
+{
+ long lObstruction;
+ float flObstructionLFRatio;
+}; // EAXOBSTRUCTIONPROPERTIES
+
+// Use this structure for EAXSOURCE_OCCLUSIONPARAMETERS property.
+struct EAXOCCLUSIONPROPERTIES
+{
+ long lOcclusion;
+ float flOcclusionLFRatio;
+ float flOcclusionRoomRatio;
+ float flOcclusionDirectRatio;
+}; // EAXOCCLUSIONPROPERTIES
+
+// Use this structure for EAXSOURCE_EXCLUSIONPARAMETERS property.
+struct EAXEXCLUSIONPROPERTIES
+{
+ long lExclusion;
+ float flExclusionLFRatio;
+}; // EAXEXCLUSIONPROPERTIES
+
+// Use this structure for EAXSOURCE_SENDPARAMETERS properties.
+struct EAXSOURCESENDPROPERTIES
+{
+ GUID guidReceivingFXSlotID;
+ long lSend;
+ long lSendHF;
+}; // EAXSOURCESENDPROPERTIES
+
+// Use this structure for EAXSOURCE_OCCLUSIONSENDPARAMETERS
+struct EAXSOURCEOCCLUSIONSENDPROPERTIES
+{
+ GUID guidReceivingFXSlotID;
+ long lOcclusion;
+ float flOcclusionLFRatio;
+ float flOcclusionRoomRatio;
+ float flOcclusionDirectRatio;
+}; // EAXSOURCEOCCLUSIONSENDPROPERTIES
+
+// Use this structure for EAXSOURCE_EXCLUSIONSENDPARAMETERS
+struct EAXSOURCEEXCLUSIONSENDPROPERTIES
+{
+ GUID guidReceivingFXSlotID;
+ long lExclusion;
+ float flExclusionLFRatio;
+}; // EAXSOURCEEXCLUSIONSENDPROPERTIES
+
+extern const EAX50ACTIVEFXSLOTS EAX40SOURCE_DEFAULTACTIVEFXSLOTID;
+
+extern const EAX50ACTIVEFXSLOTS EAX50SOURCE_3DDEFAULTACTIVEFXSLOTID;
+
+extern const EAX50ACTIVEFXSLOTS EAX50SOURCE_2DDEFAULTACTIVEFXSLOTID;
+
+
+// EAX Reverb Effect
+
+extern const GUID EAX_REVERB_EFFECT;
+
+// Reverb effect properties
+enum EAXREVERB_PROPERTY :
+ unsigned int
+{
+ EAXREVERB_NONE,
+ EAXREVERB_ALLPARAMETERS,
+ EAXREVERB_ENVIRONMENT,
+ EAXREVERB_ENVIRONMENTSIZE,
+ EAXREVERB_ENVIRONMENTDIFFUSION,
+ EAXREVERB_ROOM,
+ EAXREVERB_ROOMHF,
+ EAXREVERB_ROOMLF,
+ EAXREVERB_DECAYTIME,
+ EAXREVERB_DECAYHFRATIO,
+ EAXREVERB_DECAYLFRATIO,
+ EAXREVERB_REFLECTIONS,
+ EAXREVERB_REFLECTIONSDELAY,
+ EAXREVERB_REFLECTIONSPAN,
+ EAXREVERB_REVERB,
+ EAXREVERB_REVERBDELAY,
+ EAXREVERB_REVERBPAN,
+ EAXREVERB_ECHOTIME,
+ EAXREVERB_ECHODEPTH,
+ EAXREVERB_MODULATIONTIME,
+ EAXREVERB_MODULATIONDEPTH,
+ EAXREVERB_AIRABSORPTIONHF,
+ EAXREVERB_HFREFERENCE,
+ EAXREVERB_LFREFERENCE,
+ EAXREVERB_ROOMROLLOFFFACTOR,
+ EAXREVERB_FLAGS,
+}; // EAXREVERB_PROPERTY
+
+// used by EAXREVERB_ENVIRONMENT
+enum :
+ unsigned long
+{
+ EAX_ENVIRONMENT_GENERIC,
+ EAX_ENVIRONMENT_PADDEDCELL,
+ EAX_ENVIRONMENT_ROOM,
+ EAX_ENVIRONMENT_BATHROOM,
+ EAX_ENVIRONMENT_LIVINGROOM,
+ EAX_ENVIRONMENT_STONEROOM,
+ EAX_ENVIRONMENT_AUDITORIUM,
+ EAX_ENVIRONMENT_CONCERTHALL,
+ EAX_ENVIRONMENT_CAVE,
+ EAX_ENVIRONMENT_ARENA,
+ EAX_ENVIRONMENT_HANGAR,
+ EAX_ENVIRONMENT_CARPETEDHALLWAY,
+ EAX_ENVIRONMENT_HALLWAY,
+ EAX_ENVIRONMENT_STONECORRIDOR,
+ EAX_ENVIRONMENT_ALLEY,
+ EAX_ENVIRONMENT_FOREST,
+ EAX_ENVIRONMENT_CITY,
+ EAX_ENVIRONMENT_MOUNTAINS,
+ EAX_ENVIRONMENT_QUARRY,
+ EAX_ENVIRONMENT_PLAIN,
+ EAX_ENVIRONMENT_PARKINGLOT,
+ EAX_ENVIRONMENT_SEWERPIPE,
+ EAX_ENVIRONMENT_UNDERWATER,
+ EAX_ENVIRONMENT_DRUGGED,
+ EAX_ENVIRONMENT_DIZZY,
+ EAX_ENVIRONMENT_PSYCHOTIC,
+
+ EAX1_ENVIRONMENT_COUNT,
+
+ // EAX30
+ EAX_ENVIRONMENT_UNDEFINED = EAX1_ENVIRONMENT_COUNT,
+
+ EAX3_ENVIRONMENT_COUNT,
+};
+
+
+// reverberation decay time
+constexpr auto EAXREVERBFLAGS_DECAYTIMESCALE = 0x00000001UL;
+
+// reflection level
+constexpr auto EAXREVERBFLAGS_REFLECTIONSSCALE = 0x00000002UL;
+
+// initial reflection delay time
+constexpr auto EAXREVERBFLAGS_REFLECTIONSDELAYSCALE = 0x00000004UL;
+
+// reflections level
+constexpr auto EAXREVERBFLAGS_REVERBSCALE = 0x00000008UL;
+
+// late reverberation delay time
+constexpr auto EAXREVERBFLAGS_REVERBDELAYSCALE = 0x00000010UL;
+
+// echo time
+// EAX30+
+constexpr auto EAXREVERBFLAGS_ECHOTIMESCALE = 0x00000040UL;
+
+// modulation time
+// EAX30+
+constexpr auto EAXREVERBFLAGS_MODULATIONTIMESCALE = 0x00000080UL;
+
+// This flag limits high-frequency decay time according to air absorption.
+constexpr auto EAXREVERBFLAGS_DECAYHFLIMIT = 0x00000020UL;
+
+constexpr auto EAXREVERBFLAGS_RESERVED = 0xFFFFFF00UL; // reserved future use
+
+
+struct EAXREVERBPROPERTIES
+{
+ unsigned long ulEnvironment; // sets all reverb properties
+ float flEnvironmentSize; // environment size in meters
+ float flEnvironmentDiffusion; // environment diffusion
+ long lRoom; // room effect level (at mid frequencies)
+ long lRoomHF; // relative room effect level at high frequencies
+ long lRoomLF; // relative room effect level at low frequencies
+ float flDecayTime; // reverberation decay time at mid frequencies
+ float flDecayHFRatio; // high-frequency to mid-frequency decay time ratio
+ float flDecayLFRatio; // low-frequency to mid-frequency decay time ratio
+ long lReflections; // early reflections level relative to room effect
+ float flReflectionsDelay; // initial reflection delay time
+ EAXVECTOR vReflectionsPan; // early reflections panning vector
+ long lReverb; // late reverberation level relative to room effect
+ float flReverbDelay; // late reverberation delay time relative to initial reflection
+ EAXVECTOR vReverbPan; // late reverberation panning vector
+ float flEchoTime; // echo time
+ float flEchoDepth; // echo depth
+ float flModulationTime; // modulation time
+ float flModulationDepth; // modulation depth
+ float flAirAbsorptionHF; // change in level per meter at high frequencies
+ float flHFReference; // reference high frequency
+ float flLFReference; // reference low frequency
+ float flRoomRolloffFactor; // like DS3D flRolloffFactor but for room effect
+ unsigned long ulFlags; // modifies the behavior of properties
+}; // EAXREVERBPROPERTIES
+
+bool operator==(
+ const EAXREVERBPROPERTIES& lhs,
+ const EAXREVERBPROPERTIES& rhs) noexcept;
+
+bool operator!=(
+ const EAXREVERBPROPERTIES& lhs,
+ const EAXREVERBPROPERTIES& rhs) noexcept;
+
+
+constexpr auto EAXREVERB_MINENVIRONMENT = static_cast<unsigned long>(EAX_ENVIRONMENT_GENERIC);
+constexpr auto EAX1REVERB_MAXENVIRONMENT = static_cast<unsigned long>(EAX_ENVIRONMENT_PSYCHOTIC);
+constexpr auto EAX30REVERB_MAXENVIRONMENT = static_cast<unsigned long>(EAX_ENVIRONMENT_UNDEFINED);
+constexpr auto EAXREVERB_DEFAULTENVIRONMENT = static_cast<unsigned long>(EAX_ENVIRONMENT_GENERIC);
+
+constexpr auto EAXREVERB_MINENVIRONMENTSIZE = 1.0F;
+constexpr auto EAXREVERB_MAXENVIRONMENTSIZE = 100.0F;
+constexpr auto EAXREVERB_DEFAULTENVIRONMENTSIZE = 7.5F;
+
+constexpr auto EAXREVERB_MINENVIRONMENTDIFFUSION = 0.0F;
+constexpr auto EAXREVERB_MAXENVIRONMENTDIFFUSION = 1.0F;
+constexpr auto EAXREVERB_DEFAULTENVIRONMENTDIFFUSION = 1.0F;
+
+constexpr auto EAXREVERB_MINROOM = -10'000L;
+constexpr auto EAXREVERB_MAXROOM = 0L;
+constexpr auto EAXREVERB_DEFAULTROOM = -1'000L;
+
+constexpr auto EAXREVERB_MINROOMHF = -10'000L;
+constexpr auto EAXREVERB_MAXROOMHF = 0L;
+constexpr auto EAXREVERB_DEFAULTROOMHF = -100L;
+
+constexpr auto EAXREVERB_MINROOMLF = -10'000L;
+constexpr auto EAXREVERB_MAXROOMLF = 0L;
+constexpr auto EAXREVERB_DEFAULTROOMLF = 0L;
+
+constexpr auto EAXREVERB_MINDECAYTIME = 0.1F;
+constexpr auto EAXREVERB_MAXDECAYTIME = 20.0F;
+constexpr auto EAXREVERB_DEFAULTDECAYTIME = 1.49F;
+
+constexpr auto EAXREVERB_MINDECAYHFRATIO = 0.1F;
+constexpr auto EAXREVERB_MAXDECAYHFRATIO = 2.0F;
+constexpr auto EAXREVERB_DEFAULTDECAYHFRATIO = 0.83F;
+
+constexpr auto EAXREVERB_MINDECAYLFRATIO = 0.1F;
+constexpr auto EAXREVERB_MAXDECAYLFRATIO = 2.0F;
+constexpr auto EAXREVERB_DEFAULTDECAYLFRATIO = 1.0F;
+
+constexpr auto EAXREVERB_MINREFLECTIONS = -10'000L;
+constexpr auto EAXREVERB_MAXREFLECTIONS = 1'000L;
+constexpr auto EAXREVERB_DEFAULTREFLECTIONS = -2'602L;
+
+constexpr auto EAXREVERB_MINREFLECTIONSDELAY = 0.0F;
+constexpr auto EAXREVERB_MAXREFLECTIONSDELAY = 0.3F;
+constexpr auto EAXREVERB_DEFAULTREFLECTIONSDELAY = 0.007F;
+
+constexpr auto EAXREVERB_DEFAULTREFLECTIONSPAN = EAXVECTOR{0.0F, 0.0F, 0.0F};
+
+constexpr auto EAXREVERB_MINREVERB = -10'000L;
+constexpr auto EAXREVERB_MAXREVERB = 2'000L;
+constexpr auto EAXREVERB_DEFAULTREVERB = 200L;
+
+constexpr auto EAXREVERB_MINREVERBDELAY = 0.0F;
+constexpr auto EAXREVERB_MAXREVERBDELAY = 0.1F;
+constexpr auto EAXREVERB_DEFAULTREVERBDELAY = 0.011F;
+
+constexpr auto EAXREVERB_DEFAULTREVERBPAN = EAXVECTOR{0.0F, 0.0F, 0.0F};
+
+constexpr auto EAXREVERB_MINECHOTIME = 0.075F;
+constexpr auto EAXREVERB_MAXECHOTIME = 0.25F;
+constexpr auto EAXREVERB_DEFAULTECHOTIME = 0.25F;
+
+constexpr auto EAXREVERB_MINECHODEPTH = 0.0F;
+constexpr auto EAXREVERB_MAXECHODEPTH = 1.0F;
+constexpr auto EAXREVERB_DEFAULTECHODEPTH = 0.0F;
+
+constexpr auto EAXREVERB_MINMODULATIONTIME = 0.04F;
+constexpr auto EAXREVERB_MAXMODULATIONTIME = 4.0F;
+constexpr auto EAXREVERB_DEFAULTMODULATIONTIME = 0.25F;
+
+constexpr auto EAXREVERB_MINMODULATIONDEPTH = 0.0F;
+constexpr auto EAXREVERB_MAXMODULATIONDEPTH = 1.0F;
+constexpr auto EAXREVERB_DEFAULTMODULATIONDEPTH = 0.0F;
+
+constexpr auto EAXREVERB_MINAIRABSORPTIONHF = -100.0F;
+constexpr auto EAXREVERB_MAXAIRABSORPTIONHF = 0.0F;
+constexpr auto EAXREVERB_DEFAULTAIRABSORPTIONHF = -5.0F;
+
+constexpr auto EAXREVERB_MINHFREFERENCE = 1'000.0F;
+constexpr auto EAXREVERB_MAXHFREFERENCE = 20'000.0F;
+constexpr auto EAXREVERB_DEFAULTHFREFERENCE = 5'000.0F;
+
+constexpr auto EAXREVERB_MINLFREFERENCE = 20.0F;
+constexpr auto EAXREVERB_MAXLFREFERENCE = 1'000.0F;
+constexpr auto EAXREVERB_DEFAULTLFREFERENCE = 250.0F;
+
+constexpr auto EAXREVERB_MINROOMROLLOFFFACTOR = 0.0F;
+constexpr auto EAXREVERB_MAXROOMROLLOFFFACTOR = 10.0F;
+constexpr auto EAXREVERB_DEFAULTROOMROLLOFFFACTOR = 0.0F;
+
+constexpr auto EAX1REVERB_MINVOLUME = 0.0F;
+constexpr auto EAX1REVERB_MAXVOLUME = 1.0F;
+
+constexpr auto EAX1REVERB_MINDAMPING = 0.0F;
+constexpr auto EAX1REVERB_MAXDAMPING = 2.0F;
+
+constexpr auto EAXREVERB_DEFAULTFLAGS =
+ EAXREVERBFLAGS_DECAYTIMESCALE |
+ EAXREVERBFLAGS_REFLECTIONSSCALE |
+ EAXREVERBFLAGS_REFLECTIONSDELAYSCALE |
+ EAXREVERBFLAGS_REVERBSCALE |
+ EAXREVERBFLAGS_REVERBDELAYSCALE |
+ EAXREVERBFLAGS_DECAYHFLIMIT;
+
+
+using EaxReverbPresets = std::array<EAXREVERBPROPERTIES, EAX1_ENVIRONMENT_COUNT>;
+extern const EaxReverbPresets EAXREVERB_PRESETS;
+
+
+using Eax1ReverbPresets = std::array<EAX_REVERBPROPERTIES, EAX1_ENVIRONMENT_COUNT>;
+extern const Eax1ReverbPresets EAX1REVERB_PRESETS;
+
+
+// AGC Compressor Effect
+
+extern const GUID EAX_AGCCOMPRESSOR_EFFECT;
+
+enum EAXAGCCOMPRESSOR_PROPERTY :
+ unsigned int
+{
+ EAXAGCCOMPRESSOR_NONE,
+ EAXAGCCOMPRESSOR_ALLPARAMETERS,
+ EAXAGCCOMPRESSOR_ONOFF,
+}; // EAXAGCCOMPRESSOR_PROPERTY
+
+struct EAXAGCCOMPRESSORPROPERTIES
+{
+ unsigned long ulOnOff; // Switch Compressor on or off
+}; // EAXAGCCOMPRESSORPROPERTIES
+
+
+constexpr auto EAXAGCCOMPRESSOR_MINONOFF = 0UL;
+constexpr auto EAXAGCCOMPRESSOR_MAXONOFF = 1UL;
+constexpr auto EAXAGCCOMPRESSOR_DEFAULTONOFF = EAXAGCCOMPRESSOR_MAXONOFF;
+
+
+// Autowah Effect
+
+extern const GUID EAX_AUTOWAH_EFFECT;
+
+enum EAXAUTOWAH_PROPERTY :
+ unsigned int
+{
+ EAXAUTOWAH_NONE,
+ EAXAUTOWAH_ALLPARAMETERS,
+ EAXAUTOWAH_ATTACKTIME,
+ EAXAUTOWAH_RELEASETIME,
+ EAXAUTOWAH_RESONANCE,
+ EAXAUTOWAH_PEAKLEVEL,
+}; // EAXAUTOWAH_PROPERTY
+
+struct EAXAUTOWAHPROPERTIES
+{
+ float flAttackTime; // Attack time (seconds)
+ float flReleaseTime; // Release time (seconds)
+ long lResonance; // Resonance (mB)
+ long lPeakLevel; // Peak level (mB)
+}; // EAXAUTOWAHPROPERTIES
+
+
+constexpr auto EAXAUTOWAH_MINATTACKTIME = 0.0001F;
+constexpr auto EAXAUTOWAH_MAXATTACKTIME = 1.0F;
+constexpr auto EAXAUTOWAH_DEFAULTATTACKTIME = 0.06F;
+
+constexpr auto EAXAUTOWAH_MINRELEASETIME = 0.0001F;
+constexpr auto EAXAUTOWAH_MAXRELEASETIME = 1.0F;
+constexpr auto EAXAUTOWAH_DEFAULTRELEASETIME = 0.06F;
+
+constexpr auto EAXAUTOWAH_MINRESONANCE = 600L;
+constexpr auto EAXAUTOWAH_MAXRESONANCE = 6000L;
+constexpr auto EAXAUTOWAH_DEFAULTRESONANCE = 6000L;
+
+constexpr auto EAXAUTOWAH_MINPEAKLEVEL = -9000L;
+constexpr auto EAXAUTOWAH_MAXPEAKLEVEL = 9000L;
+constexpr auto EAXAUTOWAH_DEFAULTPEAKLEVEL = 2100L;
+
+
+// Chorus Effect
+
+extern const GUID EAX_CHORUS_EFFECT;
+
+
+enum EAXCHORUS_PROPERTY :
+ unsigned int
+{
+ EAXCHORUS_NONE,
+ EAXCHORUS_ALLPARAMETERS,
+ EAXCHORUS_WAVEFORM,
+ EAXCHORUS_PHASE,
+ EAXCHORUS_RATE,
+ EAXCHORUS_DEPTH,
+ EAXCHORUS_FEEDBACK,
+ EAXCHORUS_DELAY,
+}; // EAXCHORUS_PROPERTY
+
+enum :
+ unsigned long
+{
+ EAX_CHORUS_SINUSOID,
+ EAX_CHORUS_TRIANGLE,
+};
+
+struct EAXCHORUSPROPERTIES
+{
+ unsigned long ulWaveform; // Waveform selector - see enum above
+ long lPhase; // Phase (Degrees)
+ float flRate; // Rate (Hz)
+ float flDepth; // Depth (0 to 1)
+ float flFeedback; // Feedback (-1 to 1)
+ float flDelay; // Delay (seconds)
+}; // EAXCHORUSPROPERTIES
+
+
+constexpr auto EAXCHORUS_MINWAVEFORM = 0UL;
+constexpr auto EAXCHORUS_MAXWAVEFORM = 1UL;
+constexpr auto EAXCHORUS_DEFAULTWAVEFORM = 1UL;
+
+constexpr auto EAXCHORUS_MINPHASE = -180L;
+constexpr auto EAXCHORUS_MAXPHASE = 180L;
+constexpr auto EAXCHORUS_DEFAULTPHASE = 90L;
+
+constexpr auto EAXCHORUS_MINRATE = 0.0F;
+constexpr auto EAXCHORUS_MAXRATE = 10.0F;
+constexpr auto EAXCHORUS_DEFAULTRATE = 1.1F;
+
+constexpr auto EAXCHORUS_MINDEPTH = 0.0F;
+constexpr auto EAXCHORUS_MAXDEPTH = 1.0F;
+constexpr auto EAXCHORUS_DEFAULTDEPTH = 0.1F;
+
+constexpr auto EAXCHORUS_MINFEEDBACK = -1.0F;
+constexpr auto EAXCHORUS_MAXFEEDBACK = 1.0F;
+constexpr auto EAXCHORUS_DEFAULTFEEDBACK = 0.25F;
+
+constexpr auto EAXCHORUS_MINDELAY = 0.0002F;
+constexpr auto EAXCHORUS_MAXDELAY = 0.016F;
+constexpr auto EAXCHORUS_DEFAULTDELAY = 0.016F;
+
+
+// Distortion Effect
+
+extern const GUID EAX_DISTORTION_EFFECT;
+
+enum EAXDISTORTION_PROPERTY :
+ unsigned int
+{
+ EAXDISTORTION_NONE,
+ EAXDISTORTION_ALLPARAMETERS,
+ EAXDISTORTION_EDGE,
+ EAXDISTORTION_GAIN,
+ EAXDISTORTION_LOWPASSCUTOFF,
+ EAXDISTORTION_EQCENTER,
+ EAXDISTORTION_EQBANDWIDTH,
+}; // EAXDISTORTION_PROPERTY
+
+
+struct EAXDISTORTIONPROPERTIES
+{
+ float flEdge; // Controls the shape of the distortion (0 to 1)
+ long lGain; // Controls the post distortion gain (mB)
+ float flLowPassCutOff; // Controls the cut-off of the filter pre-distortion (Hz)
+ float flEQCenter; // Controls the center frequency of the EQ post-distortion (Hz)
+ float flEQBandwidth; // Controls the bandwidth of the EQ post-distortion (Hz)
+}; // EAXDISTORTIONPROPERTIES
+
+
+constexpr auto EAXDISTORTION_MINEDGE = 0.0F;
+constexpr auto EAXDISTORTION_MAXEDGE = 1.0F;
+constexpr auto EAXDISTORTION_DEFAULTEDGE = 0.2F;
+
+constexpr auto EAXDISTORTION_MINGAIN = -6000L;
+constexpr auto EAXDISTORTION_MAXGAIN = 0L;
+constexpr auto EAXDISTORTION_DEFAULTGAIN = -2600L;
+
+constexpr auto EAXDISTORTION_MINLOWPASSCUTOFF = 80.0F;
+constexpr auto EAXDISTORTION_MAXLOWPASSCUTOFF = 24000.0F;
+constexpr auto EAXDISTORTION_DEFAULTLOWPASSCUTOFF = 8000.0F;
+
+constexpr auto EAXDISTORTION_MINEQCENTER = 80.0F;
+constexpr auto EAXDISTORTION_MAXEQCENTER = 24000.0F;
+constexpr auto EAXDISTORTION_DEFAULTEQCENTER = 3600.0F;
+
+constexpr auto EAXDISTORTION_MINEQBANDWIDTH = 80.0F;
+constexpr auto EAXDISTORTION_MAXEQBANDWIDTH = 24000.0F;
+constexpr auto EAXDISTORTION_DEFAULTEQBANDWIDTH = 3600.0F;
+
+
+// Echo Effect
+
+extern const GUID EAX_ECHO_EFFECT;
+
+
+enum EAXECHO_PROPERTY :
+ unsigned int
+{
+ EAXECHO_NONE,
+ EAXECHO_ALLPARAMETERS,
+ EAXECHO_DELAY,
+ EAXECHO_LRDELAY,
+ EAXECHO_DAMPING,
+ EAXECHO_FEEDBACK,
+ EAXECHO_SPREAD,
+}; // EAXECHO_PROPERTY
+
+
+struct EAXECHOPROPERTIES
+{
+ float flDelay; // Controls the initial delay time (seconds)
+ float flLRDelay; // Controls the delay time between the first and second taps (seconds)
+ float flDamping; // Controls a low-pass filter that dampens the echoes (0 to 1)
+ float flFeedback; // Controls the duration of echo repetition (0 to 1)
+ float flSpread; // Controls the left-right spread of the echoes
+}; // EAXECHOPROPERTIES
+
+
+constexpr auto EAXECHO_MINDAMPING = 0.0F;
+constexpr auto EAXECHO_MAXDAMPING = 0.99F;
+constexpr auto EAXECHO_DEFAULTDAMPING = 0.5F;
+
+constexpr auto EAXECHO_MINDELAY = 0.002F;
+constexpr auto EAXECHO_MAXDELAY = 0.207F;
+constexpr auto EAXECHO_DEFAULTDELAY = 0.1F;
+
+constexpr auto EAXECHO_MINLRDELAY = 0.0F;
+constexpr auto EAXECHO_MAXLRDELAY = 0.404F;
+constexpr auto EAXECHO_DEFAULTLRDELAY = 0.1F;
+
+constexpr auto EAXECHO_MINFEEDBACK = 0.0F;
+constexpr auto EAXECHO_MAXFEEDBACK = 1.0F;
+constexpr auto EAXECHO_DEFAULTFEEDBACK = 0.5F;
+
+constexpr auto EAXECHO_MINSPREAD = -1.0F;
+constexpr auto EAXECHO_MAXSPREAD = 1.0F;
+constexpr auto EAXECHO_DEFAULTSPREAD = -1.0F;
+
+
+// Equalizer Effect
+
+extern const GUID EAX_EQUALIZER_EFFECT;
+
+
+enum EAXEQUALIZER_PROPERTY :
+ unsigned int
+{
+ EAXEQUALIZER_NONE,
+ EAXEQUALIZER_ALLPARAMETERS,
+ EAXEQUALIZER_LOWGAIN,
+ EAXEQUALIZER_LOWCUTOFF,
+ EAXEQUALIZER_MID1GAIN,
+ EAXEQUALIZER_MID1CENTER,
+ EAXEQUALIZER_MID1WIDTH,
+ EAXEQUALIZER_MID2GAIN,
+ EAXEQUALIZER_MID2CENTER,
+ EAXEQUALIZER_MID2WIDTH,
+ EAXEQUALIZER_HIGHGAIN,
+ EAXEQUALIZER_HIGHCUTOFF,
+}; // EAXEQUALIZER_PROPERTY
+
+
+struct EAXEQUALIZERPROPERTIES
+{
+ long lLowGain; // (mB)
+ float flLowCutOff; // (Hz)
+ long lMid1Gain; // (mB)
+ float flMid1Center; // (Hz)
+ float flMid1Width; // (octaves)
+ long lMid2Gain; // (mB)
+ float flMid2Center; // (Hz)
+ float flMid2Width; // (octaves)
+ long lHighGain; // (mB)
+ float flHighCutOff; // (Hz)
+}; // EAXEQUALIZERPROPERTIES
+
+
+constexpr auto EAXEQUALIZER_MINLOWGAIN = -1800L;
+constexpr auto EAXEQUALIZER_MAXLOWGAIN = 1800L;
+constexpr auto EAXEQUALIZER_DEFAULTLOWGAIN = 0L;
+
+constexpr auto EAXEQUALIZER_MINLOWCUTOFF = 50.0F;
+constexpr auto EAXEQUALIZER_MAXLOWCUTOFF = 800.0F;
+constexpr auto EAXEQUALIZER_DEFAULTLOWCUTOFF = 200.0F;
+
+constexpr auto EAXEQUALIZER_MINMID1GAIN = -1800L;
+constexpr auto EAXEQUALIZER_MAXMID1GAIN = 1800L;
+constexpr auto EAXEQUALIZER_DEFAULTMID1GAIN = 0L;
+
+constexpr auto EAXEQUALIZER_MINMID1CENTER = 200.0F;
+constexpr auto EAXEQUALIZER_MAXMID1CENTER = 3000.0F;
+constexpr auto EAXEQUALIZER_DEFAULTMID1CENTER = 500.0F;
+
+constexpr auto EAXEQUALIZER_MINMID1WIDTH = 0.01F;
+constexpr auto EAXEQUALIZER_MAXMID1WIDTH = 1.0F;
+constexpr auto EAXEQUALIZER_DEFAULTMID1WIDTH = 1.0F;
+
+constexpr auto EAXEQUALIZER_MINMID2GAIN = -1800L;
+constexpr auto EAXEQUALIZER_MAXMID2GAIN = 1800L;
+constexpr auto EAXEQUALIZER_DEFAULTMID2GAIN = 0L;
+
+constexpr auto EAXEQUALIZER_MINMID2CENTER = 1000.0F;
+constexpr auto EAXEQUALIZER_MAXMID2CENTER = 8000.0F;
+constexpr auto EAXEQUALIZER_DEFAULTMID2CENTER = 3000.0F;
+
+constexpr auto EAXEQUALIZER_MINMID2WIDTH = 0.01F;
+constexpr auto EAXEQUALIZER_MAXMID2WIDTH = 1.0F;
+constexpr auto EAXEQUALIZER_DEFAULTMID2WIDTH = 1.0F;
+
+constexpr auto EAXEQUALIZER_MINHIGHGAIN = -1800L;
+constexpr auto EAXEQUALIZER_MAXHIGHGAIN = 1800L;
+constexpr auto EAXEQUALIZER_DEFAULTHIGHGAIN = 0L;
+
+constexpr auto EAXEQUALIZER_MINHIGHCUTOFF = 4000.0F;
+constexpr auto EAXEQUALIZER_MAXHIGHCUTOFF = 16000.0F;
+constexpr auto EAXEQUALIZER_DEFAULTHIGHCUTOFF = 6000.0F;
+
+
+// Flanger Effect
+
+extern const GUID EAX_FLANGER_EFFECT;
+
+enum EAXFLANGER_PROPERTY :
+ unsigned int
+{
+ EAXFLANGER_NONE,
+ EAXFLANGER_ALLPARAMETERS,
+ EAXFLANGER_WAVEFORM,
+ EAXFLANGER_PHASE,
+ EAXFLANGER_RATE,
+ EAXFLANGER_DEPTH,
+ EAXFLANGER_FEEDBACK,
+ EAXFLANGER_DELAY,
+}; // EAXFLANGER_PROPERTY
+
+enum :
+ unsigned long
+{
+ EAX_FLANGER_SINUSOID,
+ EAX_FLANGER_TRIANGLE,
+};
+
+struct EAXFLANGERPROPERTIES
+{
+ unsigned long ulWaveform; // Waveform selector - see enum above
+ long lPhase; // Phase (Degrees)
+ float flRate; // Rate (Hz)
+ float flDepth; // Depth (0 to 1)
+ float flFeedback; // Feedback (0 to 1)
+ float flDelay; // Delay (seconds)
+}; // EAXFLANGERPROPERTIES
+
+
+constexpr auto EAXFLANGER_MINWAVEFORM = 0UL;
+constexpr auto EAXFLANGER_MAXWAVEFORM = 1UL;
+constexpr auto EAXFLANGER_DEFAULTWAVEFORM = 1UL;
+
+constexpr auto EAXFLANGER_MINPHASE = -180L;
+constexpr auto EAXFLANGER_MAXPHASE = 180L;
+constexpr auto EAXFLANGER_DEFAULTPHASE = 0L;
+
+constexpr auto EAXFLANGER_MINRATE = 0.0F;
+constexpr auto EAXFLANGER_MAXRATE = 10.0F;
+constexpr auto EAXFLANGER_DEFAULTRATE = 0.27F;
+
+constexpr auto EAXFLANGER_MINDEPTH = 0.0F;
+constexpr auto EAXFLANGER_MAXDEPTH = 1.0F;
+constexpr auto EAXFLANGER_DEFAULTDEPTH = 1.0F;
+
+constexpr auto EAXFLANGER_MINFEEDBACK = -1.0F;
+constexpr auto EAXFLANGER_MAXFEEDBACK = 1.0F;
+constexpr auto EAXFLANGER_DEFAULTFEEDBACK = -0.5F;
+
+constexpr auto EAXFLANGER_MINDELAY = 0.0002F;
+constexpr auto EAXFLANGER_MAXDELAY = 0.004F;
+constexpr auto EAXFLANGER_DEFAULTDELAY = 0.002F;
+
+
+// Frequency Shifter Effect
+
+extern const GUID EAX_FREQUENCYSHIFTER_EFFECT;
+
+enum EAXFREQUENCYSHIFTER_PROPERTY :
+ unsigned int
+{
+ EAXFREQUENCYSHIFTER_NONE,
+ EAXFREQUENCYSHIFTER_ALLPARAMETERS,
+ EAXFREQUENCYSHIFTER_FREQUENCY,
+ EAXFREQUENCYSHIFTER_LEFTDIRECTION,
+ EAXFREQUENCYSHIFTER_RIGHTDIRECTION,
+}; // EAXFREQUENCYSHIFTER_PROPERTY
+
+enum :
+ unsigned long
+{
+ EAX_FREQUENCYSHIFTER_DOWN,
+ EAX_FREQUENCYSHIFTER_UP,
+ EAX_FREQUENCYSHIFTER_OFF
+};
+
+struct EAXFREQUENCYSHIFTERPROPERTIES
+{
+ float flFrequency; // (Hz)
+ unsigned long ulLeftDirection; // see enum above
+ unsigned long ulRightDirection; // see enum above
+}; // EAXFREQUENCYSHIFTERPROPERTIES
+
+
+constexpr auto EAXFREQUENCYSHIFTER_MINFREQUENCY = 0.0F;
+constexpr auto EAXFREQUENCYSHIFTER_MAXFREQUENCY = 24000.0F;
+constexpr auto EAXFREQUENCYSHIFTER_DEFAULTFREQUENCY = EAXFREQUENCYSHIFTER_MINFREQUENCY;
+
+constexpr auto EAXFREQUENCYSHIFTER_MINLEFTDIRECTION = 0UL;
+constexpr auto EAXFREQUENCYSHIFTER_MAXLEFTDIRECTION = 2UL;
+constexpr auto EAXFREQUENCYSHIFTER_DEFAULTLEFTDIRECTION = EAXFREQUENCYSHIFTER_MINLEFTDIRECTION;
+
+constexpr auto EAXFREQUENCYSHIFTER_MINRIGHTDIRECTION = 0UL;
+constexpr auto EAXFREQUENCYSHIFTER_MAXRIGHTDIRECTION = 2UL;
+constexpr auto EAXFREQUENCYSHIFTER_DEFAULTRIGHTDIRECTION = EAXFREQUENCYSHIFTER_MINRIGHTDIRECTION;
+
+
+// Vocal Morpher Effect
+
+extern const GUID EAX_VOCALMORPHER_EFFECT;
+
+enum EAXVOCALMORPHER_PROPERTY :
+ unsigned int
+{
+ EAXVOCALMORPHER_NONE,
+ EAXVOCALMORPHER_ALLPARAMETERS,
+ EAXVOCALMORPHER_PHONEMEA,
+ EAXVOCALMORPHER_PHONEMEACOARSETUNING,
+ EAXVOCALMORPHER_PHONEMEB,
+ EAXVOCALMORPHER_PHONEMEBCOARSETUNING,
+ EAXVOCALMORPHER_WAVEFORM,
+ EAXVOCALMORPHER_RATE,
+}; // EAXVOCALMORPHER_PROPERTY
+
+enum :
+ unsigned long
+{
+ A,
+ E,
+ I,
+ O,
+ U,
+ AA,
+ AE,
+ AH,
+ AO,
+ EH,
+ ER,
+ IH,
+ IY,
+ UH,
+ UW,
+ B,
+ D,
+ F,
+ G,
+ J,
+ K,
+ L,
+ M,
+ N,
+ P,
+ R,
+ S,
+ T,
+ V,
+ Z,
+};
+
+enum :
+ unsigned long
+{
+ EAX_VOCALMORPHER_SINUSOID,
+ EAX_VOCALMORPHER_TRIANGLE,
+ EAX_VOCALMORPHER_SAWTOOTH
+};
+
+// Use this structure for EAXVOCALMORPHER_ALLPARAMETERS
+struct EAXVOCALMORPHERPROPERTIES
+{
+ unsigned long ulPhonemeA; // see enum above
+ long lPhonemeACoarseTuning; // (semitones)
+ unsigned long ulPhonemeB; // see enum above
+ long lPhonemeBCoarseTuning; // (semitones)
+ unsigned long ulWaveform; // Waveform selector - see enum above
+ float flRate; // (Hz)
+}; // EAXVOCALMORPHERPROPERTIES
+
+
+constexpr auto EAXVOCALMORPHER_MINPHONEMEA = 0UL;
+constexpr auto EAXVOCALMORPHER_MAXPHONEMEA = 29UL;
+constexpr auto EAXVOCALMORPHER_DEFAULTPHONEMEA = EAXVOCALMORPHER_MINPHONEMEA;
+
+constexpr auto EAXVOCALMORPHER_MINPHONEMEACOARSETUNING = -24L;
+constexpr auto EAXVOCALMORPHER_MAXPHONEMEACOARSETUNING = 24L;
+constexpr auto EAXVOCALMORPHER_DEFAULTPHONEMEACOARSETUNING = 0L;
+
+constexpr auto EAXVOCALMORPHER_MINPHONEMEB = 0UL;
+constexpr auto EAXVOCALMORPHER_MAXPHONEMEB = 29UL;
+constexpr auto EAXVOCALMORPHER_DEFAULTPHONEMEB = 10UL;
+
+constexpr auto EAXVOCALMORPHER_MINPHONEMEBCOARSETUNING = -24L;
+constexpr auto EAXVOCALMORPHER_MAXPHONEMEBCOARSETUNING = 24L;
+constexpr auto EAXVOCALMORPHER_DEFAULTPHONEMEBCOARSETUNING = 0L;
+
+constexpr auto EAXVOCALMORPHER_MINWAVEFORM = 0UL;
+constexpr auto EAXVOCALMORPHER_MAXWAVEFORM = 2UL;
+constexpr auto EAXVOCALMORPHER_DEFAULTWAVEFORM = EAXVOCALMORPHER_MINWAVEFORM;
+
+constexpr auto EAXVOCALMORPHER_MINRATE = 0.0F;
+constexpr auto EAXVOCALMORPHER_MAXRATE = 10.0F;
+constexpr auto EAXVOCALMORPHER_DEFAULTRATE = 1.41F;
+
+
+// Pitch Shifter Effect
+
+extern const GUID EAX_PITCHSHIFTER_EFFECT;
+
+enum EAXPITCHSHIFTER_PROPERTY :
+ unsigned int
+{
+ EAXPITCHSHIFTER_NONE,
+ EAXPITCHSHIFTER_ALLPARAMETERS,
+ EAXPITCHSHIFTER_COARSETUNE,
+ EAXPITCHSHIFTER_FINETUNE,
+}; // EAXPITCHSHIFTER_PROPERTY
+
+struct EAXPITCHSHIFTERPROPERTIES
+{
+ long lCoarseTune; // Amount of pitch shift (semitones)
+ long lFineTune; // Amount of pitch shift (cents)
+}; // EAXPITCHSHIFTERPROPERTIES
+
+
+constexpr auto EAXPITCHSHIFTER_MINCOARSETUNE = -12L;
+constexpr auto EAXPITCHSHIFTER_MAXCOARSETUNE = 12L;
+constexpr auto EAXPITCHSHIFTER_DEFAULTCOARSETUNE = 12L;
+
+constexpr auto EAXPITCHSHIFTER_MINFINETUNE = -50L;
+constexpr auto EAXPITCHSHIFTER_MAXFINETUNE = 50L;
+constexpr auto EAXPITCHSHIFTER_DEFAULTFINETUNE = 0L;
+
+
+// Ring Modulator Effect
+
+extern const GUID EAX_RINGMODULATOR_EFFECT;
+
+enum EAXRINGMODULATOR_PROPERTY :
+ unsigned int
+{
+ EAXRINGMODULATOR_NONE,
+ EAXRINGMODULATOR_ALLPARAMETERS,
+ EAXRINGMODULATOR_FREQUENCY,
+ EAXRINGMODULATOR_HIGHPASSCUTOFF,
+ EAXRINGMODULATOR_WAVEFORM,
+}; // EAXRINGMODULATOR_PROPERTY
+
+enum :
+ unsigned long
+{
+ EAX_RINGMODULATOR_SINUSOID,
+ EAX_RINGMODULATOR_SAWTOOTH,
+ EAX_RINGMODULATOR_SQUARE,
+};
+
+// Use this structure for EAXRINGMODULATOR_ALLPARAMETERS
+struct EAXRINGMODULATORPROPERTIES
+{
+ float flFrequency; // Frequency of modulation (Hz)
+ float flHighPassCutOff; // Cut-off frequency of high-pass filter (Hz)
+ unsigned long ulWaveform; // Waveform selector - see enum above
+}; // EAXRINGMODULATORPROPERTIES
+
+
+constexpr auto EAXRINGMODULATOR_MINFREQUENCY = 0.0F;
+constexpr auto EAXRINGMODULATOR_MAXFREQUENCY = 8000.0F;
+constexpr auto EAXRINGMODULATOR_DEFAULTFREQUENCY = 440.0F;
+
+constexpr auto EAXRINGMODULATOR_MINHIGHPASSCUTOFF = 0.0F;
+constexpr auto EAXRINGMODULATOR_MAXHIGHPASSCUTOFF = 24000.0F;
+constexpr auto EAXRINGMODULATOR_DEFAULTHIGHPASSCUTOFF = 800.0F;
+
+constexpr auto EAXRINGMODULATOR_MINWAVEFORM = 0UL;
+constexpr auto EAXRINGMODULATOR_MAXWAVEFORM = 2UL;
+constexpr auto EAXRINGMODULATOR_DEFAULTWAVEFORM = EAXRINGMODULATOR_MINWAVEFORM;
+
+
+using LPEAXSET = ALenum(AL_APIENTRY*)(
+ const GUID* property_set_id,
+ ALuint property_id,
+ ALuint property_source_id,
+ ALvoid* property_buffer,
+ ALuint property_size);
+
+using LPEAXGET = ALenum(AL_APIENTRY*)(
+ const GUID* property_set_id,
+ ALuint property_id,
+ ALuint property_source_id,
+ ALvoid* property_buffer,
+ ALuint property_size);
+
+
+#endif // !EAX_API_INCLUDED
diff --git a/al/eax/eax_call.cpp b/al/eax/eax_call.cpp
new file mode 100644
index 00000000..19565852
--- /dev/null
+++ b/al/eax/eax_call.cpp
@@ -0,0 +1,323 @@
+#include "config.h"
+
+#include "eax_call.h"
+#include "exception.h"
+
+
+namespace {
+
+constexpr auto deferred_flag = 0x80000000U;
+
+class EaxEaxCallException :
+ public EaxException
+{
+public:
+ explicit EaxEaxCallException(
+ const char* message)
+ :
+ EaxException{"EAX_EAX_CALL", message}
+ {
+ }
+}; // EaxEaxCallException
+
+} // namespace
+
+
+EaxEaxCall::EaxEaxCall(
+ bool is_get,
+ const GUID& property_set_guid,
+ ALuint property_id,
+ ALuint property_source_id,
+ ALvoid* property_buffer,
+ ALuint property_size)
+ : is_get_{is_get}, version_{0}, property_set_id_{EaxEaxCallPropertySetId::none}
+ , property_id_{property_id & ~deferred_flag}, property_source_id_{property_source_id}
+ , property_buffer_{property_buffer}, property_size_{property_size}
+{
+ if (false)
+ {
+ }
+ else if (property_set_guid == EAXPROPERTYID_EAX40_Context)
+ {
+ version_ = 4;
+ property_set_id_ = EaxEaxCallPropertySetId::context;
+ }
+ else if (property_set_guid == EAXPROPERTYID_EAX50_Context)
+ {
+ version_ = 5;
+ property_set_id_ = EaxEaxCallPropertySetId::context;
+ }
+ else if (property_set_guid == DSPROPSETID_EAX20_ListenerProperties)
+ {
+ version_ = 2;
+ fx_slot_index_ = 0u;
+ property_set_id_ = EaxEaxCallPropertySetId::fx_slot_effect;
+ property_id_ = convert_eax_v2_0_listener_property_id(property_id_);
+ }
+ else if (property_set_guid == DSPROPSETID_EAX30_ListenerProperties)
+ {
+ version_ = 3;
+ fx_slot_index_ = 0u;
+ property_set_id_ = EaxEaxCallPropertySetId::fx_slot_effect;
+ }
+ else if (property_set_guid == EAXPROPERTYID_EAX40_FXSlot0)
+ {
+ version_ = 4;
+ fx_slot_index_ = 0u;
+ property_set_id_ = EaxEaxCallPropertySetId::fx_slot;
+ }
+ else if (property_set_guid == EAXPROPERTYID_EAX50_FXSlot0)
+ {
+ version_ = 5;
+ fx_slot_index_ = 0u;
+ property_set_id_ = EaxEaxCallPropertySetId::fx_slot;
+ }
+ else if (property_set_guid == EAXPROPERTYID_EAX40_FXSlot1)
+ {
+ version_ = 4;
+ fx_slot_index_ = 1u;
+ property_set_id_ = EaxEaxCallPropertySetId::fx_slot;
+ }
+ else if (property_set_guid == EAXPROPERTYID_EAX50_FXSlot1)
+ {
+ version_ = 5;
+ fx_slot_index_ = 1u;
+ property_set_id_ = EaxEaxCallPropertySetId::fx_slot;
+ }
+ else if (property_set_guid == EAXPROPERTYID_EAX40_FXSlot2)
+ {
+ version_ = 4;
+ fx_slot_index_ = 2u;
+ property_set_id_ = EaxEaxCallPropertySetId::fx_slot;
+ }
+ else if (property_set_guid == EAXPROPERTYID_EAX50_FXSlot2)
+ {
+ version_ = 5;
+ fx_slot_index_ = 2u;
+ property_set_id_ = EaxEaxCallPropertySetId::fx_slot;
+ }
+ else if (property_set_guid == EAXPROPERTYID_EAX40_FXSlot3)
+ {
+ version_ = 4;
+ fx_slot_index_ = 3u;
+ property_set_id_ = EaxEaxCallPropertySetId::fx_slot;
+ }
+ else if (property_set_guid == EAXPROPERTYID_EAX50_FXSlot3)
+ {
+ version_ = 5;
+ fx_slot_index_ = 3u;
+ property_set_id_ = EaxEaxCallPropertySetId::fx_slot;
+ }
+ else if (property_set_guid == DSPROPSETID_EAX20_BufferProperties)
+ {
+ version_ = 2;
+ property_set_id_ = EaxEaxCallPropertySetId::source;
+ property_id_ = convert_eax_v2_0_buffer_property_id(property_id_);
+ }
+ else if (property_set_guid == DSPROPSETID_EAX30_BufferProperties)
+ {
+ version_ = 3;
+ property_set_id_ = EaxEaxCallPropertySetId::source;
+ }
+ else if (property_set_guid == EAXPROPERTYID_EAX40_Source)
+ {
+ version_ = 4;
+ property_set_id_ = EaxEaxCallPropertySetId::source;
+ }
+ else if (property_set_guid == EAXPROPERTYID_EAX50_Source)
+ {
+ version_ = 5;
+ property_set_id_ = EaxEaxCallPropertySetId::source;
+ }
+ else if (property_set_guid == DSPROPSETID_EAX_ReverbProperties)
+ {
+ version_ = 1;
+ fx_slot_index_ = 0u;
+ property_set_id_ = EaxEaxCallPropertySetId::fx_slot_effect;
+ }
+ else if (property_set_guid == DSPROPSETID_EAXBUFFER_ReverbProperties)
+ {
+ version_ = 1;
+ property_set_id_ = EaxEaxCallPropertySetId::source;
+ }
+ else
+ {
+ fail("Unsupported property set id.");
+ }
+
+ if (version_ < 1 || version_ > 5)
+ {
+ fail("EAX version out of range.");
+ }
+
+ if(!(property_id&deferred_flag))
+ {
+ if(property_set_id_ != EaxEaxCallPropertySetId::fx_slot && property_id_ != 0)
+ {
+ if (!property_buffer)
+ {
+ fail("Null property buffer.");
+ }
+
+ if (property_size == 0)
+ {
+ fail("Empty property.");
+ }
+ }
+ }
+
+ if(property_set_id_ == EaxEaxCallPropertySetId::source && property_source_id_ == 0)
+ {
+ fail("Null AL source id.");
+ }
+
+ if (property_set_id_ == EaxEaxCallPropertySetId::fx_slot)
+ {
+ if (property_id_ < EAXFXSLOT_NONE)
+ {
+ property_set_id_ = EaxEaxCallPropertySetId::fx_slot_effect;
+ }
+ }
+}
+
+[[noreturn]]
+void EaxEaxCall::fail(
+ const char* message)
+{
+ throw EaxEaxCallException{message};
+}
+
+ALuint EaxEaxCall::convert_eax_v2_0_listener_property_id(
+ ALuint property_id)
+{
+ switch (property_id)
+ {
+ case DSPROPERTY_EAX20LISTENER_NONE:
+ return EAXREVERB_NONE;
+
+ case DSPROPERTY_EAX20LISTENER_ALLPARAMETERS:
+ return EAXREVERB_ALLPARAMETERS;
+
+ case DSPROPERTY_EAX20LISTENER_ROOM:
+ return EAXREVERB_ROOM;
+
+ case DSPROPERTY_EAX20LISTENER_ROOMHF:
+ return EAXREVERB_ROOMHF;
+
+ case DSPROPERTY_EAX20LISTENER_ROOMROLLOFFFACTOR:
+ return EAXREVERB_ROOMROLLOFFFACTOR;
+
+ case DSPROPERTY_EAX20LISTENER_DECAYTIME:
+ return EAXREVERB_DECAYTIME;
+
+ case DSPROPERTY_EAX20LISTENER_DECAYHFRATIO:
+ return EAXREVERB_DECAYHFRATIO;
+
+ case DSPROPERTY_EAX20LISTENER_REFLECTIONS:
+ return EAXREVERB_REFLECTIONS;
+
+ case DSPROPERTY_EAX20LISTENER_REFLECTIONSDELAY:
+ return EAXREVERB_REFLECTIONSDELAY;
+
+ case DSPROPERTY_EAX20LISTENER_REVERB:
+ return EAXREVERB_REVERB;
+
+ case DSPROPERTY_EAX20LISTENER_REVERBDELAY:
+ return EAXREVERB_REVERBDELAY;
+
+ case DSPROPERTY_EAX20LISTENER_ENVIRONMENT:
+ return EAXREVERB_ENVIRONMENT;
+
+ case DSPROPERTY_EAX20LISTENER_ENVIRONMENTSIZE:
+ return EAXREVERB_ENVIRONMENTSIZE;
+
+ case DSPROPERTY_EAX20LISTENER_ENVIRONMENTDIFFUSION:
+ return EAXREVERB_ENVIRONMENTDIFFUSION;
+
+ case DSPROPERTY_EAX20LISTENER_AIRABSORPTIONHF:
+ return EAXREVERB_AIRABSORPTIONHF;
+
+ case DSPROPERTY_EAX20LISTENER_FLAGS:
+ return EAXREVERB_FLAGS;
+
+ default:
+ fail("Unsupported EAX 2.0 listener property id.");
+ }
+}
+
+ALuint EaxEaxCall::convert_eax_v2_0_buffer_property_id(
+ ALuint property_id)
+{
+ switch (property_id)
+ {
+ case DSPROPERTY_EAX20BUFFER_NONE:
+ return EAXSOURCE_NONE;
+
+ case DSPROPERTY_EAX20BUFFER_ALLPARAMETERS:
+ return EAXSOURCE_ALLPARAMETERS;
+
+ case DSPROPERTY_EAX20BUFFER_DIRECT:
+ return EAXSOURCE_DIRECT;
+
+ case DSPROPERTY_EAX20BUFFER_DIRECTHF:
+ return EAXSOURCE_DIRECTHF;
+
+ case DSPROPERTY_EAX20BUFFER_ROOM:
+ return EAXSOURCE_ROOM;
+
+ case DSPROPERTY_EAX20BUFFER_ROOMHF:
+ return EAXSOURCE_ROOMHF;
+
+ case DSPROPERTY_EAX20BUFFER_ROOMROLLOFFFACTOR:
+ return EAXSOURCE_ROOMROLLOFFFACTOR;
+
+ case DSPROPERTY_EAX20BUFFER_OBSTRUCTION:
+ return EAXSOURCE_OBSTRUCTION;
+
+ case DSPROPERTY_EAX20BUFFER_OBSTRUCTIONLFRATIO:
+ return EAXSOURCE_OBSTRUCTIONLFRATIO;
+
+ case DSPROPERTY_EAX20BUFFER_OCCLUSION:
+ return EAXSOURCE_OCCLUSION;
+
+ case DSPROPERTY_EAX20BUFFER_OCCLUSIONLFRATIO:
+ return EAXSOURCE_OCCLUSIONLFRATIO;
+
+ case DSPROPERTY_EAX20BUFFER_OCCLUSIONROOMRATIO:
+ return EAXSOURCE_OCCLUSIONROOMRATIO;
+
+ case DSPROPERTY_EAX20BUFFER_OUTSIDEVOLUMEHF:
+ return EAXSOURCE_OUTSIDEVOLUMEHF;
+
+ case DSPROPERTY_EAX20BUFFER_AIRABSORPTIONFACTOR:
+ return EAXSOURCE_AIRABSORPTIONFACTOR;
+
+ case DSPROPERTY_EAX20BUFFER_FLAGS:
+ return EAXSOURCE_FLAGS;
+
+ default:
+ fail("Unsupported EAX 2.0 buffer property id.");
+ }
+}
+
+
+EaxEaxCall create_eax_call(
+ bool is_get,
+ const GUID* property_set_id,
+ ALuint property_id,
+ ALuint property_source_id,
+ ALvoid* property_buffer,
+ ALuint property_size)
+{
+ if(!property_set_id)
+ throw EaxEaxCallException{"Null property set ID."};
+
+ return EaxEaxCall{
+ is_get,
+ *property_set_id,
+ property_id,
+ property_source_id,
+ property_buffer,
+ property_size
+ };
+}
diff --git a/al/eax/eax_call.h b/al/eax/eax_call.h
new file mode 100644
index 00000000..2c90bdc3
--- /dev/null
+++ b/al/eax/eax_call.h
@@ -0,0 +1,117 @@
+#ifndef EAX_EAX_CALL_INCLUDED
+#define EAX_EAX_CALL_INCLUDED
+
+
+#include "AL/al.h"
+
+#include "alspan.h"
+
+#include "api.h"
+#include "fx_slot_index.h"
+
+
+enum class EaxEaxCallPropertySetId
+{
+ none,
+
+ context,
+ fx_slot,
+ source,
+ fx_slot_effect,
+}; // EaxEaxCallPropertySetId
+
+
+class EaxEaxCall
+{
+public:
+ EaxEaxCall(
+ bool is_get,
+ const GUID& property_set_guid,
+ ALuint property_id,
+ ALuint property_source_id,
+ ALvoid* property_buffer,
+ ALuint property_size);
+
+ bool is_get() const noexcept { return is_get_; }
+ int get_version() const noexcept { return version_; }
+ EaxEaxCallPropertySetId get_property_set_id() const noexcept { return property_set_id_; }
+ ALuint get_property_id() const noexcept { return property_id_; }
+ ALuint get_property_al_name() const noexcept { return property_source_id_; }
+ EaxFxSlotIndex get_fx_slot_index() const noexcept { return fx_slot_index_; }
+
+ template<
+ typename TException,
+ typename TValue
+ >
+ TValue& get_value() const
+ {
+ if (property_size_ < static_cast<ALuint>(sizeof(TValue)))
+ {
+ throw TException{"Property buffer too small."};
+ }
+
+ return *static_cast<TValue*>(property_buffer_);
+ }
+
+ template<
+ typename TException,
+ typename TValue
+ >
+ al::span<TValue> get_values() const
+ {
+ if (property_size_ < static_cast<ALuint>(sizeof(TValue)))
+ {
+ throw TException{"Property buffer too small."};
+ }
+
+ const auto count = property_size_ / sizeof(TValue);
+
+ return al::span<TValue>{static_cast<TValue*>(property_buffer_), count};
+ }
+
+ template<
+ typename TException,
+ typename TValue
+ >
+ void set_value(
+ const TValue& value) const
+ {
+ get_value<TException, TValue>() = value;
+ }
+
+
+private:
+ const bool is_get_;
+ int version_;
+ EaxFxSlotIndex fx_slot_index_;
+ EaxEaxCallPropertySetId property_set_id_;
+
+ ALuint property_id_;
+ const ALuint property_source_id_;
+ ALvoid*const property_buffer_;
+ const ALuint property_size_;
+
+
+ [[noreturn]]
+ static void fail(
+ const char* message);
+
+
+ static ALuint convert_eax_v2_0_listener_property_id(
+ ALuint property_id);
+
+ static ALuint convert_eax_v2_0_buffer_property_id(
+ ALuint property_id);
+}; // EaxEaxCall
+
+
+EaxEaxCall create_eax_call(
+ bool is_get,
+ const GUID* property_set_id,
+ ALuint property_id,
+ ALuint property_source_id,
+ ALvoid* property_buffer,
+ ALuint property_size);
+
+
+#endif // !EAX_EAX_CALL_INCLUDED
diff --git a/al/eax/effect.cpp b/al/eax/effect.cpp
new file mode 100644
index 00000000..4e8faa73
--- /dev/null
+++ b/al/eax/effect.cpp
@@ -0,0 +1,3 @@
+#include "config.h"
+
+#include "effect.h"
diff --git a/al/eax/effect.h b/al/eax/effect.h
new file mode 100644
index 00000000..9c9fdef4
--- /dev/null
+++ b/al/eax/effect.h
@@ -0,0 +1,44 @@
+#ifndef EAX_EFFECT_INCLUDED
+#define EAX_EFFECT_INCLUDED
+
+
+#include <memory>
+
+#include "AL/al.h"
+#include "core/effects/base.h"
+#include "eax_call.h"
+
+class EaxEffect
+{
+public:
+ EaxEffect(ALenum type) : al_effect_type_{type} { }
+ virtual ~EaxEffect() = default;
+
+ const ALenum al_effect_type_;
+ EffectProps al_effect_props_{};
+
+ virtual void dispatch(const EaxEaxCall& eax_call) = 0;
+
+ // Returns "true" if any immediated property was changed.
+ // [[nodiscard]]
+ virtual bool apply_deferred() = 0;
+}; // EaxEffect
+
+
+using EaxEffectUPtr = std::unique_ptr<EaxEffect>;
+
+EaxEffectUPtr eax_create_eax_null_effect();
+EaxEffectUPtr eax_create_eax_chorus_effect();
+EaxEffectUPtr eax_create_eax_distortion_effect();
+EaxEffectUPtr eax_create_eax_echo_effect();
+EaxEffectUPtr eax_create_eax_flanger_effect();
+EaxEffectUPtr eax_create_eax_frequency_shifter_effect();
+EaxEffectUPtr eax_create_eax_vocal_morpher_effect();
+EaxEffectUPtr eax_create_eax_pitch_shifter_effect();
+EaxEffectUPtr eax_create_eax_ring_modulator_effect();
+EaxEffectUPtr eax_create_eax_auto_wah_effect();
+EaxEffectUPtr eax_create_eax_compressor_effect();
+EaxEffectUPtr eax_create_eax_equalizer_effect();
+EaxEffectUPtr eax_create_eax_reverb_effect();
+
+#endif // !EAX_EFFECT_INCLUDED
diff --git a/al/eax/exception.cpp b/al/eax/exception.cpp
new file mode 100644
index 00000000..3b319648
--- /dev/null
+++ b/al/eax/exception.cpp
@@ -0,0 +1,62 @@
+#include "config.h"
+
+#include "exception.h"
+
+#include <cassert>
+#include <string>
+
+
+EaxException::EaxException(
+ const char* context,
+ const char* message)
+ :
+ std::runtime_error{make_message(context, message)}
+{
+}
+
+std::string EaxException::make_message(
+ const char* context,
+ const char* message)
+{
+ const auto context_size = (context ? std::string::traits_type::length(context) : 0);
+ const auto has_contex = (context_size > 0);
+
+ const auto message_size = (message ? std::string::traits_type::length(message) : 0);
+ const auto has_message = (message_size > 0);
+
+ if (!has_contex && !has_message)
+ {
+ return std::string{};
+ }
+
+ static constexpr char left_prefix[] = "[";
+ const auto left_prefix_size = std::string::traits_type::length(left_prefix);
+
+ static constexpr char right_prefix[] = "] ";
+ const auto right_prefix_size = std::string::traits_type::length(right_prefix);
+
+ const auto what_size =
+ (
+ has_contex ?
+ left_prefix_size + context_size + right_prefix_size :
+ 0) +
+ message_size +
+ 1;
+
+ auto what = std::string{};
+ what.reserve(what_size);
+
+ if (has_contex)
+ {
+ what.append(left_prefix, left_prefix_size);
+ what.append(context, context_size);
+ what.append(right_prefix, right_prefix_size);
+ }
+
+ if (has_message)
+ {
+ what.append(message, message_size);
+ }
+
+ return what;
+}
diff --git a/al/eax/exception.h b/al/eax/exception.h
new file mode 100644
index 00000000..9a7acf71
--- /dev/null
+++ b/al/eax/exception.h
@@ -0,0 +1,25 @@
+#ifndef EAX_EXCEPTION_INCLUDED
+#define EAX_EXCEPTION_INCLUDED
+
+
+#include <stdexcept>
+#include <string>
+
+
+class EaxException :
+ public std::runtime_error
+{
+public:
+ EaxException(
+ const char* context,
+ const char* message);
+
+
+private:
+ static std::string make_message(
+ const char* context,
+ const char* message);
+}; // EaxException
+
+
+#endif // !EAX_EXCEPTION_INCLUDED
diff --git a/al/eax/fx_slot_index.cpp b/al/eax/fx_slot_index.cpp
new file mode 100644
index 00000000..28b11882
--- /dev/null
+++ b/al/eax/fx_slot_index.cpp
@@ -0,0 +1,71 @@
+#include "config.h"
+
+#include "fx_slot_index.h"
+
+#include "exception.h"
+
+
+namespace
+{
+
+
+class EaxFxSlotIndexException :
+ public EaxException
+{
+public:
+ explicit EaxFxSlotIndexException(
+ const char* message)
+ :
+ EaxException{"EAX_FX_SLOT_INDEX", message}
+ {
+ }
+}; // EaxFxSlotIndexException
+
+
+} // namespace
+
+
+void EaxFxSlotIndex::set(EaxFxSlotIndexValue index)
+{
+ if(index >= EaxFxSlotIndexValue{EAX_MAX_FXSLOTS})
+ fail("Index out of range.");
+
+ emplace(index);
+}
+
+void EaxFxSlotIndex::set(const GUID &guid)
+{
+ if (false)
+ {
+ }
+ else if (guid == EAX_NULL_GUID)
+ {
+ reset();
+ }
+ else if (guid == EAXPROPERTYID_EAX40_FXSlot0 || guid == EAXPROPERTYID_EAX50_FXSlot0)
+ {
+ emplace(0u);
+ }
+ else if (guid == EAXPROPERTYID_EAX40_FXSlot1 || guid == EAXPROPERTYID_EAX50_FXSlot1)
+ {
+ emplace(1u);
+ }
+ else if (guid == EAXPROPERTYID_EAX40_FXSlot2 || guid == EAXPROPERTYID_EAX50_FXSlot2)
+ {
+ emplace(2u);
+ }
+ else if (guid == EAXPROPERTYID_EAX40_FXSlot3 || guid == EAXPROPERTYID_EAX50_FXSlot3)
+ {
+ emplace(3u);
+ }
+ else
+ {
+ fail("Unsupported GUID.");
+ }
+}
+
+[[noreturn]]
+void EaxFxSlotIndex::fail(const char* message)
+{
+ throw EaxFxSlotIndexException{message};
+}
diff --git a/al/eax/fx_slot_index.h b/al/eax/fx_slot_index.h
new file mode 100644
index 00000000..63dba037
--- /dev/null
+++ b/al/eax/fx_slot_index.h
@@ -0,0 +1,41 @@
+#ifndef EAX_FX_SLOT_INDEX_INCLUDED
+#define EAX_FX_SLOT_INDEX_INCLUDED
+
+
+#include <cstddef>
+
+#include "aloptional.h"
+#include "api.h"
+
+
+using EaxFxSlotIndexValue = std::size_t;
+
+class EaxFxSlotIndex : public al::optional<EaxFxSlotIndexValue>
+{
+public:
+ using al::optional<EaxFxSlotIndexValue>::optional;
+
+ EaxFxSlotIndex& operator=(const EaxFxSlotIndexValue &value) { set(value); return *this; }
+ EaxFxSlotIndex& operator=(const GUID &guid) { set(guid); return *this; }
+
+ void set(EaxFxSlotIndexValue index);
+ void set(const GUID& guid);
+
+private:
+ [[noreturn]]
+ static void fail(const char *message);
+}; // EaxFxSlotIndex
+
+inline bool operator==(const EaxFxSlotIndex& lhs, const EaxFxSlotIndex& rhs) noexcept
+{
+ if(lhs.has_value() != rhs.has_value())
+ return false;
+ if(lhs.has_value())
+ return *lhs == *rhs;
+ return true;
+}
+
+inline bool operator!=(const EaxFxSlotIndex& lhs, const EaxFxSlotIndex& rhs) noexcept
+{ return !(lhs == rhs); }
+
+#endif // !EAX_FX_SLOT_INDEX_INCLUDED
diff --git a/al/eax/fx_slots.cpp b/al/eax/fx_slots.cpp
new file mode 100644
index 00000000..5897e951
--- /dev/null
+++ b/al/eax/fx_slots.cpp
@@ -0,0 +1,83 @@
+#include "config.h"
+
+#include "fx_slots.h"
+
+#include <array>
+
+#include "api.h"
+#include "exception.h"
+
+
+namespace
+{
+
+
+class EaxFxSlotsException :
+ public EaxException
+{
+public:
+ explicit EaxFxSlotsException(
+ const char* message)
+ :
+ EaxException{"EAX_FX_SLOTS", message}
+ {
+ }
+}; // EaxFxSlotsException
+
+
+} // namespace
+
+
+void EaxFxSlots::initialize(
+ ALCcontext& al_context)
+{
+ initialize_fx_slots(al_context);
+}
+
+void EaxFxSlots::uninitialize() noexcept
+{
+ for (auto& fx_slot : fx_slots_)
+ {
+ fx_slot = nullptr;
+ }
+}
+
+const ALeffectslot& EaxFxSlots::get(EaxFxSlotIndex index) const
+{
+ if(!index.has_value())
+ fail("Empty index.");
+ return *fx_slots_[index.value()];
+}
+
+ALeffectslot& EaxFxSlots::get(EaxFxSlotIndex index)
+{
+ if(!index.has_value())
+ fail("Empty index.");
+ return *fx_slots_[index.value()];
+}
+
+void EaxFxSlots::unlock_legacy() noexcept
+{
+ fx_slots_[0]->eax_unlock_legacy();
+ fx_slots_[1]->eax_unlock_legacy();
+}
+
+[[noreturn]]
+void EaxFxSlots::fail(
+ const char* message)
+{
+ throw EaxFxSlotsException{message};
+}
+
+void EaxFxSlots::initialize_fx_slots(
+ ALCcontext& al_context)
+{
+ auto fx_slot_index = EaxFxSlotIndexValue{};
+
+ for (auto& fx_slot : fx_slots_)
+ {
+ fx_slot = eax_create_al_effect_slot(al_context);
+ fx_slot->eax_initialize(al_context, fx_slot_index);
+ fx_slot_index += 1;
+ }
+}
diff --git a/al/eax/fx_slots.h b/al/eax/fx_slots.h
new file mode 100644
index 00000000..49cabd75
--- /dev/null
+++ b/al/eax/fx_slots.h
@@ -0,0 +1,53 @@
+#ifndef EAX_FX_SLOTS_INCLUDED
+#define EAX_FX_SLOTS_INCLUDED
+
+
+#include <array>
+
+#include "al/auxeffectslot.h"
+
+#include "api.h"
+#include "fx_slot_index.h"
+
+
+class EaxFxSlots
+{
+public:
+ void initialize(
+ ALCcontext& al_context);
+
+ void uninitialize() noexcept;
+
+ void commit()
+ {
+ for(auto& fx_slot : fx_slots_)
+ fx_slot->eax_commit();
+ }
+
+
+ const ALeffectslot& get(
+ EaxFxSlotIndex index) const;
+
+ ALeffectslot& get(
+ EaxFxSlotIndex index);
+
+ void unlock_legacy() noexcept;
+
+
+private:
+ using Items = std::array<EaxAlEffectSlotUPtr, EAX_MAX_FXSLOTS>;
+
+
+ Items fx_slots_{};
+
+
+ [[noreturn]]
+ static void fail(
+ const char* message);
+
+ void initialize_fx_slots(
+ ALCcontext& al_context);
+}; // EaxFxSlots
+
+
+#endif // !EAX_FX_SLOTS_INCLUDED
diff --git a/al/eax/globals.cpp b/al/eax/globals.cpp
new file mode 100644
index 00000000..80e9dbfe
--- /dev/null
+++ b/al/eax/globals.cpp
@@ -0,0 +1,21 @@
+#include "config.h"
+
+#include "globals.h"
+
+
+bool eax_g_is_enabled = true;
+
+
+const char eax1_ext_name[] = "EAX";
+const char eax2_ext_name[] = "EAX2.0";
+const char eax3_ext_name[] = "EAX3.0";
+const char eax4_ext_name[] = "EAX4.0";
+const char eax5_ext_name[] = "EAX5.0";
+
+const char eax_x_ram_ext_name[] = "EAX-RAM";
+
+const char eax_eax_set_func_name[] = "EAXSet";
+const char eax_eax_get_func_name[] = "EAXGet";
+
+const char eax_eax_set_buffer_mode_func_name[] = "EAXSetBufferMode";
+const char eax_eax_get_buffer_mode_func_name[] = "EAXGetBufferMode";
diff --git a/al/eax/globals.h b/al/eax/globals.h
new file mode 100644
index 00000000..1b4d63b8
--- /dev/null
+++ b/al/eax/globals.h
@@ -0,0 +1,22 @@
+#ifndef EAX_GLOBALS_INCLUDED
+#define EAX_GLOBALS_INCLUDED
+
+
+extern bool eax_g_is_enabled;
+
+
+extern const char eax1_ext_name[];
+extern const char eax2_ext_name[];
+extern const char eax3_ext_name[];
+extern const char eax4_ext_name[];
+extern const char eax5_ext_name[];
+
+extern const char eax_x_ram_ext_name[];
+
+extern const char eax_eax_set_func_name[];
+extern const char eax_eax_get_func_name[];
+
+extern const char eax_eax_set_buffer_mode_func_name[];
+extern const char eax_eax_get_buffer_mode_func_name[];
+
+#endif // !EAX_GLOBALS_INCLUDED
diff --git a/al/eax/utils.cpp b/al/eax/utils.cpp
new file mode 100644
index 00000000..9fa2871d
--- /dev/null
+++ b/al/eax/utils.cpp
@@ -0,0 +1,36 @@
+#include "config.h"
+
+#include "utils.h"
+
+#include <cassert>
+#include <exception>
+
+#include "core/logging.h"
+
+
+void eax_log_exception(
+ const char* message) noexcept
+{
+ const auto exception_ptr = std::current_exception();
+
+ assert(exception_ptr);
+
+ if (message)
+ {
+ ERR("%s\n", message);
+ }
+
+ try
+ {
+ std::rethrow_exception(exception_ptr);
+ }
+ catch (const std::exception& ex)
+ {
+ const auto ex_message = ex.what();
+ ERR("%s\n", ex_message);
+ }
+ catch (...)
+ {
+ ERR("%s\n", "Generic exception.");
+ }
+}
diff --git a/al/eax/utils.h b/al/eax/utils.h
new file mode 100644
index 00000000..d3d4a196
--- /dev/null
+++ b/al/eax/utils.h
@@ -0,0 +1,132 @@
+#ifndef EAX_UTILS_INCLUDED
+#define EAX_UTILS_INCLUDED
+
+#include <algorithm>
+#include <cstdint>
+#include <string>
+#include <type_traits>
+
+
+struct EaxAlLowPassParam
+{
+ float gain;
+ float gain_hf;
+}; // EaxAlLowPassParam
+
+
+void eax_log_exception(
+ const char* message = nullptr) noexcept;
+
+
+template<
+ typename TException,
+ typename TValue
+>
+void eax_validate_range(
+ const char* value_name,
+ const TValue& value,
+ const TValue& min_value,
+ const TValue& max_value)
+{
+ if (value >= min_value && value <= max_value)
+ {
+ return;
+ }
+
+ const auto message =
+ std::string{value_name} +
+ " out of range (value: " +
+ std::to_string(value) + "; min: " +
+ std::to_string(min_value) + "; max: " +
+ std::to_string(max_value) + ").";
+
+ throw TException{message.c_str()};
+}
+
+
+namespace detail
+{
+
+
+template<
+ typename T
+>
+struct EaxIsBitFieldStruct
+{
+private:
+ using yes = std::true_type;
+ using no = std::false_type;
+
+ template<
+ typename U
+ >
+ static auto test(int) -> decltype(std::declval<typename U::EaxIsBitFieldStruct>(), yes{});
+
+ template<
+ typename
+ >
+ static no test(...);
+
+
+public:
+ static constexpr auto value = std::is_same<decltype(test<T>(0)), yes>::value;
+}; // EaxIsBitFieldStruct
+
+
+template<
+ typename T,
+ typename TValue
+>
+inline bool eax_bit_fields_are_equal(
+ const T& lhs,
+ const T& rhs) noexcept
+{
+ static_assert(sizeof(T) == sizeof(TValue), "Invalid type size.");
+
+ return reinterpret_cast<const TValue&>(lhs) == reinterpret_cast<const TValue&>(rhs);
+}
+
+
+} // namespace detail
+
+
+template<
+ typename T,
+ std::enable_if_t<detail::EaxIsBitFieldStruct<T>::value, int> = 0
+>
+inline bool operator==(
+ const T& lhs,
+ const T& rhs) noexcept
+{
+ using Value = std::conditional_t<
+ sizeof(T) == 1,
+ std::uint8_t,
+ std::conditional_t<
+ sizeof(T) == 2,
+ std::uint16_t,
+ std::conditional_t<
+ sizeof(T) == 4,
+ std::uint32_t,
+ void
+ >
+ >
+ >;
+
+ static_assert(!std::is_same<Value, void>::value, "Unsupported type.");
+
+ return detail::eax_bit_fields_are_equal<T, Value>(lhs, rhs);
+}
+
+template<
+ typename T,
+ std::enable_if_t<detail::EaxIsBitFieldStruct<T>::value, int> = 0
+>
+inline bool operator!=(
+ const T& lhs,
+ const T& rhs) noexcept
+{
+ return !(lhs == rhs);
+}
+
+
+#endif // !EAX_UTILS_INCLUDED
diff --git a/al/eax/x_ram.cpp b/al/eax/x_ram.cpp
new file mode 100644
index 00000000..7332c82e
--- /dev/null
+++ b/al/eax/x_ram.cpp
@@ -0,0 +1,3 @@
+#include "config.h"
+
+#include "x_ram.h"
diff --git a/al/eax/x_ram.h b/al/eax/x_ram.h
new file mode 100644
index 00000000..438b9916
--- /dev/null
+++ b/al/eax/x_ram.h
@@ -0,0 +1,38 @@
+#ifndef EAX_X_RAM_INCLUDED
+#define EAX_X_RAM_INCLUDED
+
+
+#include "AL/al.h"
+
+
+constexpr auto eax_x_ram_min_size = ALsizei{};
+constexpr auto eax_x_ram_max_size = ALsizei{64 * 1'024 * 1'024};
+
+
+constexpr auto AL_EAX_RAM_SIZE = ALenum{0x202201};
+constexpr auto AL_EAX_RAM_FREE = ALenum{0x202202};
+
+constexpr auto AL_STORAGE_AUTOMATIC = ALenum{0x202203};
+constexpr auto AL_STORAGE_HARDWARE = ALenum{0x202204};
+constexpr auto AL_STORAGE_ACCESSIBLE = ALenum{0x202205};
+
+
+constexpr auto AL_EAX_RAM_SIZE_NAME = "AL_EAX_RAM_SIZE";
+constexpr auto AL_EAX_RAM_FREE_NAME = "AL_EAX_RAM_FREE";
+
+constexpr auto AL_STORAGE_AUTOMATIC_NAME = "AL_STORAGE_AUTOMATIC";
+constexpr auto AL_STORAGE_HARDWARE_NAME = "AL_STORAGE_HARDWARE";
+constexpr auto AL_STORAGE_ACCESSIBLE_NAME = "AL_STORAGE_ACCESSIBLE";
+
+
+ALboolean AL_APIENTRY EAXSetBufferMode(
+ ALsizei n,
+ const ALuint* buffers,
+ ALint value);
+
+ALenum AL_APIENTRY EAXGetBufferMode(
+ ALuint buffer,
+ ALint* pReserved);
+
+
+#endif // !EAX_X_RAM_INCLUDED