aboutsummaryrefslogtreecommitdiffstats
path: root/al/eax
diff options
context:
space:
mode:
Diffstat (limited to 'al/eax')
-rw-r--r--al/eax/api.cpp1621
-rw-r--r--al/eax/api.h1493
-rw-r--r--al/eax/call.cpp219
-rw-r--r--al/eax/call.h97
-rw-r--r--al/eax/effect.h418
-rw-r--r--al/eax/exception.cpp59
-rw-r--r--al/eax/exception.h18
-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.cpp75
-rw-r--r--al/eax/fx_slots.h49
-rw-r--r--al/eax/globals.cpp21
-rw-r--r--al/eax/globals.h22
-rw-r--r--al/eax/utils.cpp26
-rw-r--r--al/eax/utils.h95
-rw-r--r--al/eax/x_ram.h38
16 files changed, 4363 insertions, 0 deletions
diff --git a/al/eax/api.cpp b/al/eax/api.cpp
new file mode 100644
index 00000000..f0809df1
--- /dev/null
+++ b/al/eax/api.cpp
@@ -0,0 +1,1621 @@
+//
+// 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}
+};
+
+
+const GUID EAX40CONTEXT_DEFAULTPRIMARYFXSLOTID = EAXPROPERTYID_EAX40_FXSlot0;
+const GUID EAX50CONTEXT_DEFAULTPRIMARYFXSLOTID = EAXPROPERTYID_EAX50_FXSlot0;
+
+const EAX40ACTIVEFXSLOTS EAX40SOURCE_DEFAULTACTIVEFXSLOTID = EAX40ACTIVEFXSLOTS
+{{
+ EAX_NULL_GUID,
+ EAXPROPERTYID_EAX40_FXSlot0,
+}};
+
+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,
+}};
+
+
+// EAX1 =====================================================================
+
+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,
+}};
+
+// EAX2 =====================================================================
+
+namespace {
+
+constexpr EAX20LISTENERPROPERTIES EAX2REVERB_PRESET_GENERIC{
+ EAX2LISTENER_DEFAULTROOM,
+ EAX2LISTENER_DEFAULTROOMHF,
+ EAX2LISTENER_DEFAULTROOMROLLOFFFACTOR,
+ EAX2LISTENER_DEFAULTDECAYTIME,
+ EAX2LISTENER_DEFAULTDECAYHFRATIO,
+ EAX2LISTENER_DEFAULTREFLECTIONS,
+ EAX2LISTENER_DEFAULTREFLECTIONSDELAY,
+ EAX2LISTENER_DEFAULTREVERB,
+ EAX2LISTENER_DEFAULTREVERBDELAY,
+ EAX2LISTENER_DEFAULTENVIRONMENT,
+ EAX2LISTENER_DEFAULTENVIRONMENTSIZE,
+ EAX2LISTENER_DEFAULTENVIRONMENTDIFFUSION,
+ EAX2LISTENER_DEFAULTAIRABSORPTIONHF,
+ EAX2LISTENER_DEFAULTFLAGS,
+};
+
+constexpr EAX20LISTENERPROPERTIES EAX2REVERB_PRESET_PADDEDCELL{
+ -1'000L,
+ -6'000L,
+ 0.0F,
+ 0.17F,
+ 0.1F,
+ -1'204L,
+ 0.001F,
+ 207L,
+ 0.002F,
+ EAX2_ENVIRONMENT_PADDEDCELL,
+ 1.4F,
+ 1.0F,
+ -5.0F,
+ EAX2LISTENER_DEFAULTFLAGS,
+};
+
+constexpr EAX20LISTENERPROPERTIES EAX2REVERB_PRESET_ROOM{
+ -1'000L,
+ -454L,
+ 0.0F,
+ 0.4F,
+ 0.83F,
+ -1'646L,
+ 0.002F,
+ 53L,
+ 0.003F,
+ EAX2_ENVIRONMENT_ROOM,
+ 1.9F,
+ 1.0F,
+ -5.0F,
+ EAX2LISTENER_DEFAULTFLAGS,
+};
+
+constexpr EAX20LISTENERPROPERTIES EAX2REVERB_PRESET_BATHROOM{
+ -1'000L,
+ -1'200L,
+ 0.0F,
+ 1.49F,
+ 0.54F,
+ -370L,
+ 0.007F,
+ 1'030L,
+ 0.011F,
+ EAX2_ENVIRONMENT_BATHROOM,
+ 1.4F,
+ 1.0F,
+ -5.0F,
+ EAX2LISTENER_DEFAULTFLAGS,
+};
+
+constexpr EAX20LISTENERPROPERTIES EAX2REVERB_PRESET_LIVINGROOM{
+ -1'000L,
+ -6'000L,
+ 0.0F,
+ 0.5F,
+ 0.1F,
+ -1'376L,
+ 0.003F,
+ -1'104L,
+ 0.004F,
+ EAX2_ENVIRONMENT_LIVINGROOM,
+ 2.5F,
+ 1.0F,
+ -5.0F,
+ EAX2LISTENER_DEFAULTFLAGS,
+};
+
+constexpr EAX20LISTENERPROPERTIES EAX2REVERB_PRESET_STONEROOM{
+ -1'000L,
+ -300L,
+ 0.0F,
+ 2.31F,
+ 0.64F,
+ -711L,
+ 0.012F,
+ 83L,
+ 0.017F,
+ EAX2_ENVIRONMENT_STONEROOM,
+ 11.6F,
+ 1.0F,
+ -5.0F,
+ EAX2LISTENER_DEFAULTFLAGS,
+};
+
+constexpr EAX20LISTENERPROPERTIES EAX2REVERB_PRESET_AUDITORIUM{
+ -1'000L,
+ -476L,
+ 0.0F,
+ 4.32F,
+ 0.59F,
+ -789L,
+ 0.02F,
+ -289L,
+ 0.03F,
+ EAX2_ENVIRONMENT_AUDITORIUM,
+ 21.6F,
+ 1.0F,
+ -5.0F,
+ EAX2LISTENER_DEFAULTFLAGS,
+};
+
+constexpr EAX20LISTENERPROPERTIES EAX2REVERB_PRESET_CONCERTHALL{
+ -1'000L,
+ -500L,
+ 0.0F,
+ 3.92F,
+ 0.7F,
+ -1'230L,
+ 0.02F,
+ -2L,
+ 0.029F,
+ EAX2_ENVIRONMENT_CONCERTHALL,
+ 19.6F,
+ 1.0F,
+ -5.0F,
+ EAX2LISTENER_DEFAULTFLAGS,
+};
+
+constexpr EAX20LISTENERPROPERTIES EAX2REVERB_PRESET_CAVE{
+ -1'000L,
+ 0L,
+ 0.0F,
+ 2.91F,
+ 1.3F,
+ -602L,
+ 0.015F,
+ -302L,
+ 0.022F,
+ EAX2_ENVIRONMENT_CAVE,
+ 14.6F,
+ 1.0F,
+ -5.0F,
+ EAX2LISTENERFLAGS_DECAYTIMESCALE |
+ EAX2LISTENERFLAGS_REFLECTIONSSCALE |
+ EAX2LISTENERFLAGS_REFLECTIONSDELAYSCALE |
+ EAX2LISTENERFLAGS_REVERBSCALE |
+ EAX2LISTENERFLAGS_REVERBDELAYSCALE,
+};
+
+constexpr EAX20LISTENERPROPERTIES EAX2REVERB_PRESET_ARENA{
+ -1'000L,
+ -698L,
+ 0.0F,
+ 7.24F,
+ 0.33F,
+ -1'166L,
+ 0.02F,
+ 16L,
+ 0.03F,
+ EAX2_ENVIRONMENT_ARENA,
+ 36.2F,
+ 1.0F,
+ -5.0F,
+ EAX2LISTENER_DEFAULTFLAGS,
+};
+
+constexpr EAX20LISTENERPROPERTIES EAX2REVERB_PRESET_HANGAR{
+ -1'000L,
+ -1'000L,
+ 0.0F,
+ 10.05F,
+ 0.23F,
+ -602L,
+ 0.02F,
+ 198L,
+ 0.03F,
+ EAX2_ENVIRONMENT_HANGAR,
+ 50.3F,
+ 1.0F,
+ -5.0F,
+ EAX2LISTENER_DEFAULTFLAGS,
+};
+
+constexpr EAX20LISTENERPROPERTIES EAX2REVERB_PRESET_CARPETTEDHALLWAY{
+ -1'000L,
+ -4'000L,
+ 0.0F,
+ 0.3F,
+ 0.1F,
+ -1'831L,
+ 0.002F,
+ -1'630L,
+ 0.03F,
+ EAX2_ENVIRONMENT_CARPETEDHALLWAY,
+ 1.9F,
+ 1.0F,
+ -5.0F,
+ EAX2LISTENER_DEFAULTFLAGS,
+};
+
+constexpr EAX20LISTENERPROPERTIES EAX2REVERB_PRESET_HALLWAY{
+ -1'000L,
+ -300L,
+ 0.0F,
+ 1.49F,
+ 0.59F,
+ -1'219L,
+ 0.007F,
+ 441L,
+ 0.011F,
+ EAX2_ENVIRONMENT_HALLWAY,
+ 1.8F,
+ 1.0F,
+ -5.0F,
+ EAX2LISTENER_DEFAULTFLAGS,
+};
+
+constexpr EAX20LISTENERPROPERTIES EAX2REVERB_PRESET_STONECORRIDOR{
+ -1'000L,
+ -237L,
+ 0.0F,
+ 2.7F,
+ 0.79F,
+ -1'214L,
+ 0.013F,
+ 395L,
+ 0.02F,
+ EAX2_ENVIRONMENT_STONECORRIDOR,
+ 13.5F,
+ 1.0F,
+ -5.0F,
+ EAX2LISTENER_DEFAULTFLAGS,
+};
+
+constexpr EAX20LISTENERPROPERTIES EAX2REVERB_PRESET_ALLEY{
+ -1'000L,
+ -270L,
+ 0.0F,
+ 1.49F,
+ 0.86F,
+ -1'204L,
+ 0.007F,
+ -4L,
+ 0.011F,
+ EAX2_ENVIRONMENT_ALLEY,
+ 7.5F,
+ 0.3F,
+ -5.0F,
+ EAX2LISTENER_DEFAULTFLAGS,
+};
+
+constexpr EAX20LISTENERPROPERTIES EAX2REVERB_PRESET_FOREST{
+ -1'000L,
+ -3'300L,
+ 0.0F,
+ 1.49F,
+ 0.54F,
+ -2'560L,
+ 0.162F,
+ -229L,
+ 0.088F,
+ EAX2_ENVIRONMENT_FOREST,
+ 38.0F,
+ 0.3F,
+ -5.0F,
+ EAX2LISTENER_DEFAULTFLAGS,
+};
+
+constexpr EAX20LISTENERPROPERTIES EAX2REVERB_PRESET_CITY{
+ -1'000L,
+ -800L,
+ 0.0F,
+ 1.49F,
+ 0.67F,
+ -2'273L,
+ 0.007F,
+ -1'691L,
+ 0.011F,
+ EAX2_ENVIRONMENT_CITY,
+ 7.5F,
+ 0.5F,
+ -5.0F,
+ EAX2LISTENER_DEFAULTFLAGS,
+};
+
+constexpr EAX20LISTENERPROPERTIES EAX2REVERB_PRESET_MOUNTAINS{
+ -1'000L,
+ -2'500L,
+ 0.0F,
+ 1.49F,
+ 0.21F,
+ -2'780L,
+ 0.3F,
+ -1'434L,
+ 0.1F,
+ EAX2_ENVIRONMENT_MOUNTAINS,
+ 100.0F,
+ 0.27F,
+ -5.0F,
+ EAX2LISTENERFLAGS_DECAYTIMESCALE |
+ EAX2LISTENERFLAGS_REFLECTIONSSCALE |
+ EAX2LISTENERFLAGS_REFLECTIONSDELAYSCALE |
+ EAX2LISTENERFLAGS_REVERBSCALE |
+ EAX2LISTENERFLAGS_REVERBDELAYSCALE,
+};
+
+constexpr EAX20LISTENERPROPERTIES EAX2REVERB_PRESET_QUARRY{
+ -1'000L,
+ -1'000L,
+ 0.0F,
+ 1.49F,
+ 0.83F,
+ -10'000L,
+ 0.061F,
+ 500L,
+ 0.025F,
+ EAX2_ENVIRONMENT_QUARRY,
+ 17.5F,
+ 1.0F,
+ -5.0F,
+ EAX2LISTENER_DEFAULTFLAGS,
+};
+
+constexpr EAX20LISTENERPROPERTIES EAX2REVERB_PRESET_PLAIN{
+ -1'000L,
+ -2'000L,
+ 0.0F,
+ 1.49F,
+ 0.5F,
+ -2'466L,
+ 0.179F,
+ -1'926L,
+ 0.1F,
+ EAX2_ENVIRONMENT_PLAIN,
+ 42.5F,
+ 0.21F,
+ -5.0F,
+ EAX2LISTENER_DEFAULTFLAGS,
+};
+
+constexpr EAX20LISTENERPROPERTIES EAX2REVERB_PRESET_PARKINGLOT{
+ -1'000L,
+ 0L,
+ 0.0F,
+ 1.65F,
+ 1.5F,
+ -1'363L,
+ 0.008F,
+ -1'153L,
+ 0.012F,
+ EAX2_ENVIRONMENT_PARKINGLOT,
+ 8.3F,
+ 1.0F,
+ -5.0F,
+ EAX2LISTENERFLAGS_DECAYTIMESCALE |
+ EAX2LISTENERFLAGS_REFLECTIONSSCALE |
+ EAX2LISTENERFLAGS_REFLECTIONSDELAYSCALE |
+ EAX2LISTENERFLAGS_REVERBSCALE |
+ EAX2LISTENERFLAGS_REVERBDELAYSCALE,
+};
+
+constexpr EAX20LISTENERPROPERTIES EAX2REVERB_PRESET_SEWERPIPE{
+ -1'000L,
+ -1'000L,
+ 0.0F,
+ 2.81F,
+ 0.14F,
+ 429L,
+ 0.014F,
+ 1'023L,
+ 0.021F,
+ EAX2_ENVIRONMENT_SEWERPIPE,
+ 1.7F,
+ 0.8F,
+ -5.0F,
+ EAX2LISTENER_DEFAULTFLAGS,
+};
+
+constexpr EAX20LISTENERPROPERTIES EAX2REVERB_PRESET_UNDERWATER{
+ -1'000L,
+ -4'000L,
+ 0.0F,
+ 1.49F,
+ 0.1F,
+ -449L,
+ 0.007F,
+ 1'700L,
+ 0.011F,
+ EAX2_ENVIRONMENT_UNDERWATER,
+ 1.8F,
+ 1.0F,
+ -5.0F,
+ EAX2LISTENER_DEFAULTFLAGS,
+};
+
+constexpr EAX20LISTENERPROPERTIES EAX2REVERB_PRESET_DRUGGED{
+ -1'000L,
+ 0L,
+ 0.0F,
+ 8.39F,
+ 1.39F,
+ -115L,
+ 0.002F,
+ 985L,
+ 0.03F,
+ EAX2_ENVIRONMENT_DRUGGED,
+ 1.9F,
+ 0.5F,
+ -5.0F,
+ EAX2LISTENERFLAGS_DECAYTIMESCALE |
+ EAX2LISTENERFLAGS_REFLECTIONSSCALE |
+ EAX2LISTENERFLAGS_REFLECTIONSDELAYSCALE |
+ EAX2LISTENERFLAGS_REVERBSCALE |
+ EAX2LISTENERFLAGS_REVERBDELAYSCALE,
+};
+
+constexpr EAX20LISTENERPROPERTIES EAX2REVERB_PRESET_DIZZY{
+ -1'000L,
+ -400L,
+ 0.0F,
+ 17.23F,
+ 0.56F,
+ -1'713L,
+ 0.02F,
+ -613L,
+ 0.03F,
+ EAX2_ENVIRONMENT_DIZZY,
+ 1.8F,
+ 0.6F,
+ -5.0F,
+ EAX2LISTENERFLAGS_DECAYTIMESCALE |
+ EAX2LISTENERFLAGS_REFLECTIONSSCALE |
+ EAX2LISTENERFLAGS_REFLECTIONSDELAYSCALE |
+ EAX2LISTENERFLAGS_REVERBSCALE |
+ EAX2LISTENERFLAGS_REVERBDELAYSCALE,
+};
+
+constexpr EAX20LISTENERPROPERTIES EAX2REVERB_PRESET_PSYCHOTIC{
+ -1'000L,
+ -151L,
+ 0.0F,
+ 7.56F,
+ 0.91F,
+ -626L,
+ 0.02F,
+ 774L,
+ 0.03F,
+ EAX2_ENVIRONMENT_PSYCHOTIC,
+ 1.0F,
+ 0.5F,
+ -5.0F,
+ EAX2LISTENERFLAGS_DECAYTIMESCALE |
+ EAX2LISTENERFLAGS_REFLECTIONSSCALE |
+ EAX2LISTENERFLAGS_REFLECTIONSDELAYSCALE |
+ EAX2LISTENERFLAGS_REVERBSCALE |
+ EAX2LISTENERFLAGS_REVERBDELAYSCALE,
+};
+
+} // namespace
+
+const Eax2ReverbPresets EAX2REVERB_PRESETS{
+ EAX2REVERB_PRESET_GENERIC,
+ EAX2REVERB_PRESET_PADDEDCELL,
+ EAX2REVERB_PRESET_ROOM,
+ EAX2REVERB_PRESET_BATHROOM,
+ EAX2REVERB_PRESET_LIVINGROOM,
+ EAX2REVERB_PRESET_STONEROOM,
+ EAX2REVERB_PRESET_AUDITORIUM,
+ EAX2REVERB_PRESET_CONCERTHALL,
+ EAX2REVERB_PRESET_CAVE,
+ EAX2REVERB_PRESET_ARENA,
+ EAX2REVERB_PRESET_HANGAR,
+ EAX2REVERB_PRESET_CARPETTEDHALLWAY,
+ EAX2REVERB_PRESET_HALLWAY,
+ EAX2REVERB_PRESET_STONECORRIDOR,
+ EAX2REVERB_PRESET_ALLEY,
+ EAX2REVERB_PRESET_FOREST,
+ EAX2REVERB_PRESET_CITY,
+ EAX2REVERB_PRESET_MOUNTAINS,
+ EAX2REVERB_PRESET_QUARRY,
+ EAX2REVERB_PRESET_PLAIN,
+ EAX2REVERB_PRESET_PARKINGLOT,
+ EAX2REVERB_PRESET_SEWERPIPE,
+ EAX2REVERB_PRESET_UNDERWATER,
+ EAX2REVERB_PRESET_DRUGGED,
+ EAX2REVERB_PRESET_DIZZY,
+ EAX2REVERB_PRESET_PSYCHOTIC,
+};
+
+// EAX3+ ====================================================================
+
+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,
+}};
diff --git a/al/eax/api.h b/al/eax/api.h
new file mode 100644
index 00000000..d254da1f
--- /dev/null
+++ b/al/eax/api.h
@@ -0,0 +1,1493 @@
+#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;
+
+#ifndef _SYS_GUID_OPERATOR_EQ_
+#define _SYS_GUID_OPERATOR_EQ_
+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 // _SYS_GUID_OPERATOR_EQ_
+#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
+
+
+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;
+};
+
+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
+
+enum : unsigned long {
+ EAX2_ENVIRONMENT_GENERIC,
+ EAX2_ENVIRONMENT_PADDEDCELL,
+ EAX2_ENVIRONMENT_ROOM,
+ EAX2_ENVIRONMENT_BATHROOM,
+ EAX2_ENVIRONMENT_LIVINGROOM,
+ EAX2_ENVIRONMENT_STONEROOM,
+ EAX2_ENVIRONMENT_AUDITORIUM,
+ EAX2_ENVIRONMENT_CONCERTHALL,
+ EAX2_ENVIRONMENT_CAVE,
+ EAX2_ENVIRONMENT_ARENA,
+ EAX2_ENVIRONMENT_HANGAR,
+ EAX2_ENVIRONMENT_CARPETEDHALLWAY,
+ EAX2_ENVIRONMENT_HALLWAY,
+ EAX2_ENVIRONMENT_STONECORRIDOR,
+ EAX2_ENVIRONMENT_ALLEY,
+ EAX2_ENVIRONMENT_FOREST,
+ EAX2_ENVIRONMENT_CITY,
+ EAX2_ENVIRONMENT_MOUNTAINS,
+ EAX2_ENVIRONMENT_QUARRY,
+ EAX2_ENVIRONMENT_PLAIN,
+ EAX2_ENVIRONMENT_PARKINGLOT,
+ EAX2_ENVIRONMENT_SEWERPIPE,
+ EAX2_ENVIRONMENT_UNDERWATER,
+ EAX2_ENVIRONMENT_DRUGGED,
+ EAX2_ENVIRONMENT_DIZZY,
+ EAX2_ENVIRONMENT_PSYCHOTIC,
+
+ EAX2_ENVIRONMENT_COUNT,
+};
+
+constexpr auto EAX2LISTENERFLAGS_DECAYTIMESCALE = 0x00000001UL;
+constexpr auto EAX2LISTENERFLAGS_REFLECTIONSSCALE = 0x00000002UL;
+constexpr auto EAX2LISTENERFLAGS_REFLECTIONSDELAYSCALE = 0x00000004UL;
+constexpr auto EAX2LISTENERFLAGS_REVERBSCALE = 0x00000008UL;
+constexpr auto EAX2LISTENERFLAGS_REVERBDELAYSCALE = 0x00000010UL;
+constexpr auto EAX2LISTENERFLAGS_DECAYHFLIMIT = 0x00000020UL;
+constexpr auto EAX2LISTENERFLAGS_RESERVED = 0xFFFFFFC0UL;
+
+constexpr auto EAX2LISTENER_MINROOM = -10'000L;
+constexpr auto EAX2LISTENER_MAXROOM = 0L;
+constexpr auto EAX2LISTENER_DEFAULTROOM = -1'000L;
+
+constexpr auto EAX2LISTENER_MINROOMHF = -10'000L;
+constexpr auto EAX2LISTENER_MAXROOMHF = 0L;
+constexpr auto EAX2LISTENER_DEFAULTROOMHF = -100L;
+
+constexpr auto EAX2LISTENER_MINROOMROLLOFFFACTOR = 0.0F;
+constexpr auto EAX2LISTENER_MAXROOMROLLOFFFACTOR = 10.0F;
+constexpr auto EAX2LISTENER_DEFAULTROOMROLLOFFFACTOR = 0.0F;
+
+constexpr auto EAX2LISTENER_MINDECAYTIME = 0.1F;
+constexpr auto EAX2LISTENER_MAXDECAYTIME = 20.0F;
+constexpr auto EAX2LISTENER_DEFAULTDECAYTIME = 1.49F;
+
+constexpr auto EAX2LISTENER_MINDECAYHFRATIO = 0.1F;
+constexpr auto EAX2LISTENER_MAXDECAYHFRATIO = 2.0F;
+constexpr auto EAX2LISTENER_DEFAULTDECAYHFRATIO = 0.83F;
+
+constexpr auto EAX2LISTENER_MINREFLECTIONS = -10'000L;
+constexpr auto EAX2LISTENER_MAXREFLECTIONS = 1'000L;
+constexpr auto EAX2LISTENER_DEFAULTREFLECTIONS = -2'602L;
+
+constexpr auto EAX2LISTENER_MINREFLECTIONSDELAY = 0.0F;
+constexpr auto EAX2LISTENER_MAXREFLECTIONSDELAY = 0.3F;
+constexpr auto EAX2LISTENER_DEFAULTREFLECTIONSDELAY = 0.007F;
+
+constexpr auto EAX2LISTENER_MINREVERB = -10'000L;
+constexpr auto EAX2LISTENER_MAXREVERB = 2'000L;
+constexpr auto EAX2LISTENER_DEFAULTREVERB = 200L;
+
+constexpr auto EAX2LISTENER_MINREVERBDELAY = 0.0F;
+constexpr auto EAX2LISTENER_MAXREVERBDELAY = 0.1F;
+constexpr auto EAX2LISTENER_DEFAULTREVERBDELAY = 0.011F;
+
+constexpr auto EAX2LISTENER_MINENVIRONMENT = 0UL;
+constexpr auto EAX2LISTENER_MAXENVIRONMENT = EAX2_ENVIRONMENT_COUNT - 1;
+constexpr auto EAX2LISTENER_DEFAULTENVIRONMENT = EAX2_ENVIRONMENT_GENERIC;
+
+constexpr auto EAX2LISTENER_MINENVIRONMENTSIZE = 1.0F;
+constexpr auto EAX2LISTENER_MAXENVIRONMENTSIZE = 100.0F;
+constexpr auto EAX2LISTENER_DEFAULTENVIRONMENTSIZE = 7.5F;
+
+constexpr auto EAX2LISTENER_MINENVIRONMENTDIFFUSION = 0.0F;
+constexpr auto EAX2LISTENER_MAXENVIRONMENTDIFFUSION = 1.0F;
+constexpr auto EAX2LISTENER_DEFAULTENVIRONMENTDIFFUSION = 1.0F;
+
+constexpr auto EAX2LISTENER_MINAIRABSORPTIONHF = -100.0F;
+constexpr auto EAX2LISTENER_MAXAIRABSORPTIONHF = 0.0F;
+constexpr auto EAX2LISTENER_DEFAULTAIRABSORPTIONHF = -5.0F;
+
+constexpr auto EAX2LISTENER_DEFAULTFLAGS =
+ EAX2LISTENERFLAGS_DECAYTIMESCALE |
+ EAX2LISTENERFLAGS_REFLECTIONSSCALE |
+ EAX2LISTENERFLAGS_REFLECTIONSDELAYSCALE |
+ EAX2LISTENERFLAGS_REVERBSCALE |
+ EAX2LISTENERFLAGS_REVERBDELAYSCALE |
+ EAX2LISTENERFLAGS_DECAYHFLIMIT;
+
+
+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
+constexpr auto HEADPHONES = 0UL;
+constexpr auto SPEAKERS_2 = 1UL;
+constexpr auto SPEAKERS_4 = 2UL;
+constexpr auto SPEAKERS_5 = 3UL; // 5.1 speakers
+constexpr auto SPEAKERS_6 = 4UL; // 6.1 speakers
+constexpr auto SPEAKERS_7 = 5UL; // 7.1 speakers
+
+constexpr auto EAXCONTEXT_MINSPEAKERCONFIG = HEADPHONES;
+constexpr auto EAXCONTEXT_MAXSPEAKERCONFIG = SPEAKERS_7;
+
+// EAX50
+constexpr auto EAX_40 = 5UL; // EAX 4.0
+constexpr auto EAX_50 = 6UL; // 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;
+}; // EAX50CONTEXTPROPERTIES
+
+
+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 EAX40CONTEXT_DEFAULTPRIMARYFXSLOTID;
+extern const GUID EAX50CONTEXT_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
+
+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;
+constexpr auto EAXSOURCEFLAGS_UPMIX = 0x00000010UL;
+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;
+
+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
+
+// 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 EAX40ACTIVEFXSLOTS 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
+
+
+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 Eax1ReverbPresets = std::array<EAX_REVERBPROPERTIES, EAX1_ENVIRONMENT_COUNT>;
+extern const Eax1ReverbPresets EAX1REVERB_PRESETS;
+
+using Eax2ReverbPresets = std::array<EAX20LISTENERPROPERTIES, EAX2_ENVIRONMENT_COUNT>;
+extern const Eax2ReverbPresets EAX2REVERB_PRESETS;
+
+using EaxReverbPresets = std::array<EAXREVERBPROPERTIES, EAX1_ENVIRONMENT_COUNT>;
+extern const EaxReverbPresets EAXREVERB_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/call.cpp b/al/eax/call.cpp
new file mode 100644
index 00000000..689d5cf1
--- /dev/null
+++ b/al/eax/call.cpp
@@ -0,0 +1,219 @@
+#include "config.h"
+#include "call.h"
+#include "exception.h"
+
+namespace {
+
+constexpr auto deferred_flag = 0x80000000U;
+
+class EaxCallException : public EaxException {
+public:
+ explicit EaxCallException(const char* message)
+ : EaxException{"EAX_CALL", message}
+ {}
+}; // EaxCallException
+
+} // namespace
+
+EaxCall::EaxCall(
+ EaxCallType type,
+ const GUID& property_set_guid,
+ ALuint property_id,
+ ALuint property_source_id,
+ ALvoid* property_buffer,
+ ALuint property_size)
+ : mCallType{type}, mVersion{0}, mPropertySetId{EaxCallPropertySetId::none}
+ , mIsDeferred{(property_id & deferred_flag) != 0}
+ , mPropertyId{property_id & ~deferred_flag}, mPropertySourceId{property_source_id}
+ , mPropertyBuffer{property_buffer}, mPropertyBufferSize{property_size}
+{
+ switch(mCallType)
+ {
+ case EaxCallType::get:
+ case EaxCallType::set:
+ break;
+
+ default:
+ fail("Invalid type.");
+ }
+
+ if (false)
+ {
+ }
+ else if (property_set_guid == EAXPROPERTYID_EAX40_Context)
+ {
+ mVersion = 4;
+ mPropertySetId = EaxCallPropertySetId::context;
+ }
+ else if (property_set_guid == EAXPROPERTYID_EAX50_Context)
+ {
+ mVersion = 5;
+ mPropertySetId = EaxCallPropertySetId::context;
+ }
+ else if (property_set_guid == DSPROPSETID_EAX20_ListenerProperties)
+ {
+ mVersion = 2;
+ mFxSlotIndex = 0u;
+ mPropertySetId = EaxCallPropertySetId::fx_slot_effect;
+ }
+ else if (property_set_guid == DSPROPSETID_EAX30_ListenerProperties)
+ {
+ mVersion = 3;
+ mFxSlotIndex = 0u;
+ mPropertySetId = EaxCallPropertySetId::fx_slot_effect;
+ }
+ else if (property_set_guid == EAXPROPERTYID_EAX40_FXSlot0)
+ {
+ mVersion = 4;
+ mFxSlotIndex = 0u;
+ mPropertySetId = EaxCallPropertySetId::fx_slot;
+ }
+ else if (property_set_guid == EAXPROPERTYID_EAX50_FXSlot0)
+ {
+ mVersion = 5;
+ mFxSlotIndex = 0u;
+ mPropertySetId = EaxCallPropertySetId::fx_slot;
+ }
+ else if (property_set_guid == EAXPROPERTYID_EAX40_FXSlot1)
+ {
+ mVersion = 4;
+ mFxSlotIndex = 1u;
+ mPropertySetId = EaxCallPropertySetId::fx_slot;
+ }
+ else if (property_set_guid == EAXPROPERTYID_EAX50_FXSlot1)
+ {
+ mVersion = 5;
+ mFxSlotIndex = 1u;
+ mPropertySetId = EaxCallPropertySetId::fx_slot;
+ }
+ else if (property_set_guid == EAXPROPERTYID_EAX40_FXSlot2)
+ {
+ mVersion = 4;
+ mFxSlotIndex = 2u;
+ mPropertySetId = EaxCallPropertySetId::fx_slot;
+ }
+ else if (property_set_guid == EAXPROPERTYID_EAX50_FXSlot2)
+ {
+ mVersion = 5;
+ mFxSlotIndex = 2u;
+ mPropertySetId = EaxCallPropertySetId::fx_slot;
+ }
+ else if (property_set_guid == EAXPROPERTYID_EAX40_FXSlot3)
+ {
+ mVersion = 4;
+ mFxSlotIndex = 3u;
+ mPropertySetId = EaxCallPropertySetId::fx_slot;
+ }
+ else if (property_set_guid == EAXPROPERTYID_EAX50_FXSlot3)
+ {
+ mVersion = 5;
+ mFxSlotIndex = 3u;
+ mPropertySetId = EaxCallPropertySetId::fx_slot;
+ }
+ else if (property_set_guid == DSPROPSETID_EAX20_BufferProperties)
+ {
+ mVersion = 2;
+ mPropertySetId = EaxCallPropertySetId::source;
+ }
+ else if (property_set_guid == DSPROPSETID_EAX30_BufferProperties)
+ {
+ mVersion = 3;
+ mPropertySetId = EaxCallPropertySetId::source;
+ }
+ else if (property_set_guid == EAXPROPERTYID_EAX40_Source)
+ {
+ mVersion = 4;
+ mPropertySetId = EaxCallPropertySetId::source;
+ }
+ else if (property_set_guid == EAXPROPERTYID_EAX50_Source)
+ {
+ mVersion = 5;
+ mPropertySetId = EaxCallPropertySetId::source;
+ }
+ else if (property_set_guid == DSPROPSETID_EAX_ReverbProperties)
+ {
+ mVersion = 1;
+ mFxSlotIndex = 0u;
+ mPropertySetId = EaxCallPropertySetId::fx_slot_effect;
+ }
+ else if (property_set_guid == DSPROPSETID_EAXBUFFER_ReverbProperties)
+ {
+ mVersion = 1;
+ mPropertySetId = EaxCallPropertySetId::source;
+ }
+ else
+ {
+ fail("Unsupported property set id.");
+ }
+
+ switch(mPropertyId)
+ {
+ case EAXCONTEXT_LASTERROR:
+ case EAXCONTEXT_SPEAKERCONFIG:
+ case EAXCONTEXT_EAXSESSION:
+ case EAXFXSLOT_NONE:
+ case EAXFXSLOT_ALLPARAMETERS:
+ case EAXFXSLOT_LOADEFFECT:
+ case EAXFXSLOT_VOLUME:
+ case EAXFXSLOT_LOCK:
+ case EAXFXSLOT_FLAGS:
+ case EAXFXSLOT_OCCLUSION:
+ case EAXFXSLOT_OCCLUSIONLFRATIO:
+ // EAX allow to set "defer" flag on immediate-only properties.
+ // If we don't clear our flag then "applyAllUpdates" in EAX context won't be called.
+ mIsDeferred = false;
+ break;
+ }
+
+ if(!mIsDeferred)
+ {
+ if(mPropertySetId != EaxCallPropertySetId::fx_slot && mPropertyId != 0)
+ {
+ if(mPropertyBuffer == nullptr)
+ fail("Null property buffer.");
+
+ if(mPropertyBufferSize == 0)
+ fail("Empty property.");
+ }
+ }
+
+ if(mPropertySetId == EaxCallPropertySetId::source && mPropertySourceId == 0)
+ fail("Null AL source id.");
+
+ if(mPropertySetId == EaxCallPropertySetId::fx_slot)
+ {
+ if(mPropertyId < EAXFXSLOT_NONE)
+ mPropertySetId = EaxCallPropertySetId::fx_slot_effect;
+ }
+}
+
+[[noreturn]] void EaxCall::fail(const char* message)
+{
+ throw EaxCallException{message};
+}
+
+[[noreturn]] void EaxCall::fail_too_small()
+{
+ fail("Property buffer too small.");
+}
+
+EaxCall create_eax_call(
+ EaxCallType type,
+ const GUID* property_set_id,
+ ALuint property_id,
+ ALuint property_source_id,
+ ALvoid* property_buffer,
+ ALuint property_size)
+{
+ if(!property_set_id)
+ throw EaxCallException{"Null property set ID."};
+
+ return EaxCall{
+ type,
+ *property_set_id,
+ property_id,
+ property_source_id,
+ property_buffer,
+ property_size
+ };
+}
diff --git a/al/eax/call.h b/al/eax/call.h
new file mode 100644
index 00000000..5ec33b0f
--- /dev/null
+++ b/al/eax/call.h
@@ -0,0 +1,97 @@
+#ifndef EAX_EAX_CALL_INCLUDED
+#define EAX_EAX_CALL_INCLUDED
+
+#include "AL/al.h"
+#include "alnumeric.h"
+#include "alspan.h"
+#include "api.h"
+#include "fx_slot_index.h"
+
+enum class EaxCallType {
+ none,
+ get,
+ set,
+}; // EaxCallType
+
+enum class EaxCallPropertySetId {
+ none,
+ context,
+ fx_slot,
+ source,
+ fx_slot_effect,
+}; // EaxCallPropertySetId
+
+class EaxCall {
+public:
+ EaxCall(
+ EaxCallType type,
+ const GUID& property_set_guid,
+ ALuint property_id,
+ ALuint property_source_id,
+ ALvoid* property_buffer,
+ ALuint property_size);
+
+ bool is_get() const noexcept { return mCallType == EaxCallType::get; }
+ bool is_deferred() const noexcept { return mIsDeferred; }
+ int get_version() const noexcept { return mVersion; }
+ EaxCallPropertySetId get_property_set_id() const noexcept { return mPropertySetId; }
+ ALuint get_property_id() const noexcept { return mPropertyId; }
+ ALuint get_property_al_name() const noexcept { return mPropertySourceId; }
+ EaxFxSlotIndex get_fx_slot_index() const noexcept { return mFxSlotIndex; }
+
+ template<typename TException, typename TValue>
+ TValue& get_value() const
+ {
+ if(mPropertyBufferSize < sizeof(TValue))
+ fail_too_small();
+
+ return *static_cast<TValue*>(mPropertyBuffer);
+ }
+
+ template<typename TValue>
+ al::span<TValue> get_values(size_t max_count) const
+ {
+ if(max_count == 0 || mPropertyBufferSize < sizeof(TValue))
+ fail_too_small();
+
+ const auto count = minz(mPropertyBufferSize / sizeof(TValue), max_count);
+ return al::as_span(static_cast<TValue*>(mPropertyBuffer), count);
+ }
+
+ template<typename TValue>
+ al::span<TValue> get_values() const
+ {
+ return get_values<TValue>(~size_t{});
+ }
+
+ template<typename TException, typename TValue>
+ void set_value(const TValue& value) const
+ {
+ get_value<TException, TValue>() = value;
+ }
+
+private:
+ const EaxCallType mCallType;
+ int mVersion;
+ EaxFxSlotIndex mFxSlotIndex;
+ EaxCallPropertySetId mPropertySetId;
+ bool mIsDeferred;
+
+ const ALuint mPropertyId;
+ const ALuint mPropertySourceId;
+ ALvoid*const mPropertyBuffer;
+ const ALuint mPropertyBufferSize;
+
+ [[noreturn]] static void fail(const char* message);
+ [[noreturn]] static void fail_too_small();
+}; // EaxCall
+
+EaxCall create_eax_call(
+ EaxCallType type,
+ 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.h b/al/eax/effect.h
new file mode 100644
index 00000000..a0b4e71b
--- /dev/null
+++ b/al/eax/effect.h
@@ -0,0 +1,418 @@
+#ifndef EAX_EFFECT_INCLUDED
+#define EAX_EFFECT_INCLUDED
+
+
+#include <cassert>
+#include <memory>
+
+#include "alnumeric.h"
+#include "AL/al.h"
+#include "core/effects/base.h"
+#include "call.h"
+
+struct EaxEffectErrorMessages
+{
+ static constexpr auto unknown_property_id() noexcept { return "Unknown property id."; }
+ static constexpr auto unknown_version() noexcept { return "Unknown version."; }
+}; // EaxEffectErrorMessages
+
+/* TODO: Use std::variant (C++17). */
+enum class EaxEffectType {
+ None, Reverb, Chorus, Autowah, Compressor, Distortion, Echo, Equalizer, Flanger,
+ FrequencyShifter, Modulator, PitchShifter, VocalMorpher
+};
+struct EaxEffectProps {
+ EaxEffectType mType;
+ union {
+ EAXREVERBPROPERTIES mReverb;
+ EAXCHORUSPROPERTIES mChorus;
+ EAXAUTOWAHPROPERTIES mAutowah;
+ EAXAGCCOMPRESSORPROPERTIES mCompressor;
+ EAXDISTORTIONPROPERTIES mDistortion;
+ EAXECHOPROPERTIES mEcho;
+ EAXEQUALIZERPROPERTIES mEqualizer;
+ EAXFLANGERPROPERTIES mFlanger;
+ EAXFREQUENCYSHIFTERPROPERTIES mFrequencyShifter;
+ EAXRINGMODULATORPROPERTIES mModulator;
+ EAXPITCHSHIFTERPROPERTIES mPitchShifter;
+ EAXVOCALMORPHERPROPERTIES mVocalMorpher;
+ };
+};
+
+constexpr ALenum EnumFromEaxEffectType(const EaxEffectProps &props)
+{
+ switch(props.mType)
+ {
+ case EaxEffectType::None: break;
+ case EaxEffectType::Reverb: return AL_EFFECT_EAXREVERB;
+ case EaxEffectType::Chorus: return AL_EFFECT_CHORUS;
+ case EaxEffectType::Autowah: return AL_EFFECT_AUTOWAH;
+ case EaxEffectType::Compressor: return AL_EFFECT_COMPRESSOR;
+ case EaxEffectType::Distortion: return AL_EFFECT_DISTORTION;
+ case EaxEffectType::Echo: return AL_EFFECT_ECHO;
+ case EaxEffectType::Equalizer: return AL_EFFECT_EQUALIZER;
+ case EaxEffectType::Flanger: return AL_EFFECT_FLANGER;
+ case EaxEffectType::FrequencyShifter: return AL_EFFECT_FREQUENCY_SHIFTER;
+ case EaxEffectType::Modulator: return AL_EFFECT_RING_MODULATOR;
+ case EaxEffectType::PitchShifter: return AL_EFFECT_PITCH_SHIFTER;
+ case EaxEffectType::VocalMorpher: return AL_EFFECT_VOCAL_MORPHER;
+ }
+ return AL_EFFECT_NULL;
+}
+
+struct EaxReverbCommitter {
+ struct Exception;
+
+ EaxReverbCommitter(EaxEffectProps &eaxprops, EffectProps &alprops)
+ : mEaxProps{eaxprops}, mAlProps{alprops}
+ { }
+
+ EaxEffectProps &mEaxProps;
+ EffectProps &mAlProps;
+
+ [[noreturn]] static void fail(const char* message);
+ [[noreturn]] static void fail_unknown_property_id()
+ { fail(EaxEffectErrorMessages::unknown_property_id()); }
+
+ template<typename TValidator, typename TProperty>
+ static void defer(const EaxCall& call, TProperty& property)
+ {
+ const auto& value = call.get_value<Exception, const TProperty>();
+ TValidator{}(value);
+ property = value;
+ }
+
+ template<typename TValidator, typename TDeferrer, typename TProperties, typename TProperty>
+ static void defer(const EaxCall& call, TProperties& properties, TProperty&)
+ {
+ const auto& value = call.get_value<Exception, const TProperty>();
+ TValidator{}(value);
+ TDeferrer{}(properties, value);
+ }
+
+ template<typename TValidator, typename TProperty>
+ static void defer3(const EaxCall& call, EAXREVERBPROPERTIES& properties, TProperty& property)
+ {
+ const auto& value = call.get_value<Exception, const TProperty>();
+ TValidator{}(value);
+ if (value == property)
+ return;
+ property = value;
+ properties.ulEnvironment = EAX_ENVIRONMENT_UNDEFINED;
+ }
+
+
+ bool commit(const EAX_REVERBPROPERTIES &props);
+ bool commit(const EAX20LISTENERPROPERTIES &props);
+ bool commit(const EAXREVERBPROPERTIES &props);
+ bool commit(const EaxEffectProps &props);
+
+ static void SetDefaults(EAX_REVERBPROPERTIES &props);
+ static void SetDefaults(EAX20LISTENERPROPERTIES &props);
+ static void SetDefaults(EAXREVERBPROPERTIES &props);
+ static void SetDefaults(EaxEffectProps &props);
+
+ static void Get(const EaxCall &call, const EAX_REVERBPROPERTIES &props);
+ static void Get(const EaxCall &call, const EAX20LISTENERPROPERTIES &props);
+ static void Get(const EaxCall &call, const EAXREVERBPROPERTIES &props);
+ static void Get(const EaxCall &call, const EaxEffectProps &props);
+
+ static void Set(const EaxCall &call, EAX_REVERBPROPERTIES &props);
+ static void Set(const EaxCall &call, EAX20LISTENERPROPERTIES &props);
+ static void Set(const EaxCall &call, EAXREVERBPROPERTIES &props);
+ static void Set(const EaxCall &call, EaxEffectProps &props);
+
+ static void translate(const EAX_REVERBPROPERTIES& src, EaxEffectProps& dst) noexcept;
+ static void translate(const EAX20LISTENERPROPERTIES& src, EaxEffectProps& dst) noexcept;
+ static void translate(const EAXREVERBPROPERTIES& src, EaxEffectProps& dst) noexcept;
+};
+
+template<typename T>
+struct EaxCommitter {
+ struct Exception;
+
+ EaxCommitter(EaxEffectProps &eaxprops, EffectProps &alprops)
+ : mEaxProps{eaxprops}, mAlProps{alprops}
+ { }
+
+ EaxEffectProps &mEaxProps;
+ EffectProps &mAlProps;
+
+ template<typename TValidator, typename TProperty>
+ static void defer(const EaxCall& call, TProperty& property)
+ {
+ const auto& value = call.get_value<Exception, const TProperty>();
+ TValidator{}(value);
+ property = value;
+ }
+
+ [[noreturn]] static void fail(const char *message);
+ [[noreturn]] static void fail_unknown_property_id()
+ { fail(EaxEffectErrorMessages::unknown_property_id()); }
+
+ bool commit(const EaxEffectProps &props);
+
+ static void SetDefaults(EaxEffectProps &props);
+ static void Get(const EaxCall &call, const EaxEffectProps &props);
+ static void Set(const EaxCall &call, EaxEffectProps &props);
+};
+
+struct EaxAutowahCommitter : public EaxCommitter<EaxAutowahCommitter> {
+ using EaxCommitter<EaxAutowahCommitter>::EaxCommitter;
+};
+struct EaxChorusCommitter : public EaxCommitter<EaxChorusCommitter> {
+ using EaxCommitter<EaxChorusCommitter>::EaxCommitter;
+};
+struct EaxCompressorCommitter : public EaxCommitter<EaxCompressorCommitter> {
+ using EaxCommitter<EaxCompressorCommitter>::EaxCommitter;
+};
+struct EaxDistortionCommitter : public EaxCommitter<EaxDistortionCommitter> {
+ using EaxCommitter<EaxDistortionCommitter>::EaxCommitter;
+};
+struct EaxEchoCommitter : public EaxCommitter<EaxEchoCommitter> {
+ using EaxCommitter<EaxEchoCommitter>::EaxCommitter;
+};
+struct EaxEqualizerCommitter : public EaxCommitter<EaxEqualizerCommitter> {
+ using EaxCommitter<EaxEqualizerCommitter>::EaxCommitter;
+};
+struct EaxFlangerCommitter : public EaxCommitter<EaxFlangerCommitter> {
+ using EaxCommitter<EaxFlangerCommitter>::EaxCommitter;
+};
+struct EaxFrequencyShifterCommitter : public EaxCommitter<EaxFrequencyShifterCommitter> {
+ using EaxCommitter<EaxFrequencyShifterCommitter>::EaxCommitter;
+};
+struct EaxModulatorCommitter : public EaxCommitter<EaxModulatorCommitter> {
+ using EaxCommitter<EaxModulatorCommitter>::EaxCommitter;
+};
+struct EaxPitchShifterCommitter : public EaxCommitter<EaxPitchShifterCommitter> {
+ using EaxCommitter<EaxPitchShifterCommitter>::EaxCommitter;
+};
+struct EaxVocalMorpherCommitter : public EaxCommitter<EaxVocalMorpherCommitter> {
+ using EaxCommitter<EaxVocalMorpherCommitter>::EaxCommitter;
+};
+struct EaxNullCommitter : public EaxCommitter<EaxNullCommitter> {
+ using EaxCommitter<EaxNullCommitter>::EaxCommitter;
+};
+
+
+class EaxEffect {
+public:
+ EaxEffect() noexcept = default;
+ ~EaxEffect() = default;
+
+ ALenum al_effect_type_{AL_EFFECT_NULL};
+ EffectProps al_effect_props_{};
+
+ using Props1 = EAX_REVERBPROPERTIES;
+ using Props2 = EAX20LISTENERPROPERTIES;
+ using Props3 = EAXREVERBPROPERTIES;
+ using Props4 = EaxEffectProps;
+
+ struct State1 {
+ Props1 i; // Immediate.
+ Props1 d; // Deferred.
+ };
+
+ struct State2 {
+ Props2 i; // Immediate.
+ Props2 d; // Deferred.
+ };
+
+ struct State3 {
+ Props3 i; // Immediate.
+ Props3 d; // Deferred.
+ };
+
+ struct State4 {
+ Props4 i; // Immediate.
+ Props4 d; // Deferred.
+ };
+
+ int version_{};
+ bool changed_{};
+ Props4 props_{};
+ State1 state1_{};
+ State2 state2_{};
+ State3 state3_{};
+ State4 state4_{};
+ State4 state5_{};
+
+
+ template<typename T, typename ...Args>
+ void call_set_defaults(Args&& ...args)
+ { return T::SetDefaults(std::forward<Args>(args)...); }
+
+ void call_set_defaults(const ALenum altype, EaxEffectProps &props)
+ {
+ if(altype == AL_EFFECT_EAXREVERB)
+ return call_set_defaults<EaxReverbCommitter>(props);
+ if(altype == AL_EFFECT_CHORUS)
+ return call_set_defaults<EaxChorusCommitter>(props);
+ if(altype == AL_EFFECT_AUTOWAH)
+ return call_set_defaults<EaxAutowahCommitter>(props);
+ if(altype == AL_EFFECT_COMPRESSOR)
+ return call_set_defaults<EaxCompressorCommitter>(props);
+ if(altype == AL_EFFECT_DISTORTION)
+ return call_set_defaults<EaxDistortionCommitter>(props);
+ if(altype == AL_EFFECT_ECHO)
+ return call_set_defaults<EaxEchoCommitter>(props);
+ if(altype == AL_EFFECT_EQUALIZER)
+ return call_set_defaults<EaxEqualizerCommitter>(props);
+ if(altype == AL_EFFECT_FLANGER)
+ return call_set_defaults<EaxFlangerCommitter>(props);
+ if(altype == AL_EFFECT_FREQUENCY_SHIFTER)
+ return call_set_defaults<EaxFrequencyShifterCommitter>(props);
+ if(altype == AL_EFFECT_RING_MODULATOR)
+ return call_set_defaults<EaxModulatorCommitter>(props);
+ if(altype == AL_EFFECT_PITCH_SHIFTER)
+ return call_set_defaults<EaxPitchShifterCommitter>(props);
+ if(altype == AL_EFFECT_VOCAL_MORPHER)
+ return call_set_defaults<EaxVocalMorpherCommitter>(props);
+ return call_set_defaults<EaxNullCommitter>(props);
+ }
+
+ template<typename T>
+ void init()
+ {
+ call_set_defaults<EaxReverbCommitter>(state1_.d);
+ state1_.i = state1_.d;
+ call_set_defaults<EaxReverbCommitter>(state2_.d);
+ state2_.i = state2_.d;
+ call_set_defaults<EaxReverbCommitter>(state3_.d);
+ state3_.i = state3_.d;
+ call_set_defaults<T>(state4_.d);
+ state4_.i = state4_.d;
+ call_set_defaults<T>(state5_.d);
+ state5_.i = state5_.d;
+ }
+
+ void set_defaults(int eax_version, ALenum altype)
+ {
+ switch(eax_version)
+ {
+ case 1: call_set_defaults<EaxReverbCommitter>(state1_.d); break;
+ case 2: call_set_defaults<EaxReverbCommitter>(state2_.d); break;
+ case 3: call_set_defaults<EaxReverbCommitter>(state3_.d); break;
+ case 4: call_set_defaults(altype, state4_.d); break;
+ case 5: call_set_defaults(altype, state5_.d); break;
+ }
+ changed_ = true;
+ }
+
+
+#define EAXCALL(T, Callable, ...) \
+ if(T == EaxEffectType::Reverb) \
+ return Callable<EaxReverbCommitter>(__VA_ARGS__); \
+ if(T == EaxEffectType::Chorus) \
+ return Callable<EaxChorusCommitter>(__VA_ARGS__); \
+ if(T == EaxEffectType::Autowah) \
+ return Callable<EaxAutowahCommitter>(__VA_ARGS__); \
+ if(T == EaxEffectType::Compressor) \
+ return Callable<EaxCompressorCommitter>(__VA_ARGS__); \
+ if(T == EaxEffectType::Distortion) \
+ return Callable<EaxDistortionCommitter>(__VA_ARGS__); \
+ if(T == EaxEffectType::Echo) \
+ return Callable<EaxEchoCommitter>(__VA_ARGS__); \
+ if(T == EaxEffectType::Equalizer) \
+ return Callable<EaxEqualizerCommitter>(__VA_ARGS__); \
+ if(T == EaxEffectType::Flanger) \
+ return Callable<EaxFlangerCommitter>(__VA_ARGS__); \
+ if(T == EaxEffectType::FrequencyShifter) \
+ return Callable<EaxFrequencyShifterCommitter>(__VA_ARGS__); \
+ if(T == EaxEffectType::Modulator) \
+ return Callable<EaxModulatorCommitter>(__VA_ARGS__); \
+ if(T == EaxEffectType::PitchShifter) \
+ return Callable<EaxPitchShifterCommitter>(__VA_ARGS__); \
+ if(T == EaxEffectType::VocalMorpher) \
+ return Callable<EaxVocalMorpherCommitter>(__VA_ARGS__); \
+ return Callable<EaxNullCommitter>(__VA_ARGS__)
+
+ template<typename T, typename ...Args>
+ static void call_set(Args&& ...args)
+ { return T::Set(std::forward<Args>(args)...); }
+
+ static void call_set(const EaxCall &call, EaxEffectProps &props)
+ { EAXCALL(props.mType, call_set, call, props); }
+
+ void set(const EaxCall &call)
+ {
+ switch(call.get_version())
+ {
+ case 1: call_set<EaxReverbCommitter>(call, state1_.d); break;
+ case 2: call_set<EaxReverbCommitter>(call, state2_.d); break;
+ case 3: call_set<EaxReverbCommitter>(call, state3_.d); break;
+ case 4: call_set(call, state4_.d); break;
+ case 5: call_set(call, state5_.d); break;
+ }
+ changed_ = true;
+ }
+
+
+ template<typename T, typename ...Args>
+ static void call_get(Args&& ...args)
+ { return T::Get(std::forward<Args>(args)...); }
+
+ static void call_get(const EaxCall &call, const EaxEffectProps &props)
+ { EAXCALL(props.mType, call_get, call, props); }
+
+ void get(const EaxCall &call)
+ {
+ switch(call.get_version())
+ {
+ case 1: call_get<EaxReverbCommitter>(call, state1_.d); break;
+ case 2: call_get<EaxReverbCommitter>(call, state2_.d); break;
+ case 3: call_get<EaxReverbCommitter>(call, state3_.d); break;
+ case 4: call_get(call, state4_.d); break;
+ case 5: call_get(call, state5_.d); break;
+ }
+ }
+
+
+ template<typename T, typename ...Args>
+ bool call_commit(Args&& ...args)
+ { return T{props_, al_effect_props_}.commit(std::forward<Args>(args)...); }
+
+ bool call_commit(const EaxEffectProps &props)
+ { EAXCALL(props.mType, call_commit, props); }
+
+ bool commit(int eax_version)
+ {
+ changed_ |= version_ != eax_version;
+ if(!changed_) return false;
+
+ bool ret{version_ != eax_version};
+ version_ = eax_version;
+ changed_ = false;
+
+ switch(eax_version)
+ {
+ case 1:
+ state1_.i = state1_.d;
+ ret |= call_commit<EaxReverbCommitter>(state1_.d);
+ break;
+ case 2:
+ state2_.i = state2_.d;
+ ret |= call_commit<EaxReverbCommitter>(state2_.d);
+ break;
+ case 3:
+ state3_.i = state3_.d;
+ ret |= call_commit<EaxReverbCommitter>(state3_.d);
+ break;
+ case 4:
+ state4_.i = state4_.d;
+ ret |= call_commit(state4_.d);
+ break;
+ case 5:
+ state5_.i = state5_.d;
+ ret |= call_commit(state5_.d);
+ break;
+ }
+ al_effect_type_ = EnumFromEaxEffectType(props_);
+ return ret;
+ }
+#undef EAXCALL
+}; // EaxEffect
+
+using EaxEffectUPtr = std::unique_ptr<EaxEffect>;
+
+#endif // !EAX_EFFECT_INCLUDED
diff --git a/al/eax/exception.cpp b/al/eax/exception.cpp
new file mode 100644
index 00000000..435e7442
--- /dev/null
+++ b/al/eax/exception.cpp
@@ -0,0 +1,59 @@
+#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)}
+{
+}
+EaxException::~EaxException() = default;
+
+
+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..3ae88cdc
--- /dev/null
+++ b/al/eax/exception.h
@@ -0,0 +1,18 @@
+#ifndef EAX_EXCEPTION_INCLUDED
+#define EAX_EXCEPTION_INCLUDED
+
+
+#include <stdexcept>
+#include <string>
+
+
+class EaxException : public std::runtime_error {
+ static std::string make_message(const char *context, const char *message);
+
+public:
+ EaxException(const char *context, const char *message);
+ ~EaxException() override;
+}; // 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..d04b70df
--- /dev/null
+++ b/al/eax/fx_slots.cpp
@@ -0,0 +1,75 @@
+#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()];
+}
+
+[[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..18b2d3ad
--- /dev/null
+++ b/al/eax/fx_slots.h
@@ -0,0 +1,49 @@
+#ifndef EAX_FX_SLOTS_INCLUDED
+#define EAX_FX_SLOTS_INCLUDED
+
+
+#include <array>
+
+#include "al/auxeffectslot.h"
+
+#include "api.h"
+#include "call.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);
+
+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..b3ed6ca1
--- /dev/null
+++ b/al/eax/utils.cpp
@@ -0,0 +1,26 @@
+#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);
+
+ try {
+ std::rethrow_exception(exception_ptr);
+ }
+ catch(const std::exception& ex) {
+ const auto ex_message = ex.what();
+ ERR("%s %s\n", message ? message : "", ex_message);
+ }
+ catch(...) {
+ ERR("%s %s\n", message ? message : "", "Generic exception.");
+ }
+}
diff --git a/al/eax/utils.h b/al/eax/utils.h
new file mode 100644
index 00000000..8ff75a18
--- /dev/null
+++ b/al/eax/utils.h
@@ -0,0 +1,95 @@
+#ifndef EAX_UTILS_INCLUDED
+#define EAX_UTILS_INCLUDED
+
+#include <algorithm>
+#include <cstdint>
+#include <string>
+#include <type_traits>
+
+using EaxDirtyFlags = unsigned int;
+
+struct EaxAlLowPassParam {
+ float gain;
+ float gain_hf;
+};
+
+void eax_log_exception(const char *message) 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;
+};
+
+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.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