From 7d35d66e7d74301bce4a836784b3c6fe95320811 Mon Sep 17 00:00:00 2001 From: "C. J. Howard" Date: Wed, 4 Jan 2023 16:37:32 +0800 Subject: [PATCH] Update OpenAL Soft module --- CMakeLists.txt | 3 + modules/antkeeper-source | 2 +- modules/openal-soft/.github/workflows/ci.yml | 20 +- modules/openal-soft/Alc/alc.cpp | 70 +- modules/openal-soft/Alc/alu.cpp | 114 +- modules/openal-soft/Alc/backends/base.cpp | 74 +- modules/openal-soft/Alc/backends/base.h | 5 - .../openal-soft/Alc/backends/coreaudio.cpp | 47 +- modules/openal-soft/Alc/backends/dsound.cpp | 90 +- modules/openal-soft/Alc/backends/oboe.cpp | 90 +- modules/openal-soft/Alc/backends/opensl.cpp | 51 +- modules/openal-soft/Alc/backends/pipewire.cpp | 155 +- .../openal-soft/Alc/backends/pulseaudio.cpp | 2 + modules/openal-soft/Alc/backends/sdl2.cpp | 5 +- modules/openal-soft/Alc/backends/wasapi.cpp | 83 +- modules/openal-soft/Alc/backends/wave.cpp | 2 + modules/openal-soft/Alc/backends/winmm.cpp | 10 +- modules/openal-soft/Alc/context.cpp | 242 +- modules/openal-soft/Alc/context.h | 91 +- modules/openal-soft/Alc/device.cpp | 1 + modules/openal-soft/Alc/device.h | 4 +- modules/openal-soft/Alc/effects/reverb.cpp | 29 +- modules/openal-soft/Alc/panning.cpp | 58 +- modules/openal-soft/CMakeLists.txt | 129 +- modules/openal-soft/ChangeLog | 29 + modules/openal-soft/al/auxeffectslot.cpp | 198 +- modules/openal-soft/al/auxeffectslot.h | 103 +- modules/openal-soft/al/buffer.cpp | 4 +- modules/openal-soft/al/buffer.h | 2 +- .../al/{eax_api.cpp => eax/api.cpp} | 721 ++++- .../openal-soft/al/{eax_api.h => eax/api.h} | 416 ++- modules/openal-soft/al/eax/call.cpp | 212 ++ modules/openal-soft/al/eax/call.h | 97 + modules/openal-soft/al/eax/effect.h | 173 ++ .../{eax_exception.cpp => eax/exception.cpp} | 3 +- .../al/{eax_exception.h => eax/exception.h} | 0 .../fx_slot_index.cpp} | 4 +- .../fx_slot_index.h} | 2 +- .../al/{eax_fx_slots.cpp => eax/fx_slots.cpp} | 13 +- .../al/{eax_fx_slots.h => eax/fx_slots.h} | 8 +- .../al/{eax_globals.cpp => eax/globals.cpp} | 2 +- .../al/{eax_globals.h => eax/globals.h} | 0 .../al/{eax_utils.cpp => eax/utils.cpp} | 2 +- .../al/{eax_utils.h => eax/utils.h} | 69 +- .../al/{eax_x_ram.h => eax/x_ram.h} | 0 modules/openal-soft/al/eax_eax_call.cpp | 324 -- modules/openal-soft/al/eax_eax_call.h | 117 - modules/openal-soft/al/eax_effect.cpp | 3 - modules/openal-soft/al/eax_effect.h | 44 - modules/openal-soft/al/eax_x_ram.cpp | 3 - modules/openal-soft/al/effect.cpp | 2 +- modules/openal-soft/al/effects/autowah.cpp | 486 +-- modules/openal-soft/al/effects/chorus.cpp | 1403 +++------ modules/openal-soft/al/effects/compressor.cpp | 234 +- modules/openal-soft/al/effects/distortion.cpp | 514 +-- modules/openal-soft/al/effects/echo.cpp | 515 +-- modules/openal-soft/al/effects/effects.cpp | 26 +- modules/openal-soft/al/effects/effects.h | 5 +- modules/openal-soft/al/effects/equalizer.cpp | 866 ++---- modules/openal-soft/al/effects/fshifter.cpp | 363 +-- modules/openal-soft/al/effects/modulator.cpp | 369 +-- modules/openal-soft/al/effects/null.cpp | 38 +- modules/openal-soft/al/effects/pshifter.cpp | 305 +- modules/openal-soft/al/effects/reverb.cpp | 2710 +++++++--------- modules/openal-soft/al/effects/vmorpher.cpp | 556 ++-- modules/openal-soft/al/source.cpp | 2768 +++++------------ modules/openal-soft/al/source.h | 1332 ++++---- modules/openal-soft/al/state.cpp | 5 +- modules/openal-soft/alsoftrc.sample | 18 +- modules/openal-soft/appveyor.yml | 2 +- modules/openal-soft/common/almalloc.h | 10 +- modules/openal-soft/common/aloptional.h | 4 +- modules/openal-soft/common/alstring.h | 1 + .../openal-soft/common/polyphase_resampler.h | 4 +- modules/openal-soft/config.h.in | 3 + modules/openal-soft/core/cpu_caps.cpp | 7 +- modules/openal-soft/core/devformat.cpp | 2 + modules/openal-soft/core/devformat.h | 18 + modules/openal-soft/core/helpers.cpp | 37 +- modules/openal-soft/core/uhjfilter.cpp | 12 +- modules/openal-soft/core/uhjfilter.h | 48 +- modules/openal-soft/core/voice.cpp | 31 +- modules/openal-soft/core/voice.h | 4 +- modules/openal-soft/docs/3D7.1.txt | 15 +- modules/openal-soft/examples/alffplay.cpp | 167 +- modules/openal-soft/presets/3D7.1.ambdec | 21 +- modules/openal-soft/presets/presets.txt | 7 +- modules/openal-soft/router/al.cpp | 39 + modules/openal-soft/router/alc.cpp | 223 +- modules/openal-soft/router/router.cpp | 10 +- modules/openal-soft/router/router.h | 40 +- .../utils/alsoft-config/mainwindow.cpp | 17 + .../utils/alsoft-config/mainwindow.h | 1 + .../utils/alsoft-config/mainwindow.ui | 131 +- modules/openal-soft/utils/makemhr/loaddef.cpp | 76 +- modules/openal-soft/utils/makemhr/loaddef.h | 4 +- .../openal-soft/utils/makemhr/loadsofa.cpp | 42 +- modules/openal-soft/utils/makemhr/loadsofa.h | 2 +- modules/openal-soft/utils/makemhr/makemhr.cpp | 6 +- 99 files changed, 7128 insertions(+), 10297 deletions(-) rename modules/openal-soft/al/{eax_api.cpp => eax/api.cpp} (67%) rename modules/openal-soft/al/{eax_api.h => eax/api.h} (86%) create mode 100644 modules/openal-soft/al/eax/call.cpp create mode 100644 modules/openal-soft/al/eax/call.h create mode 100644 modules/openal-soft/al/eax/effect.h rename modules/openal-soft/al/{eax_exception.cpp => eax/exception.cpp} (98%) rename modules/openal-soft/al/{eax_exception.h => eax/exception.h} (100%) rename modules/openal-soft/al/{eax_fx_slot_index.cpp => eax/fx_slot_index.cpp} (95%) rename modules/openal-soft/al/{eax_fx_slot_index.h => eax/fx_slot_index.h} (97%) rename modules/openal-soft/al/{eax_fx_slots.cpp => eax/fx_slots.cpp} (85%) rename modules/openal-soft/al/{eax_fx_slots.h => eax/fx_slots.h} (86%) rename modules/openal-soft/al/{eax_globals.cpp => eax/globals.cpp} (95%) rename modules/openal-soft/al/{eax_globals.h => eax/globals.h} (100%) rename modules/openal-soft/al/{eax_utils.cpp => eax/utils.cpp} (96%) rename modules/openal-soft/al/{eax_utils.h => eax/utils.h} (71%) rename modules/openal-soft/al/{eax_x_ram.h => eax/x_ram.h} (100%) delete mode 100644 modules/openal-soft/al/eax_eax_call.cpp delete mode 100644 modules/openal-soft/al/eax_eax_call.h delete mode 100644 modules/openal-soft/al/eax_effect.cpp delete mode 100644 modules/openal-soft/al/eax_effect.h delete mode 100644 modules/openal-soft/al/eax_x_ram.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ddcc42b..6e9a76c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -123,6 +123,9 @@ ExternalProject_Add(openal-soft "-DCMAKE_C_FLAGS='${CMAKE_C_FLAGS}'" "-DCMAKE_C_FLAGS_DEBUG='${CMAKE_C_FLAGS_DEBUG}'" "-DCMAKE_C_FLAGS_RELEASE='${CMAKE_C_FLAGS_RELEASE}'" + "-DCMAKE_CXX_FLAGS='${CMAKE_CXX_FLAGS}'" + "-DCMAKE_CXX_FLAGS_DEBUG='${CMAKE_CXX_FLAGS_DEBUG}'" + "-DCMAKE_CXX_FLAGS_RELEASE='${CMAKE_CXX_FLAGS_RELEASE}'" "-DLIBTYPE=STATIC" "-DFORCE_STATIC_VCRT=ON" "-DALSOFT_UTILS=OFF" diff --git a/modules/antkeeper-source b/modules/antkeeper-source index 96c678e..30dc77e 160000 --- a/modules/antkeeper-source +++ b/modules/antkeeper-source @@ -1 +1 @@ -Subproject commit 96c678e5fc141df2440e8000d47dcf5cb942cd7c +Subproject commit 30dc77ef0a2d478c519acd78474b26d630b1bc14 diff --git a/modules/openal-soft/.github/workflows/ci.yml b/modules/openal-soft/.github/workflows/ci.yml index 7f044ff..faa7841 100644 --- a/modules/openal-soft/.github/workflows/ci.yml +++ b/modules/openal-soft/.github/workflows/ci.yml @@ -11,7 +11,17 @@ jobs: matrix: config: - { - name: "Visual Studio 64-bit", + name: "Win32", + os: windows-latest, + cmake_opts: "-A Win32 \ + -DALSOFT_BUILD_ROUTER=ON \ + -DALSOFT_REQUIRE_WINMM=ON \ + -DALSOFT_REQUIRE_DSOUND=ON \ + -DALSOFT_REQUIRE_WASAPI=ON", + build_type: "Release" + } + - { + name: "Win64", os: windows-latest, cmake_opts: "-A x64 \ -DALSOFT_BUILD_ROUTER=ON \ @@ -64,3 +74,11 @@ jobs: shell: bash run: | cmake --build build --config ${{matrix.config.build_type}} + + - name: Upload Archive + # Upload package as an artifact of this workflow. + uses: actions/upload-artifact@v2 + if: ${{ matrix.config.os == 'windows-latest' }} + with: + name: soft_oal-${{matrix.config.name}} + path: ${{github.workspace}}/build/${{matrix.config.build_type}}/soft_oal.dll diff --git a/modules/openal-soft/Alc/alc.cpp b/modules/openal-soft/Alc/alc.cpp index 3bbe43d..6ee6c24 100644 --- a/modules/openal-soft/Alc/alc.cpp +++ b/modules/openal-soft/Alc/alc.cpp @@ -156,8 +156,8 @@ #endif #ifdef ALSOFT_EAX -#include "al/eax_globals.h" -#include "al/eax_x_ram.h" +#include "al/eax/globals.h" +#include "al/eax/x_ram.h" #endif // ALSOFT_EAX @@ -223,15 +223,15 @@ BackendInfo BackendList[] = { #ifdef HAVE_OPENSL { "opensl", OSLBackendFactory::getFactory }, #endif +#ifdef HAVE_ALSA + { "alsa", AlsaBackendFactory::getFactory }, +#endif #ifdef HAVE_SOLARIS { "solaris", SolarisBackendFactory::getFactory }, #endif #ifdef HAVE_SNDIO { "sndio", SndIOBackendFactory::getFactory }, #endif -#ifdef HAVE_ALSA - { "alsa", AlsaBackendFactory::getFactory }, -#endif #ifdef HAVE_OSS { "oss", OSSBackendFactory::getFactory }, #endif @@ -1299,15 +1299,21 @@ void alc_initconfig(void) else eax_g_is_enabled = true; - if(eax_g_is_enabled && DisabledEffects[EAXREVERB_EFFECT]) + if((DisabledEffects[EAXREVERB_EFFECT] || DisabledEffects[CHORUS_EFFECT]) + && eax_g_is_enabled) { eax_g_is_enabled = false; - TRACE("%s\n", "EAX disabled because EAXReverb is disabled."); + TRACE("EAX disabled because %s disabled.\n", + (DisabledEffects[EAXREVERB_EFFECT] && DisabledEffects[CHORUS_EFFECT]) + ? "EAXReverb and Chorus are" : + DisabledEffects[EAXREVERB_EFFECT] ? "EAXReverb is" : + DisabledEffects[CHORUS_EFFECT] ? "Chorus is" : ""); } } #endif // ALSOFT_EAX } -#define DO_INITCONFIG() std::call_once(alc_config_once, [](){alc_initconfig();}) +inline void InitConfig() +{ std::call_once(alc_config_once, [](){alc_initconfig();}); } /************************************************ @@ -1315,7 +1321,7 @@ void alc_initconfig(void) ************************************************/ void ProbeAllDevicesList() { - DO_INITCONFIG(); + InitConfig(); std::lock_guard _{ListLock}; if(!PlaybackFactory) @@ -1329,7 +1335,7 @@ void ProbeAllDevicesList() } void ProbeCaptureDeviceList() { - DO_INITCONFIG(); + InitConfig(); std::lock_guard _{ListLock}; if(!CaptureFactory) @@ -1441,6 +1447,8 @@ ALCenum EnumFromDevFmt(DevFmtChannels channels) case DevFmtX61: return ALC_6POINT1_SOFT; case DevFmtX71: return ALC_7POINT1_SOFT; case DevFmtAmbi3D: return ALC_BFORMAT3D_SOFT; + /* FIXME: Shouldn't happen. */ + case DevFmtX3D71: break; } throw std::runtime_error{"Invalid DevFmtChannels: "+std::to_string(int(channels))}; } @@ -1911,6 +1919,7 @@ ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList) { "surround51", DevFmtX51, 0 }, { "surround61", DevFmtX61, 0 }, { "surround71", DevFmtX71, 0 }, + { "surround3d71", DevFmtX3D71, 0 }, { "surround51rear", DevFmtX51, 0 }, { "ambi1", DevFmtAmbi3D, 1 }, { "ambi2", DevFmtAmbi3D, 2 }, @@ -2090,6 +2099,7 @@ ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList) case DevFmtX51: device->RealOut.RemixMap = X51Downmix; break; case DevFmtX61: device->RealOut.RemixMap = X61Downmix; break; case DevFmtX71: device->RealOut.RemixMap = X71Downmix; break; + case DevFmtX3D71: device->RealOut.RemixMap = X51Downmix; break; case DevFmtAmbi3D: break; } @@ -3366,7 +3376,7 @@ END_API_FUNC ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) START_API_FUNC { - DO_INITCONFIG(); + InitConfig(); if(!PlaybackFactory) { @@ -3395,6 +3405,13 @@ START_API_FUNC deviceName = nullptr; } + const uint DefaultSends{ +#ifdef ALSOFT_EAX + eax_g_is_enabled ? uint{EAX_MAX_FXSLOTS} : +#endif // ALSOFT_EAX + DEFAULT_SENDS + }; + DeviceRef device{new ALCdevice{DeviceType::Playback}}; /* Set output format */ @@ -3406,11 +3423,7 @@ START_API_FUNC device->SourcesMax = 256; device->AuxiliaryEffectSlotMax = 64; - device->NumAuxSends = DEFAULT_SENDS; -#ifdef ALSOFT_EAX - if(eax_g_is_enabled) - device->NumAuxSends = EAX_MAX_FXSLOTS; -#endif // ALSOFT_EAX + device->NumAuxSends = DefaultSends; try { auto backend = PlaybackFactory->createBackend(device.get(), BackendType::Playback); @@ -3447,8 +3460,10 @@ START_API_FUNC device->AuxiliaryEffectSlotMax = minu(slotsmax, INT_MAX); if(auto sendsopt = device->configValue(nullptr, "sends")) - device->NumAuxSends = minu(DEFAULT_SENDS, - static_cast(clampi(*sendsopt, 0, MAX_SENDS))); + { + const int max_sends{clampi(*sendsopt, 0, MAX_SENDS)}; + device->NumAuxSends = minu(DefaultSends, static_cast(max_sends)); + } device->NumStereoSources = 1; device->NumMonoSources = device->SourcesMax - device->NumStereoSources; @@ -3521,7 +3536,7 @@ END_API_FUNC ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei samples) START_API_FUNC { - DO_INITCONFIG(); + InitConfig(); if(!CaptureFactory) { @@ -3704,7 +3719,7 @@ END_API_FUNC ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceName) START_API_FUNC { - DO_INITCONFIG(); + InitConfig(); /* Make sure the device name, if specified, is us. */ if(deviceName && strcmp(deviceName, alcDefaultName) != 0) @@ -3713,11 +3728,18 @@ START_API_FUNC return nullptr; } + const uint DefaultSends{ +#ifdef ALSOFT_EAX + eax_g_is_enabled ? uint{EAX_MAX_FXSLOTS} : +#endif // ALSOFT_EAX + DEFAULT_SENDS + }; + DeviceRef device{new ALCdevice{DeviceType::Loopback}}; device->SourcesMax = 256; device->AuxiliaryEffectSlotMax = 64; - device->NumAuxSends = DEFAULT_SENDS; + device->NumAuxSends = DefaultSends; //Set output format device->BufferSize = 0; @@ -3734,8 +3756,10 @@ START_API_FUNC device->AuxiliaryEffectSlotMax = minu(slotsmax, INT_MAX); if(auto sendsopt = ConfigValueInt(nullptr, nullptr, "sends")) - device->NumAuxSends = minu(DEFAULT_SENDS, - static_cast(clampi(*sendsopt, 0, MAX_SENDS))); + { + const int max_sends{clampi(*sendsopt, 0, MAX_SENDS)}; + device->NumAuxSends = minu(DefaultSends, static_cast(max_sends)); + } device->NumStereoSources = 1; device->NumMonoSources = device->SourcesMax - device->NumStereoSources; diff --git a/modules/openal-soft/Alc/alu.cpp b/modules/openal-soft/Alc/alu.cpp index ef88515..a06d567 100644 --- a/modules/openal-soft/Alc/alu.cpp +++ b/modules/openal-soft/Alc/alu.cpp @@ -135,9 +135,6 @@ float XScale{1.0f}; float YScale{1.0f}; float ZScale{1.0f}; -} // namespace - -namespace { struct ChanMap { Channel channel; @@ -213,30 +210,30 @@ inline ResamplerFunc SelectResampler(Resampler resampler, uint increment) return Resample_; case Resampler::BSinc12: case Resampler::BSinc24: - if(increment <= MixerFracOne) + if(increment > MixerFracOne) { - /* fall-through */ - case Resampler::FastBSinc12: - case Resampler::FastBSinc24: #ifdef HAVE_NEON if((CPUCapFlags&CPU_CAP_NEON)) - return Resample_; + return Resample_; #endif #ifdef HAVE_SSE if((CPUCapFlags&CPU_CAP_SSE)) - return Resample_; + return Resample_; #endif - return Resample_; + return Resample_; } + /* fall-through */ + case Resampler::FastBSinc12: + case Resampler::FastBSinc24: #ifdef HAVE_NEON if((CPUCapFlags&CPU_CAP_NEON)) - return Resample_; + return Resample_; #endif #ifdef HAVE_SSE if((CPUCapFlags&CPU_CAP_SSE)) - return Resample_; + return Resample_; #endif - return Resample_; + return Resample_; } return Resample_; @@ -308,7 +305,7 @@ void DeviceBase::ProcessUhj(const size_t SamplesToDo) /* Encode to stereo-compatible 2-channel UHJ output. */ mUhjEncoder->encode(RealOut.Buffer[lidx].data(), RealOut.Buffer[ridx].data(), - Dry.Buffer.data(), SamplesToDo); + {{Dry.Buffer[0].data(), Dry.Buffer[1].data(), Dry.Buffer[2].data()}}, SamplesToDo); } void DeviceBase::ProcessBs2b(const size_t SamplesToDo) @@ -328,6 +325,8 @@ void DeviceBase::ProcessBs2b(const size_t SamplesToDo) namespace { +using AmbiRotateMatrix = std::array,MaxAmbiChannels>; + /* This RNG method was created based on the math found in opusdec. It's quick, * and starting with a seed value of 22222, is suitable for generating * whitenoise. @@ -573,14 +572,13 @@ const auto RotatorCoeffArray = RotatorCoeffs::ConcatArrays(RotatorCoeffs::GenCoe * coefficients, this fills in the coefficients for the higher orders up to and * including the given order. The matrix is in ACN layout. */ -void AmbiRotator(std::array,MaxAmbiChannels> &matrix, - const int order) +void AmbiRotator(AmbiRotateMatrix &matrix, const int order) { /* Don't do anything for < 2nd order. */ if(order < 2) return; auto P = [](const int i, const int l, const int a, const int n, const size_t last_band, - const std::array,MaxAmbiChannels> &R) + const AmbiRotateMatrix &R) { const float ri1{ R[static_cast(i+2)][ 1+2]}; const float rim1{R[static_cast(i+2)][-1+2]}; @@ -595,12 +593,12 @@ void AmbiRotator(std::array,MaxAmbiChannels> & }; auto U = [P](const int l, const int m, const int n, const size_t last_band, - const std::array,MaxAmbiChannels> &R) + const AmbiRotateMatrix &R) { return P(0, l, m, n, last_band, R); }; auto V = [P](const int l, const int m, const int n, const size_t last_band, - const std::array,MaxAmbiChannels> &R) + const AmbiRotateMatrix &R) { using namespace al::numbers; if(m > 0) @@ -616,7 +614,7 @@ void AmbiRotator(std::array,MaxAmbiChannels> & return d ? p1*sqrt2_v : (p0 + p1); }; auto W = [P](const int l, const int m, const int n, const size_t last_band, - const std::array,MaxAmbiChannels> &R) + const AmbiRotateMatrix &R) { assert(m != 0); if(m > 0) @@ -863,7 +861,7 @@ void CalcPanningAndFilters(Voice *voice, const float xpos, const float ypos, con * order elements, then construct the rotation for the higher * orders. */ - std::array,MaxAmbiChannels> shrot{}; + AmbiRotateMatrix shrot{}; shrot[0][0] = 1.0f; shrot[1][1] = U[0]; shrot[1][2] = -V[0]; shrot[1][3] = -N[0]; shrot[2][1] = -U[1]; shrot[2][2] = V[1]; shrot[2][3] = N[1]; @@ -1393,7 +1391,7 @@ void CalcAttnSourceParams(Voice *voice, const VoiceProps *props, const ContextBa */ for(uint i{props->WetGainAuto ? 0u : NumSends};i < NumSends;++i) { - if(!SendSlots[i]) + if(!SendSlots[i] || !(SendSlots[i]->DecayTime > 0.0f)) continue; auto calc_attenuation = [](float distance, float refdist, float rolloff) noexcept @@ -2006,50 +2004,50 @@ void DeviceBase::renderSamples(void *outBuffer, const uint numSamples, const siz void DeviceBase::handleDisconnect(const char *msg, ...) { - if(!Connected.exchange(false, std::memory_order_acq_rel)) - return; - - AsyncEvent evt{AsyncEvent::Disconnected}; + IncrementRef(MixCount); + if(Connected.exchange(false, std::memory_order_acq_rel)) + { + AsyncEvent evt{AsyncEvent::Disconnected}; - va_list args; - va_start(args, msg); - int msglen{vsnprintf(evt.u.disconnect.msg, sizeof(evt.u.disconnect.msg), msg, args)}; - va_end(args); + va_list args; + va_start(args, msg); + int msglen{vsnprintf(evt.u.disconnect.msg, sizeof(evt.u.disconnect.msg), msg, args)}; + va_end(args); - if(msglen < 0 || static_cast(msglen) >= sizeof(evt.u.disconnect.msg)) - evt.u.disconnect.msg[sizeof(evt.u.disconnect.msg)-1] = 0; + if(msglen < 0 || static_cast(msglen) >= sizeof(evt.u.disconnect.msg)) + evt.u.disconnect.msg[sizeof(evt.u.disconnect.msg)-1] = 0; - IncrementRef(MixCount); - for(ContextBase *ctx : *mContexts.load()) - { - const uint enabledevt{ctx->mEnabledEvts.load(std::memory_order_acquire)}; - if((enabledevt&AsyncEvent::Disconnected)) + for(ContextBase *ctx : *mContexts.load()) { - RingBuffer *ring{ctx->mAsyncEvents.get()}; - auto evt_data = ring->getWriteVector().first; - if(evt_data.len > 0) + const uint enabledevt{ctx->mEnabledEvts.load(std::memory_order_acquire)}; + if((enabledevt&AsyncEvent::Disconnected)) { - al::construct_at(reinterpret_cast(evt_data.buf), evt); - ring->writeAdvance(1); - ctx->mEventSem.post(); + RingBuffer *ring{ctx->mAsyncEvents.get()}; + auto evt_data = ring->getWriteVector().first; + if(evt_data.len > 0) + { + al::construct_at(reinterpret_cast(evt_data.buf), evt); + ring->writeAdvance(1); + ctx->mEventSem.post(); + } } - } - if(!ctx->mStopVoicesOnDisconnect) - { - ProcessVoiceChanges(ctx); - continue; - } + if(!ctx->mStopVoicesOnDisconnect) + { + ProcessVoiceChanges(ctx); + continue; + } - auto voicelist = ctx->getVoicesSpanAcquired(); - auto stop_voice = [](Voice *voice) -> void - { - voice->mCurrentBuffer.store(nullptr, std::memory_order_relaxed); - voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed); - voice->mSourceID.store(0u, std::memory_order_relaxed); - voice->mPlayState.store(Voice::Stopped, std::memory_order_release); - }; - std::for_each(voicelist.begin(), voicelist.end(), stop_voice); + auto voicelist = ctx->getVoicesSpanAcquired(); + auto stop_voice = [](Voice *voice) -> void + { + voice->mCurrentBuffer.store(nullptr, std::memory_order_relaxed); + voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed); + voice->mSourceID.store(0u, std::memory_order_relaxed); + voice->mPlayState.store(Voice::Stopped, std::memory_order_release); + }; + std::for_each(voicelist.begin(), voicelist.end(), stop_voice); + } } IncrementRef(MixCount); } diff --git a/modules/openal-soft/Alc/backends/base.cpp b/modules/openal-soft/Alc/backends/base.cpp index cd1b76b..4abd7c0 100644 --- a/modules/openal-soft/Alc/backends/base.cpp +++ b/modules/openal-soft/Alc/backends/base.cpp @@ -98,6 +98,16 @@ void BackendBase::setDefaultWFXChannelOrder() mDevice->RealOut.ChannelIndex[SideLeft] = 6; mDevice->RealOut.ChannelIndex[SideRight] = 7; break; + case DevFmtX3D71: + mDevice->RealOut.ChannelIndex[FrontLeft] = 0; + mDevice->RealOut.ChannelIndex[FrontRight] = 1; + mDevice->RealOut.ChannelIndex[FrontCenter] = 2; + mDevice->RealOut.ChannelIndex[LFE] = 3; + mDevice->RealOut.ChannelIndex[Aux0] = 4; + mDevice->RealOut.ChannelIndex[Aux1] = 5; + mDevice->RealOut.ChannelIndex[SideLeft] = 6; + mDevice->RealOut.ChannelIndex[SideRight] = 7; + break; case DevFmtAmbi3D: break; } @@ -127,6 +137,16 @@ void BackendBase::setDefaultChannelOrder() mDevice->RealOut.ChannelIndex[SideLeft] = 6; mDevice->RealOut.ChannelIndex[SideRight] = 7; return; + case DevFmtX3D71: + mDevice->RealOut.ChannelIndex[FrontLeft] = 0; + mDevice->RealOut.ChannelIndex[FrontRight] = 1; + mDevice->RealOut.ChannelIndex[Aux0] = 2; + mDevice->RealOut.ChannelIndex[Aux1] = 3; + mDevice->RealOut.ChannelIndex[FrontCenter] = 4; + mDevice->RealOut.ChannelIndex[LFE] = 5; + mDevice->RealOut.ChannelIndex[SideLeft] = 6; + mDevice->RealOut.ChannelIndex[SideRight] = 7; + return; /* Same as WFX order */ case DevFmtMono: @@ -138,57 +158,3 @@ void BackendBase::setDefaultChannelOrder() break; } } - -#ifdef _WIN32 -void BackendBase::setChannelOrderFromWFXMask(uint chanmask) -{ - static constexpr uint x51{SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER - | SPEAKER_LOW_FREQUENCY | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT}; - static constexpr uint x51rear{SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER - | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT}; - /* Swap a 5.1 mask using the back channels for one with the sides. */ - if(chanmask == x51rear) chanmask = x51; - - auto get_channel = [](const DWORD chanbit) noexcept -> al::optional - { - switch(chanbit) - { - case SPEAKER_FRONT_LEFT: return al::make_optional(FrontLeft); - case SPEAKER_FRONT_RIGHT: return al::make_optional(FrontRight); - case SPEAKER_FRONT_CENTER: return al::make_optional(FrontCenter); - case SPEAKER_LOW_FREQUENCY: return al::make_optional(LFE); - case SPEAKER_BACK_LEFT: return al::make_optional(BackLeft); - case SPEAKER_BACK_RIGHT: return al::make_optional(BackRight); - case SPEAKER_FRONT_LEFT_OF_CENTER: break; - case SPEAKER_FRONT_RIGHT_OF_CENTER: break; - case SPEAKER_BACK_CENTER: return al::make_optional(BackCenter); - case SPEAKER_SIDE_LEFT: return al::make_optional(SideLeft); - case SPEAKER_SIDE_RIGHT: return al::make_optional(SideRight); - case SPEAKER_TOP_CENTER: return al::make_optional(TopCenter); - case SPEAKER_TOP_FRONT_LEFT: return al::make_optional(TopFrontLeft); - case SPEAKER_TOP_FRONT_CENTER: return al::make_optional(TopFrontCenter); - case SPEAKER_TOP_FRONT_RIGHT: return al::make_optional(TopFrontRight); - case SPEAKER_TOP_BACK_LEFT: return al::make_optional(TopBackLeft); - case SPEAKER_TOP_BACK_CENTER: return al::make_optional(TopBackCenter); - case SPEAKER_TOP_BACK_RIGHT: return al::make_optional(TopBackRight); - } - WARN("Unhandled WFX channel bit 0x%lx\n", chanbit); - return al::nullopt; - }; - - const uint numchans{mDevice->channelsFromFmt()}; - uint idx{0}; - while(chanmask) - { - const int bit{al::countr_zero(chanmask)}; - const uint mask{1u << bit}; - chanmask &= ~mask; - - if(auto label = get_channel(mask)) - { - mDevice->RealOut.ChannelIndex[*label] = idx; - if(++idx == numchans) break; - } - } -} -#endif diff --git a/modules/openal-soft/Alc/backends/base.h b/modules/openal-soft/Alc/backends/base.h index a3562f5..65bc636 100644 --- a/modules/openal-soft/Alc/backends/base.h +++ b/modules/openal-soft/Alc/backends/base.h @@ -41,11 +41,6 @@ protected: void setDefaultChannelOrder(); /** Sets the default channel order used by WaveFormatEx. */ void setDefaultWFXChannelOrder(); - -#ifdef _WIN32 - /** Sets the channel order given the WaveFormatEx mask. */ - void setChannelOrderFromWFXMask(uint chanmask); -#endif }; using BackendPtr = std::unique_ptr; diff --git a/modules/openal-soft/Alc/backends/coreaudio.cpp b/modules/openal-soft/Alc/backends/coreaudio.cpp index ed85e2a..f779f84 100644 --- a/modules/openal-soft/Alc/backends/coreaudio.cpp +++ b/modules/openal-soft/Alc/backends/coreaudio.cpp @@ -51,6 +51,8 @@ namespace { #define CAN_ENUMERATE 1 #endif +constexpr auto OutputElement = 0; +constexpr auto InputElement = 1; #if CAN_ENUMERATE struct DeviceEntry { @@ -354,7 +356,7 @@ void CoreAudioPlayback::open(const char *name) #if CAN_ENUMERATE if(audioDevice != kAudioDeviceUnknown) AudioUnitSetProperty(audioUnit, kAudioOutputUnitProperty_CurrentDevice, - kAudioUnitScope_Global, 0, &audioDevice, sizeof(AudioDeviceID)); + kAudioUnitScope_Global, OutputElement, &audioDevice, sizeof(AudioDeviceID)); #endif err = AudioUnitInitialize(audioUnit); @@ -380,7 +382,7 @@ void CoreAudioPlayback::open(const char *name) UInt32 propSize{sizeof(audioDevice)}; audioDevice = kAudioDeviceUnknown; AudioUnitGetProperty(audioUnit, kAudioOutputUnitProperty_CurrentDevice, - kAudioUnitScope_Global, 0, &audioDevice, &propSize); + kAudioUnitScope_Global, OutputElement, &audioDevice, &propSize); std::string devname{GetDeviceName(audioDevice)}; if(!devname.empty()) mDevice->DeviceName = std::move(devname); @@ -401,7 +403,7 @@ bool CoreAudioPlayback::reset() AudioStreamBasicDescription streamFormat{}; UInt32 size{sizeof(streamFormat)}; err = AudioUnitGetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, - 0, &streamFormat, &size); + OutputElement, &streamFormat, &size); if(err != noErr || size != sizeof(streamFormat)) { ERR("AudioUnitGetProperty failed\n"); @@ -423,8 +425,8 @@ bool CoreAudioPlayback::reset() */ if(mDevice->Frequency != streamFormat.mSampleRate) { - mDevice->BufferSize = static_cast(uint64_t{mDevice->BufferSize} * - streamFormat.mSampleRate / mDevice->Frequency); + mDevice->BufferSize = static_cast(mDevice->BufferSize*streamFormat.mSampleRate/ + mDevice->Frequency + 0.5); mDevice->Frequency = static_cast(streamFormat.mSampleRate); } @@ -468,7 +470,7 @@ bool CoreAudioPlayback::reset() streamFormat.mBytesPerPacket = streamFormat.mBytesPerFrame*streamFormat.mFramesPerPacket; err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, - 0, &streamFormat, sizeof(streamFormat)); + OutputElement, &streamFormat, sizeof(streamFormat)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); @@ -484,7 +486,7 @@ bool CoreAudioPlayback::reset() input.inputProcRefCon = this; err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_SetRenderCallback, - kAudioUnitScope_Input, 0, &input, sizeof(AURenderCallbackStruct)); + kAudioUnitScope_Input, OutputElement, &input, sizeof(AURenderCallbackStruct)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); @@ -658,16 +660,10 @@ void CoreAudioCapture::open(const char *name) throw al::backend_exception{al::backend_error::NoDevice, "Could not create component instance: %u", err}; -#if CAN_ENUMERATE - if(audioDevice != kAudioDeviceUnknown) - AudioUnitSetProperty(mAudioUnit, kAudioOutputUnitProperty_CurrentDevice, - kAudioUnitScope_Global, 0, &audioDevice, sizeof(AudioDeviceID)); -#endif - // Turn off AudioUnit output UInt32 enableIO{0}; err = AudioUnitSetProperty(mAudioUnit, kAudioOutputUnitProperty_EnableIO, - kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO)); + kAudioUnitScope_Output, OutputElement, &enableIO, sizeof(enableIO)); if(err != noErr) throw al::backend_exception{al::backend_error::DeviceError, "Could not disable audio unit output property: %u", err}; @@ -675,18 +671,24 @@ void CoreAudioCapture::open(const char *name) // Turn on AudioUnit input enableIO = 1; err = AudioUnitSetProperty(mAudioUnit, kAudioOutputUnitProperty_EnableIO, - kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO)); + kAudioUnitScope_Input, InputElement, &enableIO, sizeof(enableIO)); if(err != noErr) throw al::backend_exception{al::backend_error::DeviceError, "Could not enable audio unit input property: %u", err}; +#if CAN_ENUMERATE + if(audioDevice != kAudioDeviceUnknown) + AudioUnitSetProperty(mAudioUnit, kAudioOutputUnitProperty_CurrentDevice, + kAudioUnitScope_Global, InputElement, &audioDevice, sizeof(AudioDeviceID)); +#endif + // set capture callback AURenderCallbackStruct input{}; input.inputProc = CoreAudioCapture::RecordProcC; input.inputProcRefCon = this; err = AudioUnitSetProperty(mAudioUnit, kAudioOutputUnitProperty_SetInputCallback, - kAudioUnitScope_Global, 0, &input, sizeof(AURenderCallbackStruct)); + kAudioUnitScope_Global, InputElement, &input, sizeof(AURenderCallbackStruct)); if(err != noErr) throw al::backend_exception{al::backend_error::DeviceError, "Could not set capture callback: %u", err}; @@ -694,7 +696,7 @@ void CoreAudioCapture::open(const char *name) // Disable buffer allocation for capture UInt32 flag{0}; err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_ShouldAllocateBuffer, - kAudioUnitScope_Output, 1, &flag, sizeof(flag)); + kAudioUnitScope_Output, InputElement, &flag, sizeof(flag)); if(err != noErr) throw al::backend_exception{al::backend_error::DeviceError, "Could not disable buffer allocation property: %u", err}; @@ -709,7 +711,7 @@ void CoreAudioCapture::open(const char *name) AudioStreamBasicDescription hardwareFormat{}; UInt32 propertySize{sizeof(hardwareFormat)}; err = AudioUnitGetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, - 1, &hardwareFormat, &propertySize); + InputElement, &hardwareFormat, &propertySize); if(err != noErr || propertySize != sizeof(hardwareFormat)) throw al::backend_exception{al::backend_error::DeviceError, "Could not get input format: %u", err}; @@ -764,6 +766,7 @@ void CoreAudioCapture::open(const char *name) case DevFmtX51: case DevFmtX61: case DevFmtX71: + case DevFmtX3D71: case DevFmtAmbi3D: throw al::backend_exception{al::backend_error::DeviceError, "%s not supported", DevFmtChannelsString(mDevice->FmtChans)}; @@ -788,7 +791,7 @@ void CoreAudioCapture::open(const char *name) // The output format should be the requested format, but using the hardware sample rate // This is because the AudioUnit will automatically scale other properties, except for sample rate err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, - 1, &outputFormat, sizeof(outputFormat)); + InputElement, &outputFormat, sizeof(outputFormat)); if(err != noErr) throw al::backend_exception{al::backend_error::DeviceError, "Could not set input format: %u", err}; @@ -796,7 +799,7 @@ void CoreAudioCapture::open(const char *name) /* Calculate the minimum AudioUnit output format frame count for the pre- * conversion ring buffer. Ensure at least 100ms for the total buffer. */ - double srateScale{double{outputFormat.mSampleRate} / mDevice->Frequency}; + double srateScale{outputFormat.mSampleRate / mDevice->Frequency}; auto FrameCount64 = maxu64(static_cast(std::ceil(mDevice->BufferSize*srateScale)), static_cast(outputFormat.mSampleRate)/10); FrameCount64 += MaxResamplerPadding; @@ -807,7 +810,7 @@ void CoreAudioCapture::open(const char *name) UInt32 outputFrameCount{}; propertySize = sizeof(outputFrameCount); err = AudioUnitGetProperty(mAudioUnit, kAudioUnitProperty_MaximumFramesPerSlice, - kAudioUnitScope_Global, 0, &outputFrameCount, &propertySize); + kAudioUnitScope_Global, OutputElement, &outputFrameCount, &propertySize); if(err != noErr || propertySize != sizeof(outputFrameCount)) throw al::backend_exception{al::backend_error::DeviceError, "Could not get input frame count: %u", err}; @@ -829,7 +832,7 @@ void CoreAudioCapture::open(const char *name) UInt32 propSize{sizeof(audioDevice)}; audioDevice = kAudioDeviceUnknown; AudioUnitGetProperty(mAudioUnit, kAudioOutputUnitProperty_CurrentDevice, - kAudioUnitScope_Global, 0, &audioDevice, &propSize); + kAudioUnitScope_Global, InputElement, &audioDevice, &propSize); std::string devname{GetDeviceName(audioDevice)}; if(!devname.empty()) mDevice->DeviceName = std::move(devname); diff --git a/modules/openal-soft/Alc/backends/dsound.cpp b/modules/openal-soft/Alc/backends/dsound.cpp index 0edc286..3f2bf8d 100644 --- a/modules/openal-soft/Alc/backends/dsound.cpp +++ b/modules/openal-soft/Alc/backends/dsound.cpp @@ -389,52 +389,55 @@ bool DSoundPlayback::reset() } WAVEFORMATEXTENSIBLE OutputType{}; - DWORD speakers; + DWORD speakers{}; HRESULT hr{mDS->GetSpeakerConfig(&speakers)}; - if(SUCCEEDED(hr)) + if(FAILED(hr)) + throw al::backend_exception{al::backend_error::DeviceError, + "Failed to get speaker config: 0x%08lx", hr}; + + speakers = DSSPEAKER_CONFIG(speakers); + if(!mDevice->Flags.test(ChannelsRequest)) { - speakers = DSSPEAKER_CONFIG(speakers); - if(!mDevice->Flags.test(ChannelsRequest)) - { - if(speakers == DSSPEAKER_MONO) - mDevice->FmtChans = DevFmtMono; - else if(speakers == DSSPEAKER_STEREO || speakers == DSSPEAKER_HEADPHONE) - mDevice->FmtChans = DevFmtStereo; - else if(speakers == DSSPEAKER_QUAD) - mDevice->FmtChans = DevFmtQuad; - else if(speakers == DSSPEAKER_5POINT1_SURROUND || speakers == DSSPEAKER_5POINT1_BACK) - mDevice->FmtChans = DevFmtX51; - else if(speakers == DSSPEAKER_7POINT1 || speakers == DSSPEAKER_7POINT1_SURROUND) - mDevice->FmtChans = DevFmtX71; - else - ERR("Unknown system speaker config: 0x%lx\n", speakers); - } - mDevice->Flags.set(DirectEar, (speakers == DSSPEAKER_HEADPHONE)); + if(speakers == DSSPEAKER_MONO) + mDevice->FmtChans = DevFmtMono; + else if(speakers == DSSPEAKER_STEREO || speakers == DSSPEAKER_HEADPHONE) + mDevice->FmtChans = DevFmtStereo; + else if(speakers == DSSPEAKER_QUAD) + mDevice->FmtChans = DevFmtQuad; + else if(speakers == DSSPEAKER_5POINT1_SURROUND || speakers == DSSPEAKER_5POINT1_BACK) + mDevice->FmtChans = DevFmtX51; + else if(speakers == DSSPEAKER_7POINT1 || speakers == DSSPEAKER_7POINT1_SURROUND) + mDevice->FmtChans = DevFmtX71; + else + ERR("Unknown system speaker config: 0x%lx\n", speakers); + } + mDevice->Flags.set(DirectEar, (speakers == DSSPEAKER_HEADPHONE)); + const bool isRear51{speakers == DSSPEAKER_5POINT1_BACK}; - switch(mDevice->FmtChans) - { - case DevFmtMono: OutputType.dwChannelMask = MONO; break; - case DevFmtAmbi3D: mDevice->FmtChans = DevFmtStereo; - /*fall-through*/ - case DevFmtStereo: OutputType.dwChannelMask = STEREO; break; - case DevFmtQuad: OutputType.dwChannelMask = QUAD; break; - case DevFmtX51: OutputType.dwChannelMask = X5DOT1; break; - case DevFmtX61: OutputType.dwChannelMask = X6DOT1; break; - case DevFmtX71: OutputType.dwChannelMask = X7DOT1; break; - } + switch(mDevice->FmtChans) + { + case DevFmtMono: OutputType.dwChannelMask = MONO; break; + case DevFmtAmbi3D: mDevice->FmtChans = DevFmtStereo; + /* fall-through */ + case DevFmtStereo: OutputType.dwChannelMask = STEREO; break; + case DevFmtQuad: OutputType.dwChannelMask = QUAD; break; + case DevFmtX51: OutputType.dwChannelMask = isRear51 ? X5DOT1REAR : X5DOT1; break; + case DevFmtX61: OutputType.dwChannelMask = X6DOT1; break; + case DevFmtX71: OutputType.dwChannelMask = X7DOT1; break; + case DevFmtX3D71: OutputType.dwChannelMask = X7DOT1; break; + } retry_open: - hr = S_OK; - OutputType.Format.wFormatTag = WAVE_FORMAT_PCM; - OutputType.Format.nChannels = static_cast(mDevice->channelsFromFmt()); - OutputType.Format.wBitsPerSample = static_cast(mDevice->bytesFromFmt() * 8); - OutputType.Format.nBlockAlign = static_cast(OutputType.Format.nChannels * - OutputType.Format.wBitsPerSample / 8); - OutputType.Format.nSamplesPerSec = mDevice->Frequency; - OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec * - OutputType.Format.nBlockAlign; - OutputType.Format.cbSize = 0; - } + hr = S_OK; + OutputType.Format.wFormatTag = WAVE_FORMAT_PCM; + OutputType.Format.nChannels = static_cast(mDevice->channelsFromFmt()); + OutputType.Format.wBitsPerSample = static_cast(mDevice->bytesFromFmt() * 8); + OutputType.Format.nBlockAlign = static_cast(OutputType.Format.nChannels * + OutputType.Format.wBitsPerSample / 8); + OutputType.Format.nSamplesPerSec = mDevice->Frequency; + OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec * + OutputType.Format.nBlockAlign; + OutputType.Format.cbSize = 0; if(OutputType.Format.nChannels > 2 || mDevice->FmtType == DevFmtFloat) { @@ -514,7 +517,7 @@ retry_open: } ResetEvent(mNotifyEvent); - setChannelOrderFromWFXMask(OutputType.dwChannelMask); + setDefaultWFXChannelOrder(); return true; } @@ -635,6 +638,7 @@ void DSoundCapture::open(const char *name) case DevFmtX51: InputType.dwChannelMask = X5DOT1; break; case DevFmtX61: InputType.dwChannelMask = X6DOT1; break; case DevFmtX71: InputType.dwChannelMask = X7DOT1; break; + case DevFmtX3D71: case DevFmtAmbi3D: WARN("%s capture not supported\n", DevFmtChannelsString(mDevice->FmtChans)); throw al::backend_exception{al::backend_error::DeviceError, "%s capture not supported", @@ -689,7 +693,7 @@ void DSoundCapture::open(const char *name) } mBufferBytes = DSCBDescription.dwBufferBytes; - setChannelOrderFromWFXMask(InputType.dwChannelMask); + setDefaultWFXChannelOrder(); mDevice->DeviceName = name; } diff --git a/modules/openal-soft/Alc/backends/oboe.cpp b/modules/openal-soft/Alc/backends/oboe.cpp index 38f048c..7b1dc96 100644 --- a/modules/openal-soft/Alc/backends/oboe.cpp +++ b/modules/openal-soft/Alc/backends/oboe.cpp @@ -10,6 +10,7 @@ #include "alnumeric.h" #include "core/device.h" #include "core/logging.h" +#include "ringbuffer.h" #include "oboe/Oboe.h" @@ -188,13 +189,15 @@ void OboePlayback::stop() } -struct OboeCapture final : public BackendBase { +struct OboeCapture final : public BackendBase, public oboe::AudioStreamCallback { OboeCapture(DeviceBase *device) : BackendBase{device} { } oboe::ManagedStream mStream; - std::vector mSamples; - uint mLastAvail{0u}; + RingBufferPtr mRing{nullptr}; + + oboe::DataCallbackResult onAudioReady(oboe::AudioStream *oboeStream, void *audioData, + int32_t numFrames) override; void open(const char *name) override; void start() override; @@ -203,6 +206,14 @@ struct OboeCapture final : public BackendBase { uint availableSamples() override; }; +oboe::DataCallbackResult OboeCapture::onAudioReady(oboe::AudioStream*, void *audioData, + int32_t numFrames) +{ + mRing->write(audioData, static_cast(numFrames)); + return oboe::DataCallbackResult::Continue; +} + + void OboeCapture::open(const char *name) { if(!name) @@ -217,8 +228,8 @@ void OboeCapture::open(const char *name) ->setSampleRateConversionQuality(oboe::SampleRateConversionQuality::High) ->setChannelConversionAllowed(true) ->setFormatConversionAllowed(true) - ->setBufferCapacityInFrames(static_cast(mDevice->BufferSize)) - ->setSampleRate(static_cast(mDevice->Frequency)); + ->setSampleRate(static_cast(mDevice->Frequency)) + ->setCallback(this); /* Only use mono or stereo at user request. There's no telling what * other counts may be inferred as. */ @@ -234,13 +245,14 @@ void OboeCapture::open(const char *name) case DevFmtX51: case DevFmtX61: case DevFmtX71: + case DevFmtX3D71: case DevFmtAmbi3D: throw al::backend_exception{al::backend_error::DeviceError, "%s capture not supported", DevFmtChannelsString(mDevice->FmtChans)}; } /* FIXME: This really should support UByte, but Oboe doesn't. We'll need to - * use a temp buffer and convert. + * convert. */ switch(mDevice->FmtType) { @@ -263,22 +275,13 @@ void OboeCapture::open(const char *name) if(result != oboe::Result::OK) throw al::backend_exception{al::backend_error::DeviceError, "Failed to create stream: %s", oboe::convertToText(result)}; - if(static_cast(mDevice->BufferSize) > mStream->getBufferCapacityInFrames()) - throw al::backend_exception{al::backend_error::DeviceError, - "Buffer size too large (%u > %d)", mDevice->BufferSize, - mStream->getBufferCapacityInFrames()}; - auto buffer_result = mStream->setBufferSizeInFrames(static_cast(mDevice->BufferSize)); - if(!buffer_result) - throw al::backend_exception{al::backend_error::DeviceError, - "Failed to set buffer size: %s", oboe::convertToText(buffer_result.error())}; - else if(buffer_result.value() < static_cast(mDevice->BufferSize)) - throw al::backend_exception{al::backend_error::DeviceError, - "Failed to set large enough buffer size (%u > %d)", mDevice->BufferSize, - buffer_result.value()}; - mDevice->BufferSize = static_cast(buffer_result.value()); TRACE("Got stream with properties:\n%s", oboe::convertToText(mStream.get())); + /* Ensure a minimum ringbuffer size of 100ms. */ + mRing = RingBuffer::Create(maxu(mDevice->BufferSize, mDevice->Frequency/10), + static_cast(mStream->getBytesPerFrame()), false); + mDevice->DeviceName = name; } @@ -292,23 +295,6 @@ void OboeCapture::start() void OboeCapture::stop() { - /* Capture any unread samples before stopping. Oboe drops whatever's left - * in the stream. - */ - if(auto availres = mStream->getAvailableFrames()) - { - const auto avail = std::max(static_cast(availres.value()), mLastAvail); - const size_t frame_size{static_cast(mStream->getBytesPerFrame())}; - const size_t pos{mSamples.size()}; - mSamples.resize(pos + avail*frame_size); - - auto result = mStream->read(&mSamples[pos], availres.value(), 0); - uint got{bool{result} ? static_cast(result.value()) : 0u}; - if(got < avail) - std::fill_n(&mSamples[pos + got*frame_size], (avail-got)*frame_size, al::byte{}); - mLastAvail = 0; - } - const oboe::Result result{mStream->stop()}; if(result != oboe::Result::OK) throw al::backend_exception{al::backend_error::DeviceError, "Failed to stop stream: %s", @@ -316,38 +302,10 @@ void OboeCapture::stop() } uint OboeCapture::availableSamples() -{ - /* Keep track of the max available frame count, to ensure it doesn't go - * backwards. - */ - if(auto result = mStream->getAvailableFrames()) - mLastAvail = std::max(static_cast(result.value()), mLastAvail); - - const auto frame_size = static_cast(mStream->getBytesPerFrame()); - return static_cast(mSamples.size()/frame_size) + mLastAvail; -} +{ return static_cast(mRing->readSpace()); } void OboeCapture::captureSamples(al::byte *buffer, uint samples) -{ - const auto frame_size = static_cast(mStream->getBytesPerFrame()); - if(const size_t storelen{mSamples.size()}) - { - const auto instore = static_cast(storelen / frame_size); - const uint tocopy{std::min(samples, instore) * frame_size}; - std::copy_n(mSamples.begin(), tocopy, buffer); - mSamples.erase(mSamples.begin(), mSamples.begin() + tocopy); - - buffer += tocopy; - samples -= tocopy/frame_size; - if(!samples) return; - } - - auto result = mStream->read(buffer, static_cast(samples), 0); - uint got{bool{result} ? static_cast(result.value()) : 0u}; - if(got < samples) - std::fill_n(buffer + got*frame_size, (samples-got)*frame_size, al::byte{}); - mLastAvail = std::max(mLastAvail, samples) - samples; -} +{ mRing->read(buffer, samples); } } // namespace diff --git a/modules/openal-soft/Alc/backends/opensl.cpp b/modules/openal-soft/Alc/backends/opensl.cpp index 85a5f48..49e5c26 100644 --- a/modules/openal-soft/Alc/backends/opensl.cpp +++ b/modules/openal-soft/Alc/backends/opensl.cpp @@ -71,7 +71,8 @@ constexpr SLuint32 GetChannelMask(DevFmtChannels chans) noexcept case DevFmtX61: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY | SL_SPEAKER_BACK_CENTER | SL_SPEAKER_SIDE_LEFT | SL_SPEAKER_SIDE_RIGHT; - case DevFmtX71: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | + case DevFmtX71: + case DevFmtX3D71: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY | SL_SPEAKER_BACK_LEFT | SL_SPEAKER_BACK_RIGHT | SL_SPEAKER_SIDE_LEFT | SL_SPEAKER_SIDE_RIGHT; case DevFmtAmbi3D: @@ -612,6 +613,8 @@ void OpenSLPlayback::stop() result = VCALL(bufferQueue,GetState)(&state); } while(SL_RESULT_SUCCESS == result && state.count > 0); PRINTERR(result, "bufferQueue->GetState"); + + mRing.reset(); } } @@ -878,7 +881,6 @@ void OpenSLCapture::captureSamples(al::byte *buffer, uint samples) { const uint update_size{mDevice->UpdateSize}; const uint chunk_size{update_size * mFrameSize}; - const auto silence = (mDevice->FmtType == DevFmtUByte) ? al::byte{0x80} : al::byte{0}; /* Read the desired samples from the ring buffer then advance its read * pointer. @@ -907,39 +909,52 @@ void OpenSLCapture::captureSamples(al::byte *buffer, uint samples) i += rem; } - mRing->readAdvance(adv_count); SLAndroidSimpleBufferQueueItf bufferQueue{}; - if LIKELY(mDevice->Connected.load(std::memory_order_acquire)) + if(likely(mDevice->Connected.load(std::memory_order_acquire))) { const SLresult result{VCALL(mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bufferQueue)}; PRINTERR(result, "recordObj->GetInterface"); - if UNLIKELY(SL_RESULT_SUCCESS != result) + if(unlikely(SL_RESULT_SUCCESS != result)) { mDevice->handleDisconnect("Failed to get capture buffer queue: 0x%08x", result); bufferQueue = nullptr; } } + if(unlikely(!bufferQueue) || adv_count == 0) + return; + + /* For each buffer chunk that was fully read, queue another writable buffer + * chunk to keep the OpenSL queue full. This is rather convulated, as a + * result of the ring buffer holding more elements than are writable at a + * given time. The end of the write vector increments when the read pointer + * advances, which will "expose" a previously unwritable element. So for + * every element that we've finished reading, we queue that many elements + * from the end of the write vector. + */ + mRing->readAdvance(adv_count); - if LIKELY(bufferQueue) + SLresult result{SL_RESULT_SUCCESS}; + auto wdata = mRing->getWriteVector(); + if(likely(adv_count > wdata.second.len)) { - SLresult result{SL_RESULT_SUCCESS}; - auto wdata = mRing->getWriteVector(); - std::fill_n(wdata.first.buf, wdata.first.len*chunk_size, silence); - for(size_t i{0u};i < wdata.first.len && SL_RESULT_SUCCESS == result;i++) + auto len1 = std::min(wdata.first.len, adv_count-wdata.second.len); + auto buf1 = wdata.first.buf + chunk_size*(wdata.first.len-len1); + for(size_t i{0u};i < len1 && SL_RESULT_SUCCESS == result;i++) { - result = VCALL(bufferQueue,Enqueue)(wdata.first.buf + chunk_size*i, chunk_size); + result = VCALL(bufferQueue,Enqueue)(buf1 + chunk_size*i, chunk_size); PRINTERR(result, "bufferQueue->Enqueue"); } - if(wdata.second.len > 0) + } + if(wdata.second.len > 0) + { + auto len2 = std::min(wdata.second.len, adv_count); + auto buf2 = wdata.second.buf + chunk_size*(wdata.second.len-len2); + for(size_t i{0u};i < len2 && SL_RESULT_SUCCESS == result;i++) { - std::fill_n(wdata.second.buf, wdata.second.len*chunk_size, silence); - for(size_t i{0u};i < wdata.second.len && SL_RESULT_SUCCESS == result;i++) - { - result = VCALL(bufferQueue,Enqueue)(wdata.second.buf + chunk_size*i, chunk_size); - PRINTERR(result, "bufferQueue->Enqueue"); - } + result = VCALL(bufferQueue,Enqueue)(buf2 + chunk_size*i, chunk_size); + PRINTERR(result, "bufferQueue->Enqueue"); } } } diff --git a/modules/openal-soft/Alc/backends/pipewire.cpp b/modules/openal-soft/Alc/backends/pipewire.cpp index a19dcb6..0048e1e 100644 --- a/modules/openal-soft/Alc/backends/pipewire.cpp +++ b/modules/openal-soft/Alc/backends/pipewire.cpp @@ -50,8 +50,20 @@ #include "opthelpers.h" #include "ringbuffer.h" -/* Ignore warnings caused by PipeWire headers (lots in standard C++ mode). */ +/* Ignore warnings caused by PipeWire headers (lots in standard C++ mode). GCC + * doesn't support ignoring -Weverything, so we have the list the individual + * warnings to ignore (and ignoring -Winline doesn't seem to work). + */ _Pragma("GCC diagnostic push") +_Pragma("GCC diagnostic ignored \"-Wpedantic\"") +_Pragma("GCC diagnostic ignored \"-Wconversion\"") +_Pragma("GCC diagnostic ignored \"-Wfloat-conversion\"") +_Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"") +_Pragma("GCC diagnostic ignored \"-Wunused-parameter\"") +_Pragma("GCC diagnostic ignored \"-Wold-style-cast\"") +_Pragma("GCC diagnostic ignored \"-Wsign-compare\"") +_Pragma("GCC diagnostic ignored \"-Winline\"") +_Pragma("GCC diagnostic ignored \"-Wpragmas\"") _Pragma("GCC diagnostic ignored \"-Weverything\"") #include "pipewire/pipewire.h" #include "pipewire/extensions/metadata.h" @@ -107,6 +119,11 @@ _Pragma("GCC diagnostic pop") namespace { +/* Added in 0.3.33, but we currently only require 0.3.23. */ +#ifndef PW_KEY_NODE_RATE +#define PW_KEY_NODE_RATE "node.rate" +#endif + using std::chrono::seconds; using std::chrono::nanoseconds; using uint = unsigned int; @@ -115,12 +132,27 @@ constexpr char pwireDevice[] = "PipeWire Output"; constexpr char pwireInput[] = "PipeWire Input"; +bool check_version(const char *version) +{ + /* There doesn't seem to be a function to get the version as an integer, so + * instead we have to parse the string, which hopefully won't break in the + * future. + */ + int major{0}, minor{0}, revision{0}; + int ret{sscanf(version, "%d.%d.%d", &major, &minor, &revision)}; + if(ret == 3 && (major > PW_MAJOR || (major == PW_MAJOR && minor > PW_MINOR) + || (major == PW_MAJOR && minor == PW_MINOR && revision >= PW_MICRO))) + return true; + return false; +} + #ifdef HAVE_DYNLOAD #define PWIRE_FUNCS(MAGIC) \ MAGIC(pw_context_connect) \ MAGIC(pw_context_destroy) \ MAGIC(pw_context_new) \ MAGIC(pw_core_disconnect) \ + MAGIC(pw_get_library_version) \ MAGIC(pw_init) \ MAGIC(pw_properties_free) \ MAGIC(pw_properties_new) \ @@ -134,7 +166,6 @@ constexpr char pwireInput[] = "PipeWire Input"; MAGIC(pw_stream_dequeue_buffer) \ MAGIC(pw_stream_destroy) \ MAGIC(pw_stream_get_state) \ - MAGIC(pw_stream_get_time) \ MAGIC(pw_stream_new) \ MAGIC(pw_stream_queue_buffer) \ MAGIC(pw_stream_set_active) \ @@ -146,11 +177,19 @@ constexpr char pwireInput[] = "PipeWire Input"; MAGIC(pw_thread_loop_lock) \ MAGIC(pw_thread_loop_wait) \ MAGIC(pw_thread_loop_signal) \ - MAGIC(pw_thread_loop_unlock) \ + MAGIC(pw_thread_loop_unlock) +#if PW_CHECK_VERSION(0,3,50) +#define PWIRE_FUNCS2(MAGIC) \ + MAGIC(pw_stream_get_time_n) +#else +#define PWIRE_FUNCS2(MAGIC) \ + MAGIC(pw_stream_get_time) +#endif void *pwire_handle; #define MAKE_FUNC(f) decltype(f) * p##f; PWIRE_FUNCS(MAKE_FUNC) +PWIRE_FUNCS2(MAKE_FUNC) #undef MAKE_FUNC bool pwire_load() @@ -173,6 +212,7 @@ bool pwire_load() if(p##f == nullptr) missing_funcs += "\n" #f; \ } while(0); PWIRE_FUNCS(LOAD_FUNC) + PWIRE_FUNCS2(LOAD_FUNC) #undef LOAD_FUNC if(!missing_funcs.empty()) @@ -191,6 +231,7 @@ bool pwire_load() #define pw_context_destroy ppw_context_destroy #define pw_context_new ppw_context_new #define pw_core_disconnect ppw_core_disconnect +#define pw_get_library_version ppw_get_library_version #define pw_init ppw_init #define pw_properties_free ppw_properties_free #define pw_properties_new ppw_properties_new @@ -204,7 +245,6 @@ bool pwire_load() #define pw_stream_dequeue_buffer ppw_stream_dequeue_buffer #define pw_stream_destroy ppw_stream_destroy #define pw_stream_get_state ppw_stream_get_state -#define pw_stream_get_time ppw_stream_get_time #define pw_stream_new ppw_stream_new #define pw_stream_queue_buffer ppw_stream_queue_buffer #define pw_stream_set_active ppw_stream_set_active @@ -217,6 +257,12 @@ bool pwire_load() #define pw_thread_loop_stop ppw_thread_loop_stop #define pw_thread_loop_unlock ppw_thread_loop_unlock #define pw_thread_loop_wait ppw_thread_loop_wait +#if PW_CHECK_VERSION(0,3,50) +#define pw_stream_get_time_n ppw_stream_get_time_n +#else +inline auto pw_stream_get_time_n(pw_stream *stream, pw_time *ptime, size_t /*size*/) +{ return ppw_stream_get_time(stream, ptime); } +#endif #endif #else @@ -1181,6 +1227,7 @@ spa_audio_info_raw make_spa_info(DeviceBase *device, bool is51rear, use_f32p_e u break; case DevFmtX61: map = X61Map; break; case DevFmtX71: map = X71Map; break; + case DevFmtX3D71: map = X71Map; break; case DevFmtAmbi3D: info.flags |= SPA_AUDIO_FLAG_UNPOSITIONED; info.channels = device->channelsFromFmt(); @@ -1267,32 +1314,42 @@ void PipeWirePlayback::outputCallback() pw_buffer *pw_buf{pw_stream_dequeue_buffer(mStream.get())}; if(unlikely(!pw_buf)) return; + const al::span datas{pw_buf->buffer->datas, + minu(mNumChannels, pw_buf->buffer->n_datas)}; +#if PW_CHECK_VERSION(0,3,49) + /* In 0.3.49, pw_buffer::requested specifies the number of samples needed + * by the resampler/graph for this audio update. + */ + uint length{static_cast(pw_buf->requested)}; +#else + /* In 0.3.48 and earlier, spa_io_rate_match::size apparently has the number + * of samples per update. + */ + uint length{mRateMatch ? mRateMatch->size : 0u}; +#endif + /* If no length is specified, use the device's update size as a fallback. */ + if(unlikely(!length)) length = mDevice->UpdateSize; + /* For planar formats, each datas[] seems to contain one channel, so store * the pointers in an array. Limit the render length in case the available * buffer length in any one channel is smaller than we wanted (shouldn't * be, but just in case). */ - spa_data *datas{pw_buf->buffer->datas}; - const size_t chancount{minu(mNumChannels, pw_buf->buffer->n_datas)}; - /* TODO: How many samples should actually be written? 'maxsize' can be 16k - * samples, which is excessive (~341ms @ 48khz). SPA_IO_RateMatch contains - * a 'size' field that apparently indicates how many samples should be - * written per update, but it's not obviously right. - */ - uint length{mRateMatch ? mRateMatch->size : mDevice->UpdateSize}; - for(size_t i{0};i < chancount;++i) + float **chanptr_end{mChannelPtrs.get()}; + for(const auto &data : datas) { - length = minu(length, datas[i].maxsize/sizeof(float)); - mChannelPtrs[i] = static_cast(datas[i].data); + length = minu(length, data.maxsize/sizeof(float)); + *chanptr_end = static_cast(data.data); + ++chanptr_end; } - mDevice->renderSamples({mChannelPtrs.get(), chancount}, length); + mDevice->renderSamples({mChannelPtrs.get(), chanptr_end}, length); - for(size_t i{0};i < chancount;++i) + for(const auto &data : datas) { - datas[i].chunk->offset = 0; - datas[i].chunk->stride = sizeof(float); - datas[i].chunk->size = length * sizeof(float); + data.chunk->offset = 0; + data.chunk->stride = sizeof(float); + data.chunk->size = length * sizeof(float); } pw_buf->size = length; pw_stream_queue_buffer(mStream.get(), pw_buf); @@ -1482,11 +1539,10 @@ bool PipeWirePlayback::reset() "Error connecting PipeWire stream (res: %d)", res}; /* Wait for the stream to become paused (ready to start streaming). */ - pw_stream_state state{}; - const char *error{}; - plock.wait([stream=mStream.get(),&state,&error]() + plock.wait([stream=mStream.get()]() { - state = pw_stream_get_state(stream, &error); + const char *error{}; + pw_stream_state state{pw_stream_get_state(stream, &error)}; if(state == PW_STREAM_STATE_ERROR) throw al::backend_exception{al::backend_error::DeviceError, "Error connecting PipeWire stream: \"%s\"", error}; @@ -1517,18 +1573,17 @@ void PipeWirePlayback::start() /* Wait for the stream to start playing (would be nice to not, but we need * the actual update size which is only available after starting). */ - pw_stream_state state{}; - const char *error{}; - plock.wait([stream=mStream.get(),&state,&error]() + plock.wait([stream=mStream.get()]() { - state = pw_stream_get_state(stream, &error); - return state != PW_STREAM_STATE_PAUSED; + const char *error{}; + pw_stream_state state{pw_stream_get_state(stream, &error)}; + if(state == PW_STREAM_STATE_ERROR) + throw al::backend_exception{al::backend_error::DeviceError, + "PipeWire stream error: %s", error ? error : "(unknown)"}; + return state == PW_STREAM_STATE_STREAMING; }); - if(state == PW_STREAM_STATE_ERROR) - throw al::backend_exception{al::backend_error::DeviceError, - "PipeWire stream error: %s", error ? error : "(unknown)"}; - if(state == PW_STREAM_STATE_STREAMING && mRateMatch && mRateMatch->size) + if(mRateMatch && mRateMatch->size) { mDevice->UpdateSize = mRateMatch->size; mDevice->BufferSize = mDevice->UpdateSize * 2; @@ -1560,7 +1615,7 @@ ClockLatency PipeWirePlayback::getClockLatency() if(mStream) { MainloopLockGuard _{mLoop}; - if(int res{pw_stream_get_time(mStream.get(), &ptime)}) + if(int res{pw_stream_get_time_n(mStream.get(), &ptime, sizeof(ptime))}) ERR("Failed to get PipeWire stream time (res: %d)\n", res); } @@ -1851,11 +1906,10 @@ void PipeWireCapture::open(const char *name) "Error connecting PipeWire stream (res: %d)", res}; /* Wait for the stream to become paused (ready to start streaming). */ - pw_stream_state state{}; - const char *error{}; - plock.wait([stream=mStream.get(),&state,&error]() + plock.wait([stream=mStream.get()]() { - state = pw_stream_get_state(stream, &error); + const char *error{}; + pw_stream_state state{pw_stream_get_state(stream, &error)}; if(state == PW_STREAM_STATE_ERROR) throw al::backend_exception{al::backend_error::DeviceError, "Error connecting PipeWire stream: \"%s\"", error}; @@ -1878,17 +1932,15 @@ void PipeWireCapture::start() throw al::backend_exception{al::backend_error::DeviceError, "Failed to start PipeWire stream (res: %d)", res}; - pw_stream_state state{}; - const char *error{}; - plock.wait([stream=mStream.get(),&state,&error]() + plock.wait([stream=mStream.get()]() { - state = pw_stream_get_state(stream, &error); - return state != PW_STREAM_STATE_PAUSED; + const char *error{}; + pw_stream_state state{pw_stream_get_state(stream, &error)}; + if(state == PW_STREAM_STATE_ERROR) + throw al::backend_exception{al::backend_error::DeviceError, + "PipeWire stream error: %s", error ? error : "(unknown)"}; + return state == PW_STREAM_STATE_STREAMING; }); - - if(state == PW_STREAM_STATE_ERROR) - throw al::backend_exception{al::backend_error::DeviceError, - "PipeWire stream error: %s", error ? error : "(unknown)"}; } void PipeWireCapture::stop() @@ -1916,6 +1968,15 @@ bool PipeWireBackendFactory::init() if(!pwire_load()) return false; + const char *version{pw_get_library_version()}; + if(!check_version(version)) + { + WARN("PipeWire version \"%s\" too old (%s or newer required)\n", version, + pw_get_headers_version()); + return false; + } + TRACE("Found PipeWire version \"%s\" (%s or newer)\n", version, pw_get_headers_version()); + pw_init(0, nullptr); if(!gEventHandler.init()) return false; diff --git a/modules/openal-soft/Alc/backends/pulseaudio.cpp b/modules/openal-soft/Alc/backends/pulseaudio.cpp index 67e0023..30f486c 100644 --- a/modules/openal-soft/Alc/backends/pulseaudio.cpp +++ b/modules/openal-soft/Alc/backends/pulseaudio.cpp @@ -893,6 +893,7 @@ bool PulsePlayback::reset() chanmap = X61ChanMap; break; case DevFmtX71: + case DevFmtX3D71: chanmap = X71ChanMap; break; } @@ -1173,6 +1174,7 @@ void PulseCapture::open(const char *name) case DevFmtX71: chanmap = X71ChanMap; break; + case DevFmtX3D71: case DevFmtAmbi3D: throw al::backend_exception{al::backend_error::DeviceError, "%s capture not supported", DevFmtChannelsString(mDevice->FmtChans)}; diff --git a/modules/openal-soft/Alc/backends/sdl2.cpp b/modules/openal-soft/Alc/backends/sdl2.cpp index c072603..a4a5a9a 100644 --- a/modules/openal-soft/Alc/backends/sdl2.cpp +++ b/modules/openal-soft/Alc/backends/sdl2.cpp @@ -32,7 +32,10 @@ #include "core/device.h" #include "core/logging.h" -#include +_Pragma("GCC diagnostic push") +_Pragma("GCC diagnostic ignored \"-Wold-style-cast\"") +#include "SDL.h" +_Pragma("GCC diagnostic pop") namespace { diff --git a/modules/openal-soft/Alc/backends/wasapi.cpp b/modules/openal-soft/Alc/backends/wasapi.cpp index 063fca9..9007da1 100644 --- a/modules/openal-soft/Alc/backends/wasapi.cpp +++ b/modules/openal-soft/Alc/backends/wasapi.cpp @@ -863,6 +863,7 @@ HRESULT WasapiPlayback::resetProxy() ERR("Failed to get mix format: 0x%08lx\n", hr); return hr; } + TraceFormat("Device mix format", wfx); WAVEFORMATEXTENSIBLE OutputType; if(!MakeExtensible(&OutputType, wfx)) @@ -875,29 +876,44 @@ HRESULT WasapiPlayback::resetProxy() const ReferenceTime per_time{ReferenceTime{seconds{mDevice->UpdateSize}} / mDevice->Frequency}; const ReferenceTime buf_time{ReferenceTime{seconds{mDevice->BufferSize}} / mDevice->Frequency}; + bool isRear51{false}; if(!mDevice->Flags.test(FrequencyRequest)) mDevice->Frequency = OutputType.Format.nSamplesPerSec; if(!mDevice->Flags.test(ChannelsRequest)) { + /* If not requesting a channel configuration, auto-select given what + * fits the mask's lsb (to ensure no gaps in the output channels). If + * there's no mask, we can only assume mono or stereo. + */ const uint32_t chancount{OutputType.Format.nChannels}; const DWORD chanmask{OutputType.dwChannelMask}; if(chancount >= 8 && (chanmask&X71Mask) == X7DOT1) mDevice->FmtChans = DevFmtX71; else if(chancount >= 7 && (chanmask&X61Mask) == X6DOT1) mDevice->FmtChans = DevFmtX61; - else if(chancount >= 6 && ((chanmask&X51Mask) == X5DOT1 - || (chanmask&X51RearMask) == X5DOT1REAR)) + else if(chancount >= 6 && (chanmask&X51Mask) == X5DOT1) + mDevice->FmtChans = DevFmtX51; + else if(chancount >= 6 && (chanmask&X51RearMask) == X5DOT1REAR) + { mDevice->FmtChans = DevFmtX51; + isRear51 = true; + } else if(chancount >= 4 && (chanmask&QuadMask) == QUAD) mDevice->FmtChans = DevFmtQuad; - else if(chancount >= 2 && (chanmask&StereoMask) == STEREO) + else if(chancount >= 2 && ((chanmask&StereoMask) == STEREO || !chanmask)) mDevice->FmtChans = DevFmtStereo; - else if(chancount >= 1 && (chanmask&MonoMask) == MONO) + else if(chancount >= 1 && ((chanmask&MonoMask) == MONO || !chanmask)) mDevice->FmtChans = DevFmtMono; else ERR("Unhandled channel config: %d -- 0x%08lx\n", chancount, chanmask); } + else + { + const uint32_t chancount{OutputType.Format.nChannels}; + const DWORD chanmask{OutputType.dwChannelMask}; + isRear51 = (chancount == 6 && (chanmask&X51RearMask) == X5DOT1REAR); + } OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; switch(mDevice->FmtChans) @@ -919,13 +935,14 @@ HRESULT WasapiPlayback::resetProxy() break; case DevFmtX51: OutputType.Format.nChannels = 6; - OutputType.dwChannelMask = X5DOT1; + OutputType.dwChannelMask = isRear51 ? X5DOT1REAR : X5DOT1; break; case DevFmtX61: OutputType.Format.nChannels = 7; OutputType.dwChannelMask = X6DOT1; break; case DevFmtX71: + case DevFmtX3D71: OutputType.Format.nChannels = 8; OutputType.dwChannelMask = X7DOT1; break; @@ -1002,26 +1019,31 @@ HRESULT WasapiPlayback::resetProxy() bool chansok{false}; if(mDevice->Flags.test(ChannelsRequest)) { + /* When requesting a channel configuration, make sure it fits the + * mask's lsb (to ensure no gaps in the output channels). If + * there's no mask, assume the request fits with enough channels. + */ switch(mDevice->FmtChans) { case DevFmtMono: - chansok = (chancount >= 1 && (chanmask&MonoMask) == MONO); + chansok = (chancount >= 1 && ((chanmask&MonoMask) == MONO || !chanmask)); break; case DevFmtStereo: - chansok = (chancount >= 2 && (chanmask&StereoMask) == STEREO); + chansok = (chancount >= 2 && ((chanmask&StereoMask) == STEREO || !chanmask)); break; case DevFmtQuad: - chansok = (chancount >= 4 && (chanmask&QuadMask) == QUAD); + chansok = (chancount >= 4 && ((chanmask&QuadMask) == QUAD || !chanmask)); break; case DevFmtX51: chansok = (chancount >= 6 && ((chanmask&X51Mask) == X5DOT1 - || (chanmask&X51RearMask) == X5DOT1REAR)); + || (chanmask&X51RearMask) == X5DOT1REAR || !chanmask)); break; case DevFmtX61: - chansok = (chancount >= 7 && (chanmask&X61Mask) == X6DOT1); + chansok = (chancount >= 7 && ((chanmask&X61Mask) == X6DOT1 || !chanmask)); break; case DevFmtX71: - chansok = (chancount >= 8 && (chanmask&X71Mask) == X7DOT1); + case DevFmtX3D71: + chansok = (chancount >= 8 && ((chanmask&X71Mask) == X7DOT1 || !chanmask)); break; case DevFmtAmbi3D: break; @@ -1038,9 +1060,9 @@ HRESULT WasapiPlayback::resetProxy() mDevice->FmtChans = DevFmtX51; else if(chancount >= 4 && (chanmask&QuadMask) == QUAD) mDevice->FmtChans = DevFmtQuad; - else if(chancount >= 2 && (chanmask&StereoMask) == STEREO) + else if(chancount >= 2 && ((chanmask&StereoMask) == STEREO || !chanmask)) mDevice->FmtChans = DevFmtStereo; - else if(chancount >= 1 && (chanmask&MonoMask) == MONO) + else if(chancount >= 1 && ((chanmask&MonoMask) == MONO || !chanmask)) mDevice->FmtChans = DevFmtMono; else { @@ -1087,7 +1109,7 @@ HRESULT WasapiPlayback::resetProxy() const EndpointFormFactor formfactor{get_device_formfactor(mMMDev.get())}; mDevice->Flags.set(DirectEar, (formfactor == Headphones || formfactor == Headset)); - setChannelOrderFromWFXMask(OutputType.dwChannelMask); + setDefaultWFXChannelOrder(); hr = mClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, buf_time.count(), 0, &OutputType.Format, nullptr); @@ -1443,11 +1465,32 @@ HRESULT WasapiCapture::resetProxy() } mClient = ComPtr{static_cast(ptr)}; + WAVEFORMATEX *wfx; + hr = mClient->GetMixFormat(&wfx); + if(FAILED(hr)) + { + ERR("Failed to get capture format: 0x%08lx\n", hr); + return hr; + } + TraceFormat("Device capture format", wfx); + + WAVEFORMATEXTENSIBLE InputType{}; + if(!MakeExtensible(&InputType, wfx)) + { + CoTaskMemFree(wfx); + return E_FAIL; + } + CoTaskMemFree(wfx); + wfx = nullptr; + + const bool isRear51{InputType.Format.nChannels == 6 + && (InputType.dwChannelMask&X51RearMask) == X5DOT1REAR}; + // Make sure buffer is at least 100ms in size ReferenceTime buf_time{ReferenceTime{seconds{mDevice->BufferSize}} / mDevice->Frequency}; buf_time = std::max(buf_time, ReferenceTime{milliseconds{100}}); - WAVEFORMATEXTENSIBLE InputType{}; + InputType = {}; InputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; switch(mDevice->FmtChans) { @@ -1465,7 +1508,7 @@ HRESULT WasapiCapture::resetProxy() break; case DevFmtX51: InputType.Format.nChannels = 6; - InputType.dwChannelMask = X5DOT1; + InputType.dwChannelMask = isRear51 ? X5DOT1REAR : X5DOT1; break; case DevFmtX61: InputType.Format.nChannels = 7; @@ -1476,6 +1519,7 @@ HRESULT WasapiCapture::resetProxy() InputType.dwChannelMask = X7DOT1; break; + case DevFmtX3D71: case DevFmtAmbi3D: return E_FAIL; } @@ -1512,9 +1556,13 @@ HRESULT WasapiCapture::resetProxy() InputType.Format.cbSize = sizeof(InputType) - sizeof(InputType.Format); TraceFormat("Requesting capture format", &InputType.Format); - WAVEFORMATEX *wfx; hr = mClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, &InputType.Format, &wfx); if(FAILED(hr)) + { + WARN("Failed to check format support: 0x%08lx\n", hr); + hr = mClient->GetMixFormat(&wfx); + } + if(FAILED(hr)) { ERR("Failed to check format support: 0x%08lx\n", hr); return hr; @@ -1556,6 +1604,7 @@ HRESULT WasapiCapture::resetProxy() case DevFmtX61: return (chancount == 7 && (chanmask == 0 || (chanmask&X61Mask) == X6DOT1)); case DevFmtX71: + case DevFmtX3D71: return (chancount == 8 && (chanmask == 0 || (chanmask&X71Mask) == X7DOT1)); case DevFmtAmbi3D: return (chanmask == 0 && chancount == device->channelsFromFmt()); diff --git a/modules/openal-soft/Alc/backends/wave.cpp b/modules/openal-soft/Alc/backends/wave.cpp index 6360166..80e93f6 100644 --- a/modules/openal-soft/Alc/backends/wave.cpp +++ b/modules/openal-soft/Alc/backends/wave.cpp @@ -265,6 +265,8 @@ bool WaveBackend::reset() case DevFmtX51: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x200 | 0x400; break; case DevFmtX61: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x100 | 0x200 | 0x400; break; case DevFmtX71: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020 | 0x200 | 0x400; break; + /* NOTE: Same as 7.1. */ + case DevFmtX3D71: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020 | 0x200 | 0x400; break; case DevFmtAmbi3D: /* .amb output requires FuMa */ mDevice->mAmbiOrder = minu(mDevice->mAmbiOrder, 3); diff --git a/modules/openal-soft/Alc/backends/winmm.cpp b/modules/openal-soft/Alc/backends/winmm.cpp index 0fdd8a0..14cc4f9 100644 --- a/modules/openal-soft/Alc/backends/winmm.cpp +++ b/modules/openal-soft/Alc/backends/winmm.cpp @@ -301,23 +301,16 @@ bool WinMMPlayback::reset() return false; } - uint chanmask{}; if(mFormat.nChannels >= 2) - { mDevice->FmtChans = DevFmtStereo; - chanmask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; - } else if(mFormat.nChannels == 1) - { mDevice->FmtChans = DevFmtMono; - chanmask = SPEAKER_FRONT_CENTER; - } else { ERR("Unhandled channel count: %d\n", mFormat.nChannels); return false; } - setChannelOrderFromWFXMask(chanmask); + setDefaultWFXChannelOrder(); uint BufferSize{mDevice->UpdateSize * mFormat.nChannels * mDevice->bytesFromFmt()}; @@ -476,6 +469,7 @@ void WinMMCapture::open(const char *name) case DevFmtX51: case DevFmtX61: case DevFmtX71: + case DevFmtX3D71: case DevFmtAmbi3D: throw al::backend_exception{al::backend_error::DeviceError, "%s capture not supported", DevFmtChannelsString(mDevice->FmtChans)}; diff --git a/modules/openal-soft/Alc/context.cpp b/modules/openal-soft/Alc/context.cpp index 456c054..9292926 100644 --- a/modules/openal-soft/Alc/context.cpp +++ b/modules/openal-soft/Alc/context.cpp @@ -34,8 +34,8 @@ #include #include "alstring.h" -#include "al/eax_exception.h" -#include "al/eax_globals.h" +#include "al/eax/exception.h" +#include "al/eax/globals.h" #endif // ALSOFT_EAX namespace { @@ -330,32 +330,30 @@ ALenum ALCcontext::eax_eax_set( ALvoid* property_value, ALuint property_value_size) { - eax_initialize(); - - const auto eax_call = create_eax_call( - false, + const auto call = create_eax_call( + EaxCallType::set, property_set_id, property_id, property_source_id, property_value, - property_value_size - ); + property_value_size); + eax_version_ = call.get_version(); + eax_initialize(call); + eax_unlock_legacy_fx_slots(call); - eax_unlock_legacy_fx_slots(eax_call); - - switch (eax_call.get_property_set_id()) + switch (call.get_property_set_id()) { - case EaxEaxCallPropertySetId::context: - eax_set(eax_call); + case EaxCallPropertySetId::context: + eax_set(call); break; - case EaxEaxCallPropertySetId::fx_slot: - case EaxEaxCallPropertySetId::fx_slot_effect: - eax_dispatch_fx_slot(eax_call); + case EaxCallPropertySetId::fx_slot: + case EaxCallPropertySetId::fx_slot_effect: + eax_dispatch_fx_slot(call); break; - case EaxEaxCallPropertySetId::source: - eax_dispatch_source(eax_call); + case EaxCallPropertySetId::source: + eax_dispatch_source(call); break; default: @@ -376,32 +374,30 @@ ALenum ALCcontext::eax_eax_get( ALvoid* property_value, ALuint property_value_size) { - eax_initialize(); - - const auto eax_call = create_eax_call( - true, + const auto call = create_eax_call( + EaxCallType::get, property_set_id, property_id, property_source_id, property_value, - property_value_size - ); - - eax_unlock_legacy_fx_slots(eax_call); + property_value_size); + eax_version_ = call.get_version(); + eax_initialize(call); + eax_unlock_legacy_fx_slots(call); - switch (eax_call.get_property_set_id()) + switch (call.get_property_set_id()) { - case EaxEaxCallPropertySetId::context: - eax_get(eax_call); + case EaxCallPropertySetId::context: + eax_get(call); break; - case EaxEaxCallPropertySetId::fx_slot: - case EaxEaxCallPropertySetId::fx_slot_effect: - eax_dispatch_fx_slot(eax_call); + case EaxCallPropertySetId::fx_slot: + case EaxCallPropertySetId::fx_slot_effect: + eax_dispatch_fx_slot(call); break; - case EaxEaxCallPropertySetId::source: - eax_dispatch_source(eax_call); + case EaxCallPropertySetId::source: + eax_dispatch_source(call); break; default: @@ -413,7 +409,7 @@ ALenum ALCcontext::eax_eax_get( void ALCcontext::eax_update_filters() { - ForEachSource(this, std::mem_fn(&ALsource::eax_update_filters)); + ForEachSource(this, [](ALsource& source){ source.eax_commit(); }); } void ALCcontext::eax_commit_and_update_sources() @@ -478,7 +474,7 @@ void ALCcontext::eax_initialize_extensions() mExtensionList = eax_extension_list_.c_str(); } -void ALCcontext::eax_initialize() +void ALCcontext::eax_initialize(const EaxCall& call) { if (eax_is_initialized_) { @@ -501,7 +497,7 @@ void ALCcontext::eax_initialize() eax_set_defaults(); eax_set_air_absorbtion_hf(); eax_update_speaker_configuration(); - eax_initialize_fx_slots(); + eax_initialize_fx_slots(call); eax_initialize_sources(); eax_is_initialized_ = true; @@ -558,6 +554,10 @@ unsigned long ALCcontext::eax_detect_speaker_configuration() const case DevFmtX51: return SPEAKERS_5; case DevFmtX61: return SPEAKERS_6; case DevFmtX71: return SPEAKERS_7; + /* 3D7.1 is only compatible with 5.1. This could instead be HEADPHONES to + * suggest full-sphere surround sound (like HRTF). + */ + case DevFmtX3D71: return SPEAKERS_5; /* This could also be HEADPHONES, since headphones-based HRTF and Ambi3D * provide full-sphere surround sound. Depends if apps are more likely to * consider headphones or 7.1 for surround sound support. @@ -603,108 +603,93 @@ void ALCcontext::eax_set_defaults() noexcept eax_d_ = eax_; } -void ALCcontext::eax_unlock_legacy_fx_slots(const EaxEaxCall& eax_call) noexcept +void ALCcontext::eax_unlock_legacy_fx_slots(const EaxCall& call) noexcept { - if (eax_call.get_version() != 5 || eax_are_legacy_fx_slots_unlocked_) + if (call.get_version() != 5 || eax_are_legacy_fx_slots_unlocked_) return; eax_are_legacy_fx_slots_unlocked_ = true; eax_fx_slots_.unlock_legacy(); } -void ALCcontext::eax_dispatch_fx_slot( - const EaxEaxCall& eax_call) +void ALCcontext::eax_dispatch_fx_slot(const EaxCall& call) { - const auto fx_slot_index = eax_call.get_fx_slot_index(); + const auto fx_slot_index = call.get_fx_slot_index(); if(!fx_slot_index.has_value()) eax_fail("Invalid fx slot index."); auto& fx_slot = eax_get_fx_slot(*fx_slot_index); - if(fx_slot.eax_dispatch(eax_call)) + if(fx_slot.eax_dispatch(call)) { std::lock_guard source_lock{mSourceLock}; eax_update_filters(); } } -void ALCcontext::eax_dispatch_source( - const EaxEaxCall& eax_call) +void ALCcontext::eax_dispatch_source(const EaxCall& call) { - const auto source_id = eax_call.get_property_al_name(); - + const auto source_id = call.get_property_al_name(); std::lock_guard source_lock{mSourceLock}; - const auto source = ALsource::eax_lookup_source(*this, source_id); - if (!source) - { + if (source == nullptr) eax_fail("Source not found."); - } - source->eax_dispatch(eax_call); + source->eax_dispatch(call); } -void ALCcontext::eax_get_primary_fx_slot_id( - const EaxEaxCall& eax_call) +void ALCcontext::eax_get_primary_fx_slot_id(const EaxCall& call) { - eax_call.set_value(eax_.context.guidPrimaryFXSlotID); + call.set_value(eax_.context.guidPrimaryFXSlotID); } -void ALCcontext::eax_get_distance_factor( - const EaxEaxCall& eax_call) +void ALCcontext::eax_get_distance_factor(const EaxCall& call) { - eax_call.set_value(eax_.context.flDistanceFactor); + call.set_value(eax_.context.flDistanceFactor); } -void ALCcontext::eax_get_air_absorption_hf( - const EaxEaxCall& eax_call) +void ALCcontext::eax_get_air_absorption_hf(const EaxCall& call) { - eax_call.set_value(eax_.context.flAirAbsorptionHF); + call.set_value(eax_.context.flAirAbsorptionHF); } -void ALCcontext::eax_get_hf_reference( - const EaxEaxCall& eax_call) +void ALCcontext::eax_get_hf_reference(const EaxCall& call) { - eax_call.set_value(eax_.context.flHFReference); + call.set_value(eax_.context.flHFReference); } -void ALCcontext::eax_get_last_error( - const EaxEaxCall& eax_call) +void ALCcontext::eax_get_last_error(const EaxCall& call) { const auto eax_last_error = eax_last_error_; eax_last_error_ = EAX_OK; - eax_call.set_value(eax_last_error); + call.set_value(eax_last_error); } -void ALCcontext::eax_get_speaker_config( - const EaxEaxCall& eax_call) +void ALCcontext::eax_get_speaker_config(const EaxCall& call) { - eax_call.set_value(eax_speaker_config_); + call.set_value(eax_speaker_config_); } -void ALCcontext::eax_get_session( - const EaxEaxCall& eax_call) +void ALCcontext::eax_get_session(const EaxCall& call) { - eax_call.set_value(eax_session_); + call.set_value(eax_session_); } -void ALCcontext::eax_get_macro_fx_factor( - const EaxEaxCall& eax_call) +void ALCcontext::eax_get_macro_fx_factor(const EaxCall& call) { - eax_call.set_value(eax_.context.flMacroFXFactor); + call.set_value(eax_.context.flMacroFXFactor); } -void ALCcontext::eax_get_context_all( - const EaxEaxCall& eax_call) +void ALCcontext::eax_get_context_all(const EaxCall& call) { - switch (eax_call.get_version()) + switch (call.get_version()) { case 4: - eax_call.set_value(static_cast(eax_.context)); + call.set_value(static_cast(eax_.context)); break; case 5: - eax_call.set_value(static_cast(eax_.context)); + call.set_value(static_cast(eax_.context)); break; default: @@ -712,48 +697,47 @@ void ALCcontext::eax_get_context_all( } } -void ALCcontext::eax_get( - const EaxEaxCall& eax_call) +void ALCcontext::eax_get(const EaxCall& call) { - switch (eax_call.get_property_id()) + switch (call.get_property_id()) { case EAXCONTEXT_NONE: break; case EAXCONTEXT_ALLPARAMETERS: - eax_get_context_all(eax_call); + eax_get_context_all(call); break; case EAXCONTEXT_PRIMARYFXSLOTID: - eax_get_primary_fx_slot_id(eax_call); + eax_get_primary_fx_slot_id(call); break; case EAXCONTEXT_DISTANCEFACTOR: - eax_get_distance_factor(eax_call); + eax_get_distance_factor(call); break; case EAXCONTEXT_AIRABSORPTIONHF: - eax_get_air_absorption_hf(eax_call); + eax_get_air_absorption_hf(call); break; case EAXCONTEXT_HFREFERENCE: - eax_get_hf_reference(eax_call); + eax_get_hf_reference(call); break; case EAXCONTEXT_LASTERROR: - eax_get_last_error(eax_call); + eax_get_last_error(call); break; case EAXCONTEXT_SPEAKERCONFIG: - eax_get_speaker_config(eax_call); + eax_get_speaker_config(call); break; case EAXCONTEXT_EAXSESSION: - eax_get_session(eax_call); + eax_get_session(call); break; case EAXCONTEXT_MACROFXFACTOR: - eax_get_macro_fx_factor(eax_call); + eax_get_macro_fx_factor(call); break; default: @@ -763,7 +747,6 @@ void ALCcontext::eax_get( void ALCcontext::eax_set_primary_fx_slot_id() { - eax_previous_primary_fx_slot_index_ = eax_primary_fx_slot_index_; eax_primary_fx_slot_index_ = eax_.context.guidPrimaryFXSlotID; } @@ -797,10 +780,9 @@ void ALCcontext::eax_set_context() eax_set_hf_reference(); } -void ALCcontext::eax_initialize_fx_slots() +void ALCcontext::eax_initialize_fx_slots(const EaxCall& call) { - eax_fx_slots_.initialize(*this); - eax_previous_primary_fx_slot_index_ = eax_.context.guidPrimaryFXSlotID; + eax_fx_slots_.initialize(call, *this); eax_primary_fx_slot_index_ = eax_.context.guidPrimaryFXSlotID; } @@ -815,8 +797,8 @@ void ALCcontext::eax_initialize_sources() void ALCcontext::eax_update_sources() { std::unique_lock source_lock{mSourceLock}; - auto update_source = [this](ALsource &source) - { source.eax_update(eax_context_shared_dirty_flags_); }; + auto update_source = [](ALsource &source) + { source.eax_commit(); }; ForEachSource(this, update_source); } @@ -1003,15 +985,14 @@ void ALCcontext::eax_defer_context_all( eax_defer_macro_fx_factor(context_all.flMacroFXFactor); } -void ALCcontext::eax_defer_context_all( - const EaxEaxCall& eax_call) +void ALCcontext::eax_defer_context_all(const EaxCall& call) { - switch(eax_call.get_version()) + switch(call.get_version()) { case 4: { const auto& context_all = - eax_call.get_value(); + call.get_value(); eax_validate_context_all(context_all); eax_defer_context_all(context_all); @@ -1021,7 +1002,7 @@ void ALCcontext::eax_defer_context_all( case 5: { const auto& context_all = - eax_call.get_value(); + call.get_value(); eax_validate_context_all(context_all); eax_defer_context_all(context_all); @@ -1033,93 +1014,86 @@ void ALCcontext::eax_defer_context_all( } } -void ALCcontext::eax_defer_primary_fx_slot_id( - const EaxEaxCall& eax_call) +void ALCcontext::eax_defer_primary_fx_slot_id(const EaxCall& call) { const auto& primary_fx_slot_id = - eax_call.get_value(); + call.get_value(); eax_validate_primary_fx_slot_id(primary_fx_slot_id); eax_defer_primary_fx_slot_id(primary_fx_slot_id); } -void ALCcontext::eax_defer_distance_factor( - const EaxEaxCall& eax_call) +void ALCcontext::eax_defer_distance_factor(const EaxCall& call) { const auto& distance_factor = - eax_call.get_value(); + call.get_value(); eax_validate_distance_factor(distance_factor); eax_defer_distance_factor(distance_factor); } -void ALCcontext::eax_defer_air_absorption_hf( - const EaxEaxCall& eax_call) +void ALCcontext::eax_defer_air_absorption_hf(const EaxCall& call) { const auto& air_absorption_hf = - eax_call.get_value(); + call.get_value(); eax_validate_air_absorption_hf(air_absorption_hf); eax_defer_air_absorption_hf(air_absorption_hf); } -void ALCcontext::eax_defer_hf_reference( - const EaxEaxCall& eax_call) +void ALCcontext::eax_defer_hf_reference(const EaxCall& call) { const auto& hf_reference = - eax_call.get_value(); + call.get_value(); eax_validate_hf_reference(hf_reference); eax_defer_hf_reference(hf_reference); } -void ALCcontext::eax_set_session( - const EaxEaxCall& eax_call) +void ALCcontext::eax_set_session(const EaxCall& call) { const auto& eax_session = - eax_call.get_value(); + call.get_value(); eax_validate_session(eax_session); eax_session_ = eax_session; } -void ALCcontext::eax_defer_macro_fx_factor( - const EaxEaxCall& eax_call) +void ALCcontext::eax_defer_macro_fx_factor(const EaxCall& call) { const auto& macro_fx_factor = - eax_call.get_value(); + call.get_value(); eax_validate_macro_fx_factor(macro_fx_factor); eax_defer_macro_fx_factor(macro_fx_factor); } -void ALCcontext::eax_set( - const EaxEaxCall& eax_call) +void ALCcontext::eax_set(const EaxCall& call) { - switch (eax_call.get_property_id()) + switch (call.get_property_id()) { case EAXCONTEXT_NONE: break; case EAXCONTEXT_ALLPARAMETERS: - eax_defer_context_all(eax_call); + eax_defer_context_all(call); break; case EAXCONTEXT_PRIMARYFXSLOTID: - eax_defer_primary_fx_slot_id(eax_call); + eax_defer_primary_fx_slot_id(call); break; case EAXCONTEXT_DISTANCEFACTOR: - eax_defer_distance_factor(eax_call); + eax_defer_distance_factor(call); break; case EAXCONTEXT_AIRABSORPTIONHF: - eax_defer_air_absorption_hf(eax_call); + eax_defer_air_absorption_hf(call); break; case EAXCONTEXT_HFREFERENCE: - eax_defer_hf_reference(eax_call); + eax_defer_hf_reference(call); break; case EAXCONTEXT_LASTERROR: @@ -1129,11 +1103,11 @@ void ALCcontext::eax_set( eax_fail("Speaker configuration is read-only."); case EAXCONTEXT_EAXSESSION: - eax_set_session(eax_call); + eax_set_session(call); break; case EAXCONTEXT_MACROFXFACTOR: - eax_defer_macro_fx_factor(eax_call); + eax_defer_macro_fx_factor(call); break; default: @@ -1152,7 +1126,6 @@ void ALCcontext::eax_apply_deferred() if (eax_context_dirty_flags_.guidPrimaryFXSlotID) { - eax_context_shared_dirty_flags_.primary_fx_slot_id = true; eax_set_primary_fx_slot_id(); } @@ -1176,12 +1149,11 @@ void ALCcontext::eax_apply_deferred() eax_set_macro_fx_factor(); } - if (eax_context_shared_dirty_flags_ != EaxContextSharedDirtyFlags{}) + if (eax_context_dirty_flags_.guidPrimaryFXSlotID) { eax_update_sources(); } - eax_context_shared_dirty_flags_ = EaxContextSharedDirtyFlags{}; eax_context_dirty_flags_ = ContextDirtyFlags{}; } diff --git a/modules/openal-soft/Alc/context.h b/modules/openal-soft/Alc/context.h index 72b259e..2290839 100644 --- a/modules/openal-soft/Alc/context.h +++ b/modules/openal-soft/Alc/context.h @@ -20,20 +20,10 @@ #include "vector.h" #ifdef ALSOFT_EAX -#include "al/eax_eax_call.h" -#include "al/eax_fx_slot_index.h" -#include "al/eax_fx_slots.h" -#include "al/eax_utils.h" - - -using EaxContextSharedDirtyFlagsValue = std::uint_least8_t; - -struct EaxContextSharedDirtyFlags -{ - using EaxIsBitFieldStruct = bool; - - EaxContextSharedDirtyFlagsValue primary_fx_slot_id : 1; -}; // EaxContextSharedDirtyFlags +#include "al/eax/call.h" +#include "al/eax/fx_slot_index.h" +#include "al/eax/fx_slots.h" +#include "al/eax/utils.h" using ContextDirtyFlagsValue = std::uint_least8_t; @@ -224,6 +214,7 @@ public: void eax_uninitialize() noexcept; + int eax_get_version() const noexcept { return eax_version_; } ALenum eax_eax_set( const GUID* property_set_id, @@ -248,8 +239,6 @@ public: void eax_set_last_error() noexcept; - EaxFxSlotIndex eax_get_previous_primary_fx_slot_index() const noexcept - { return eax_previous_primary_fx_slot_index_; } EaxFxSlotIndex eax_get_primary_fx_slot_index() const noexcept { return eax_primary_fx_slot_index_; } @@ -275,12 +264,10 @@ private: long eax_last_error_{}; unsigned long eax_speaker_config_{}; - EaxFxSlotIndex eax_previous_primary_fx_slot_index_{}; EaxFxSlotIndex eax_primary_fx_slot_index_{}; EaxFxSlots eax_fx_slots_{}; - EaxContextSharedDirtyFlags eax_context_shared_dirty_flags_{}; - + int eax_version_{}; Eax eax_{}; Eax eax_d_{}; EAXSESSIONPROPERTIES eax_session_{}; @@ -297,7 +284,7 @@ private: void eax_initialize_extensions(); - void eax_initialize(); + void eax_initialize(const EaxCall& call); bool eax_has_no_default_effect_slot() const noexcept; @@ -326,45 +313,33 @@ private: void eax_initialize_sources(); - void eax_unlock_legacy_fx_slots(const EaxEaxCall& eax_call) noexcept; + void eax_unlock_legacy_fx_slots(const EaxCall& call) noexcept; - void eax_dispatch_fx_slot( - const EaxEaxCall& eax_call); + void eax_dispatch_fx_slot(const EaxCall& call); - void eax_dispatch_source( - const EaxEaxCall& eax_call); + void eax_dispatch_source(const EaxCall& call); - void eax_get_primary_fx_slot_id( - const EaxEaxCall& eax_call); + void eax_get_primary_fx_slot_id(const EaxCall& call); - void eax_get_distance_factor( - const EaxEaxCall& eax_call); + void eax_get_distance_factor(const EaxCall& call); - void eax_get_air_absorption_hf( - const EaxEaxCall& eax_call); + void eax_get_air_absorption_hf(const EaxCall& call); - void eax_get_hf_reference( - const EaxEaxCall& eax_call); + void eax_get_hf_reference(const EaxCall& call); - void eax_get_last_error( - const EaxEaxCall& eax_call); + void eax_get_last_error(const EaxCall& call); - void eax_get_speaker_config( - const EaxEaxCall& eax_call); + void eax_get_speaker_config(const EaxCall& call); - void eax_get_session( - const EaxEaxCall& eax_call); + void eax_get_session(const EaxCall& call); - void eax_get_macro_fx_factor( - const EaxEaxCall& eax_call); + void eax_get_macro_fx_factor(const EaxCall& call); - void eax_get_context_all( - const EaxEaxCall& eax_call); + void eax_get_context_all(const EaxCall& call); - void eax_get( - const EaxEaxCall& eax_call); + void eax_get(const EaxCall& call); void eax_set_primary_fx_slot_id(); @@ -379,7 +354,7 @@ private: void eax_set_context(); - void eax_initialize_fx_slots(); + void eax_initialize_fx_slots(const EaxCall& call); void eax_update_sources(); @@ -441,29 +416,21 @@ private: const EAX50CONTEXTPROPERTIES& context_all); - void eax_defer_context_all( - const EaxEaxCall& eax_call); + void eax_defer_context_all(const EaxCall& call); - void eax_defer_primary_fx_slot_id( - const EaxEaxCall& eax_call); + void eax_defer_primary_fx_slot_id(const EaxCall& call); - void eax_defer_distance_factor( - const EaxEaxCall& eax_call); + void eax_defer_distance_factor(const EaxCall& call); - void eax_defer_air_absorption_hf( - const EaxEaxCall& eax_call); + void eax_defer_air_absorption_hf(const EaxCall& call); - void eax_defer_hf_reference( - const EaxEaxCall& eax_call); + void eax_defer_hf_reference(const EaxCall& call); - void eax_set_session( - const EaxEaxCall& eax_call); + void eax_set_session(const EaxCall& call); - void eax_defer_macro_fx_factor( - const EaxEaxCall& eax_call); + void eax_defer_macro_fx_factor(const EaxCall& call); - void eax_set( - const EaxEaxCall& eax_call); + void eax_set(const EaxCall& call); void eax_apply_deferred(); #endif // ALSOFT_EAX diff --git a/modules/openal-soft/Alc/device.cpp b/modules/openal-soft/Alc/device.cpp index e06c0d7..6eeb907 100644 --- a/modules/openal-soft/Alc/device.cpp +++ b/modules/openal-soft/Alc/device.cpp @@ -84,6 +84,7 @@ auto ALCdevice::getOutputMode1() const noexcept -> OutputMode1 case DevFmtX51: return OutputMode1::X51; case DevFmtX61: return OutputMode1::X61; case DevFmtX71: return OutputMode1::X71; + case DevFmtX3D71: case DevFmtAmbi3D: break; } return OutputMode1::Any; diff --git a/modules/openal-soft/Alc/device.h b/modules/openal-soft/Alc/device.h index 04931a5..ef50f53 100644 --- a/modules/openal-soft/Alc/device.h +++ b/modules/openal-soft/Alc/device.h @@ -20,7 +20,7 @@ #include "vector.h" #ifdef ALSOFT_EAX -#include "al/eax_x_ram.h" +#include "al/eax/x_ram.h" #endif // ALSOFT_EAX struct ALbuffer; @@ -141,7 +141,7 @@ struct ALCdevice : public al::intrusive_ref, DeviceBase { { return GetConfigValueBool(DeviceName.c_str(), block, key, def); } template - al::optional configValue(const char *block, const char *key) = delete; + inline al::optional configValue(const char *block, const char *key) = delete; DEF_NEWDEL(ALCdevice) }; diff --git a/modules/openal-soft/Alc/effects/reverb.cpp b/modules/openal-soft/Alc/effects/reverb.cpp index 81c6f86..e9f2e35 100644 --- a/modules/openal-soft/Alc/effects/reverb.cpp +++ b/modules/openal-soft/Alc/effects/reverb.cpp @@ -454,10 +454,8 @@ struct ReverbState final : public EffectState { alignas(16) std::array mEarlySamples{}; alignas(16) std::array mLateSamples{}; - using MixOutT = void (ReverbState::*)(const al::span samplesOut, - const size_t counter, const size_t offset, const size_t todo); - MixOutT mMixOut{&ReverbState::MixOutPlain}; + bool mUpmixOutput{false}; std::array mOrderScales{}; std::array,2> mAmbiSplitter; @@ -535,6 +533,15 @@ struct ReverbState final : public EffectState { } } + void mixOut(const al::span samplesOut, const size_t counter, + const size_t offset, const size_t todo) + { + if(mUpmixOutput) + MixOutAmbiUp(samplesOut, counter, offset, todo); + else + MixOutPlain(samplesOut, counter, offset, todo); + } + void allocLines(const float frequency); void updateDelayLine(const float earlyDelay, const float lateDelay, const float density_mult, @@ -688,12 +695,12 @@ void ReverbState::deviceUpdate(const DeviceBase *device, const Buffer&) if(device->mAmbiOrder > 1) { - mMixOut = &ReverbState::MixOutAmbiUp; + mUpmixOutput = true; mOrderScales = AmbiScale::GetHFOrderScales(1, device->mAmbiOrder); } else { - mMixOut = &ReverbState::MixOutPlain; + mUpmixOutput = false; mOrderScales.fill(1.0f); } mAmbiSplitter[0][0].init(device->mXOverFreq / frequency); @@ -1427,14 +1434,14 @@ void ReverbState::earlyFaded(const size_t offset, const size_t todo, const float void Modulation::calcDelays(size_t todo) { - constexpr float inv_scale{MOD_FRACONE / al::numbers::pi_v / 2.0f}; + constexpr float mod_scale{al::numbers::pi_v * 2.0f / MOD_FRACONE}; uint idx{Index}; const uint step{Step}; const float depth{Depth[0]}; for(size_t i{0};i < todo;++i) { idx += step; - const float lfo{std::sin(static_cast(idx&MOD_FRACMASK) / inv_scale)}; + const float lfo{std::sin(static_cast(idx&MOD_FRACMASK) * mod_scale)}; ModDelays[i] = (lfo+1.0f) * depth; } Index = idx; @@ -1442,7 +1449,7 @@ void Modulation::calcDelays(size_t todo) void Modulation::calcFadedDelays(size_t todo, float fadeCount, float fadeStep) { - constexpr float inv_scale{MOD_FRACONE / al::numbers::pi_v / 2.0f}; + constexpr float mod_scale{al::numbers::pi_v * 2.0f / MOD_FRACONE}; uint idx{Index}; const uint step{Step}; const float depth{Depth[0]}; @@ -1451,7 +1458,7 @@ void Modulation::calcFadedDelays(size_t todo, float fadeCount, float fadeStep) { fadeCount += 1.0f; idx += step; - const float lfo{std::sin(static_cast(idx&MOD_FRACMASK) / inv_scale)}; + const float lfo{std::sin(static_cast(idx&MOD_FRACMASK) * mod_scale)}; ModDelays[i] = (lfo+1.0f) * (depth + depthStep*fadeCount); } Index = idx; @@ -1650,7 +1657,7 @@ void ReverbState::process(const size_t samplesToDo, const al::span*mMixOut)(samplesOut, samplesToDo-base, base, todo); + mixOut(samplesOut, samplesToDo-base, base, todo); offset += todo; base += todo; @@ -1670,7 +1677,7 @@ void ReverbState::process(const size_t samplesToDo, const al::span*mMixOut)(samplesOut, samplesToDo-base, base, todo); + mixOut(samplesOut, samplesToDo-base, base, todo); offset += todo; base += todo; diff --git a/modules/openal-soft/Alc/panning.cpp b/modules/openal-soft/Alc/panning.cpp index 00bf566..d0afd57 100644 --- a/modules/openal-soft/Alc/panning.cpp +++ b/modules/openal-soft/Alc/panning.cpp @@ -89,6 +89,23 @@ inline const char *GetLabelFromChannel(Channel channel) case TopBackCenter: return "top-back-center"; case TopBackRight: return "top-back-right"; + case Aux0: return "Aux0"; + case Aux1: return "Aux1"; + case Aux2: return "Aux2"; + case Aux3: return "Aux3"; + case Aux4: return "Aux4"; + case Aux5: return "Aux5"; + case Aux6: return "Aux6"; + case Aux7: return "Aux7"; + case Aux8: return "Aux8"; + case Aux9: return "Aux9"; + case Aux10: return "Aux10"; + case Aux11: return "Aux11"; + case Aux12: return "Aux12"; + case Aux13: return "Aux13"; + case Aux14: return "Aux14"; + case Aux15: return "Aux15"; + case MaxChannels: break; } return "(unknown)"; @@ -202,6 +219,8 @@ struct DecoderConfig { mCoeffsLF = rhs.mCoeffsLF; return *this; } + + explicit operator bool() const noexcept { return mOrder != 0; } }; using DecoderView = DecoderConfig; @@ -412,8 +431,15 @@ DecoderView MakeDecoderView(ALCdevice *device, const AmbDecConf *conf, ch = BackCenter; else { - ERR("AmbDec speaker label \"%s\" not recognized\n", speaker.Name.c_str()); - continue; + int idx{}; + char c{}; + if(sscanf(speaker.Name.c_str(), "AUX%d%c", &idx, &c) != 1 || idx < 0 + || idx >= MaxChannels-Aux0) + { + ERR("AmbDec speaker label \"%s\" not recognized\n", speaker.Name.c_str()); + continue; + } + ch = static_cast(Aux0+idx); } decoder.mChannels[chan_count] = ch; @@ -537,11 +563,33 @@ constexpr DecoderConfig X71Config{ {{1.66666667e-1f, -9.62250449e-2f, -1.66666667e-1f, 1.49071198e-1f, 8.60662966e-2f, -7.96819073e-2f, 0.00000000e+0f}}, }} }; +constexpr DecoderConfig X3D71Config{ + 1, true, {{Aux0, SideLeft, FrontLeft, FrontRight, SideRight, Aux1}}, + DevAmbiScaling::N3D, + /*HF*/{{1.73205081e+0f, 1.00000000e+0f}}, + {{ + {{1.66669447e-1f, 0.00000000e+0f, 2.36070520e-1f, -1.66153012e-1f}}, + {{1.66669447e-1f, 2.04127551e-1f, -1.17487922e-1f, -1.66927066e-1f}}, + {{1.66669447e-1f, 2.04127551e-1f, 1.17487922e-1f, 1.66927066e-1f}}, + {{1.66669447e-1f, -2.04127551e-1f, 1.17487922e-1f, 1.66927066e-1f}}, + {{1.66669447e-1f, -2.04127551e-1f, -1.17487922e-1f, -1.66927066e-1f}}, + {{1.66669447e-1f, 0.00000000e+0f, -2.36070520e-1f, 1.66153012e-1f}}, + }}, + /*LF*/{{1.00000000e+0f, 1.00000000e+0f}}, + {{ + {{1.66669447e-1f, 0.00000000e+0f, 2.36070520e-1f, -1.66153012e-1f}}, + {{1.66669447e-1f, 2.04127551e-1f, -1.17487922e-1f, -1.66927066e-1f}}, + {{1.66669447e-1f, 2.04127551e-1f, 1.17487922e-1f, 1.66927066e-1f}}, + {{1.66669447e-1f, -2.04127551e-1f, 1.17487922e-1f, 1.66927066e-1f}}, + {{1.66669447e-1f, -2.04127551e-1f, -1.17487922e-1f, -1.66927066e-1f}}, + {{1.66669447e-1f, 0.00000000e+0f, -2.36070520e-1f, 1.66153012e-1f}}, + }} +}; void InitPanning(ALCdevice *device, const bool hqdec=false, const bool stablize=false, DecoderView decoder={}) { - if(!decoder.mOrder) + if(!decoder) { switch(device->FmtChans) { @@ -551,6 +599,7 @@ void InitPanning(ALCdevice *device, const bool hqdec=false, const bool stablize= case DevFmtX51: decoder = X51Config; break; case DevFmtX61: decoder = X61Config; break; case DevFmtX71: decoder = X71Config; break; + case DevFmtX3D71: decoder = X3D71Config; break; case DevFmtAmbi3D: auto&& acnmap = GetAmbiLayout(device->mAmbiLayout); auto&& n3dscale = GetAmbiScales(device->mAmbiScale); @@ -906,6 +955,7 @@ void aluInitRenderer(ALCdevice *device, int hrtf_id, al::optional> decoder_store; DecoderView decoder{}; - float speakerdists[MaxChannels]{}; + float speakerdists[MAX_OUTPUT_CHANNELS]{}; auto load_config = [device,&decoder_store,&decoder,&speakerdists](const char *config) { AmbDecConf conf{}; diff --git a/modules/openal-soft/CMakeLists.txt b/modules/openal-soft/CMakeLists.txt index 2edb30a..1984ac9 100644 --- a/modules/openal-soft/CMakeLists.txt +++ b/modules/openal-soft/CMakeLists.txt @@ -30,8 +30,6 @@ if(CMAKE_SYSTEM_NAME STREQUAL "iOS") endif() endif() -project(OpenAL) - if(COMMAND CMAKE_POLICY) cmake_policy(SET CMP0003 NEW) cmake_policy(SET CMP0005 NEW) @@ -47,8 +45,16 @@ if(COMMAND CMAKE_POLICY) if(POLICY CMP0075) cmake_policy(SET CMP0075 NEW) endif(POLICY CMP0075) + if(POLICY CMP0092) + cmake_policy(SET CMP0092 NEW) + endif(POLICY CMP0092) + if(POLICY CMP0117) + cmake_policy(SET CMP0117 NEW) + endif(POLICY CMP0117) endif(COMMAND CMAKE_POLICY) +project(OpenAL) + if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." @@ -97,6 +103,11 @@ option(ALSOFT_UPDATE_BUILD_VERSION "Update git build version info" ON) option(ALSOFT_EAX "Enable legacy EAX extensions" ${WIN32}) +option(ALSOFT_SEARCH_INSTALL_DATADIR "Search the installation data directory" OFF) +if(ALSOFT_SEARCH_INSTALL_DATADIR) + set(ALSOFT_INSTALL_DATADIR ${CMAKE_INSTALL_FULL_DATADIR}) +endif() + if(DEFINED SHARE_INSTALL_DIR) message(WARNING "SHARE_INSTALL_DIR is deprecated. Use the variables provided by the GNUInstallDirs module instead") set(CMAKE_INSTALL_DATADIR "${SHARE_INSTALL_DIR}") @@ -151,7 +162,7 @@ endif() set(LIB_MAJOR_VERSION "1") set(LIB_MINOR_VERSION "22") -set(LIB_REVISION "0") +set(LIB_REVISION "2") set(LIB_VERSION "${LIB_MAJOR_VERSION}.${LIB_MINOR_VERSION}.${LIB_REVISION}") set(LIB_VERSION_NUM ${LIB_MAJOR_VERSION},${LIB_MINOR_VERSION},${LIB_REVISION},0) @@ -220,13 +231,6 @@ if(MSVC) set(C_FLAGS ${C_FLAGS} $<$:/permissive->) endif() set(C_FLAGS ${C_FLAGS} /W4 /w14640 /wd4065 /wd4127 /wd4268 /wd4324 /wd5030) - # Remove /W3, which is added by default, since we set /W4. Some build - # generators with MSVC complain about both /W3 and /W4 being specified. - foreach(flag_var CMAKE_C_FLAGS CMAKE_CXX_FLAGS) - if(${flag_var} MATCHES "/W3") - string(REGEX REPLACE "/W3" "" ${flag_var} "${${flag_var}}") - endif() - endforeach() if(NOT DXSDK_DIR) string(REGEX REPLACE "\\\\" "/" DXSDK_DIR "$ENV{DXSDK_DIR}") @@ -677,30 +681,42 @@ set(CORE_OBJS core/voice_change.h) set(HAVE_RTKIT 0) -option(ALSOFT_REQUIRE_RTKIT "Require RTKit/D-Bus support" FALSE) -find_package(DBus1 QUIET) -if(DBus1_FOUND) - option(ALSOFT_RTKIT "Enable RTKit support" ON) - if(ALSOFT_RTKIT) - set(HAVE_RTKIT 1) - set(CORE_OBJS ${CORE_OBJS} core/dbus_wrap.cpp core/dbus_wrap.h core/rtkit.cpp core/rtkit.h) - if(WIN32 OR HAVE_DLFCN_H) - set(INC_PATHS ${INC_PATHS} ${DBus1_INCLUDE_DIRS}) - set(CPP_DEFS ${CPP_DEFS} ${DBus1_DEFINITIONS}) - else() - set(EXTRA_LIBS ${EXTRA_LIBS} ${DBus1_LIBRARIES}) - endif() - endif() -else() - set(MISSING_VARS "") - if(NOT DBus1_INCLUDE_DIRS) - set(MISSING_VARS "${MISSING_VARS} DBus1_INCLUDE_DIRS") +if(NOT WIN32) + option(ALSOFT_REQUIRE_RTKIT "Require RTKit/D-Bus support" FALSE) + find_package(DBus1 QUIET) + if(NOT DBus1_FOUND AND PkgConfig_FOUND) + pkg_check_modules(DBUS dbus-1) endif() - if(NOT DBus1_LIBRARIES) - set(MISSING_VARS "${MISSING_VARS} DBus1_LIBRARIES") + if(DBus1_FOUND OR DBUS_FOUND) + option(ALSOFT_RTKIT "Enable RTKit support" ON) + if(ALSOFT_RTKIT) + set(HAVE_RTKIT 1) + set(CORE_OBJS ${CORE_OBJS} core/dbus_wrap.cpp core/dbus_wrap.h + core/rtkit.cpp core/rtkit.h) + if(NOT DBus1_FOUND) + set(INC_PATHS ${INC_PATHS} ${DBUS_INCLUDE_DIRS}) + set(CPP_DEFS ${CPP_DEFS} ${DBUS_CFLAGS_OTHER}) + if(NOT HAVE_DLFCN_H) + set(EXTRA_LIBS ${EXTRA_LIBS} ${DBUS_LINK_LIBRARIES}) + endif() + elseif(HAVE_DLFCN_H) + set(INC_PATHS ${INC_PATHS} ${DBus1_INCLUDE_DIRS}) + set(CPP_DEFS ${CPP_DEFS} ${DBus1_DEFINITIONS}) + else() + set(EXTRA_LIBS ${EXTRA_LIBS} ${DBus1_LIBRARIES}) + endif() + endif() + else() + set(MISSING_VARS "") + if(NOT DBus1_INCLUDE_DIRS) + set(MISSING_VARS "${MISSING_VARS} DBus1_INCLUDE_DIRS") + endif() + if(NOT DBus1_LIBRARIES) + set(MISSING_VARS "${MISSING_VARS} DBus1_LIBRARIES") + endif() + message(STATUS "Could NOT find DBus1 (missing:${MISSING_VARS})") + unset(MISSING_VARS) endif() - message(STATUS "Could NOT find DBus1 (missing:${MISSING_VARS})") - unset(MISSING_VARS) endif() if(ALSOFT_REQUIRE_RTKIT AND NOT HAVE_RTKIT) message(FATAL_ERROR "Failed to enabled required RTKit support") @@ -781,24 +797,22 @@ set(ALC_OBJS if (ALSOFT_EAX) set(OPENAL_OBJS ${OPENAL_OBJS} - al/eax_api.cpp - al/eax_api.h - al/eax_eax_call.cpp - al/eax_eax_call.h - al/eax_effect.cpp - al/eax_effect.h - al/eax_exception.cpp - al/eax_exception.h - al/eax_fx_slot_index.cpp - al/eax_fx_slot_index.h - al/eax_fx_slots.cpp - al/eax_fx_slots.h - al/eax_globals.cpp - al/eax_globals.h - al/eax_utils.cpp - al/eax_utils.h - al/eax_x_ram.cpp - al/eax_x_ram.h + al/eax/api.cpp + al/eax/api.h + al/eax/call.cpp + al/eax/call.h + al/eax/effect.h + al/eax/exception.cpp + al/eax/exception.h + al/eax/fx_slot_index.cpp + al/eax/fx_slot_index.h + al/eax/fx_slots.cpp + al/eax/fx_slots.h + al/eax/globals.cpp + al/eax/globals.h + al/eax/utils.cpp + al/eax/utils.h + al/eax/x_ram.h ) endif () @@ -903,7 +917,7 @@ endif() # Check PipeWire backend option(ALSOFT_REQUIRE_PIPEWIRE "Require PipeWire backend" OFF) if(PkgConfig_FOUND) - pkg_check_modules(PIPEWIRE libpipewire-0.3) + pkg_check_modules(PIPEWIRE libpipewire-0.3>=0.3.23) if(PIPEWIRE_FOUND) option(ALSOFT_BACKEND_PIPEWIRE "Enable PipeWire backend" ON) if(ALSOFT_BACKEND_PIPEWIRE) @@ -1128,8 +1142,11 @@ if(ANDROID) set(OBOE_TARGET oboe) else() - find_package(Oboe) - if(OBOE_FOUND) + find_package(oboe CONFIG) + if(NOT TARGET oboe::oboe) + find_package(Oboe) + endif() + if(TARGET oboe::oboe) set(OBOE_TARGET "oboe::oboe") endif() endif() @@ -1244,9 +1261,9 @@ endif() # Needed for openal.pc.in set(prefix ${CMAKE_INSTALL_PREFIX}) set(exec_prefix "\${prefix}") -set(libdir "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}") -set(bindir "\${exec_prefix}/${CMAKE_INSTALL_BINDIR}") -set(includedir "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}") +set(libdir "${CMAKE_INSTALL_FULL_LIBDIR}") +set(bindir "${CMAKE_INSTALL_FULL_BINDIR}") +set(includedir "${CMAKE_INSTALL_FULL_INCLUDEDIR}") set(PACKAGE_VERSION "${LIB_VERSION}") set(PKG_CONFIG_CFLAGS ) set(PKG_CONFIG_PRIVATE_LIBS ) diff --git a/modules/openal-soft/ChangeLog b/modules/openal-soft/ChangeLog index c26f096..51f409f 100644 --- a/modules/openal-soft/ChangeLog +++ b/modules/openal-soft/ChangeLog @@ -1,3 +1,32 @@ +openal-soft-1.22.2: + + Fixed PipeWire version check. + + Fixed building with PipeWire versions before 0.3.33. + +openal-soft-1.22.1: + + Fixed CoreAudio capture. + + Fixed air absorption strength. + + Fixed handling 5.1 devices on Windows that use Rear channels instead of + Side channels. + + Fixed some compilation issues on MinGW. + + Fixed ALSA not being used on some systems without PipeWire and PulseAudio. + + Fixed OpenSL capturing noise. + + Fixed Oboe capture failing with some buffer sizes. + + Added checks for the runtime PipeWire version. The same or newer version + than is used for building will be needed at runtime for the backend to + work. + + Separated 3D7.1 into its own speaker configuration. + openal-soft-1.22.0: Implemented the ALC_SOFT_reopen_device extension. This allows for moving diff --git a/modules/openal-soft/al/auxeffectslot.cpp b/modules/openal-soft/al/auxeffectslot.cpp index c33fb14..d37168e 100644 --- a/modules/openal-soft/al/auxeffectslot.cpp +++ b/modules/openal-soft/al/auxeffectslot.cpp @@ -51,8 +51,8 @@ #include "opthelpers.h" #ifdef ALSOFT_EAX -#include "eax_exception.h" -#include "eax_utils.h" +#include "eax/exception.h" +#include "eax/utils.h" #endif // ALSOFT_EAX namespace { @@ -1076,6 +1076,7 @@ public: void ALeffectslot::eax_initialize( + const EaxCall& call, ALCcontext& al_context, EaxFxSlotIndexValue index) { @@ -1090,7 +1091,7 @@ void ALeffectslot::eax_initialize( eax_initialize_eax(); eax_initialize_lock(); - eax_initialize_effects(); + eax_initialize_effects(call); } const EAX50FXSLOTPROPERTIES& ALeffectslot::eax_get_eax_fx_slot() const noexcept @@ -1104,8 +1105,7 @@ void ALeffectslot::eax_ensure_is_unlocked() const eax_fail("Locked."); } -void ALeffectslot::eax_validate_fx_slot_effect( - const GUID& eax_effect_id) +void ALeffectslot::eax_validate_fx_slot_effect(const GUID& eax_effect_id) { eax_ensure_is_unlocked(); @@ -1127,8 +1127,7 @@ void ALeffectslot::eax_validate_fx_slot_effect( } } -void ALeffectslot::eax_validate_fx_slot_volume( - long eax_volume) +void ALeffectslot::eax_validate_fx_slot_volume(long eax_volume) { eax_validate_range( "Volume", @@ -1137,8 +1136,7 @@ void ALeffectslot::eax_validate_fx_slot_volume( EAXFXSLOT_MAXVOLUME); } -void ALeffectslot::eax_validate_fx_slot_lock( - long eax_lock) +void ALeffectslot::eax_validate_fx_slot_lock(long eax_lock) { eax_ensure_is_unlocked(); @@ -1149,19 +1147,16 @@ void ALeffectslot::eax_validate_fx_slot_lock( EAXFXSLOT_MAXLOCK); } -void ALeffectslot::eax_validate_fx_slot_flags( - unsigned long eax_flags, - int eax_version) +void ALeffectslot::eax_validate_fx_slot_flags(const EaxCall& call, unsigned long eax_flags) { eax_validate_range( "Flags", eax_flags, 0UL, - ~(eax_version == 4 ? EAX40FXSLOTFLAGS_RESERVED : EAX50FXSLOTFLAGS_RESERVED)); + ~(call.get_version() == 4 ? EAX40FXSLOTFLAGS_RESERVED : EAX50FXSLOTFLAGS_RESERVED)); } -void ALeffectslot::eax_validate_fx_slot_occlusion( - long eax_occlusion) +void ALeffectslot::eax_validate_fx_slot_occlusion(long eax_occlusion) { eax_validate_range( "Occlusion", @@ -1170,8 +1165,7 @@ void ALeffectslot::eax_validate_fx_slot_occlusion( EAXFXSLOT_MAXOCCLUSION); } -void ALeffectslot::eax_validate_fx_slot_occlusion_lf_ratio( - float eax_occlusion_lf_ratio) +void ALeffectslot::eax_validate_fx_slot_occlusion_lf_ratio(float eax_occlusion_lf_ratio) { eax_validate_range( "Occlusion LF Ratio", @@ -1180,28 +1174,22 @@ void ALeffectslot::eax_validate_fx_slot_occlusion_lf_ratio( EAXFXSLOT_MAXOCCLUSIONLFRATIO); } -void ALeffectslot::eax_validate_fx_slot_all( - const EAX40FXSLOTPROPERTIES& fx_slot, - int eax_version) +void ALeffectslot::eax_validate_fx_slot_all(const EaxCall& call, const EAX40FXSLOTPROPERTIES& fx_slot) { eax_validate_fx_slot_effect(fx_slot.guidLoadEffect); eax_validate_fx_slot_volume(fx_slot.lVolume); eax_validate_fx_slot_lock(fx_slot.lLock); - eax_validate_fx_slot_flags(fx_slot.ulFlags, eax_version); + eax_validate_fx_slot_flags(call, fx_slot.ulFlags); } -void ALeffectslot::eax_validate_fx_slot_all( - const EAX50FXSLOTPROPERTIES& fx_slot, - int eax_version) +void ALeffectslot::eax_validate_fx_slot_all(const EaxCall& call, const EAX50FXSLOTPROPERTIES& fx_slot) { - eax_validate_fx_slot_all(static_cast(fx_slot), eax_version); - + eax_validate_fx_slot_all(call, static_cast(fx_slot)); eax_validate_fx_slot_occlusion(fx_slot.lOcclusion); eax_validate_fx_slot_occlusion_lf_ratio(fx_slot.flOcclusionLFRatio); } -void ALeffectslot::eax_set_fx_slot_effect( - const GUID& eax_effect_id) +void ALeffectslot::eax_set_fx_slot_effect(const EaxCall& call, const GUID& eax_effect_id) { if (eax_eax_fx_slot_.guidLoadEffect == eax_effect_id) { @@ -1210,7 +1198,7 @@ void ALeffectslot::eax_set_fx_slot_effect( eax_eax_fx_slot_.guidLoadEffect = eax_effect_id; - eax_set_fx_slot_effect(); + eax_set_fx_slot_effect(call); } void ALeffectslot::eax_set_fx_slot_volume( @@ -1278,20 +1266,18 @@ bool ALeffectslot::eax_set_fx_slot_occlusion_lf_ratio( return true; } -void ALeffectslot::eax_set_fx_slot_all( - const EAX40FXSLOTPROPERTIES& eax_fx_slot) +void ALeffectslot::eax_set_fx_slot_all(const EaxCall& call, const EAX40FXSLOTPROPERTIES& eax_fx_slot) { - eax_set_fx_slot_effect(eax_fx_slot.guidLoadEffect); + eax_set_fx_slot_effect(call, eax_fx_slot.guidLoadEffect); eax_set_fx_slot_volume(eax_fx_slot.lVolume); eax_set_fx_slot_lock(eax_fx_slot.lLock); eax_set_fx_slot_flags(eax_fx_slot.ulFlags); } // [[nodiscard]] -bool ALeffectslot::eax_set_fx_slot_all( - const EAX50FXSLOTPROPERTIES& eax_fx_slot) +bool ALeffectslot::eax_set_fx_slot_all(const EaxCall& call, const EAX50FXSLOTPROPERTIES& eax_fx_slot) { - eax_set_fx_slot_all(static_cast(eax_fx_slot)); + eax_set_fx_slot_all(call, static_cast(eax_fx_slot)); const auto is_occlusion_modified = eax_set_fx_slot_occlusion(eax_fx_slot.lOcclusion); const auto is_occlusion_lf_ratio_modified = eax_set_fx_slot_occlusion_lf_ratio(eax_fx_slot.flOcclusionLFRatio); @@ -1348,22 +1334,21 @@ void ALeffectslot::eax_initialize_lock() eax_is_locked_ = (eax_fx_slot_index_ < 2); } -void ALeffectslot::eax_initialize_effects() +void ALeffectslot::eax_initialize_effects(const EaxCall& call) { - eax_set_fx_slot_effect(); + eax_set_fx_slot_effect(call); } -void ALeffectslot::eax_get_fx_slot_all( - const EaxEaxCall& eax_call) const +void ALeffectslot::eax_get_fx_slot_all(const EaxCall& call) const { - switch (eax_call.get_version()) + switch (call.get_version()) { case 4: - eax_call.set_value(eax_eax_fx_slot_); + call.set_value(eax_eax_fx_slot_); break; case 5: - eax_call.set_value(eax_eax_fx_slot_); + call.set_value(eax_eax_fx_slot_); break; default: @@ -1371,37 +1356,36 @@ void ALeffectslot::eax_get_fx_slot_all( } } -void ALeffectslot::eax_get_fx_slot( - const EaxEaxCall& eax_call) const +void ALeffectslot::eax_get_fx_slot(const EaxCall& call) const { - switch (eax_call.get_property_id()) + switch (call.get_property_id()) { case EAXFXSLOT_ALLPARAMETERS: - eax_get_fx_slot_all(eax_call); + eax_get_fx_slot_all(call); break; case EAXFXSLOT_LOADEFFECT: - eax_call.set_value(eax_eax_fx_slot_.guidLoadEffect); + call.set_value(eax_eax_fx_slot_.guidLoadEffect); break; case EAXFXSLOT_VOLUME: - eax_call.set_value(eax_eax_fx_slot_.lVolume); + call.set_value(eax_eax_fx_slot_.lVolume); break; case EAXFXSLOT_LOCK: - eax_call.set_value(eax_eax_fx_slot_.lLock); + call.set_value(eax_eax_fx_slot_.lLock); break; case EAXFXSLOT_FLAGS: - eax_call.set_value(eax_eax_fx_slot_.ulFlags); + call.set_value(eax_eax_fx_slot_.ulFlags); break; case EAXFXSLOT_OCCLUSION: - eax_call.set_value(eax_eax_fx_slot_.lOcclusion); + call.set_value(eax_eax_fx_slot_.lOcclusion); break; case EAXFXSLOT_OCCLUSIONLFRATIO: - eax_call.set_value(eax_eax_fx_slot_.flOcclusionLFRatio); + call.set_value(eax_eax_fx_slot_.flOcclusionLFRatio); break; default: @@ -1410,17 +1394,16 @@ void ALeffectslot::eax_get_fx_slot( } // [[nodiscard]] -bool ALeffectslot::eax_get( - const EaxEaxCall& eax_call) +bool ALeffectslot::eax_get(const EaxCall& call) { - switch (eax_call.get_property_set_id()) + switch (call.get_property_set_id()) { - case EaxEaxCallPropertySetId::fx_slot: - eax_get_fx_slot(eax_call); + case EaxCallPropertySetId::fx_slot: + eax_get_fx_slot(call); break; - case EaxEaxCallPropertySetId::fx_slot_effect: - eax_dispatch_effect(eax_call); + case EaxCallPropertySetId::fx_slot_effect: + eax_dispatch_effect(call); break; default: @@ -1430,19 +1413,18 @@ bool ALeffectslot::eax_get( return false; } -void ALeffectslot::eax_set_fx_slot_effect( - ALenum al_effect_type) +void ALeffectslot::eax_set_fx_slot_effect(const EaxCall& call, ALenum al_effect_type) { if(!IsValidEffectType(al_effect_type)) eax_fail("Unsupported effect."); eax_effect_ = nullptr; - eax_effect_ = eax_create_eax_effect(al_effect_type); + eax_effect_ = eax_create_eax_effect(al_effect_type, call); eax_set_effect_slot_effect(*eax_effect_); } -void ALeffectslot::eax_set_fx_slot_effect() +void ALeffectslot::eax_set_fx_slot_effect(const EaxCall& call) { auto al_effect_type = ALenum{}; @@ -1506,7 +1488,7 @@ void ALeffectslot::eax_set_fx_slot_effect() eax_fail("Unsupported effect."); } - eax_set_fx_slot_effect(al_effect_type); + eax_set_fx_slot_effect(call, al_effect_type); } void ALeffectslot::eax_set_efx_effect_slot_gain() @@ -1535,52 +1517,47 @@ void ALeffectslot::eax_set_fx_slot_flags() eax_set_effect_slot_send_auto(); } -void ALeffectslot::eax_set_fx_slot_effect( - const EaxEaxCall& eax_call) +void ALeffectslot::eax_defer_fx_slot_effect(const EaxCall& call) { const auto& eax_effect_id = - eax_call.get_value(); + call.get_value(); eax_validate_fx_slot_effect(eax_effect_id); - eax_set_fx_slot_effect(eax_effect_id); + eax_set_fx_slot_effect(call, eax_effect_id); } -void ALeffectslot::eax_set_fx_slot_volume( - const EaxEaxCall& eax_call) +void ALeffectslot::eax_defer_fx_slot_volume(const EaxCall& call) { const auto& eax_volume = - eax_call.get_value(); + call.get_value(); eax_validate_fx_slot_volume(eax_volume); eax_set_fx_slot_volume(eax_volume); } -void ALeffectslot::eax_set_fx_slot_lock( - const EaxEaxCall& eax_call) +void ALeffectslot::eax_defer_fx_slot_lock(const EaxCall& call) { const auto& eax_lock = - eax_call.get_value(); + call.get_value(); eax_validate_fx_slot_lock(eax_lock); eax_set_fx_slot_lock(eax_lock); } -void ALeffectslot::eax_set_fx_slot_flags( - const EaxEaxCall& eax_call) +void ALeffectslot::eax_defer_fx_slot_flags(const EaxCall& call) { const auto& eax_flags = - eax_call.get_value(); + call.get_value(); - eax_validate_fx_slot_flags(eax_flags, eax_call.get_version()); + eax_validate_fx_slot_flags(call, eax_flags); eax_set_fx_slot_flags(eax_flags); } // [[nodiscard]] -bool ALeffectslot::eax_set_fx_slot_occlusion( - const EaxEaxCall& eax_call) +bool ALeffectslot::eax_defer_fx_slot_occlusion(const EaxCall& call) { const auto& eax_occlusion = - eax_call.get_value(); + call.get_value(); eax_validate_fx_slot_occlusion(eax_occlusion); @@ -1588,11 +1565,10 @@ bool ALeffectslot::eax_set_fx_slot_occlusion( } // [[nodiscard]] -bool ALeffectslot::eax_set_fx_slot_occlusion_lf_ratio( - const EaxEaxCall& eax_call) +bool ALeffectslot::eax_defer_fx_slot_occlusion_lf_ratio(const EaxCall& call) { const auto& eax_occlusion_lf_ratio = - eax_call.get_value(); + call.get_value(); eax_validate_fx_slot_occlusion_lf_ratio(eax_occlusion_lf_ratio); @@ -1600,18 +1576,17 @@ bool ALeffectslot::eax_set_fx_slot_occlusion_lf_ratio( } // [[nodiscard]] -bool ALeffectslot::eax_set_fx_slot_all( - const EaxEaxCall& eax_call) +bool ALeffectslot::eax_defer_fx_slot_all(const EaxCall& call) { - switch (eax_call.get_version()) + switch (call.get_version()) { case 4: { const auto& eax_all = - eax_call.get_value(); + call.get_value(); - eax_validate_fx_slot_all(eax_all, eax_call.get_version()); - eax_set_fx_slot_all(eax_all); + eax_validate_fx_slot_all(call, eax_all); + eax_set_fx_slot_all(call, eax_all); return false; } @@ -1619,10 +1594,10 @@ bool ALeffectslot::eax_set_fx_slot_all( case 5: { const auto& eax_all = - eax_call.get_value(); + call.get_value(); - eax_validate_fx_slot_all(eax_all, eax_call.get_version()); - return eax_set_fx_slot_all(eax_all); + eax_validate_fx_slot_all(call, eax_all); + return eax_set_fx_slot_all(call, eax_all); } default: @@ -1630,38 +1605,37 @@ bool ALeffectslot::eax_set_fx_slot_all( } } -bool ALeffectslot::eax_set_fx_slot( - const EaxEaxCall& eax_call) +bool ALeffectslot::eax_set_fx_slot(const EaxCall& call) { - switch (eax_call.get_property_id()) + switch (call.get_property_id()) { case EAXFXSLOT_NONE: return false; case EAXFXSLOT_ALLPARAMETERS: - return eax_set_fx_slot_all(eax_call); + return eax_defer_fx_slot_all(call); case EAXFXSLOT_LOADEFFECT: - eax_set_fx_slot_effect(eax_call); + eax_defer_fx_slot_effect(call); return false; case EAXFXSLOT_VOLUME: - eax_set_fx_slot_volume(eax_call); + eax_defer_fx_slot_volume(call); return false; case EAXFXSLOT_LOCK: - eax_set_fx_slot_lock(eax_call); + eax_defer_fx_slot_lock(call); return false; case EAXFXSLOT_FLAGS: - eax_set_fx_slot_flags(eax_call); + eax_defer_fx_slot_flags(call); return false; case EAXFXSLOT_OCCLUSION: - return eax_set_fx_slot_occlusion(eax_call); + return eax_defer_fx_slot_occlusion(call); case EAXFXSLOT_OCCLUSIONLFRATIO: - return eax_set_fx_slot_occlusion_lf_ratio(eax_call); + return eax_defer_fx_slot_occlusion_lf_ratio(call); default: @@ -1670,15 +1644,15 @@ bool ALeffectslot::eax_set_fx_slot( } // [[nodiscard]] -bool ALeffectslot::eax_set(const EaxEaxCall& eax_call) +bool ALeffectslot::eax_set(const EaxCall& call) { - switch(eax_call.get_property_set_id()) + switch(call.get_property_set_id()) { - case EaxEaxCallPropertySetId::fx_slot: - return eax_set_fx_slot(eax_call); + case EaxCallPropertySetId::fx_slot: + return eax_set_fx_slot(call); - case EaxEaxCallPropertySetId::fx_slot_effect: - eax_dispatch_effect(eax_call); + case EaxCallPropertySetId::fx_slot_effect: + eax_dispatch_effect(call); break; default: @@ -1688,8 +1662,8 @@ bool ALeffectslot::eax_set(const EaxEaxCall& eax_call) return false; } -void ALeffectslot::eax_dispatch_effect(const EaxEaxCall& eax_call) -{ if(eax_effect_) eax_effect_->dispatch(eax_call); } +void ALeffectslot::eax_dispatch_effect(const EaxCall& call) +{ if(eax_effect_) eax_effect_->dispatch(call); } void ALeffectslot::eax_apply_deferred() { @@ -1697,7 +1671,7 @@ void ALeffectslot::eax_apply_deferred() auto is_changed = false; if(eax_effect_) - is_changed = eax_effect_->apply_deferred(); + is_changed = eax_effect_->commit(); if(is_changed) eax_set_effect_slot_effect(*eax_effect_); } diff --git a/modules/openal-soft/al/auxeffectslot.h b/modules/openal-soft/al/auxeffectslot.h index ca0dcd3..8371137 100644 --- a/modules/openal-soft/al/auxeffectslot.h +++ b/modules/openal-soft/al/auxeffectslot.h @@ -18,10 +18,9 @@ #ifdef ALSOFT_EAX #include - -#include "eax_eax_call.h" -#include "eax_effect.h" -#include "eax_fx_slot_index.h" +#include "eax/call.h" +#include "eax/effect.h" +#include "eax/fx_slot_index.h" #endif // ALSOFT_EAX struct ALbuffer; @@ -74,6 +73,7 @@ struct ALeffectslot { #ifdef ALSOFT_EAX public: void eax_initialize( + const EaxCall& call, ALCcontext& al_context, EaxFxSlotIndexValue index); @@ -81,8 +81,8 @@ public: // [[nodiscard]] - bool eax_dispatch(const EaxEaxCall& eax_call) - { return eax_call.is_get() ? eax_get(eax_call) : eax_set(eax_call); } + bool eax_dispatch(const EaxCall& call) + { return call.is_get() ? eax_get(call) : eax_set(call); } void eax_unlock_legacy() noexcept; @@ -115,24 +115,20 @@ private: void eax_initialize_lock(); - void eax_initialize_effects(); + void eax_initialize_effects(const EaxCall& call); - void eax_get_fx_slot_all( - const EaxEaxCall& eax_call) const; + void eax_get_fx_slot_all(const EaxCall& call) const; - void eax_get_fx_slot( - const EaxEaxCall& eax_call) const; + void eax_get_fx_slot(const EaxCall& call) const; // [[nodiscard]] - bool eax_get( - const EaxEaxCall& eax_call); + bool eax_get(const EaxCall& call); - void eax_set_fx_slot_effect( - ALenum effect_type); + void eax_set_fx_slot_effect(const EaxCall& call, ALenum effect_type); - void eax_set_fx_slot_effect(); + void eax_set_fx_slot_effect(const EaxCall& call); void eax_set_efx_effect_slot_gain(); @@ -147,37 +143,16 @@ private: void eax_ensure_is_unlocked() const; + void eax_validate_fx_slot_effect(const GUID& eax_effect_id); + void eax_validate_fx_slot_volume(long eax_volume); + void eax_validate_fx_slot_lock(long eax_lock); + void eax_validate_fx_slot_flags(const EaxCall& call, unsigned long eax_flags); + void eax_validate_fx_slot_occlusion(long eax_occlusion); + void eax_validate_fx_slot_occlusion_lf_ratio(float eax_occlusion_lf_ratio); + void eax_validate_fx_slot_all(const EaxCall& call, const EAX40FXSLOTPROPERTIES& fx_slot); + void eax_validate_fx_slot_all(const EaxCall& call, const EAX50FXSLOTPROPERTIES& fx_slot); - void eax_validate_fx_slot_effect( - const GUID& eax_effect_id); - - void eax_validate_fx_slot_volume( - long eax_volume); - - void eax_validate_fx_slot_lock( - long eax_lock); - - void eax_validate_fx_slot_flags( - unsigned long eax_flags, - int eax_version); - - void eax_validate_fx_slot_occlusion( - long eax_occlusion); - - void eax_validate_fx_slot_occlusion_lf_ratio( - float eax_occlusion_lf_ratio); - - void eax_validate_fx_slot_all( - const EAX40FXSLOTPROPERTIES& fx_slot, - int eax_version); - - void eax_validate_fx_slot_all( - const EAX50FXSLOTPROPERTIES& fx_slot, - int eax_version); - - - void eax_set_fx_slot_effect( - const GUID& eax_effect_id); + void eax_set_fx_slot_effect(const EaxCall& call, const GUID& eax_effect_id); void eax_set_fx_slot_volume( long eax_volume); @@ -196,50 +171,38 @@ private: bool eax_set_fx_slot_occlusion_lf_ratio( float eax_occlusion_lf_ratio); - void eax_set_fx_slot_all( - const EAX40FXSLOTPROPERTIES& eax_fx_slot); + void eax_set_fx_slot_all(const EaxCall& call, const EAX40FXSLOTPROPERTIES& eax_fx_slot); // [[nodiscard]] - bool eax_set_fx_slot_all( - const EAX50FXSLOTPROPERTIES& eax_fx_slot); + bool eax_set_fx_slot_all(const EaxCall& call, const EAX50FXSLOTPROPERTIES& eax_fx_slot); - void eax_set_fx_slot_effect( - const EaxEaxCall& eax_call); + void eax_defer_fx_slot_effect(const EaxCall& call); - void eax_set_fx_slot_volume( - const EaxEaxCall& eax_call); + void eax_defer_fx_slot_volume(const EaxCall& call); - void eax_set_fx_slot_lock( - const EaxEaxCall& eax_call); + void eax_defer_fx_slot_lock(const EaxCall& call); - void eax_set_fx_slot_flags( - const EaxEaxCall& eax_call); + void eax_defer_fx_slot_flags(const EaxCall& call); // [[nodiscard]] - bool eax_set_fx_slot_occlusion( - const EaxEaxCall& eax_call); + bool eax_defer_fx_slot_occlusion(const EaxCall& call); // [[nodiscard]] - bool eax_set_fx_slot_occlusion_lf_ratio( - const EaxEaxCall& eax_call); + bool eax_defer_fx_slot_occlusion_lf_ratio(const EaxCall& call); // [[nodiscard]] - bool eax_set_fx_slot_all( - const EaxEaxCall& eax_call); + bool eax_defer_fx_slot_all(const EaxCall& call); - bool eax_set_fx_slot( - const EaxEaxCall& eax_call); + bool eax_set_fx_slot(const EaxCall& call); void eax_apply_deferred(); // [[nodiscard]] - bool eax_set( - const EaxEaxCall& eax_call); + bool eax_set(const EaxCall& call); - void eax_dispatch_effect( - const EaxEaxCall& eax_call); + void eax_dispatch_effect(const EaxCall& call); // `alAuxiliaryEffectSloti(effect_slot, AL_EFFECTSLOT_EFFECT, effect)` diff --git a/modules/openal-soft/al/buffer.cpp b/modules/openal-soft/al/buffer.cpp index 1340710..9b455b9 100644 --- a/modules/openal-soft/al/buffer.cpp +++ b/modules/openal-soft/al/buffer.cpp @@ -57,8 +57,8 @@ #include "opthelpers.h" #ifdef ALSOFT_EAX -#include "eax_globals.h" -#include "eax_x_ram.h" +#include "eax/globals.h" +#include "eax/x_ram.h" #endif // ALSOFT_EAX diff --git a/modules/openal-soft/al/buffer.h b/modules/openal-soft/al/buffer.h index b3a0f0d..7ded83b 100644 --- a/modules/openal-soft/al/buffer.h +++ b/modules/openal-soft/al/buffer.h @@ -13,7 +13,7 @@ #include "vector.h" #ifdef ALSOFT_EAX -#include "eax_x_ram.h" +#include "eax/x_ram.h" #endif // ALSOFT_EAX /* User formats */ diff --git a/modules/openal-soft/al/eax_api.cpp b/modules/openal-soft/al/eax/api.cpp similarity index 67% rename from modules/openal-soft/al/eax_api.cpp rename to modules/openal-soft/al/eax/api.cpp index 6b1f7fc..1eb5b20 100644 --- a/modules/openal-soft/al/eax_api.cpp +++ b/modules/openal-soft/al/eax/api.cpp @@ -9,7 +9,7 @@ #include -#include "al/eax_api.h" +#include "api.h" const GUID DSPROPSETID_EAX_ReverbProperties = @@ -269,74 +269,14 @@ const GUID EAX_RINGMODULATOR_EFFECT = }; -bool operator==( - const EAX40CONTEXTPROPERTIES& lhs, - const EAX40CONTEXTPROPERTIES& rhs) noexcept -{ - return - lhs.guidPrimaryFXSlotID == rhs.guidPrimaryFXSlotID && - lhs.flDistanceFactor == rhs.flDistanceFactor && - lhs.flAirAbsorptionHF == rhs.flAirAbsorptionHF && - lhs.flHFReference == rhs.flHFReference; -} - -bool operator==( - const EAX50CONTEXTPROPERTIES& lhs, - const EAX50CONTEXTPROPERTIES& rhs) noexcept -{ - return - static_cast(lhs) == static_cast(rhs) && - lhs.flMacroFXFactor == rhs.flMacroFXFactor; -} - - const GUID EAXCONTEXT_DEFAULTPRIMARYFXSLOTID = EAXPROPERTYID_EAX40_FXSlot0; -bool operator==( - const EAX40FXSLOTPROPERTIES& lhs, - const EAX40FXSLOTPROPERTIES& rhs) noexcept -{ - return - lhs.guidLoadEffect == rhs.guidLoadEffect && - lhs.lVolume == rhs.lVolume && - lhs.lLock == rhs.lLock && - lhs.ulFlags == rhs.ulFlags; -} - -bool operator==( - const EAX50FXSLOTPROPERTIES& lhs, - const EAX50FXSLOTPROPERTIES& rhs) noexcept -{ - return - static_cast(lhs) == static_cast(rhs) && - lhs.lOcclusion == rhs.lOcclusion && - lhs.flOcclusionLFRatio == rhs.flOcclusionLFRatio; -} - -const EAX50ACTIVEFXSLOTS EAX40SOURCE_DEFAULTACTIVEFXSLOTID = EAX50ACTIVEFXSLOTS +const EAX40ACTIVEFXSLOTS EAX40SOURCE_DEFAULTACTIVEFXSLOTID = EAX40ACTIVEFXSLOTS {{ EAX_NULL_GUID, EAXPROPERTYID_EAX40_FXSlot0, }}; -bool operator==( - const EAX50ACTIVEFXSLOTS& lhs, - const EAX50ACTIVEFXSLOTS& rhs) noexcept -{ - return std::equal( - std::cbegin(lhs.guidActiveFXSlots), - std::cend(lhs.guidActiveFXSlots), - std::begin(rhs.guidActiveFXSlots)); -} - -bool operator!=( - const EAX50ACTIVEFXSLOTS& lhs, - const EAX50ACTIVEFXSLOTS& rhs) noexcept -{ - return !(lhs == rhs); -} - - const EAX50ACTIVEFXSLOTS EAX50SOURCE_3DDEFAULTACTIVEFXSLOTID = EAX50ACTIVEFXSLOTS {{ EAX_NULL_GUID, @@ -354,44 +294,569 @@ const EAX50ACTIVEFXSLOTS EAX50SOURCE_2DDEFAULTACTIVEFXSLOTID = EAX50ACTIVEFXSLOT EAX_NULL_GUID, }}; -bool operator==( - const EAXREVERBPROPERTIES& lhs, - const EAXREVERBPROPERTIES& rhs) noexcept -{ - return - lhs.ulEnvironment == rhs.ulEnvironment && - lhs.flEnvironmentSize == rhs.flEnvironmentSize && - lhs.flEnvironmentDiffusion == rhs.flEnvironmentDiffusion && - lhs.lRoom == rhs.lRoom && - lhs.lRoomHF == rhs.lRoomHF && - lhs.lRoomLF == rhs.lRoomLF && - lhs.flDecayTime == rhs.flDecayTime && - lhs.flDecayHFRatio == rhs.flDecayHFRatio && - lhs.flDecayLFRatio == rhs.flDecayLFRatio && - lhs.lReflections == rhs.lReflections && - lhs.flReflectionsDelay == rhs.flReflectionsDelay && - lhs.vReflectionsPan == rhs.vReflectionsPan && - lhs.lReverb == rhs.lReverb && - lhs.flReverbDelay == rhs.flReverbDelay && - lhs.vReverbPan == rhs.vReverbPan && - lhs.flEchoTime == rhs.flEchoTime && - lhs.flEchoDepth == rhs.flEchoDepth && - lhs.flModulationTime == rhs.flModulationTime && - lhs.flModulationDepth == rhs.flModulationDepth && - lhs.flAirAbsorptionHF == rhs.flAirAbsorptionHF && - lhs.flHFReference == rhs.flHFReference && - lhs.flLFReference == rhs.flLFReference && - lhs.flRoomRolloffFactor == rhs.flRoomRolloffFactor && - lhs.ulFlags == rhs.ulFlags; -} - -bool operator!=( - const EAXREVERBPROPERTIES& lhs, - const EAXREVERBPROPERTIES& rhs) noexcept -{ - return !(lhs == rhs); -} +// 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 { @@ -1153,61 +1618,3 @@ const EaxReverbPresets EAXREVERB_PRESETS{{ EAXREVERB_PRESET_DIZZY, EAXREVERB_PRESET_PSYCHOTIC, }}; - -namespace { -constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_GENERIC = {EAX_ENVIRONMENT_GENERIC, 0.5F, 1.493F, 0.5F}; -constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_PADDEDCELL = {EAX_ENVIRONMENT_PADDEDCELL, 0.25F, 0.1F, 0.0F}; -constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_ROOM = {EAX_ENVIRONMENT_ROOM, 0.417F, 0.4F, 0.666F}; -constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_BATHROOM = {EAX_ENVIRONMENT_BATHROOM, 0.653F, 1.499F, 0.166F}; -constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_LIVINGROOM = {EAX_ENVIRONMENT_LIVINGROOM, 0.208F, 0.478F, 0.0F}; -constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_STONEROOM = {EAX_ENVIRONMENT_STONEROOM, 0.5F, 2.309F, 0.888F}; -constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_AUDITORIUM = {EAX_ENVIRONMENT_AUDITORIUM, 0.403F, 4.279F, 0.5F}; -constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_CONCERTHALL = {EAX_ENVIRONMENT_CONCERTHALL, 0.5F, 3.961F, 0.5F}; -constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_CAVE = {EAX_ENVIRONMENT_CAVE, 0.5F, 2.886F, 1.304F}; -constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_ARENA = {EAX_ENVIRONMENT_ARENA, 0.361F, 7.284F, 0.332F}; -constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_HANGAR = {EAX_ENVIRONMENT_HANGAR, 0.5F, 10.0F, 0.3F}; -constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_CARPETTEDHALLWAY = {EAX_ENVIRONMENT_CARPETEDHALLWAY, 0.153F, 0.259F, 2.0F}; -constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_HALLWAY = {EAX_ENVIRONMENT_HALLWAY, 0.361F, 1.493F, 0.0F}; -constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_STONECORRIDOR = {EAX_ENVIRONMENT_STONECORRIDOR, 0.444F, 2.697F, 0.638F}; -constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_ALLEY = {EAX_ENVIRONMENT_ALLEY, 0.25F, 1.752F, 0.776F}; -constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_FOREST = {EAX_ENVIRONMENT_FOREST, 0.111F, 3.145F, 0.472F}; -constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_CITY = {EAX_ENVIRONMENT_CITY, 0.111F, 2.767F, 0.224F}; -constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_MOUNTAINS = {EAX_ENVIRONMENT_MOUNTAINS, 0.194F, 7.841F, 0.472F}; -constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_QUARRY = {EAX_ENVIRONMENT_QUARRY, 1.0F, 1.499F, 0.5F}; -constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_PLAIN = {EAX_ENVIRONMENT_PLAIN, 0.097F, 2.767F, 0.224F}; -constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_PARKINGLOT = {EAX_ENVIRONMENT_PARKINGLOT, 0.208F, 1.652F, 1.5F}; -constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_SEWERPIPE = {EAX_ENVIRONMENT_SEWERPIPE, 0.652F, 2.886F, 0.25F}; -constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_UNDERWATER = {EAX_ENVIRONMENT_UNDERWATER, 1.0F, 1.499F, 0.0F}; -constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_DRUGGED = {EAX_ENVIRONMENT_DRUGGED, 0.875F, 8.392F, 1.388F}; -constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_DIZZY = {EAX_ENVIRONMENT_DIZZY, 0.139F, 17.234F, 0.666F}; -constexpr EAX_REVERBPROPERTIES EAX1REVERB_PRESET_PSYCHOTIC = {EAX_ENVIRONMENT_PSYCHOTIC, 0.486F, 7.563F, 0.806F}; -} // namespace - -const Eax1ReverbPresets EAX1REVERB_PRESETS{{ - EAX1REVERB_PRESET_GENERIC, - EAX1REVERB_PRESET_PADDEDCELL, - EAX1REVERB_PRESET_ROOM, - EAX1REVERB_PRESET_BATHROOM, - EAX1REVERB_PRESET_LIVINGROOM, - EAX1REVERB_PRESET_STONEROOM, - EAX1REVERB_PRESET_AUDITORIUM, - EAX1REVERB_PRESET_CONCERTHALL, - EAX1REVERB_PRESET_CAVE, - EAX1REVERB_PRESET_ARENA, - EAX1REVERB_PRESET_HANGAR, - EAX1REVERB_PRESET_CARPETTEDHALLWAY, - EAX1REVERB_PRESET_HALLWAY, - EAX1REVERB_PRESET_STONECORRIDOR, - EAX1REVERB_PRESET_ALLEY, - EAX1REVERB_PRESET_FOREST, - EAX1REVERB_PRESET_CITY, - EAX1REVERB_PRESET_MOUNTAINS, - EAX1REVERB_PRESET_QUARRY, - EAX1REVERB_PRESET_PLAIN, - EAX1REVERB_PRESET_PARKINGLOT, - EAX1REVERB_PRESET_SEWERPIPE, - EAX1REVERB_PRESET_UNDERWATER, - EAX1REVERB_PRESET_DRUGGED, - EAX1REVERB_PRESET_DIZZY, - EAX1REVERB_PRESET_PSYCHOTIC, -}}; diff --git a/modules/openal-soft/al/eax_api.h b/modules/openal-soft/al/eax/api.h similarity index 86% rename from modules/openal-soft/al/eax_api.h rename to modules/openal-soft/al/eax/api.h index d0737d1..a436acb 100644 --- a/modules/openal-soft/al/eax_api.h +++ b/modules/openal-soft/al/eax/api.h @@ -21,8 +21,7 @@ #ifndef GUID_DEFINED #define GUID_DEFINED -typedef struct _GUID -{ +typedef struct _GUID { std::uint32_t Data1; std::uint16_t Data2; std::uint16_t Data3; @@ -30,21 +29,16 @@ typedef struct _GUID } GUID; inline bool operator==(const GUID& lhs, const GUID& rhs) noexcept -{ - return std::memcmp(&lhs, &rhs, sizeof(GUID)) == 0; -} +{ return std::memcmp(&lhs, &rhs, sizeof(GUID)) == 0; } inline bool operator!=(const GUID& lhs, const GUID& rhs) noexcept -{ - return !(lhs == rhs); -} +{ return !(lhs == rhs); } #endif // GUID_DEFINED extern const GUID DSPROPSETID_EAX_ReverbProperties; -enum DSPROPERTY_EAX_REVERBPROPERTY : unsigned int -{ +enum DSPROPERTY_EAX_REVERBPROPERTY : unsigned int { DSPROPERTY_EAX_ALL, DSPROPERTY_EAX_ENVIRONMENT, DSPROPERTY_EAX_VOLUME, @@ -52,37 +46,25 @@ enum DSPROPERTY_EAX_REVERBPROPERTY : unsigned int DSPROPERTY_EAX_DAMPING, }; // DSPROPERTY_EAX_REVERBPROPERTY -struct EAX_REVERBPROPERTIES -{ +struct EAX_REVERBPROPERTIES { unsigned long environment; float fVolume; float fDecayTime_sec; float fDamping; }; // EAX_REVERBPROPERTIES -inline bool operator==(const EAX_REVERBPROPERTIES& lhs, const EAX_REVERBPROPERTIES& rhs) noexcept -{ - return std::memcmp(&lhs, &rhs, sizeof(EAX_REVERBPROPERTIES)) == 0; -} extern const GUID DSPROPSETID_EAXBUFFER_ReverbProperties; -enum DSPROPERTY_EAXBUFFER_REVERBPROPERTY : unsigned int -{ +enum DSPROPERTY_EAXBUFFER_REVERBPROPERTY : unsigned int { DSPROPERTY_EAXBUFFER_ALL, DSPROPERTY_EAXBUFFER_REVERBMIX, }; // DSPROPERTY_EAXBUFFER_REVERBPROPERTY -struct EAXBUFFER_REVERBPROPERTIES -{ +struct EAXBUFFER_REVERBPROPERTIES { float fMix; }; -inline bool operator==(const EAXBUFFER_REVERBPROPERTIES& lhs, const EAXBUFFER_REVERBPROPERTIES& rhs) noexcept -{ - return lhs.fMix == rhs.fMix; -} - constexpr auto EAX_BUFFER_MINREVERBMIX = 0.0F; constexpr auto EAX_BUFFER_MAXREVERBMIX = 1.0F; constexpr auto EAX_REVERBMIX_USEDISTANCE = -1.0F; @@ -90,9 +72,7 @@ constexpr auto EAX_REVERBMIX_USEDISTANCE = -1.0F; extern const GUID DSPROPSETID_EAX20_ListenerProperties; -enum DSPROPERTY_EAX20_LISTENERPROPERTY : - unsigned int -{ +enum DSPROPERTY_EAX20_LISTENERPROPERTY : unsigned int { DSPROPERTY_EAX20LISTENER_NONE, DSPROPERTY_EAX20LISTENER_ALLPARAMETERS, DSPROPERTY_EAX20LISTENER_ROOM, @@ -111,8 +91,7 @@ enum DSPROPERTY_EAX20_LISTENERPROPERTY : DSPROPERTY_EAX20LISTENER_FLAGS }; // DSPROPERTY_EAX20_LISTENERPROPERTY -struct EAX20LISTENERPROPERTIES -{ +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 @@ -129,13 +108,109 @@ struct EAX20LISTENERPROPERTIES 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, +}; -extern const GUID DSPROPSETID_EAX20_BufferProperties; +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; -enum DSPROPERTY_EAX20_BUFFERPROPERTY : - unsigned int -{ +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, @@ -153,9 +228,7 @@ enum DSPROPERTY_EAX20_BUFFERPROPERTY : DSPROPERTY_EAX20BUFFER_FLAGS }; // DSPROPERTY_EAX20_BUFFERPROPERTY - -struct EAX20BUFFERPROPERTIES -{ +struct EAX20BUFFERPROPERTIES { long lDirect; // direct path level long lDirectHF; // direct path level at high frequencies long lRoom; // room effect level @@ -171,7 +244,6 @@ struct EAX20BUFFERPROPERTIES unsigned long dwFlags; // modifies the behavior of properties }; // EAX20BUFFERPROPERTIES - extern const GUID DSPROPSETID_EAX30_ListenerProperties; extern const GUID DSPROPSETID_EAX30_BufferProperties; @@ -197,8 +269,7 @@ extern const GUID EAX_NULL_GUID; extern const GUID EAX_PrimaryFXSlotID; -struct EAXVECTOR -{ +struct EAXVECTOR { float x; float y; float z; @@ -216,8 +287,7 @@ extern const GUID EAXPROPERTYID_EAX40_Context; extern const GUID EAXPROPERTYID_EAX50_Context; // EAX50 -enum : - unsigned long +enum : unsigned long { HEADPHONES = 0, SPEAKERS_2, @@ -228,9 +298,7 @@ enum : }; // EAX50 -enum : - unsigned long -{ +enum : unsigned long { EAX_40 = 5, // EAX 4.0 EAX_50 = 6, // EAX 5.0 }; @@ -244,15 +312,12 @@ constexpr auto EAXCONTEXT_MAXMAXACTIVESENDS = 4UL; constexpr auto EAXCONTEXT_DEFAULTMAXACTIVESENDS = 2UL; // EAX50 -struct EAXSESSIONPROPERTIES -{ +struct EAXSESSIONPROPERTIES { unsigned long ulEAXVersion; unsigned long ulMaxActiveSends; }; // EAXSESSIONPROPERTIES -enum EAXCONTEXT_PROPERTY : - unsigned int -{ +enum EAXCONTEXT_PROPERTY : unsigned int { EAXCONTEXT_NONE = 0, EAXCONTEXT_ALLPARAMETERS, EAXCONTEXT_PRIMARYFXSLOTID, @@ -267,28 +332,16 @@ enum EAXCONTEXT_PROPERTY : EAXCONTEXT_MACROFXFACTOR, }; // EAXCONTEXT_PROPERTY -struct EAX40CONTEXTPROPERTIES -{ +struct EAX40CONTEXTPROPERTIES { GUID guidPrimaryFXSlotID; float flDistanceFactor; float flAirAbsorptionHF; float flHFReference; }; // EAX40CONTEXTPROPERTIES -struct EAX50CONTEXTPROPERTIES : - public EAX40CONTEXTPROPERTIES -{ +struct EAX50CONTEXTPROPERTIES : public EAX40CONTEXTPROPERTIES { float flMacroFXFactor; -}; // EAX40CONTEXTPROPERTIES - - -bool operator==( - const EAX40CONTEXTPROPERTIES& lhs, - const EAX40CONTEXTPROPERTIES& rhs) noexcept; - -bool operator==( - const EAX50CONTEXTPROPERTIES& lhs, - const EAX50CONTEXTPROPERTIES& rhs) noexcept; +}; // EAX50CONTEXTPROPERTIES constexpr auto EAXCONTEXT_MINDISTANCEFACTOR = FLT_MIN; @@ -309,26 +362,17 @@ constexpr auto EAXCONTEXT_DEFAULTMACROFXFACTOR = 0.0F; extern const GUID EAXPROPERTYID_EAX40_FXSlot0; - extern const GUID EAXPROPERTYID_EAX50_FXSlot0; - extern const GUID EAXPROPERTYID_EAX40_FXSlot1; - extern const GUID EAXPROPERTYID_EAX50_FXSlot1; - extern const GUID EAXPROPERTYID_EAX40_FXSlot2; - extern const GUID EAXPROPERTYID_EAX50_FXSlot2; - extern const GUID EAXPROPERTYID_EAX40_FXSlot3; - extern const GUID EAXPROPERTYID_EAX50_FXSlot3; extern const GUID EAXCONTEXT_DEFAULTPRIMARYFXSLOTID; -enum EAXFXSLOT_PROPERTY : - unsigned int -{ +enum EAXFXSLOT_PROPERTY : unsigned int { EAXFXSLOT_PARAMETER = 0, EAXFXSLOT_NONE = 0x10000, @@ -358,9 +402,7 @@ constexpr auto EAXFXSLOT_DEFAULTVOLUME = 0L; constexpr auto EAXFXSLOT_MINLOCK = 0L; constexpr auto EAXFXSLOT_MAXLOCK = 1L; -enum : - long -{ +enum : long { EAXFXSLOT_UNLOCKED = 0, EAXFXSLOT_LOCKED = 1 }; @@ -379,39 +421,24 @@ constexpr auto EAX50FXSLOT_DEFAULTFLAGS = EAXFXSLOTFLAGS_ENVIRONMENT | EAXFXSLOTFLAGS_UPMIX; // ignored for reverb; -struct EAX40FXSLOTPROPERTIES -{ +struct EAX40FXSLOTPROPERTIES { GUID guidLoadEffect; long lVolume; long lLock; unsigned long ulFlags; }; // EAX40FXSLOTPROPERTIES -struct EAX50FXSLOTPROPERTIES : - public EAX40FXSLOTPROPERTIES -{ +struct EAX50FXSLOTPROPERTIES : public EAX40FXSLOTPROPERTIES { long lOcclusion; float flOcclusionLFRatio; }; // EAX50FXSLOTPROPERTIES -bool operator==( - const EAX40FXSLOTPROPERTIES& lhs, - const EAX40FXSLOTPROPERTIES& rhs) noexcept; - -bool operator==( - const EAX50FXSLOTPROPERTIES& lhs, - const EAX50FXSLOTPROPERTIES& rhs) noexcept; - extern const GUID EAXPROPERTYID_EAX40_Source; - extern const GUID EAXPROPERTYID_EAX50_Source; // Source object properties -enum EAXSOURCE_PROPERTY : - unsigned int -{ +enum EAXSOURCE_PROPERTY : unsigned int { // EAX30 - EAXSOURCE_NONE, EAXSOURCE_ALLPARAMETERS, EAXSOURCE_OBSTRUCTIONPARAMETERS, @@ -437,7 +464,6 @@ enum EAXSOURCE_PROPERTY : EAXSOURCE_FLAGS, // EAX40 - EAXSOURCE_SENDPARAMETERS, EAXSOURCE_ALLSENDPARAMETERS, EAXSOURCE_OCCLUSIONSENDPARAMETERS, @@ -445,7 +471,6 @@ enum EAXSOURCE_PROPERTY : EAXSOURCE_ACTIVEFXSLOTID, // EAX50 - EAXSOURCE_MACROFXFACTOR, EAXSOURCE_SPEAKERLEVELS, EAXSOURCE_ALL2DPARAMETERS, @@ -457,9 +482,7 @@ constexpr auto EAXSOURCEFLAGS_ROOMAUTO = 0x00000002UL; // relates to EAXSOURCE_R constexpr auto EAXSOURCEFLAGS_ROOMHFAUTO = 0x00000004UL; // relates to EAXSOURCE_ROOMHF // EAX50 constexpr auto EAXSOURCEFLAGS_3DELEVATIONFILTER = 0x00000008UL; -// EAX50 constexpr auto EAXSOURCEFLAGS_UPMIX = 0x00000010UL; -// EAX50 constexpr auto EAXSOURCEFLAGS_APPLYSPEAKERLEVELS = 0x00000020UL; constexpr auto EAX20SOURCEFLAGS_RESERVED = 0xFFFFFFF8UL; // reserved future use @@ -548,8 +571,6 @@ constexpr auto EAXSOURCE_MINMACROFXFACTOR = 0.0F; constexpr auto EAXSOURCE_MAXMACROFXFACTOR = 1.0F; constexpr auto EAXSOURCE_DEFAULTMACROFXFACTOR = 1.0F; -// EAX50 - constexpr auto EAXSOURCE_MINSPEAKERLEVEL = -10'000L; constexpr auto EAXSOURCE_MAXSPEAKERLEVEL = 0L; constexpr auto EAXSOURCE_DEFAULTSPEAKERLEVEL = -10'000L; @@ -559,9 +580,7 @@ constexpr auto EAXSOURCE_DEFAULTFLAGS = EAXSOURCEFLAGS_ROOMAUTO | EAXSOURCEFLAGS_ROOMHFAUTO; -enum : - long -{ +enum : long { EAXSPEAKER_FRONT_LEFT = 1, EAXSPEAKER_FRONT_CENTER = 2, EAXSPEAKER_FRONT_RIGHT = 3, @@ -581,8 +600,7 @@ constexpr auto EAX50SOURCE_DEFAULTFLAGS = EAXSOURCEFLAGS_ROOMHFAUTO | EAXSOURCEFLAGS_UPMIX; -struct EAX30SOURCEPROPERTIES -{ +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) @@ -603,14 +621,11 @@ struct EAX30SOURCEPROPERTIES unsigned long ulFlags; // modifies the behavior of properties }; // EAX30SOURCEPROPERTIES -struct EAX50SOURCEPROPERTIES : - public EAX30SOURCEPROPERTIES -{ +struct EAX50SOURCEPROPERTIES : public EAX30SOURCEPROPERTIES { float flMacroFXFactor; }; // EAX50SOURCEPROPERTIES -struct EAXSOURCEALLSENDPROPERTIES -{ +struct EAXSOURCEALLSENDPROPERTIES { GUID guidReceivingFXSlotID; long lSend; // send level (at low and mid frequencies) long lSendHF; // relative send level at high frequencies @@ -622,8 +637,7 @@ struct EAXSOURCEALLSENDPROPERTIES float flExclusionLFRatio; }; // EAXSOURCEALLSENDPROPERTIES -struct EAXSOURCE2DPROPERTIES -{ +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) @@ -631,40 +645,27 @@ struct EAXSOURCE2DPROPERTIES unsigned long ulFlags; // modifies the behavior of properties }; // EAXSOURCE2DPROPERTIES -struct EAXSPEAKERLEVELPROPERTIES -{ +struct EAXSPEAKERLEVELPROPERTIES { long lSpeakerID; long lLevel; }; // EAXSPEAKERLEVELPROPERTIES -struct EAX40ACTIVEFXSLOTS -{ +struct EAX40ACTIVEFXSLOTS { GUID guidActiveFXSlots[EAX40_MAX_ACTIVE_FXSLOTS]; }; // EAX40ACTIVEFXSLOTS -struct EAX50ACTIVEFXSLOTS -{ +struct EAX50ACTIVEFXSLOTS { GUID guidActiveFXSlots[EAX50_MAX_ACTIVE_FXSLOTS]; }; // EAX50ACTIVEFXSLOTS -bool operator==( - const EAX50ACTIVEFXSLOTS& lhs, - const EAX50ACTIVEFXSLOTS& rhs) noexcept; - -bool operator!=( - const EAX50ACTIVEFXSLOTS& lhs, - const EAX50ACTIVEFXSLOTS& rhs) noexcept; - // Use this structure for EAXSOURCE_OBSTRUCTIONPARAMETERS property. -struct EAXOBSTRUCTIONPROPERTIES -{ +struct EAXOBSTRUCTIONPROPERTIES { long lObstruction; float flObstructionLFRatio; }; // EAXOBSTRUCTIONPROPERTIES // Use this structure for EAXSOURCE_OCCLUSIONPARAMETERS property. -struct EAXOCCLUSIONPROPERTIES -{ +struct EAXOCCLUSIONPROPERTIES { long lOcclusion; float flOcclusionLFRatio; float flOcclusionRoomRatio; @@ -672,23 +673,20 @@ struct EAXOCCLUSIONPROPERTIES }; // EAXOCCLUSIONPROPERTIES // Use this structure for EAXSOURCE_EXCLUSIONPARAMETERS property. -struct EAXEXCLUSIONPROPERTIES -{ +struct EAXEXCLUSIONPROPERTIES { long lExclusion; float flExclusionLFRatio; }; // EAXEXCLUSIONPROPERTIES // Use this structure for EAXSOURCE_SENDPARAMETERS properties. -struct EAXSOURCESENDPROPERTIES -{ +struct EAXSOURCESENDPROPERTIES { GUID guidReceivingFXSlotID; long lSend; long lSendHF; }; // EAXSOURCESENDPROPERTIES // Use this structure for EAXSOURCE_OCCLUSIONSENDPARAMETERS -struct EAXSOURCEOCCLUSIONSENDPROPERTIES -{ +struct EAXSOURCEOCCLUSIONSENDPROPERTIES { GUID guidReceivingFXSlotID; long lOcclusion; float flOcclusionLFRatio; @@ -697,14 +695,13 @@ struct EAXSOURCEOCCLUSIONSENDPROPERTIES }; // EAXSOURCEOCCLUSIONSENDPROPERTIES // Use this structure for EAXSOURCE_EXCLUSIONSENDPARAMETERS -struct EAXSOURCEEXCLUSIONSENDPROPERTIES -{ +struct EAXSOURCEEXCLUSIONSENDPROPERTIES { GUID guidReceivingFXSlotID; long lExclusion; float flExclusionLFRatio; }; // EAXSOURCEEXCLUSIONSENDPROPERTIES -extern const EAX50ACTIVEFXSLOTS EAX40SOURCE_DEFAULTACTIVEFXSLOTID; +extern const EAX40ACTIVEFXSLOTS EAX40SOURCE_DEFAULTACTIVEFXSLOTID; extern const EAX50ACTIVEFXSLOTS EAX50SOURCE_3DDEFAULTACTIVEFXSLOTID; @@ -716,9 +713,7 @@ extern const EAX50ACTIVEFXSLOTS EAX50SOURCE_2DDEFAULTACTIVEFXSLOTID; extern const GUID EAX_REVERB_EFFECT; // Reverb effect properties -enum EAXREVERB_PROPERTY : - unsigned int -{ +enum EAXREVERB_PROPERTY : unsigned int { EAXREVERB_NONE, EAXREVERB_ALLPARAMETERS, EAXREVERB_ENVIRONMENT, @@ -748,9 +743,7 @@ enum EAXREVERB_PROPERTY : }; // EAXREVERB_PROPERTY // used by EAXREVERB_ENVIRONMENT -enum : - unsigned long -{ +enum : unsigned long { EAX_ENVIRONMENT_GENERIC, EAX_ENVIRONMENT_PADDEDCELL, EAX_ENVIRONMENT_ROOM, @@ -816,8 +809,7 @@ constexpr auto EAXREVERBFLAGS_DECAYHFLIMIT = 0x00000020UL; constexpr auto EAXREVERBFLAGS_RESERVED = 0xFFFFFF00UL; // reserved future use -struct EAXREVERBPROPERTIES -{ +struct EAXREVERBPROPERTIES { unsigned long ulEnvironment; // sets all reverb properties float flEnvironmentSize; // environment size in meters float flEnvironmentDiffusion; // environment diffusion @@ -844,14 +836,6 @@ struct EAXREVERBPROPERTIES unsigned long ulFlags; // modifies the behavior of properties }; // EAXREVERBPROPERTIES -bool operator==( - const EAXREVERBPROPERTIES& lhs, - const EAXREVERBPROPERTIES& rhs) noexcept; - -bool operator!=( - const EAXREVERBPROPERTIES& lhs, - const EAXREVERBPROPERTIES& rhs) noexcept; - constexpr auto EAXREVERB_MINENVIRONMENT = static_cast(EAX_ENVIRONMENT_GENERIC); constexpr auto EAX1REVERB_MAXENVIRONMENT = static_cast(EAX_ENVIRONMENT_PSYCHOTIC); @@ -957,28 +941,27 @@ constexpr auto EAXREVERB_DEFAULTFLAGS = EAXREVERBFLAGS_DECAYHFLIMIT; -using EaxReverbPresets = std::array; -extern const EaxReverbPresets EAXREVERB_PRESETS; - - using Eax1ReverbPresets = std::array; extern const Eax1ReverbPresets EAX1REVERB_PRESETS; +using Eax2ReverbPresets = std::array; +extern const Eax2ReverbPresets EAX2REVERB_PRESETS; + +using EaxReverbPresets = std::array; +extern const EaxReverbPresets EAXREVERB_PRESETS; + // AGC Compressor Effect extern const GUID EAX_AGCCOMPRESSOR_EFFECT; -enum EAXAGCCOMPRESSOR_PROPERTY : - unsigned int -{ +enum EAXAGCCOMPRESSOR_PROPERTY : unsigned int { EAXAGCCOMPRESSOR_NONE, EAXAGCCOMPRESSOR_ALLPARAMETERS, EAXAGCCOMPRESSOR_ONOFF, }; // EAXAGCCOMPRESSOR_PROPERTY -struct EAXAGCCOMPRESSORPROPERTIES -{ +struct EAXAGCCOMPRESSORPROPERTIES { unsigned long ulOnOff; // Switch Compressor on or off }; // EAXAGCCOMPRESSORPROPERTIES @@ -992,9 +975,7 @@ constexpr auto EAXAGCCOMPRESSOR_DEFAULTONOFF = EAXAGCCOMPRESSOR_MAXONOFF; extern const GUID EAX_AUTOWAH_EFFECT; -enum EAXAUTOWAH_PROPERTY : - unsigned int -{ +enum EAXAUTOWAH_PROPERTY : unsigned int { EAXAUTOWAH_NONE, EAXAUTOWAH_ALLPARAMETERS, EAXAUTOWAH_ATTACKTIME, @@ -1003,8 +984,7 @@ enum EAXAUTOWAH_PROPERTY : EAXAUTOWAH_PEAKLEVEL, }; // EAXAUTOWAH_PROPERTY -struct EAXAUTOWAHPROPERTIES -{ +struct EAXAUTOWAHPROPERTIES { float flAttackTime; // Attack time (seconds) float flReleaseTime; // Release time (seconds) long lResonance; // Resonance (mB) @@ -1033,10 +1013,7 @@ constexpr auto EAXAUTOWAH_DEFAULTPEAKLEVEL = 2100L; extern const GUID EAX_CHORUS_EFFECT; - -enum EAXCHORUS_PROPERTY : - unsigned int -{ +enum EAXCHORUS_PROPERTY : unsigned int { EAXCHORUS_NONE, EAXCHORUS_ALLPARAMETERS, EAXCHORUS_WAVEFORM, @@ -1047,15 +1024,12 @@ enum EAXCHORUS_PROPERTY : EAXCHORUS_DELAY, }; // EAXCHORUS_PROPERTY -enum : - unsigned long -{ +enum : unsigned long { EAX_CHORUS_SINUSOID, EAX_CHORUS_TRIANGLE, }; -struct EAXCHORUSPROPERTIES -{ +struct EAXCHORUSPROPERTIES { unsigned long ulWaveform; // Waveform selector - see enum above long lPhase; // Phase (Degrees) float flRate; // Rate (Hz) @@ -1094,9 +1068,7 @@ constexpr auto EAXCHORUS_DEFAULTDELAY = 0.016F; extern const GUID EAX_DISTORTION_EFFECT; -enum EAXDISTORTION_PROPERTY : - unsigned int -{ +enum EAXDISTORTION_PROPERTY : unsigned int { EAXDISTORTION_NONE, EAXDISTORTION_ALLPARAMETERS, EAXDISTORTION_EDGE, @@ -1106,9 +1078,7 @@ enum EAXDISTORTION_PROPERTY : EAXDISTORTION_EQBANDWIDTH, }; // EAXDISTORTION_PROPERTY - -struct EAXDISTORTIONPROPERTIES -{ +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) @@ -1142,10 +1112,7 @@ constexpr auto EAXDISTORTION_DEFAULTEQBANDWIDTH = 3600.0F; extern const GUID EAX_ECHO_EFFECT; - -enum EAXECHO_PROPERTY : - unsigned int -{ +enum EAXECHO_PROPERTY : unsigned int { EAXECHO_NONE, EAXECHO_ALLPARAMETERS, EAXECHO_DELAY, @@ -1155,9 +1122,7 @@ enum EAXECHO_PROPERTY : EAXECHO_SPREAD, }; // EAXECHO_PROPERTY - -struct EAXECHOPROPERTIES -{ +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) @@ -1191,10 +1156,7 @@ constexpr auto EAXECHO_DEFAULTSPREAD = -1.0F; extern const GUID EAX_EQUALIZER_EFFECT; - -enum EAXEQUALIZER_PROPERTY : - unsigned int -{ +enum EAXEQUALIZER_PROPERTY : unsigned int { EAXEQUALIZER_NONE, EAXEQUALIZER_ALLPARAMETERS, EAXEQUALIZER_LOWGAIN, @@ -1209,9 +1171,7 @@ enum EAXEQUALIZER_PROPERTY : EAXEQUALIZER_HIGHCUTOFF, }; // EAXEQUALIZER_PROPERTY - -struct EAXEQUALIZERPROPERTIES -{ +struct EAXEQUALIZERPROPERTIES { long lLowGain; // (mB) float flLowCutOff; // (Hz) long lMid1Gain; // (mB) @@ -1270,9 +1230,7 @@ constexpr auto EAXEQUALIZER_DEFAULTHIGHCUTOFF = 6000.0F; extern const GUID EAX_FLANGER_EFFECT; -enum EAXFLANGER_PROPERTY : - unsigned int -{ +enum EAXFLANGER_PROPERTY : unsigned int { EAXFLANGER_NONE, EAXFLANGER_ALLPARAMETERS, EAXFLANGER_WAVEFORM, @@ -1283,15 +1241,12 @@ enum EAXFLANGER_PROPERTY : EAXFLANGER_DELAY, }; // EAXFLANGER_PROPERTY -enum : - unsigned long -{ +enum : unsigned long { EAX_FLANGER_SINUSOID, EAX_FLANGER_TRIANGLE, }; -struct EAXFLANGERPROPERTIES -{ +struct EAXFLANGERPROPERTIES { unsigned long ulWaveform; // Waveform selector - see enum above long lPhase; // Phase (Degrees) float flRate; // Rate (Hz) @@ -1330,9 +1285,7 @@ constexpr auto EAXFLANGER_DEFAULTDELAY = 0.002F; extern const GUID EAX_FREQUENCYSHIFTER_EFFECT; -enum EAXFREQUENCYSHIFTER_PROPERTY : - unsigned int -{ +enum EAXFREQUENCYSHIFTER_PROPERTY : unsigned int { EAXFREQUENCYSHIFTER_NONE, EAXFREQUENCYSHIFTER_ALLPARAMETERS, EAXFREQUENCYSHIFTER_FREQUENCY, @@ -1340,16 +1293,13 @@ enum EAXFREQUENCYSHIFTER_PROPERTY : EAXFREQUENCYSHIFTER_RIGHTDIRECTION, }; // EAXFREQUENCYSHIFTER_PROPERTY -enum : - unsigned long -{ +enum : unsigned long { EAX_FREQUENCYSHIFTER_DOWN, EAX_FREQUENCYSHIFTER_UP, EAX_FREQUENCYSHIFTER_OFF }; -struct EAXFREQUENCYSHIFTERPROPERTIES -{ +struct EAXFREQUENCYSHIFTERPROPERTIES { float flFrequency; // (Hz) unsigned long ulLeftDirection; // see enum above unsigned long ulRightDirection; // see enum above @@ -1373,9 +1323,7 @@ constexpr auto EAXFREQUENCYSHIFTER_DEFAULTRIGHTDIRECTION = EAXFREQUENCYSHIFTER_M extern const GUID EAX_VOCALMORPHER_EFFECT; -enum EAXVOCALMORPHER_PROPERTY : - unsigned int -{ +enum EAXVOCALMORPHER_PROPERTY : unsigned int { EAXVOCALMORPHER_NONE, EAXVOCALMORPHER_ALLPARAMETERS, EAXVOCALMORPHER_PHONEMEA, @@ -1386,9 +1334,7 @@ enum EAXVOCALMORPHER_PROPERTY : EAXVOCALMORPHER_RATE, }; // EAXVOCALMORPHER_PROPERTY -enum : - unsigned long -{ +enum : unsigned long { A, E, I, @@ -1421,17 +1367,14 @@ enum : Z, }; -enum : - unsigned long -{ +enum : unsigned long { EAX_VOCALMORPHER_SINUSOID, EAX_VOCALMORPHER_TRIANGLE, EAX_VOCALMORPHER_SAWTOOTH }; // Use this structure for EAXVOCALMORPHER_ALLPARAMETERS -struct EAXVOCALMORPHERPROPERTIES -{ +struct EAXVOCALMORPHERPROPERTIES { unsigned long ulPhonemeA; // see enum above long lPhonemeACoarseTuning; // (semitones) unsigned long ulPhonemeB; // see enum above @@ -1470,17 +1413,14 @@ constexpr auto EAXVOCALMORPHER_DEFAULTRATE = 1.41F; extern const GUID EAX_PITCHSHIFTER_EFFECT; -enum EAXPITCHSHIFTER_PROPERTY : - unsigned int -{ +enum EAXPITCHSHIFTER_PROPERTY : unsigned int { EAXPITCHSHIFTER_NONE, EAXPITCHSHIFTER_ALLPARAMETERS, EAXPITCHSHIFTER_COARSETUNE, EAXPITCHSHIFTER_FINETUNE, }; // EAXPITCHSHIFTER_PROPERTY -struct EAXPITCHSHIFTERPROPERTIES -{ +struct EAXPITCHSHIFTERPROPERTIES { long lCoarseTune; // Amount of pitch shift (semitones) long lFineTune; // Amount of pitch shift (cents) }; // EAXPITCHSHIFTERPROPERTIES @@ -1499,9 +1439,7 @@ constexpr auto EAXPITCHSHIFTER_DEFAULTFINETUNE = 0L; extern const GUID EAX_RINGMODULATOR_EFFECT; -enum EAXRINGMODULATOR_PROPERTY : - unsigned int -{ +enum EAXRINGMODULATOR_PROPERTY : unsigned int { EAXRINGMODULATOR_NONE, EAXRINGMODULATOR_ALLPARAMETERS, EAXRINGMODULATOR_FREQUENCY, @@ -1509,17 +1447,14 @@ enum EAXRINGMODULATOR_PROPERTY : EAXRINGMODULATOR_WAVEFORM, }; // EAXRINGMODULATOR_PROPERTY -enum : - unsigned long -{ +enum : unsigned long { EAX_RINGMODULATOR_SINUSOID, EAX_RINGMODULATOR_SAWTOOTH, EAX_RINGMODULATOR_SQUARE, }; // Use this structure for EAXRINGMODULATOR_ALLPARAMETERS -struct EAXRINGMODULATORPROPERTIES -{ +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 @@ -1553,5 +1488,4 @@ using LPEAXGET = ALenum(AL_APIENTRY*)( ALvoid* property_buffer, ALuint property_size); - #endif // !EAX_API_INCLUDED diff --git a/modules/openal-soft/al/eax/call.cpp b/modules/openal-soft/al/eax/call.cpp new file mode 100644 index 0000000..1fd0596 --- /dev/null +++ b/modules/openal-soft/al/eax/call.cpp @@ -0,0 +1,212 @@ +#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) + : type_{type}, version_{0}, property_set_id_{EaxCallPropertySetId::none} + , property_id_{property_id & ~deferred_flag}, property_source_id_{property_source_id} + , property_buffer_{property_buffer}, property_size_{property_size} +{ + switch (type_) + { + case EaxCallType::get: + case EaxCallType::set: + break; + + default: + fail("Invalid type."); + } + + if (false) + { + } + else if (property_set_guid == EAXPROPERTYID_EAX40_Context) + { + version_ = 4; + property_set_id_ = EaxCallPropertySetId::context; + } + else if (property_set_guid == EAXPROPERTYID_EAX50_Context) + { + version_ = 5; + property_set_id_ = EaxCallPropertySetId::context; + } + else if (property_set_guid == DSPROPSETID_EAX20_ListenerProperties) + { + version_ = 2; + fx_slot_index_ = 0u; + property_set_id_ = EaxCallPropertySetId::fx_slot_effect; + } + else if (property_set_guid == DSPROPSETID_EAX30_ListenerProperties) + { + version_ = 3; + fx_slot_index_ = 0u; + property_set_id_ = EaxCallPropertySetId::fx_slot_effect; + } + else if (property_set_guid == EAXPROPERTYID_EAX40_FXSlot0) + { + version_ = 4; + fx_slot_index_ = 0u; + property_set_id_ = EaxCallPropertySetId::fx_slot; + } + else if (property_set_guid == EAXPROPERTYID_EAX50_FXSlot0) + { + version_ = 5; + fx_slot_index_ = 0u; + property_set_id_ = EaxCallPropertySetId::fx_slot; + } + else if (property_set_guid == EAXPROPERTYID_EAX40_FXSlot1) + { + version_ = 4; + fx_slot_index_ = 1u; + property_set_id_ = EaxCallPropertySetId::fx_slot; + } + else if (property_set_guid == EAXPROPERTYID_EAX50_FXSlot1) + { + version_ = 5; + fx_slot_index_ = 1u; + property_set_id_ = EaxCallPropertySetId::fx_slot; + } + else if (property_set_guid == EAXPROPERTYID_EAX40_FXSlot2) + { + version_ = 4; + fx_slot_index_ = 2u; + property_set_id_ = EaxCallPropertySetId::fx_slot; + } + else if (property_set_guid == EAXPROPERTYID_EAX50_FXSlot2) + { + version_ = 5; + fx_slot_index_ = 2u; + property_set_id_ = EaxCallPropertySetId::fx_slot; + } + else if (property_set_guid == EAXPROPERTYID_EAX40_FXSlot3) + { + version_ = 4; + fx_slot_index_ = 3u; + property_set_id_ = EaxCallPropertySetId::fx_slot; + } + else if (property_set_guid == EAXPROPERTYID_EAX50_FXSlot3) + { + version_ = 5; + fx_slot_index_ = 3u; + property_set_id_ = EaxCallPropertySetId::fx_slot; + } + else if (property_set_guid == DSPROPSETID_EAX20_BufferProperties) + { + version_ = 2; + property_set_id_ = EaxCallPropertySetId::source; + } + else if (property_set_guid == DSPROPSETID_EAX30_BufferProperties) + { + version_ = 3; + property_set_id_ = EaxCallPropertySetId::source; + } + else if (property_set_guid == EAXPROPERTYID_EAX40_Source) + { + version_ = 4; + property_set_id_ = EaxCallPropertySetId::source; + } + else if (property_set_guid == EAXPROPERTYID_EAX50_Source) + { + version_ = 5; + property_set_id_ = EaxCallPropertySetId::source; + } + else if (property_set_guid == DSPROPSETID_EAX_ReverbProperties) + { + version_ = 1; + fx_slot_index_ = 0u; + property_set_id_ = EaxCallPropertySetId::fx_slot_effect; + } + else if (property_set_guid == DSPROPSETID_EAXBUFFER_ReverbProperties) + { + version_ = 1; + property_set_id_ = EaxCallPropertySetId::source; + } + else + { + fail("Unsupported property set id."); + } + + if (version_ < 1 || version_ > 5) + { + fail("EAX version out of range."); + } + + if(!(property_id&deferred_flag)) + { + if(property_set_id_ != EaxCallPropertySetId::fx_slot && property_id_ != 0) + { + if (property_buffer == nullptr) + { + fail("Null property buffer."); + } + + if (property_size == 0) + { + fail("Empty property."); + } + } + } + + if(property_set_id_ == EaxCallPropertySetId::source && property_source_id_ == 0) + { + fail("Null AL source id."); + } + + if (property_set_id_ == EaxCallPropertySetId::fx_slot) + { + if (property_id_ < EAXFXSLOT_NONE) + { + property_set_id_ = 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/modules/openal-soft/al/eax/call.h b/modules/openal-soft/al/eax/call.h new file mode 100644 index 0000000..9c2706c --- /dev/null +++ b/modules/openal-soft/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 type_ == EaxCallType::get; } + int get_version() const noexcept { return version_; } + EaxCallPropertySetId get_property_set_id() const noexcept { return property_set_id_; } + ALuint get_property_id() const noexcept { return property_id_; } + ALuint get_property_al_name() const noexcept { return property_source_id_; } + EaxFxSlotIndex get_fx_slot_index() const noexcept { return fx_slot_index_; } + + template + TValue& get_value() const + { + if (property_size_ < static_cast(sizeof(TValue))) + { + fail_too_small(); + } + + return *static_cast(property_buffer_); + } + + template + al::span get_values(size_t max_count) const + { + if (max_count == 0 || property_size_ < static_cast(sizeof(TValue))) + fail_too_small(); + + const auto count = minz(property_size_ / sizeof(TValue), max_count); + return al::span{static_cast(property_buffer_), count}; + } + + template + al::span get_values() const + { + return get_values(~size_t{}); + } + + template + void set_value(const TValue& value) const + { + get_value() = value; + } + +private: + EaxCallType type_; + int version_; + EaxFxSlotIndex fx_slot_index_; + EaxCallPropertySetId property_set_id_; + + ALuint property_id_; + ALuint property_source_id_; + ALvoid*property_buffer_; + ALuint property_size_; + + [[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/modules/openal-soft/al/eax/effect.h b/modules/openal-soft/al/eax/effect.h new file mode 100644 index 0000000..b57bf24 --- /dev/null +++ b/modules/openal-soft/al/eax/effect.h @@ -0,0 +1,173 @@ +#ifndef EAX_EFFECT_INCLUDED +#define EAX_EFFECT_INCLUDED + + +#include +#include + +#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 + +class EaxEffect { +public: + EaxEffect(ALenum type) noexcept : al_effect_type_{type} { } + virtual ~EaxEffect() = default; + + const ALenum al_effect_type_; + EffectProps al_effect_props_{}; + + virtual void dispatch(const EaxCall& call) = 0; + + // Returns "true" if any immediated property was changed. + /*[[nodiscard]]*/ virtual bool commit() = 0; +}; // EaxEffect + +// Base class for EAX4+ effects. +template +class EaxEffect4 : public EaxEffect +{ +public: + EaxEffect4(ALenum type, const EaxCall& call) + : EaxEffect{type}, version_{clamp(call.get_version(), 4, 5)} + {} + + void initialize() + { + set_defaults(); + set_efx_defaults(); + } + + void dispatch(const EaxCall& call) override + { + call.is_get() ? get(call) : set(call); + version_ = call.get_version(); + } + + bool commit() final + { + switch (version_) + { + case 4: return commit_state(state4_); + case 5: return commit_state(state5_); + default: fail_unknown_version(); + } + } + +protected: + using Exception = TException; + using Props = TProps; + + struct State { + Props i; // Immediate. + Props d; // Deferred. + }; // State + + int version_; + Props props_; + State state4_; + State state5_; + + template + static void defer(const EaxCall& call, TProperty& property) + { + const auto& value = call.get_value(); + TValidator{}(value); + property = value; + } + + virtual void set_defaults(Props& props) = 0; + virtual void set_efx_defaults() = 0; + + virtual void get(const EaxCall& call, const Props& props) = 0; + virtual void set(const EaxCall& call, Props& props) = 0; + + virtual bool commit_props(const Props& props) = 0; + + [[noreturn]] static void fail(const char* message) + { + throw Exception{message}; + } + + [[noreturn]] static void fail_unknown_property_id() + { + fail(EaxEffectErrorMessages::unknown_property_id()); + } + + [[noreturn]] static void fail_unknown_version() + { + fail(EaxEffectErrorMessages::unknown_version()); + } + +private: + void set_defaults() + { + set_defaults(props_); + state4_.i = props_; + state4_.d = props_; + state5_.i = props_; + state5_.d = props_; + } + + void get(const EaxCall& call) + { + switch (call.get_version()) + { + case 4: get(call, state4_.i); break; + case 5: get(call, state5_.i); break; + default: fail_unknown_version(); + } + } + + void set(const EaxCall& call) + { + switch (call.get_version()) + { + case 4: set(call, state4_.d); break; + case 5: set(call, state5_.d); break; + default: fail_unknown_version(); + } + } + + bool commit_state(State& state) + { + const auto props = props_; + state.i = state.d; + props_ = state.d; + return commit_props(props); + } +}; // EaxEffect4 + +using EaxEffectUPtr = std::unique_ptr; + +// Creates EAX4+ effect. +template +EaxEffectUPtr eax_create_eax4_effect(const EaxCall& call) +{ + auto effect = std::make_unique(call); + effect->initialize(); + return effect; +} + +EaxEffectUPtr eax_create_eax_null_effect(); +EaxEffectUPtr eax_create_eax_chorus_effect(const EaxCall& call); +EaxEffectUPtr eax_create_eax_distortion_effect(const EaxCall& call); +EaxEffectUPtr eax_create_eax_echo_effect(const EaxCall& call); +EaxEffectUPtr eax_create_eax_flanger_effect(const EaxCall& call); +EaxEffectUPtr eax_create_eax_frequency_shifter_effect(const EaxCall& call); +EaxEffectUPtr eax_create_eax_vocal_morpher_effect(const EaxCall& call); +EaxEffectUPtr eax_create_eax_pitch_shifter_effect(const EaxCall& call); +EaxEffectUPtr eax_create_eax_ring_modulator_effect(const EaxCall& call); +EaxEffectUPtr eax_create_eax_auto_wah_effect(const EaxCall& call); +EaxEffectUPtr eax_create_eax_compressor_effect(const EaxCall& call); +EaxEffectUPtr eax_create_eax_equalizer_effect(const EaxCall& call); +EaxEffectUPtr eax_create_eax_reverb_effect(const EaxCall& call); + +#endif // !EAX_EFFECT_INCLUDED diff --git a/modules/openal-soft/al/eax_exception.cpp b/modules/openal-soft/al/eax/exception.cpp similarity index 98% rename from modules/openal-soft/al/eax_exception.cpp rename to modules/openal-soft/al/eax/exception.cpp index fdeecaa..3b31964 100644 --- a/modules/openal-soft/al/eax_exception.cpp +++ b/modules/openal-soft/al/eax/exception.cpp @@ -1,9 +1,8 @@ #include "config.h" -#include "eax_exception.h" +#include "exception.h" #include - #include diff --git a/modules/openal-soft/al/eax_exception.h b/modules/openal-soft/al/eax/exception.h similarity index 100% rename from modules/openal-soft/al/eax_exception.h rename to modules/openal-soft/al/eax/exception.h diff --git a/modules/openal-soft/al/eax_fx_slot_index.cpp b/modules/openal-soft/al/eax/fx_slot_index.cpp similarity index 95% rename from modules/openal-soft/al/eax_fx_slot_index.cpp rename to modules/openal-soft/al/eax/fx_slot_index.cpp index 9aa695a..28b1188 100644 --- a/modules/openal-soft/al/eax_fx_slot_index.cpp +++ b/modules/openal-soft/al/eax/fx_slot_index.cpp @@ -1,8 +1,8 @@ #include "config.h" -#include "eax_fx_slot_index.h" +#include "fx_slot_index.h" -#include "eax_exception.h" +#include "exception.h" namespace diff --git a/modules/openal-soft/al/eax_fx_slot_index.h b/modules/openal-soft/al/eax/fx_slot_index.h similarity index 97% rename from modules/openal-soft/al/eax_fx_slot_index.h rename to modules/openal-soft/al/eax/fx_slot_index.h index e1e5475..63dba03 100644 --- a/modules/openal-soft/al/eax_fx_slot_index.h +++ b/modules/openal-soft/al/eax/fx_slot_index.h @@ -5,7 +5,7 @@ #include #include "aloptional.h" -#include "eax_api.h" +#include "api.h" using EaxFxSlotIndexValue = std::size_t; diff --git a/modules/openal-soft/al/eax_fx_slots.cpp b/modules/openal-soft/al/eax/fx_slots.cpp similarity index 85% rename from modules/openal-soft/al/eax_fx_slots.cpp rename to modules/openal-soft/al/eax/fx_slots.cpp index 3a27dab..671d2cf 100644 --- a/modules/openal-soft/al/eax_fx_slots.cpp +++ b/modules/openal-soft/al/eax/fx_slots.cpp @@ -1,12 +1,11 @@ #include "config.h" -#include "eax_fx_slots.h" +#include "fx_slots.h" #include -#include "eax_exception.h" - -#include "eax_api.h" +#include "api.h" +#include "exception.h" namespace @@ -30,9 +29,10 @@ public: void EaxFxSlots::initialize( + const EaxCall& call, ALCcontext& al_context) { - initialize_fx_slots(al_context); + initialize_fx_slots(call, al_context); } void EaxFxSlots::uninitialize() noexcept @@ -71,6 +71,7 @@ void EaxFxSlots::fail( } void EaxFxSlots::initialize_fx_slots( + const EaxCall& call, ALCcontext& al_context) { auto fx_slot_index = EaxFxSlotIndexValue{}; @@ -78,7 +79,7 @@ void EaxFxSlots::initialize_fx_slots( 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->eax_initialize(call, al_context, fx_slot_index); fx_slot_index += 1; } } diff --git a/modules/openal-soft/al/eax_fx_slots.h b/modules/openal-soft/al/eax/fx_slots.h similarity index 86% rename from modules/openal-soft/al/eax_fx_slots.h rename to modules/openal-soft/al/eax/fx_slots.h index a104c6a..e7d1452 100644 --- a/modules/openal-soft/al/eax_fx_slots.h +++ b/modules/openal-soft/al/eax/fx_slots.h @@ -6,15 +6,16 @@ #include "al/auxeffectslot.h" -#include "eax_api.h" - -#include "eax_fx_slot_index.h" +#include "api.h" +#include "call.h" +#include "fx_slot_index.h" class EaxFxSlots { public: void initialize( + const EaxCall& call, ALCcontext& al_context); void uninitialize() noexcept; @@ -47,6 +48,7 @@ private: const char* message); void initialize_fx_slots( + const EaxCall& call, ALCcontext& al_context); }; // EaxFxSlots diff --git a/modules/openal-soft/al/eax_globals.cpp b/modules/openal-soft/al/eax/globals.cpp similarity index 95% rename from modules/openal-soft/al/eax_globals.cpp rename to modules/openal-soft/al/eax/globals.cpp index 0790945..80e9dbf 100644 --- a/modules/openal-soft/al/eax_globals.cpp +++ b/modules/openal-soft/al/eax/globals.cpp @@ -1,6 +1,6 @@ #include "config.h" -#include "eax_globals.h" +#include "globals.h" bool eax_g_is_enabled = true; diff --git a/modules/openal-soft/al/eax_globals.h b/modules/openal-soft/al/eax/globals.h similarity index 100% rename from modules/openal-soft/al/eax_globals.h rename to modules/openal-soft/al/eax/globals.h diff --git a/modules/openal-soft/al/eax_utils.cpp b/modules/openal-soft/al/eax/utils.cpp similarity index 96% rename from modules/openal-soft/al/eax_utils.cpp rename to modules/openal-soft/al/eax/utils.cpp index 67389de..9fa2871 100644 --- a/modules/openal-soft/al/eax_utils.cpp +++ b/modules/openal-soft/al/eax/utils.cpp @@ -1,6 +1,6 @@ #include "config.h" -#include "eax_utils.h" +#include "utils.h" #include #include diff --git a/modules/openal-soft/al/eax_utils.h b/modules/openal-soft/al/eax/utils.h similarity index 71% rename from modules/openal-soft/al/eax_utils.h rename to modules/openal-soft/al/eax/utils.h index d3d4a19..5a8fdd6 100644 --- a/modules/openal-soft/al/eax_utils.h +++ b/modules/openal-soft/al/eax/utils.h @@ -6,22 +6,14 @@ #include #include - -struct EaxAlLowPassParam -{ +struct EaxAlLowPassParam { float gain; float gain_hf; -}; // EaxAlLowPassParam - +}; -void eax_log_exception( - const char* message = nullptr) noexcept; +void eax_log_exception(const char* message = nullptr) noexcept; - -template< - typename TException, - typename TValue -> +template void eax_validate_range( const char* value_name, const TValue& value, @@ -29,9 +21,7 @@ void eax_validate_range( const TValue& max_value) { if (value >= min_value && value <= max_value) - { return; - } const auto message = std::string{value_name} + @@ -43,60 +33,38 @@ void eax_validate_range( throw TException{message.c_str()}; } +namespace detail { -namespace detail -{ - - -template< - typename T -> -struct EaxIsBitFieldStruct -{ +template +struct EaxIsBitFieldStruct { private: using yes = std::true_type; using no = std::false_type; - template< - typename U - > + template static auto test(int) -> decltype(std::declval(), yes{}); - template< - typename - > + template static no test(...); - public: static constexpr auto value = std::is_same(0)), yes>::value; -}; // EaxIsBitFieldStruct - +}; -template< - typename T, - typename TValue -> -inline bool eax_bit_fields_are_equal( - const T& lhs, - const T& rhs) noexcept +template +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(lhs) == reinterpret_cast(rhs); } - } // namespace detail - template< typename T, std::enable_if_t::value, int> = 0 > -inline bool operator==( - const T& lhs, - const T& rhs) noexcept +inline bool operator==(const T& lhs, const T& rhs) noexcept { using Value = std::conditional_t< sizeof(T) == 1, @@ -107,13 +75,9 @@ inline bool operator==( std::conditional_t< sizeof(T) == 4, std::uint32_t, - void - > - > - >; + void>>>; static_assert(!std::is_same::value, "Unsupported type."); - return detail::eax_bit_fields_are_equal(lhs, rhs); } @@ -121,12 +85,9 @@ template< typename T, std::enable_if_t::value, int> = 0 > -inline bool operator!=( - const T& lhs, - const T& rhs) noexcept +inline bool operator!=(const T& lhs, const T& rhs) noexcept { return !(lhs == rhs); } - #endif // !EAX_UTILS_INCLUDED diff --git a/modules/openal-soft/al/eax_x_ram.h b/modules/openal-soft/al/eax/x_ram.h similarity index 100% rename from modules/openal-soft/al/eax_x_ram.h rename to modules/openal-soft/al/eax/x_ram.h diff --git a/modules/openal-soft/al/eax_eax_call.cpp b/modules/openal-soft/al/eax_eax_call.cpp deleted file mode 100644 index 914d2fb..0000000 --- a/modules/openal-soft/al/eax_eax_call.cpp +++ /dev/null @@ -1,324 +0,0 @@ -#include "config.h" - -#include "al/eax_eax_call.h" - -#include "al/eax_exception.h" - - -namespace { - -constexpr auto deferred_flag = 0x80000000U; - -class EaxEaxCallException : - public EaxException -{ -public: - explicit EaxEaxCallException( - const char* message) - : - EaxException{"EAX_EAX_CALL", message} - { - } -}; // EaxEaxCallException - -} // namespace - - -EaxEaxCall::EaxEaxCall( - bool is_get, - const GUID& property_set_guid, - ALuint property_id, - ALuint property_source_id, - ALvoid* property_buffer, - ALuint property_size) - : is_get_{is_get}, version_{0}, property_set_id_{EaxEaxCallPropertySetId::none} - , property_id_{property_id & ~deferred_flag}, property_source_id_{property_source_id} - , property_buffer_{property_buffer}, property_size_{property_size} -{ - if (false) - { - } - else if (property_set_guid == EAXPROPERTYID_EAX40_Context) - { - version_ = 4; - property_set_id_ = EaxEaxCallPropertySetId::context; - } - else if (property_set_guid == EAXPROPERTYID_EAX50_Context) - { - version_ = 5; - property_set_id_ = EaxEaxCallPropertySetId::context; - } - else if (property_set_guid == DSPROPSETID_EAX20_ListenerProperties) - { - version_ = 2; - fx_slot_index_ = 0u; - property_set_id_ = EaxEaxCallPropertySetId::fx_slot_effect; - property_id_ = convert_eax_v2_0_listener_property_id(property_id_); - } - else if (property_set_guid == DSPROPSETID_EAX30_ListenerProperties) - { - version_ = 3; - fx_slot_index_ = 0u; - property_set_id_ = EaxEaxCallPropertySetId::fx_slot_effect; - } - else if (property_set_guid == EAXPROPERTYID_EAX40_FXSlot0) - { - version_ = 4; - fx_slot_index_ = 0u; - property_set_id_ = EaxEaxCallPropertySetId::fx_slot; - } - else if (property_set_guid == EAXPROPERTYID_EAX50_FXSlot0) - { - version_ = 5; - fx_slot_index_ = 0u; - property_set_id_ = EaxEaxCallPropertySetId::fx_slot; - } - else if (property_set_guid == EAXPROPERTYID_EAX40_FXSlot1) - { - version_ = 4; - fx_slot_index_ = 1u; - property_set_id_ = EaxEaxCallPropertySetId::fx_slot; - } - else if (property_set_guid == EAXPROPERTYID_EAX50_FXSlot1) - { - version_ = 5; - fx_slot_index_ = 1u; - property_set_id_ = EaxEaxCallPropertySetId::fx_slot; - } - else if (property_set_guid == EAXPROPERTYID_EAX40_FXSlot2) - { - version_ = 4; - fx_slot_index_ = 2u; - property_set_id_ = EaxEaxCallPropertySetId::fx_slot; - } - else if (property_set_guid == EAXPROPERTYID_EAX50_FXSlot2) - { - version_ = 5; - fx_slot_index_ = 2u; - property_set_id_ = EaxEaxCallPropertySetId::fx_slot; - } - else if (property_set_guid == EAXPROPERTYID_EAX40_FXSlot3) - { - version_ = 4; - fx_slot_index_ = 3u; - property_set_id_ = EaxEaxCallPropertySetId::fx_slot; - } - else if (property_set_guid == EAXPROPERTYID_EAX50_FXSlot3) - { - version_ = 5; - fx_slot_index_ = 3u; - property_set_id_ = EaxEaxCallPropertySetId::fx_slot; - } - else if (property_set_guid == DSPROPSETID_EAX20_BufferProperties) - { - version_ = 2; - property_set_id_ = EaxEaxCallPropertySetId::source; - property_id_ = convert_eax_v2_0_buffer_property_id(property_id_); - } - else if (property_set_guid == DSPROPSETID_EAX30_BufferProperties) - { - version_ = 3; - property_set_id_ = EaxEaxCallPropertySetId::source; - } - else if (property_set_guid == EAXPROPERTYID_EAX40_Source) - { - version_ = 4; - property_set_id_ = EaxEaxCallPropertySetId::source; - } - else if (property_set_guid == EAXPROPERTYID_EAX50_Source) - { - version_ = 5; - property_set_id_ = EaxEaxCallPropertySetId::source; - } - else if (property_set_guid == DSPROPSETID_EAX_ReverbProperties) - { - version_ = 1; - fx_slot_index_ = 0u; - property_set_id_ = EaxEaxCallPropertySetId::fx_slot_effect; - } - else if (property_set_guid == DSPROPSETID_EAXBUFFER_ReverbProperties) - { - version_ = 1; - property_set_id_ = EaxEaxCallPropertySetId::source; - } - else - { - fail("Unsupported property set id."); - } - - if (version_ < 1 || version_ > 5) - { - fail("EAX version out of range."); - } - - if(!(property_id&deferred_flag)) - { - if(property_set_id_ != EaxEaxCallPropertySetId::fx_slot && property_id_ != 0) - { - if (!property_buffer) - { - fail("Null property buffer."); - } - - if (property_size == 0) - { - fail("Empty property."); - } - } - } - - if(property_set_id_ == EaxEaxCallPropertySetId::source && property_source_id_ == 0) - { - fail("Null AL source id."); - } - - if (property_set_id_ == EaxEaxCallPropertySetId::fx_slot) - { - if (property_id_ < EAXFXSLOT_NONE) - { - property_set_id_ = EaxEaxCallPropertySetId::fx_slot_effect; - } - } -} - -[[noreturn]] -void EaxEaxCall::fail( - const char* message) -{ - throw EaxEaxCallException{message}; -} - -ALuint EaxEaxCall::convert_eax_v2_0_listener_property_id( - ALuint property_id) -{ - switch (property_id) - { - case DSPROPERTY_EAX20LISTENER_NONE: - return EAXREVERB_NONE; - - case DSPROPERTY_EAX20LISTENER_ALLPARAMETERS: - return EAXREVERB_ALLPARAMETERS; - - case DSPROPERTY_EAX20LISTENER_ROOM: - return EAXREVERB_ROOM; - - case DSPROPERTY_EAX20LISTENER_ROOMHF: - return EAXREVERB_ROOMHF; - - case DSPROPERTY_EAX20LISTENER_ROOMROLLOFFFACTOR: - return EAXREVERB_ROOMROLLOFFFACTOR; - - case DSPROPERTY_EAX20LISTENER_DECAYTIME: - return EAXREVERB_DECAYTIME; - - case DSPROPERTY_EAX20LISTENER_DECAYHFRATIO: - return EAXREVERB_DECAYHFRATIO; - - case DSPROPERTY_EAX20LISTENER_REFLECTIONS: - return EAXREVERB_REFLECTIONS; - - case DSPROPERTY_EAX20LISTENER_REFLECTIONSDELAY: - return EAXREVERB_REFLECTIONSDELAY; - - case DSPROPERTY_EAX20LISTENER_REVERB: - return EAXREVERB_REVERB; - - case DSPROPERTY_EAX20LISTENER_REVERBDELAY: - return EAXREVERB_REVERBDELAY; - - case DSPROPERTY_EAX20LISTENER_ENVIRONMENT: - return EAXREVERB_ENVIRONMENT; - - case DSPROPERTY_EAX20LISTENER_ENVIRONMENTSIZE: - return EAXREVERB_ENVIRONMENTSIZE; - - case DSPROPERTY_EAX20LISTENER_ENVIRONMENTDIFFUSION: - return EAXREVERB_ENVIRONMENTDIFFUSION; - - case DSPROPERTY_EAX20LISTENER_AIRABSORPTIONHF: - return EAXREVERB_AIRABSORPTIONHF; - - case DSPROPERTY_EAX20LISTENER_FLAGS: - return EAXREVERB_FLAGS; - - default: - fail("Unsupported EAX 2.0 listener property id."); - } -} - -ALuint EaxEaxCall::convert_eax_v2_0_buffer_property_id( - ALuint property_id) -{ - switch (property_id) - { - case DSPROPERTY_EAX20BUFFER_NONE: - return EAXSOURCE_NONE; - - case DSPROPERTY_EAX20BUFFER_ALLPARAMETERS: - return EAXSOURCE_ALLPARAMETERS; - - case DSPROPERTY_EAX20BUFFER_DIRECT: - return EAXSOURCE_DIRECT; - - case DSPROPERTY_EAX20BUFFER_DIRECTHF: - return EAXSOURCE_DIRECTHF; - - case DSPROPERTY_EAX20BUFFER_ROOM: - return EAXSOURCE_ROOM; - - case DSPROPERTY_EAX20BUFFER_ROOMHF: - return EAXSOURCE_ROOMHF; - - case DSPROPERTY_EAX20BUFFER_ROOMROLLOFFFACTOR: - return EAXSOURCE_ROOMROLLOFFFACTOR; - - case DSPROPERTY_EAX20BUFFER_OBSTRUCTION: - return EAXSOURCE_OBSTRUCTION; - - case DSPROPERTY_EAX20BUFFER_OBSTRUCTIONLFRATIO: - return EAXSOURCE_OBSTRUCTIONLFRATIO; - - case DSPROPERTY_EAX20BUFFER_OCCLUSION: - return EAXSOURCE_OCCLUSION; - - case DSPROPERTY_EAX20BUFFER_OCCLUSIONLFRATIO: - return EAXSOURCE_OCCLUSIONLFRATIO; - - case DSPROPERTY_EAX20BUFFER_OCCLUSIONROOMRATIO: - return EAXSOURCE_OCCLUSIONROOMRATIO; - - case DSPROPERTY_EAX20BUFFER_OUTSIDEVOLUMEHF: - return EAXSOURCE_OUTSIDEVOLUMEHF; - - case DSPROPERTY_EAX20BUFFER_AIRABSORPTIONFACTOR: - return EAXSOURCE_AIRABSORPTIONFACTOR; - - case DSPROPERTY_EAX20BUFFER_FLAGS: - return EAXSOURCE_FLAGS; - - default: - fail("Unsupported EAX 2.0 buffer property id."); - } -} - - -EaxEaxCall create_eax_call( - bool is_get, - const GUID* property_set_id, - ALuint property_id, - ALuint property_source_id, - ALvoid* property_buffer, - ALuint property_size) -{ - if(!property_set_id) - throw EaxEaxCallException{"Null property set ID."}; - - return EaxEaxCall{ - is_get, - *property_set_id, - property_id, - property_source_id, - property_buffer, - property_size - }; -} diff --git a/modules/openal-soft/al/eax_eax_call.h b/modules/openal-soft/al/eax_eax_call.h deleted file mode 100644 index 7b990d8..0000000 --- a/modules/openal-soft/al/eax_eax_call.h +++ /dev/null @@ -1,117 +0,0 @@ -#ifndef EAX_EAX_CALL_INCLUDED -#define EAX_EAX_CALL_INCLUDED - - -#include "AL/al.h" - -#include "alspan.h" - -#include "eax_api.h" -#include "eax_fx_slot_index.h" - - -enum class EaxEaxCallPropertySetId -{ - none, - - context, - fx_slot, - source, - fx_slot_effect, -}; // EaxEaxCallPropertySetId - - -class EaxEaxCall -{ -public: - EaxEaxCall( - bool is_get, - const GUID& property_set_guid, - ALuint property_id, - ALuint property_source_id, - ALvoid* property_buffer, - ALuint property_size); - - bool is_get() const noexcept { return is_get_; } - int get_version() const noexcept { return version_; } - EaxEaxCallPropertySetId get_property_set_id() const noexcept { return property_set_id_; } - ALuint get_property_id() const noexcept { return property_id_; } - ALuint get_property_al_name() const noexcept { return property_source_id_; } - EaxFxSlotIndex get_fx_slot_index() const noexcept { return fx_slot_index_; } - - template< - typename TException, - typename TValue - > - TValue& get_value() const - { - if (property_size_ < static_cast(sizeof(TValue))) - { - throw TException{"Property buffer too small."}; - } - - return *static_cast(property_buffer_); - } - - template< - typename TException, - typename TValue - > - al::span get_values() const - { - if (property_size_ < static_cast(sizeof(TValue))) - { - throw TException{"Property buffer too small."}; - } - - const auto count = property_size_ / sizeof(TValue); - - return al::span{static_cast(property_buffer_), count}; - } - - template< - typename TException, - typename TValue - > - void set_value( - const TValue& value) const - { - get_value() = value; - } - - -private: - const bool is_get_; - int version_; - EaxFxSlotIndex fx_slot_index_; - EaxEaxCallPropertySetId property_set_id_; - - ALuint property_id_; - const ALuint property_source_id_; - ALvoid*const property_buffer_; - const ALuint property_size_; - - - [[noreturn]] - static void fail( - const char* message); - - - static ALuint convert_eax_v2_0_listener_property_id( - ALuint property_id); - - static ALuint convert_eax_v2_0_buffer_property_id( - ALuint property_id); -}; // EaxEaxCall - - -EaxEaxCall create_eax_call( - bool is_get, - const GUID* property_set_id, - ALuint property_id, - ALuint property_source_id, - ALvoid* property_buffer, - ALuint property_size); - - -#endif // !EAX_EAX_CALL_INCLUDED diff --git a/modules/openal-soft/al/eax_effect.cpp b/modules/openal-soft/al/eax_effect.cpp deleted file mode 100644 index 9cbf4c1..0000000 --- a/modules/openal-soft/al/eax_effect.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "config.h" - -#include "eax_effect.h" diff --git a/modules/openal-soft/al/eax_effect.h b/modules/openal-soft/al/eax_effect.h deleted file mode 100644 index 45315ca..0000000 --- a/modules/openal-soft/al/eax_effect.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef EAX_EFFECT_INCLUDED -#define EAX_EFFECT_INCLUDED - - -#include - -#include "AL/al.h" -#include "core/effects/base.h" -#include "eax_eax_call.h" - -class EaxEffect -{ -public: - EaxEffect(ALenum type) : al_effect_type_{type} { } - virtual ~EaxEffect() = default; - - const ALenum al_effect_type_; - EffectProps al_effect_props_{}; - - virtual void dispatch(const EaxEaxCall& eax_call) = 0; - - // Returns "true" if any immediated property was changed. - // [[nodiscard]] - virtual bool apply_deferred() = 0; -}; // EaxEffect - - -using EaxEffectUPtr = std::unique_ptr; - -EaxEffectUPtr eax_create_eax_null_effect(); -EaxEffectUPtr eax_create_eax_chorus_effect(); -EaxEffectUPtr eax_create_eax_distortion_effect(); -EaxEffectUPtr eax_create_eax_echo_effect(); -EaxEffectUPtr eax_create_eax_flanger_effect(); -EaxEffectUPtr eax_create_eax_frequency_shifter_effect(); -EaxEffectUPtr eax_create_eax_vocal_morpher_effect(); -EaxEffectUPtr eax_create_eax_pitch_shifter_effect(); -EaxEffectUPtr eax_create_eax_ring_modulator_effect(); -EaxEffectUPtr eax_create_eax_auto_wah_effect(); -EaxEffectUPtr eax_create_eax_compressor_effect(); -EaxEffectUPtr eax_create_eax_equalizer_effect(); -EaxEffectUPtr eax_create_eax_reverb_effect(); - -#endif // !EAX_EFFECT_INCLUDED diff --git a/modules/openal-soft/al/eax_x_ram.cpp b/modules/openal-soft/al/eax_x_ram.cpp deleted file mode 100644 index ac3e7eb..0000000 --- a/modules/openal-soft/al/eax_x_ram.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "config.h" - -#include "eax_x_ram.h" diff --git a/modules/openal-soft/al/effect.cpp b/modules/openal-soft/al/effect.cpp index 5a74ca5..90a4dfd 100644 --- a/modules/openal-soft/al/effect.cpp +++ b/modules/openal-soft/al/effect.cpp @@ -54,7 +54,7 @@ #ifdef ALSOFT_EAX #include -#include "eax_exception.h" +#include "eax/exception.h" #endif // ALSOFT_EAX const EffectList gEffectList[16]{ diff --git a/modules/openal-soft/al/effects/autowah.cpp b/modules/openal-soft/al/effects/autowah.cpp index 273ec7a..7e0e34a 100644 --- a/modules/openal-soft/al/effects/autowah.cpp +++ b/modules/openal-soft/al/effects/autowah.cpp @@ -13,9 +13,8 @@ #ifdef ALSOFT_EAX #include "alnumeric.h" - -#include "al/eax_exception.h" -#include "al/eax_utils.h" +#include "al/eax/exception.h" +#include "al/eax/utils.h" #endif // ALSOFT_EAX @@ -119,178 +118,127 @@ const EffectProps AutowahEffectProps{genDefaultProps()}; #ifdef ALSOFT_EAX namespace { -using EaxAutoWahEffectDirtyFlagsValue = std::uint_least8_t; - -struct EaxAutoWahEffectDirtyFlags -{ - using EaxIsBitFieldStruct = bool; - - EaxAutoWahEffectDirtyFlagsValue flAttackTime : 1; - EaxAutoWahEffectDirtyFlagsValue flReleaseTime : 1; - EaxAutoWahEffectDirtyFlagsValue lResonance : 1; - EaxAutoWahEffectDirtyFlagsValue lPeakLevel : 1; -}; // EaxAutoWahEffectDirtyFlags - - -class EaxAutoWahEffect final : - public EaxEffect -{ +class EaxAutoWahEffectException : public EaxException { public: - EaxAutoWahEffect(); - - - void dispatch(const EaxEaxCall& eax_call) override; + explicit EaxAutoWahEffectException(const char* message) + : EaxException{"EAX_AUTO_WAH_EFFECT", message} + {} +}; // EaxAutoWahEffectException - // [[nodiscard]] - bool apply_deferred() override; +class EaxAutoWahEffect final : public EaxEffect4 { +public: + EaxAutoWahEffect(const EaxCall& call); private: - EAXAUTOWAHPROPERTIES eax_{}; - EAXAUTOWAHPROPERTIES eax_d_{}; - EaxAutoWahEffectDirtyFlags eax_dirty_flags_{}; - - - void set_eax_defaults(); - - - void set_efx_attack_time(); - - void set_efx_release_time(); - - void set_efx_resonance(); - - void set_efx_peak_gain(); - - void set_efx_defaults(); - - - void get(const EaxEaxCall& eax_call); - - - void validate_attack_time( - float flAttackTime); - - void validate_release_time( - float flReleaseTime); - - void validate_resonance( - long lResonance); - - void validate_peak_level( - long lPeakLevel); - - void validate_all( - const EAXAUTOWAHPROPERTIES& eax_all); - - - void defer_attack_time( - float flAttackTime); - - void defer_release_time( - float flReleaseTime); - - void defer_resonance( - long lResonance); - - void defer_peak_level( - long lPeakLevel); - - void defer_all( - const EAXAUTOWAHPROPERTIES& eax_all); - - - void defer_attack_time( - const EaxEaxCall& eax_call); - - void defer_release_time( - const EaxEaxCall& eax_call); - - void defer_resonance( - const EaxEaxCall& eax_call); - - void defer_peak_level( - const EaxEaxCall& eax_call); - - void defer_all( - const EaxEaxCall& eax_call); - - void set(const EaxEaxCall& eax_call); + struct AttackTimeValidator { + void operator()(float flAttackTime) const + { + eax_validate_range( + "Attack Time", + flAttackTime, + EAXAUTOWAH_MINATTACKTIME, + EAXAUTOWAH_MAXATTACKTIME); + } + }; // AttackTimeValidator + + struct ReleaseTimeValidator { + void operator()(float flReleaseTime) const + { + eax_validate_range( + "Release Time", + flReleaseTime, + EAXAUTOWAH_MINRELEASETIME, + EAXAUTOWAH_MAXRELEASETIME); + } + }; // ReleaseTimeValidator + + struct ResonanceValidator { + void operator()(long lResonance) const + { + eax_validate_range( + "Resonance", + lResonance, + EAXAUTOWAH_MINRESONANCE, + EAXAUTOWAH_MAXRESONANCE); + } + }; // ResonanceValidator + + struct PeakLevelValidator { + void operator()(long lPeakLevel) const + { + eax_validate_range( + "Peak Level", + lPeakLevel, + EAXAUTOWAH_MINPEAKLEVEL, + EAXAUTOWAH_MAXPEAKLEVEL); + } + }; // PeakLevelValidator + + struct AllValidator { + void operator()(const Props& all) const + { + AttackTimeValidator{}(all.flAttackTime); + ReleaseTimeValidator{}(all.flReleaseTime); + ResonanceValidator{}(all.lResonance); + PeakLevelValidator{}(all.lPeakLevel); + } + }; // AllValidator + + void set_defaults(Props& props) override; + + void set_efx_attack_time() noexcept; + void set_efx_release_time() noexcept; + void set_efx_resonance() noexcept; + void set_efx_peak_gain() noexcept; + void set_efx_defaults() override; + + void get(const EaxCall& call, const Props& props) override; + void set(const EaxCall& call, Props& props) override; + bool commit_props(const Props& props) override; }; // EaxAutoWahEffect +EaxAutoWahEffect::EaxAutoWahEffect(const EaxCall& call) + : EaxEffect4{AL_EFFECT_AUTOWAH, call} +{} -class EaxAutoWahEffectException : - public EaxException -{ -public: - explicit EaxAutoWahEffectException( - const char* message) - : - EaxException{"EAX_AUTO_WAH_EFFECT", message} - { - } -}; // EaxAutoWahEffectException - - -EaxAutoWahEffect::EaxAutoWahEffect() - : EaxEffect{AL_EFFECT_AUTOWAH} -{ - set_eax_defaults(); - set_efx_defaults(); -} - -void EaxAutoWahEffect::dispatch(const EaxEaxCall& eax_call) -{ - eax_call.is_get() ? get(eax_call) : set(eax_call); -} - -void EaxAutoWahEffect::set_eax_defaults() +void EaxAutoWahEffect::set_defaults(Props& props) { - eax_.flAttackTime = EAXAUTOWAH_DEFAULTATTACKTIME; - eax_.flReleaseTime = EAXAUTOWAH_DEFAULTRELEASETIME; - eax_.lResonance = EAXAUTOWAH_DEFAULTRESONANCE; - eax_.lPeakLevel = EAXAUTOWAH_DEFAULTPEAKLEVEL; - - eax_d_ = eax_; + props.flAttackTime = EAXAUTOWAH_DEFAULTATTACKTIME; + props.flReleaseTime = EAXAUTOWAH_DEFAULTRELEASETIME; + props.lResonance = EAXAUTOWAH_DEFAULTRESONANCE; + props.lPeakLevel = EAXAUTOWAH_DEFAULTPEAKLEVEL; } -void EaxAutoWahEffect::set_efx_attack_time() +void EaxAutoWahEffect::set_efx_attack_time() noexcept { - const auto attack_time = clamp( - eax_.flAttackTime, + al_effect_props_.Autowah.AttackTime = clamp( + props_.flAttackTime, AL_AUTOWAH_MIN_ATTACK_TIME, AL_AUTOWAH_MAX_ATTACK_TIME); - - al_effect_props_.Autowah.AttackTime = attack_time; } -void EaxAutoWahEffect::set_efx_release_time() +void EaxAutoWahEffect::set_efx_release_time() noexcept { - const auto release_time = clamp( - eax_.flReleaseTime, + al_effect_props_.Autowah.ReleaseTime = clamp( + props_.flReleaseTime, AL_AUTOWAH_MIN_RELEASE_TIME, AL_AUTOWAH_MAX_RELEASE_TIME); - - al_effect_props_.Autowah.ReleaseTime = release_time; } -void EaxAutoWahEffect::set_efx_resonance() +void EaxAutoWahEffect::set_efx_resonance() noexcept { - const auto resonance = clamp( - level_mb_to_gain(static_cast(eax_.lResonance)), + al_effect_props_.Autowah.Resonance = clamp( + level_mb_to_gain(static_cast(props_.lResonance)), AL_AUTOWAH_MIN_RESONANCE, AL_AUTOWAH_MAX_RESONANCE); - - al_effect_props_.Autowah.Resonance = resonance; } -void EaxAutoWahEffect::set_efx_peak_gain() +void EaxAutoWahEffect::set_efx_peak_gain() noexcept { - const auto peak_gain = clamp( - level_mb_to_gain(static_cast(eax_.lPeakLevel)), + al_effect_props_.Autowah.PeakGain = clamp( + level_mb_to_gain(static_cast(props_.lPeakLevel)), AL_AUTOWAH_MIN_PEAK_GAIN, AL_AUTOWAH_MAX_PEAK_GAIN); - - al_effect_props_.Autowah.PeakGain = peak_gain; } void EaxAutoWahEffect::set_efx_defaults() @@ -301,248 +249,70 @@ void EaxAutoWahEffect::set_efx_defaults() set_efx_peak_gain(); } -void EaxAutoWahEffect::get(const EaxEaxCall& eax_call) +void EaxAutoWahEffect::get(const EaxCall& call, const Props& props) { - switch (eax_call.get_property_id()) + switch (call.get_property_id()) { - case EAXAUTOWAH_NONE: - break; - - case EAXAUTOWAH_ALLPARAMETERS: - eax_call.set_value(eax_); - break; - - case EAXAUTOWAH_ATTACKTIME: - eax_call.set_value(eax_.flAttackTime); - break; - - case EAXAUTOWAH_RELEASETIME: - eax_call.set_value(eax_.flReleaseTime); - break; - - case EAXAUTOWAH_RESONANCE: - eax_call.set_value(eax_.lResonance); - break; - - case EAXAUTOWAH_PEAKLEVEL: - eax_call.set_value(eax_.lPeakLevel); - break; - - default: - throw EaxAutoWahEffectException{"Unsupported property id."}; + case EAXAUTOWAH_NONE: break; + case EAXAUTOWAH_ALLPARAMETERS: call.set_value(props); break; + case EAXAUTOWAH_ATTACKTIME: call.set_value(props.flAttackTime); break; + case EAXAUTOWAH_RELEASETIME: call.set_value(props.flReleaseTime); break; + case EAXAUTOWAH_RESONANCE: call.set_value(props.lResonance); break; + case EAXAUTOWAH_PEAKLEVEL: call.set_value(props.lPeakLevel); break; + default: fail_unknown_property_id(); } } -void EaxAutoWahEffect::validate_attack_time( - float flAttackTime) +void EaxAutoWahEffect::set(const EaxCall& call, Props& props) { - eax_validate_range( - "Attack Time", - flAttackTime, - EAXAUTOWAH_MINATTACKTIME, - EAXAUTOWAH_MAXATTACKTIME); -} - -void EaxAutoWahEffect::validate_release_time( - float flReleaseTime) -{ - eax_validate_range( - "Release Time", - flReleaseTime, - EAXAUTOWAH_MINRELEASETIME, - EAXAUTOWAH_MAXRELEASETIME); -} - -void EaxAutoWahEffect::validate_resonance( - long lResonance) -{ - eax_validate_range( - "Resonance", - lResonance, - EAXAUTOWAH_MINRESONANCE, - EAXAUTOWAH_MAXRESONANCE); -} - -void EaxAutoWahEffect::validate_peak_level( - long lPeakLevel) -{ - eax_validate_range( - "Peak Level", - lPeakLevel, - EAXAUTOWAH_MINPEAKLEVEL, - EAXAUTOWAH_MAXPEAKLEVEL); -} - -void EaxAutoWahEffect::validate_all( - const EAXAUTOWAHPROPERTIES& eax_all) -{ - validate_attack_time(eax_all.flAttackTime); - validate_release_time(eax_all.flReleaseTime); - validate_resonance(eax_all.lResonance); - validate_peak_level(eax_all.lPeakLevel); -} - -void EaxAutoWahEffect::defer_attack_time( - float flAttackTime) -{ - eax_d_.flAttackTime = flAttackTime; - eax_dirty_flags_.flAttackTime = (eax_.flAttackTime != eax_d_.flAttackTime); -} - -void EaxAutoWahEffect::defer_release_time( - float flReleaseTime) -{ - eax_d_.flReleaseTime = flReleaseTime; - eax_dirty_flags_.flReleaseTime = (eax_.flReleaseTime != eax_d_.flReleaseTime); -} - -void EaxAutoWahEffect::defer_resonance( - long lResonance) -{ - eax_d_.lResonance = lResonance; - eax_dirty_flags_.lResonance = (eax_.lResonance != eax_d_.lResonance); -} - -void EaxAutoWahEffect::defer_peak_level( - long lPeakLevel) -{ - eax_d_.lPeakLevel = lPeakLevel; - eax_dirty_flags_.lPeakLevel = (eax_.lPeakLevel != eax_d_.lPeakLevel); -} - -void EaxAutoWahEffect::defer_all( - const EAXAUTOWAHPROPERTIES& eax_all) -{ - validate_all(eax_all); - - defer_attack_time(eax_all.flAttackTime); - defer_release_time(eax_all.flReleaseTime); - defer_resonance(eax_all.lResonance); - defer_peak_level(eax_all.lPeakLevel); -} - -void EaxAutoWahEffect::defer_attack_time( - const EaxEaxCall& eax_call) -{ - const auto& attack_time = - eax_call.get_value(); - - validate_attack_time(attack_time); - defer_attack_time(attack_time); -} - -void EaxAutoWahEffect::defer_release_time( - const EaxEaxCall& eax_call) -{ - const auto& release_time = - eax_call.get_value(); - - validate_release_time(release_time); - defer_release_time(release_time); -} - -void EaxAutoWahEffect::defer_resonance( - const EaxEaxCall& eax_call) -{ - const auto& resonance = - eax_call.get_value(); - - validate_resonance(resonance); - defer_resonance(resonance); -} - -void EaxAutoWahEffect::defer_peak_level( - const EaxEaxCall& eax_call) -{ - const auto& peak_level = - eax_call.get_value(); - - validate_peak_level(peak_level); - defer_peak_level(peak_level); -} - -void EaxAutoWahEffect::defer_all( - const EaxEaxCall& eax_call) -{ - const auto& all = - eax_call.get_value(); - - validate_all(all); - defer_all(all); -} - -// [[nodiscard]] -bool EaxAutoWahEffect::apply_deferred() -{ - if (eax_dirty_flags_ == EaxAutoWahEffectDirtyFlags{}) + switch (call.get_property_id()) { - return false; + case EAXAUTOWAH_NONE: break; + case EAXAUTOWAH_ALLPARAMETERS: defer(call, props); break; + case EAXAUTOWAH_ATTACKTIME: defer(call, props.flAttackTime); break; + case EAXAUTOWAH_RELEASETIME: defer(call, props.flReleaseTime); break; + case EAXAUTOWAH_RESONANCE: defer(call, props.lResonance); break; + case EAXAUTOWAH_PEAKLEVEL: defer(call, props.lPeakLevel); break; + default: fail_unknown_property_id(); } +} - eax_ = eax_d_; +bool EaxAutoWahEffect::commit_props(const Props& props) +{ + auto is_dirty = false; - if (eax_dirty_flags_.flAttackTime) + if (props_.flAttackTime != props.flAttackTime) { + is_dirty = true; set_efx_attack_time(); } - if (eax_dirty_flags_.flReleaseTime) + if (props_.flReleaseTime != props.flReleaseTime) { + is_dirty = true; set_efx_release_time(); } - if (eax_dirty_flags_.lResonance) + if (props_.lResonance != props.lResonance) { + is_dirty = true; set_efx_resonance(); } - if (eax_dirty_flags_.lPeakLevel) + if (props_.lPeakLevel != props.lPeakLevel) { + is_dirty = true; set_efx_peak_gain(); } - eax_dirty_flags_ = EaxAutoWahEffectDirtyFlags{}; - - return true; -} - -void EaxAutoWahEffect::set(const EaxEaxCall& eax_call) -{ - switch (eax_call.get_property_id()) - { - case EAXAUTOWAH_NONE: - break; - - case EAXAUTOWAH_ALLPARAMETERS: - defer_all(eax_call); - break; - - case EAXAUTOWAH_ATTACKTIME: - defer_attack_time(eax_call); - break; - - case EAXAUTOWAH_RELEASETIME: - defer_release_time(eax_call); - break; - - case EAXAUTOWAH_RESONANCE: - defer_resonance(eax_call); - break; - - case EAXAUTOWAH_PEAKLEVEL: - defer_peak_level(eax_call); - break; - - default: - throw EaxAutoWahEffectException{"Unsupported property id."}; - } + return is_dirty; } } // namespace -EaxEffectUPtr eax_create_eax_auto_wah_effect() +EaxEffectUPtr eax_create_eax_auto_wah_effect(const EaxCall& call) { - return std::make_unique<::EaxAutoWahEffect>(); + return eax_create_eax4_effect(call); } #endif // ALSOFT_EAX diff --git a/modules/openal-soft/al/effects/chorus.cpp b/modules/openal-soft/al/effects/chorus.cpp index 5631809..0d4283c 100644 --- a/modules/openal-soft/al/effects/chorus.cpp +++ b/modules/openal-soft/al/effects/chorus.cpp @@ -13,11 +13,9 @@ #ifdef ALSOFT_EAX #include - #include "alnumeric.h" - -#include "al/eax_exception.h" -#include "al/eax_utils.h" +#include "al/eax/exception.h" +#include "al/eax/utils.h" #endif // ALSOFT_EAX @@ -293,1065 +291,444 @@ const EffectProps FlangerEffectProps{genDefaultFlangerProps()}; #ifdef ALSOFT_EAX namespace { -void eax_set_efx_waveform( - ALenum waveform, - EffectProps& al_effect_props) -{ - const auto efx_waveform = WaveformFromEnum(waveform); - assert(efx_waveform.has_value()); - al_effect_props.Chorus.Waveform = *efx_waveform; -} - -void eax_set_efx_phase( - ALint phase, - EffectProps& al_effect_props) -{ - al_effect_props.Chorus.Phase = phase; -} - -void eax_set_efx_rate( - ALfloat rate, - EffectProps& al_effect_props) -{ - al_effect_props.Chorus.Rate = rate; -} - -void eax_set_efx_depth( - ALfloat depth, - EffectProps& al_effect_props) -{ - al_effect_props.Chorus.Depth = depth; -} - -void eax_set_efx_feedback( - ALfloat feedback, - EffectProps& al_effect_props) -{ - al_effect_props.Chorus.Feedback = feedback; -} - -void eax_set_efx_delay( - ALfloat delay, - EffectProps& al_effect_props) -{ - al_effect_props.Chorus.Delay = delay; -} - - -using EaxChorusEffectDirtyFlagsValue = std::uint_least8_t; - -struct EaxChorusEffectDirtyFlags -{ - using EaxIsBitFieldStruct = bool; - - EaxChorusEffectDirtyFlagsValue ulWaveform : 1; - EaxChorusEffectDirtyFlagsValue lPhase : 1; - EaxChorusEffectDirtyFlagsValue flRate : 1; - EaxChorusEffectDirtyFlagsValue flDepth : 1; - EaxChorusEffectDirtyFlagsValue flFeedback : 1; - EaxChorusEffectDirtyFlagsValue flDelay : 1; -}; // EaxChorusEffectDirtyFlags - +class EaxChorusEffectException : public EaxException { +public: + explicit EaxChorusEffectException(const char* message) + : EaxException{"EAX_CHORUS_EFFECT", message} + {} +}; // EaxChorusEffectException -class EaxChorusEffect final : - public EaxEffect -{ +class EaxFlangerEffectException : public EaxException { public: - EaxChorusEffect(); + explicit EaxFlangerEffectException(const char* message) + : EaxException{"EAX_FLANGER_EFFECT", message} + {} +}; // EaxFlangerEffectException - void dispatch(const EaxEaxCall& eax_call) override; +struct EaxChorusTraits +{ + using Exception = EaxChorusEffectException; + using Props = EAXCHORUSPROPERTIES; + + static constexpr auto efx_effect() { return AL_EFFECT_CHORUS; } + + static constexpr auto eax_none_param_id() { return EAXCHORUS_NONE; } + static constexpr auto eax_allparameters_param_id() { return EAXCHORUS_ALLPARAMETERS; } + static constexpr auto eax_waveform_param_id() { return EAXCHORUS_WAVEFORM; } + static constexpr auto eax_phase_param_id() { return EAXCHORUS_PHASE; } + static constexpr auto eax_rate_param_id() { return EAXCHORUS_RATE; } + static constexpr auto eax_depth_param_id() { return EAXCHORUS_DEPTH; } + static constexpr auto eax_feedback_param_id() { return EAXCHORUS_FEEDBACK; } + static constexpr auto eax_delay_param_id() { return EAXCHORUS_DELAY; } + + static constexpr auto eax_min_waveform() { return EAXCHORUS_MINWAVEFORM; } + static constexpr auto eax_min_phase() { return EAXCHORUS_MINPHASE; } + static constexpr auto eax_min_rate() { return EAXCHORUS_MINRATE; } + static constexpr auto eax_min_depth() { return EAXCHORUS_MINDEPTH; } + static constexpr auto eax_min_feedback() { return EAXCHORUS_MINFEEDBACK; } + static constexpr auto eax_min_delay() { return EAXCHORUS_MINDELAY; } + + static constexpr auto eax_max_waveform() { return EAXCHORUS_MAXWAVEFORM; } + static constexpr auto eax_max_phase() { return EAXCHORUS_MAXPHASE; } + static constexpr auto eax_max_rate() { return EAXCHORUS_MAXRATE; } + static constexpr auto eax_max_depth() { return EAXCHORUS_MAXDEPTH; } + static constexpr auto eax_max_feedback() { return EAXCHORUS_MAXFEEDBACK; } + static constexpr auto eax_max_delay() { return EAXCHORUS_MAXDELAY; } + + static constexpr auto eax_default_waveform() { return EAXCHORUS_DEFAULTWAVEFORM; } + static constexpr auto eax_default_phase() { return EAXCHORUS_DEFAULTPHASE; } + static constexpr auto eax_default_rate() { return EAXCHORUS_DEFAULTRATE; } + static constexpr auto eax_default_depth() { return EAXCHORUS_DEFAULTDEPTH; } + static constexpr auto eax_default_feedback() { return EAXCHORUS_DEFAULTFEEDBACK; } + static constexpr auto eax_default_delay() { return EAXCHORUS_DEFAULTDELAY; } + + static constexpr auto efx_min_waveform() { return AL_CHORUS_MIN_WAVEFORM; } + static constexpr auto efx_min_phase() { return AL_CHORUS_MIN_PHASE; } + static constexpr auto efx_min_rate() { return AL_CHORUS_MIN_RATE; } + static constexpr auto efx_min_depth() { return AL_CHORUS_MIN_DEPTH; } + static constexpr auto efx_min_feedback() { return AL_CHORUS_MIN_FEEDBACK; } + static constexpr auto efx_min_delay() { return AL_CHORUS_MIN_DELAY; } + + static constexpr auto efx_max_waveform() { return AL_CHORUS_MAX_WAVEFORM; } + static constexpr auto efx_max_phase() { return AL_CHORUS_MAX_PHASE; } + static constexpr auto efx_max_rate() { return AL_CHORUS_MAX_RATE; } + static constexpr auto efx_max_depth() { return AL_CHORUS_MAX_DEPTH; } + static constexpr auto efx_max_feedback() { return AL_CHORUS_MAX_FEEDBACK; } + static constexpr auto efx_max_delay() { return AL_CHORUS_MAX_DELAY; } + + static constexpr auto efx_default_waveform() { return AL_CHORUS_DEFAULT_WAVEFORM; } + static constexpr auto efx_default_phase() { return AL_CHORUS_DEFAULT_PHASE; } + static constexpr auto efx_default_rate() { return AL_CHORUS_DEFAULT_RATE; } + static constexpr auto efx_default_depth() { return AL_CHORUS_DEFAULT_DEPTH; } + static constexpr auto efx_default_feedback() { return AL_CHORUS_DEFAULT_FEEDBACK; } + static constexpr auto efx_default_delay() { return AL_CHORUS_DEFAULT_DELAY; } +}; // EaxChorusTraits + +struct EaxFlangerTraits +{ + using Exception = EaxFlangerEffectException; + using Props = EAXFLANGERPROPERTIES; + + static constexpr auto efx_effect() { return AL_EFFECT_FLANGER; } + + static constexpr auto eax_none_param_id() { return EAXFLANGER_NONE; } + static constexpr auto eax_allparameters_param_id() { return EAXFLANGER_ALLPARAMETERS; } + static constexpr auto eax_waveform_param_id() { return EAXFLANGER_WAVEFORM; } + static constexpr auto eax_phase_param_id() { return EAXFLANGER_PHASE; } + static constexpr auto eax_rate_param_id() { return EAXFLANGER_RATE; } + static constexpr auto eax_depth_param_id() { return EAXFLANGER_DEPTH; } + static constexpr auto eax_feedback_param_id() { return EAXFLANGER_FEEDBACK; } + static constexpr auto eax_delay_param_id() { return EAXFLANGER_DELAY; } + + static constexpr auto eax_min_waveform() { return EAXFLANGER_MINWAVEFORM; } + static constexpr auto eax_min_phase() { return EAXFLANGER_MINPHASE; } + static constexpr auto eax_min_rate() { return EAXFLANGER_MINRATE; } + static constexpr auto eax_min_depth() { return EAXFLANGER_MINDEPTH; } + static constexpr auto eax_min_feedback() { return EAXFLANGER_MINFEEDBACK; } + static constexpr auto eax_min_delay() { return EAXFLANGER_MINDELAY; } + + static constexpr auto eax_max_waveform() { return EAXFLANGER_MAXWAVEFORM; } + static constexpr auto eax_max_phase() { return EAXFLANGER_MAXPHASE; } + static constexpr auto eax_max_rate() { return EAXFLANGER_MAXRATE; } + static constexpr auto eax_max_depth() { return EAXFLANGER_MAXDEPTH; } + static constexpr auto eax_max_feedback() { return EAXFLANGER_MAXFEEDBACK; } + static constexpr auto eax_max_delay() { return EAXFLANGER_MAXDELAY; } + + static constexpr auto eax_default_waveform() { return EAXFLANGER_DEFAULTWAVEFORM; } + static constexpr auto eax_default_phase() { return EAXFLANGER_DEFAULTPHASE; } + static constexpr auto eax_default_rate() { return EAXFLANGER_DEFAULTRATE; } + static constexpr auto eax_default_depth() { return EAXFLANGER_DEFAULTDEPTH; } + static constexpr auto eax_default_feedback() { return EAXFLANGER_DEFAULTFEEDBACK; } + static constexpr auto eax_default_delay() { return EAXFLANGER_DEFAULTDELAY; } + + static constexpr auto efx_min_waveform() { return AL_FLANGER_MIN_WAVEFORM; } + static constexpr auto efx_min_phase() { return AL_FLANGER_MIN_PHASE; } + static constexpr auto efx_min_rate() { return AL_FLANGER_MIN_RATE; } + static constexpr auto efx_min_depth() { return AL_FLANGER_MIN_DEPTH; } + static constexpr auto efx_min_feedback() { return AL_FLANGER_MIN_FEEDBACK; } + static constexpr auto efx_min_delay() { return AL_FLANGER_MIN_DELAY; } + + static constexpr auto efx_max_waveform() { return AL_FLANGER_MAX_WAVEFORM; } + static constexpr auto efx_max_phase() { return AL_FLANGER_MAX_PHASE; } + static constexpr auto efx_max_rate() { return AL_FLANGER_MAX_RATE; } + static constexpr auto efx_max_depth() { return AL_FLANGER_MAX_DEPTH; } + static constexpr auto efx_max_feedback() { return AL_FLANGER_MAX_FEEDBACK; } + static constexpr auto efx_max_delay() { return AL_FLANGER_MAX_DELAY; } + + static constexpr auto efx_default_waveform() { return AL_FLANGER_DEFAULT_WAVEFORM; } + static constexpr auto efx_default_phase() { return AL_FLANGER_DEFAULT_PHASE; } + static constexpr auto efx_default_rate() { return AL_FLANGER_DEFAULT_RATE; } + static constexpr auto efx_default_depth() { return AL_FLANGER_DEFAULT_DEPTH; } + static constexpr auto efx_default_feedback() { return AL_FLANGER_DEFAULT_FEEDBACK; } + static constexpr auto efx_default_delay() { return AL_FLANGER_DEFAULT_DELAY; } +}; // EaxFlangerTraits + +template +class EaxChorusFlangerEffect final : public EaxEffect4 { +public: + using Traits = TTraits; + using Base = EaxEffect4; + using typename Base::Exception; + using typename Base::Props; + using typename Base::State; + using Base::defer; - // [[nodiscard]] - bool apply_deferred() override; + EaxChorusFlangerEffect(const EaxCall& call) + : Base{Traits::efx_effect(), call} + {} private: - EAXCHORUSPROPERTIES eax_{}; - EAXCHORUSPROPERTIES eax_d_{}; - EaxChorusEffectDirtyFlags eax_dirty_flags_{}; - - void set_eax_defaults() noexcept; - - void set_efx_waveform(); - void set_efx_phase(); - void set_efx_rate(); - void set_efx_depth(); - void set_efx_feedback(); - void set_efx_delay(); - void set_efx_defaults(); - - void get(const EaxEaxCall& eax_call); - - void validate_waveform(unsigned long ulWaveform); - void validate_phase(long lPhase); - void validate_rate(float flRate); - void validate_depth(float flDepth); - void validate_feedback(float flFeedback); - void validate_delay(float flDelay); - void validate_all(const EAXCHORUSPROPERTIES& eax_all); - - void defer_waveform(unsigned long ulWaveform); - void defer_phase(long lPhase); - void defer_rate(float flRate); - void defer_depth(float flDepth); - void defer_feedback(float flFeedback); - void defer_delay(float flDelay); - void defer_all(const EAXCHORUSPROPERTIES& eax_all); - - void defer_waveform(const EaxEaxCall& eax_call); - void defer_phase(const EaxEaxCall& eax_call); - void defer_rate(const EaxEaxCall& eax_call); - void defer_depth(const EaxEaxCall& eax_call); - void defer_feedback(const EaxEaxCall& eax_call); - void defer_delay(const EaxEaxCall& eax_call); - void defer_all(const EaxEaxCall& eax_call); - - void set(const EaxEaxCall& eax_call); -}; // EaxChorusEffect - - -class EaxChorusEffectException : - public EaxException -{ -public: - explicit EaxChorusEffectException( - const char* message) - : - EaxException{"EAX_CHORUS_EFFECT", message} + struct WaveformValidator { + void operator()(unsigned long ulWaveform) const + { + eax_validate_range( + "Waveform", + ulWaveform, + Traits::eax_min_waveform(), + Traits::eax_max_waveform()); + } + }; // WaveformValidator + + struct PhaseValidator { + void operator()(long lPhase) const + { + eax_validate_range( + "Phase", + lPhase, + Traits::eax_min_phase(), + Traits::eax_max_phase()); + } + }; // PhaseValidator + + struct RateValidator { + void operator()(float flRate) const + { + eax_validate_range( + "Rate", + flRate, + Traits::eax_min_rate(), + Traits::eax_max_rate()); + } + }; // RateValidator + + struct DepthValidator { + void operator()(float flDepth) const + { + eax_validate_range( + "Depth", + flDepth, + Traits::eax_min_depth(), + Traits::eax_max_depth()); + } + }; // DepthValidator + + struct FeedbackValidator { + void operator()(float flFeedback) const + { + eax_validate_range( + "Feedback", + flFeedback, + Traits::eax_min_feedback(), + Traits::eax_max_feedback()); + } + }; // FeedbackValidator + + struct DelayValidator { + void operator()(float flDelay) const + { + eax_validate_range( + "Delay", + flDelay, + Traits::eax_min_delay(), + Traits::eax_max_delay()); + } + }; // DelayValidator + + struct AllValidator { + void operator()(const Props& all) const + { + WaveformValidator{}(all.ulWaveform); + PhaseValidator{}(all.lPhase); + RateValidator{}(all.flRate); + DepthValidator{}(all.flDepth); + FeedbackValidator{}(all.flFeedback); + DelayValidator{}(all.flDelay); + } + }; // AllValidator + + void set_defaults(Props& props) override { + props.ulWaveform = Traits::eax_default_waveform(); + props.lPhase = Traits::eax_default_phase(); + props.flRate = Traits::eax_default_rate(); + props.flDepth = Traits::eax_default_depth(); + props.flFeedback = Traits::eax_default_feedback(); + props.flDelay = Traits::eax_default_delay(); } -}; // EaxChorusEffectException - - -EaxChorusEffect::EaxChorusEffect() - : EaxEffect{AL_EFFECT_CHORUS} -{ - set_eax_defaults(); - set_efx_defaults(); -} - -void EaxChorusEffect::dispatch(const EaxEaxCall& eax_call) -{ - eax_call.is_get() ? get(eax_call) : set(eax_call); -} - -void EaxChorusEffect::set_eax_defaults() noexcept -{ - eax_.ulWaveform = EAXCHORUS_DEFAULTWAVEFORM; - eax_.lPhase = EAXCHORUS_DEFAULTPHASE; - eax_.flRate = EAXCHORUS_DEFAULTRATE; - eax_.flDepth = EAXCHORUS_DEFAULTDEPTH; - eax_.flFeedback = EAXCHORUS_DEFAULTFEEDBACK; - eax_.flDelay = EAXCHORUS_DEFAULTDELAY; - - eax_d_ = eax_; -} - -void EaxChorusEffect::set_efx_waveform() -{ - const auto waveform = clamp( - static_cast(eax_.ulWaveform), - AL_CHORUS_MIN_WAVEFORM, - AL_CHORUS_MAX_WAVEFORM); - eax_set_efx_waveform(waveform, al_effect_props_); -} - -void EaxChorusEffect::set_efx_phase() -{ - const auto phase = clamp( - static_cast(eax_.lPhase), - AL_CHORUS_MIN_PHASE, - AL_CHORUS_MAX_PHASE); - - eax_set_efx_phase(phase, al_effect_props_); -} - -void EaxChorusEffect::set_efx_rate() -{ - const auto rate = clamp( - eax_.flRate, - AL_CHORUS_MIN_RATE, - AL_CHORUS_MAX_RATE); - - eax_set_efx_rate(rate, al_effect_props_); -} - -void EaxChorusEffect::set_efx_depth() -{ - const auto depth = clamp( - eax_.flDepth, - AL_CHORUS_MIN_DEPTH, - AL_CHORUS_MAX_DEPTH); - - eax_set_efx_depth(depth, al_effect_props_); -} - -void EaxChorusEffect::set_efx_feedback() -{ - const auto feedback = clamp( - eax_.flFeedback, - AL_CHORUS_MIN_FEEDBACK, - AL_CHORUS_MAX_FEEDBACK); - - eax_set_efx_feedback(feedback, al_effect_props_); -} - -void EaxChorusEffect::set_efx_delay() -{ - const auto delay = clamp( - eax_.flDelay, - AL_CHORUS_MIN_DELAY, - AL_CHORUS_MAX_DELAY); - - eax_set_efx_delay(delay, al_effect_props_); -} - -void EaxChorusEffect::set_efx_defaults() -{ - set_efx_waveform(); - set_efx_phase(); - set_efx_rate(); - set_efx_depth(); - set_efx_feedback(); - set_efx_delay(); -} - -void EaxChorusEffect::get(const EaxEaxCall& eax_call) -{ - switch(eax_call.get_property_id()) + void set_efx_waveform() { - case EAXCHORUS_NONE: - break; - - case EAXCHORUS_ALLPARAMETERS: - eax_call.set_value(eax_); - break; - - case EAXCHORUS_WAVEFORM: - eax_call.set_value(eax_.ulWaveform); - break; - - case EAXCHORUS_PHASE: - eax_call.set_value(eax_.lPhase); - break; - - case EAXCHORUS_RATE: - eax_call.set_value(eax_.flRate); - break; - - case EAXCHORUS_DEPTH: - eax_call.set_value(eax_.flDepth); - break; - - case EAXCHORUS_FEEDBACK: - eax_call.set_value(eax_.flFeedback); - break; - - case EAXCHORUS_DELAY: - eax_call.set_value(eax_.flDelay); - break; - - default: - throw EaxChorusEffectException{"Unsupported property id."}; + const auto waveform = clamp( + static_cast(Base::props_.ulWaveform), + Traits::efx_min_waveform(), + Traits::efx_max_waveform()); + const auto efx_waveform = WaveformFromEnum(waveform); + assert(efx_waveform.has_value()); + Base::al_effect_props_.Chorus.Waveform = *efx_waveform; } -} - -void EaxChorusEffect::validate_waveform( - unsigned long ulWaveform) -{ - eax_validate_range( - "Waveform", - ulWaveform, - EAXCHORUS_MINWAVEFORM, - EAXCHORUS_MAXWAVEFORM); -} - -void EaxChorusEffect::validate_phase( - long lPhase) -{ - eax_validate_range( - "Phase", - lPhase, - EAXCHORUS_MINPHASE, - EAXCHORUS_MAXPHASE); -} - -void EaxChorusEffect::validate_rate( - float flRate) -{ - eax_validate_range( - "Rate", - flRate, - EAXCHORUS_MINRATE, - EAXCHORUS_MAXRATE); -} - -void EaxChorusEffect::validate_depth( - float flDepth) -{ - eax_validate_range( - "Depth", - flDepth, - EAXCHORUS_MINDEPTH, - EAXCHORUS_MAXDEPTH); -} - -void EaxChorusEffect::validate_feedback( - float flFeedback) -{ - eax_validate_range( - "Feedback", - flFeedback, - EAXCHORUS_MINFEEDBACK, - EAXCHORUS_MAXFEEDBACK); -} - -void EaxChorusEffect::validate_delay( - float flDelay) -{ - eax_validate_range( - "Delay", - flDelay, - EAXCHORUS_MINDELAY, - EAXCHORUS_MAXDELAY); -} - -void EaxChorusEffect::validate_all( - const EAXCHORUSPROPERTIES& eax_all) -{ - validate_waveform(eax_all.ulWaveform); - validate_phase(eax_all.lPhase); - validate_rate(eax_all.flRate); - validate_depth(eax_all.flDepth); - validate_feedback(eax_all.flFeedback); - validate_delay(eax_all.flDelay); -} - -void EaxChorusEffect::defer_waveform( - unsigned long ulWaveform) -{ - eax_d_.ulWaveform = ulWaveform; - eax_dirty_flags_.ulWaveform = (eax_.ulWaveform != eax_d_.ulWaveform); -} - -void EaxChorusEffect::defer_phase( - long lPhase) -{ - eax_d_.lPhase = lPhase; - eax_dirty_flags_.lPhase = (eax_.lPhase != eax_d_.lPhase); -} - -void EaxChorusEffect::defer_rate( - float flRate) -{ - eax_d_.flRate = flRate; - eax_dirty_flags_.flRate = (eax_.flRate != eax_d_.flRate); -} - -void EaxChorusEffect::defer_depth( - float flDepth) -{ - eax_d_.flDepth = flDepth; - eax_dirty_flags_.flDepth = (eax_.flDepth != eax_d_.flDepth); -} - -void EaxChorusEffect::defer_feedback( - float flFeedback) -{ - eax_d_.flFeedback = flFeedback; - eax_dirty_flags_.flFeedback = (eax_.flFeedback != eax_d_.flFeedback); -} - -void EaxChorusEffect::defer_delay( - float flDelay) -{ - eax_d_.flDelay = flDelay; - eax_dirty_flags_.flDelay = (eax_.flDelay != eax_d_.flDelay); -} - -void EaxChorusEffect::defer_all( - const EAXCHORUSPROPERTIES& eax_all) -{ - defer_waveform(eax_all.ulWaveform); - defer_phase(eax_all.lPhase); - defer_rate(eax_all.flRate); - defer_depth(eax_all.flDepth); - defer_feedback(eax_all.flFeedback); - defer_delay(eax_all.flDelay); -} - -void EaxChorusEffect::defer_waveform( - const EaxEaxCall& eax_call) -{ - const auto& waveform = - eax_call.get_value(); - - validate_waveform(waveform); - defer_waveform(waveform); -} - -void EaxChorusEffect::defer_phase( - const EaxEaxCall& eax_call) -{ - const auto& phase = - eax_call.get_value(); - - validate_phase(phase); - defer_phase(phase); -} - -void EaxChorusEffect::defer_rate( - const EaxEaxCall& eax_call) -{ - const auto& rate = - eax_call.get_value(); - - validate_rate(rate); - defer_rate(rate); -} - -void EaxChorusEffect::defer_depth( - const EaxEaxCall& eax_call) -{ - const auto& depth = - eax_call.get_value(); - - validate_depth(depth); - defer_depth(depth); -} - -void EaxChorusEffect::defer_feedback( - const EaxEaxCall& eax_call) -{ - const auto& feedback = - eax_call.get_value(); - - validate_feedback(feedback); - defer_feedback(feedback); -} - -void EaxChorusEffect::defer_delay( - const EaxEaxCall& eax_call) -{ - const auto& delay = - eax_call.get_value(); - validate_delay(delay); - defer_delay(delay); -} - -void EaxChorusEffect::defer_all( - const EaxEaxCall& eax_call) -{ - const auto& all = - eax_call.get_value(); - - validate_all(all); - defer_all(all); -} - -// [[nodiscard]] -bool EaxChorusEffect::apply_deferred() -{ - if (eax_dirty_flags_ == EaxChorusEffectDirtyFlags{}) + void set_efx_phase() noexcept { - return false; + Base::al_effect_props_.Chorus.Phase = clamp( + static_cast(Base::props_.lPhase), + Traits::efx_min_phase(), + Traits::efx_max_phase()); } - eax_ = eax_d_; - - if (eax_dirty_flags_.ulWaveform) + void set_efx_rate() noexcept { - set_efx_waveform(); + Base::al_effect_props_.Chorus.Rate = clamp( + Base::props_.flRate, + Traits::efx_min_rate(), + Traits::efx_max_rate()); } - if (eax_dirty_flags_.lPhase) + void set_efx_depth() noexcept { - set_efx_phase(); + Base::al_effect_props_.Chorus.Depth = clamp( + Base::props_.flDepth, + Traits::efx_min_depth(), + Traits::efx_max_depth()); } - if (eax_dirty_flags_.flRate) + void set_efx_feedback() noexcept { - set_efx_rate(); + Base::al_effect_props_.Chorus.Feedback = clamp( + Base::props_.flFeedback, + Traits::efx_min_feedback(), + Traits::efx_max_feedback()); } - if (eax_dirty_flags_.flDepth) + void set_efx_delay() noexcept { - set_efx_depth(); + Base::al_effect_props_.Chorus.Delay = clamp( + Base::props_.flDelay, + Traits::efx_min_delay(), + Traits::efx_max_delay()); } - if (eax_dirty_flags_.flFeedback) + void set_efx_defaults() override { + set_efx_waveform(); + set_efx_phase(); + set_efx_rate(); + set_efx_depth(); set_efx_feedback(); - } - - if (eax_dirty_flags_.flDelay) - { set_efx_delay(); } - eax_dirty_flags_ = EaxChorusEffectDirtyFlags{}; - - return true; -} - -void EaxChorusEffect::set(const EaxEaxCall& eax_call) -{ - switch(eax_call.get_property_id()) + void get(const EaxCall& call, const Props& props) override { - case EAXCHORUS_NONE: - break; - - case EAXCHORUS_ALLPARAMETERS: - defer_all(eax_call); - break; - - case EAXCHORUS_WAVEFORM: - defer_waveform(eax_call); - break; - - case EAXCHORUS_PHASE: - defer_phase(eax_call); - break; - - case EAXCHORUS_RATE: - defer_rate(eax_call); - break; - - case EAXCHORUS_DEPTH: - defer_depth(eax_call); - break; - - case EAXCHORUS_FEEDBACK: - defer_feedback(eax_call); - break; - - case EAXCHORUS_DELAY: - defer_delay(eax_call); - break; - - default: - throw EaxChorusEffectException{"Unsupported property id."}; + switch(call.get_property_id()) + { + case Traits::eax_none_param_id(): + break; + + case Traits::eax_allparameters_param_id(): + call.template set_value(props); + break; + + case Traits::eax_waveform_param_id(): + call.template set_value(props.ulWaveform); + break; + + case Traits::eax_phase_param_id(): + call.template set_value(props.lPhase); + break; + + case Traits::eax_rate_param_id(): + call.template set_value(props.flRate); + break; + + case Traits::eax_depth_param_id(): + call.template set_value(props.flDepth); + break; + + case Traits::eax_feedback_param_id(): + call.template set_value(props.flFeedback); + break; + + case Traits::eax_delay_param_id(): + call.template set_value(props.flDelay); + break; + + default: + Base::fail_unknown_property_id(); + } } -} - - -} // namespace - -EaxEffectUPtr eax_create_eax_chorus_effect() -{ - return std::make_unique<::EaxChorusEffect>(); -} - - -namespace -{ - - -using EaxFlangerEffectDirtyFlagsValue = std::uint_least8_t; - -struct EaxFlangerEffectDirtyFlags -{ - using EaxIsBitFieldStruct = bool; - - EaxFlangerEffectDirtyFlagsValue ulWaveform : 1; - EaxFlangerEffectDirtyFlagsValue lPhase : 1; - EaxFlangerEffectDirtyFlagsValue flRate : 1; - EaxFlangerEffectDirtyFlagsValue flDepth : 1; - EaxFlangerEffectDirtyFlagsValue flFeedback : 1; - EaxFlangerEffectDirtyFlagsValue flDelay : 1; -}; // EaxFlangerEffectDirtyFlags - - -class EaxFlangerEffect final : - public EaxEffect -{ -public: - EaxFlangerEffect(); - - - void dispatch(const EaxEaxCall& eax_call) override; - - // [[nodiscard]] - bool apply_deferred() override; - -private: - EAXFLANGERPROPERTIES eax_{}; - EAXFLANGERPROPERTIES eax_d_{}; - EaxFlangerEffectDirtyFlags eax_dirty_flags_{}; - - void set_eax_defaults(); - - void set_efx_waveform(); - void set_efx_phase(); - void set_efx_rate(); - void set_efx_depth(); - void set_efx_feedback(); - void set_efx_delay(); - void set_efx_defaults(); - - void get(const EaxEaxCall& eax_call); - - void validate_waveform(unsigned long ulWaveform); - void validate_phase(long lPhase); - void validate_rate(float flRate); - void validate_depth(float flDepth); - void validate_feedback(float flFeedback); - void validate_delay(float flDelay); - void validate_all(const EAXFLANGERPROPERTIES& all); - - void defer_waveform(unsigned long ulWaveform); - void defer_phase(long lPhase); - void defer_rate(float flRate); - void defer_depth(float flDepth); - void defer_feedback(float flFeedback); - void defer_delay(float flDelay); - void defer_all(const EAXFLANGERPROPERTIES& all); - - void defer_waveform(const EaxEaxCall& eax_call); - void defer_phase(const EaxEaxCall& eax_call); - void defer_rate(const EaxEaxCall& eax_call); - void defer_depth(const EaxEaxCall& eax_call); - void defer_feedback(const EaxEaxCall& eax_call); - void defer_delay(const EaxEaxCall& eax_call); - void defer_all(const EaxEaxCall& eax_call); - - void set(const EaxEaxCall& eax_call); -}; // EaxFlangerEffect - - -class EaxFlangerEffectException : - public EaxException -{ -public: - explicit EaxFlangerEffectException( - const char* message) - : - EaxException{"EAX_FLANGER_EFFECT", message} + void set(const EaxCall& call, Props& props) override { + switch(call.get_property_id()) + { + case Traits::eax_none_param_id(): + break; + + case Traits::eax_allparameters_param_id(): + Base::template defer(call, props); + break; + + case Traits::eax_waveform_param_id(): + Base::template defer(call, props.ulWaveform); + break; + + case Traits::eax_phase_param_id(): + Base::template defer(call, props.lPhase); + break; + + case Traits::eax_rate_param_id(): + Base::template defer(call, props.flRate); + break; + + case Traits::eax_depth_param_id(): + Base::template defer(call, props.flDepth); + break; + + case Traits::eax_feedback_param_id(): + Base::template defer(call, props.flFeedback); + break; + + case Traits::eax_delay_param_id(): + Base::template defer(call, props.flDelay); + break; + + default: + Base::fail_unknown_property_id(); + } } -}; // EaxFlangerEffectException - - -EaxFlangerEffect::EaxFlangerEffect() - : EaxEffect{AL_EFFECT_FLANGER} -{ - set_eax_defaults(); - set_efx_defaults(); -} - -void EaxFlangerEffect::dispatch(const EaxEaxCall& eax_call) -{ - eax_call.is_get() ? get(eax_call) : set(eax_call); -} - -void EaxFlangerEffect::set_eax_defaults() -{ - eax_.ulWaveform = EAXFLANGER_DEFAULTWAVEFORM; - eax_.lPhase = EAXFLANGER_DEFAULTPHASE; - eax_.flRate = EAXFLANGER_DEFAULTRATE; - eax_.flDepth = EAXFLANGER_DEFAULTDEPTH; - eax_.flFeedback = EAXFLANGER_DEFAULTFEEDBACK; - eax_.flDelay = EAXFLANGER_DEFAULTDELAY; - - eax_d_ = eax_; -} - -void EaxFlangerEffect::set_efx_waveform() -{ - const auto waveform = clamp( - static_cast(eax_.ulWaveform), - AL_FLANGER_MIN_WAVEFORM, - AL_FLANGER_MAX_WAVEFORM); - - eax_set_efx_waveform(waveform, al_effect_props_); -} - -void EaxFlangerEffect::set_efx_phase() -{ - const auto phase = clamp( - static_cast(eax_.lPhase), - AL_FLANGER_MIN_PHASE, - AL_FLANGER_MAX_PHASE); - - eax_set_efx_phase(phase, al_effect_props_); -} - -void EaxFlangerEffect::set_efx_rate() -{ - const auto rate = clamp( - eax_.flRate, - AL_FLANGER_MIN_RATE, - AL_FLANGER_MAX_RATE); - - eax_set_efx_rate(rate, al_effect_props_); -} - -void EaxFlangerEffect::set_efx_depth() -{ - const auto depth = clamp( - eax_.flDepth, - AL_FLANGER_MIN_DEPTH, - AL_FLANGER_MAX_DEPTH); - - eax_set_efx_depth(depth, al_effect_props_); -} - -void EaxFlangerEffect::set_efx_feedback() -{ - const auto feedback = clamp( - eax_.flFeedback, - AL_FLANGER_MIN_FEEDBACK, - AL_FLANGER_MAX_FEEDBACK); - - eax_set_efx_feedback(feedback, al_effect_props_); -} - -void EaxFlangerEffect::set_efx_delay() -{ - const auto delay = clamp( - eax_.flDelay, - AL_FLANGER_MIN_DELAY, - AL_FLANGER_MAX_DELAY); - eax_set_efx_delay(delay, al_effect_props_); -} - -void EaxFlangerEffect::set_efx_defaults() -{ - set_efx_waveform(); - set_efx_phase(); - set_efx_rate(); - set_efx_depth(); - set_efx_feedback(); - set_efx_delay(); -} - -void EaxFlangerEffect::get(const EaxEaxCall& eax_call) -{ - switch(eax_call.get_property_id()) + bool commit_props(const Props& props) override { - case EAXFLANGER_NONE: - break; - - case EAXFLANGER_ALLPARAMETERS: - eax_call.set_value(eax_); - break; - - case EAXFLANGER_WAVEFORM: - eax_call.set_value(eax_.ulWaveform); - break; - - case EAXFLANGER_PHASE: - eax_call.set_value(eax_.lPhase); - break; - - case EAXFLANGER_RATE: - eax_call.set_value(eax_.flRate); - break; - - case EAXFLANGER_DEPTH: - eax_call.set_value(eax_.flDepth); - break; - - case EAXFLANGER_FEEDBACK: - eax_call.set_value(eax_.flFeedback); - break; - - case EAXFLANGER_DELAY: - eax_call.set_value(eax_.flDelay); - break; - - default: - throw EaxFlangerEffectException{"Unsupported property id."}; + auto is_dirty = false; + + if (Base::props_.ulWaveform != props.ulWaveform) + { + is_dirty = true; + set_efx_waveform(); + } + + if (Base::props_.lPhase != props.lPhase) + { + is_dirty = true; + set_efx_phase(); + } + + if (Base::props_.flRate != props.flRate) + { + is_dirty = true; + set_efx_rate(); + } + + if (Base::props_.flDepth != props.flDepth) + { + is_dirty = true; + set_efx_depth(); + } + + if (Base::props_.flFeedback != props.flFeedback) + { + is_dirty = true; + set_efx_feedback(); + } + + if (Base::props_.flDelay != props.flDelay) + { + is_dirty = true; + set_efx_delay(); + } + + return is_dirty; } -} - -void EaxFlangerEffect::validate_waveform( - unsigned long ulWaveform) -{ - eax_validate_range( - "Waveform", - ulWaveform, - EAXFLANGER_MINWAVEFORM, - EAXFLANGER_MAXWAVEFORM); -} - -void EaxFlangerEffect::validate_phase( - long lPhase) -{ - eax_validate_range( - "Phase", - lPhase, - EAXFLANGER_MINPHASE, - EAXFLANGER_MAXPHASE); -} - -void EaxFlangerEffect::validate_rate( - float flRate) -{ - eax_validate_range( - "Rate", - flRate, - EAXFLANGER_MINRATE, - EAXFLANGER_MAXRATE); -} - -void EaxFlangerEffect::validate_depth( - float flDepth) -{ - eax_validate_range( - "Depth", - flDepth, - EAXFLANGER_MINDEPTH, - EAXFLANGER_MAXDEPTH); -} - -void EaxFlangerEffect::validate_feedback( - float flFeedback) -{ - eax_validate_range( - "Feedback", - flFeedback, - EAXFLANGER_MINFEEDBACK, - EAXFLANGER_MAXFEEDBACK); -} - -void EaxFlangerEffect::validate_delay( - float flDelay) -{ - eax_validate_range( - "Delay", - flDelay, - EAXFLANGER_MINDELAY, - EAXFLANGER_MAXDELAY); -} - -void EaxFlangerEffect::validate_all( - const EAXFLANGERPROPERTIES& all) -{ - validate_waveform(all.ulWaveform); - validate_phase(all.lPhase); - validate_rate(all.flRate); - validate_depth(all.flDepth); - validate_feedback(all.flDelay); - validate_delay(all.flDelay); -} +}; // EaxChorusFlangerEffect -void EaxFlangerEffect::defer_waveform( - unsigned long ulWaveform) +template +EaxEffectUPtr eax_create_eax_chorus_flanger_effect(const EaxCall& call) { - eax_d_.ulWaveform = ulWaveform; - eax_dirty_flags_.ulWaveform = (eax_.ulWaveform != eax_d_.ulWaveform); + return eax_create_eax4_effect>(call); } -void EaxFlangerEffect::defer_phase( - long lPhase) -{ - eax_d_.lPhase = lPhase; - eax_dirty_flags_.lPhase = (eax_.lPhase != eax_d_.lPhase); -} - -void EaxFlangerEffect::defer_rate( - float flRate) -{ - eax_d_.flRate = flRate; - eax_dirty_flags_.flRate = (eax_.flRate != eax_d_.flRate); -} - -void EaxFlangerEffect::defer_depth( - float flDepth) -{ - eax_d_.flDepth = flDepth; - eax_dirty_flags_.flDepth = (eax_.flDepth != eax_d_.flDepth); -} - -void EaxFlangerEffect::defer_feedback( - float flFeedback) -{ - eax_d_.flFeedback = flFeedback; - eax_dirty_flags_.flFeedback = (eax_.flFeedback != eax_d_.flFeedback); -} - -void EaxFlangerEffect::defer_delay( - float flDelay) -{ - eax_d_.flDelay = flDelay; - eax_dirty_flags_.flDelay = (eax_.flDelay != eax_d_.flDelay); -} - -void EaxFlangerEffect::defer_all( - const EAXFLANGERPROPERTIES& all) -{ - defer_waveform(all.ulWaveform); - defer_phase(all.lPhase); - defer_rate(all.flRate); - defer_depth(all.flDepth); - defer_feedback(all.flDelay); - defer_delay(all.flDelay); -} - -void EaxFlangerEffect::defer_waveform( - const EaxEaxCall& eax_call) -{ - const auto& waveform = - eax_call.get_value(); - - validate_waveform(waveform); - defer_waveform(waveform); -} - -void EaxFlangerEffect::defer_phase( - const EaxEaxCall& eax_call) -{ - const auto& phase = - eax_call.get_value(); - - validate_phase(phase); - defer_phase(phase); -} - -void EaxFlangerEffect::defer_rate( - const EaxEaxCall& eax_call) -{ - const auto& rate = - eax_call.get_value(); - - validate_rate(rate); - defer_rate(rate); -} - -void EaxFlangerEffect::defer_depth( - const EaxEaxCall& eax_call) -{ - const auto& depth = - eax_call.get_value(); - - validate_depth(depth); - defer_depth(depth); -} - -void EaxFlangerEffect::defer_feedback( - const EaxEaxCall& eax_call) -{ - const auto& feedback = - eax_call.get_value(); - - validate_feedback(feedback); - defer_feedback(feedback); -} - -void EaxFlangerEffect::defer_delay( - const EaxEaxCall& eax_call) -{ - const auto& delay = - eax_call.get_value(); - - validate_delay(delay); - defer_delay(delay); -} - -void EaxFlangerEffect::defer_all( - const EaxEaxCall& eax_call) -{ - const auto& all = - eax_call.get_value(); - - validate_all(all); - defer_all(all); -} - -// [[nodiscard]] -bool EaxFlangerEffect::apply_deferred() -{ - if (eax_dirty_flags_ == EaxFlangerEffectDirtyFlags{}) - { - return false; - } - - eax_ = eax_d_; - - if (eax_dirty_flags_.ulWaveform) - { - set_efx_waveform(); - } - - if (eax_dirty_flags_.lPhase) - { - set_efx_phase(); - } - - if (eax_dirty_flags_.flRate) - { - set_efx_rate(); - } - - if (eax_dirty_flags_.flDepth) - { - set_efx_depth(); - } - - if (eax_dirty_flags_.flFeedback) - { - set_efx_feedback(); - } - - if (eax_dirty_flags_.flDelay) - { - set_efx_delay(); - } +} // namespace - eax_dirty_flags_ = EaxFlangerEffectDirtyFlags{}; +// ========================================================================== - return true; -} - -void EaxFlangerEffect::set(const EaxEaxCall& eax_call) +EaxEffectUPtr eax_create_eax_chorus_effect(const EaxCall& call) { - switch(eax_call.get_property_id()) - { - case EAXFLANGER_NONE: - break; - - case EAXFLANGER_ALLPARAMETERS: - defer_all(eax_call); - break; - - case EAXFLANGER_WAVEFORM: - defer_waveform(eax_call); - break; - - case EAXFLANGER_PHASE: - defer_phase(eax_call); - break; - - case EAXFLANGER_RATE: - defer_rate(eax_call); - break; - - case EAXFLANGER_DEPTH: - defer_depth(eax_call); - break; - - case EAXFLANGER_FEEDBACK: - defer_feedback(eax_call); - break; - - case EAXFLANGER_DELAY: - defer_delay(eax_call); - break; - - default: - throw EaxFlangerEffectException{"Unsupported property id."}; - } + return eax_create_eax_chorus_flanger_effect(call); } -} // namespace - -EaxEffectUPtr eax_create_eax_flanger_effect() +EaxEffectUPtr eax_create_eax_flanger_effect(const EaxCall& call) { - return std::make_unique(); + return eax_create_eax_chorus_flanger_effect(call); } #endif // ALSOFT_EAX diff --git a/modules/openal-soft/al/effects/compressor.cpp b/modules/openal-soft/al/effects/compressor.cpp index bb5dfa3..9824d11 100644 --- a/modules/openal-soft/al/effects/compressor.cpp +++ b/modules/openal-soft/al/effects/compressor.cpp @@ -9,9 +9,8 @@ #ifdef ALSOFT_EAX #include "alnumeric.h" - -#include "al/eax_exception.h" -#include "al/eax_utils.h" +#include "al/eax/exception.h" +#include "al/eax/utils.h" #endif // ALSOFT_EAX @@ -81,94 +80,63 @@ const EffectProps CompressorEffectProps{genDefaultProps()}; #ifdef ALSOFT_EAX namespace { -using EaxCompressorEffectDirtyFlagsValue = std::uint_least8_t; - -struct EaxCompressorEffectDirtyFlags +class EaxCompressorEffectException : public EaxException { - using EaxIsBitFieldStruct = bool; - - EaxCompressorEffectDirtyFlagsValue ulOnOff : 1; -}; // EaxCompressorEffectDirtyFlags - +public: + explicit EaxCompressorEffectException(const char* message) + : EaxException{"EAX_COMPRESSOR_EFFECT", message} + {} +}; // EaxCompressorEffectException -class EaxCompressorEffect final : - public EaxEffect +class EaxCompressorEffect final : public EaxEffect4 { public: - EaxCompressorEffect(); - - - void dispatch(const EaxEaxCall& eax_call) override; - - // [[nodiscard]] - bool apply_deferred() override; + EaxCompressorEffect(const EaxCall& call); private: - EAXAGCCOMPRESSORPROPERTIES eax_{}; - EAXAGCCOMPRESSORPROPERTIES eax_d_{}; - EaxCompressorEffectDirtyFlags eax_dirty_flags_{}; - - - void set_eax_defaults(); - - void set_efx_on_off(); - void set_efx_defaults(); - - void get(const EaxEaxCall& eax_call); - - void validate_on_off(unsigned long ulOnOff); - void validate_all(const EAXAGCCOMPRESSORPROPERTIES& eax_all); - - void defer_on_off(unsigned long ulOnOff); - void defer_all(const EAXAGCCOMPRESSORPROPERTIES& eax_all); - - void defer_on_off(const EaxEaxCall& eax_call); - void defer_all(const EaxEaxCall& eax_call); - - void set(const EaxEaxCall& eax_call); + struct OnOffValidator { + void operator()(unsigned long ulOnOff) const + { + eax_validate_range( + "On-Off", + ulOnOff, + EAXAGCCOMPRESSOR_MINONOFF, + EAXAGCCOMPRESSOR_MAXONOFF); + } + }; // OnOffValidator + + struct AllValidator { + void operator()(const Props& all) const + { + OnOffValidator{}(all.ulOnOff); + } + }; // AllValidator + + void set_defaults(Props& props) override; + + void set_efx_on_off() noexcept; + void set_efx_defaults() override; + + void get(const EaxCall& call, const Props& props) override; + void set(const EaxCall& call, Props& props) override; + bool commit_props(const Props& props) override; }; // EaxCompressorEffect +EaxCompressorEffect::EaxCompressorEffect(const EaxCall& call) + : EaxEffect4{AL_EFFECT_COMPRESSOR, call} +{} -class EaxCompressorEffectException : - public EaxException +void EaxCompressorEffect::set_defaults(Props& props) { -public: - explicit EaxCompressorEffectException( - const char* message) - : - EaxException{"EAX_COMPRESSOR_EFFECT", message} - { - } -}; // EaxCompressorEffectException - - -EaxCompressorEffect::EaxCompressorEffect() - : EaxEffect{AL_EFFECT_COMPRESSOR} -{ - set_eax_defaults(); - set_efx_defaults(); -} - -// [[nodiscard]] -void EaxCompressorEffect::dispatch(const EaxEaxCall& eax_call) -{ - eax_call.is_get() ? get(eax_call) : set(eax_call); -} - -void EaxCompressorEffect::set_eax_defaults() -{ - eax_.ulOnOff = EAXAGCCOMPRESSOR_DEFAULTONOFF; - - eax_d_ = eax_; + props.ulOnOff = EAXAGCCOMPRESSOR_DEFAULTONOFF; } -void EaxCompressorEffect::set_efx_on_off() +void EaxCompressorEffect::set_efx_on_off() noexcept { const auto on_off = clamp( - static_cast(eax_.ulOnOff), + static_cast(props_.ulOnOff), AL_COMPRESSOR_MIN_ONOFF, AL_COMPRESSOR_MAX_ONOFF); - al_effect_props_.Compressor.OnOff = (on_off != AL_FALSE); } @@ -177,120 +145,46 @@ void EaxCompressorEffect::set_efx_defaults() set_efx_on_off(); } -void EaxCompressorEffect::get(const EaxEaxCall& eax_call) +void EaxCompressorEffect::get(const EaxCall& call, const Props& props) { - switch(eax_call.get_property_id()) + switch(call.get_property_id()) { - case EAXAGCCOMPRESSOR_NONE: - break; - - case EAXAGCCOMPRESSOR_ALLPARAMETERS: - eax_call.set_value(eax_); - break; - - case EAXAGCCOMPRESSOR_ONOFF: - eax_call.set_value(eax_.ulOnOff); - break; - - default: - throw EaxCompressorEffectException{"Unsupported property id."}; + case EAXAGCCOMPRESSOR_NONE: break; + case EAXAGCCOMPRESSOR_ALLPARAMETERS: call.set_value(props); break; + case EAXAGCCOMPRESSOR_ONOFF: call.set_value(props.ulOnOff); break; + default: fail_unknown_property_id(); } } -void EaxCompressorEffect::validate_on_off( - unsigned long ulOnOff) -{ - eax_validate_range( - "On-Off", - ulOnOff, - EAXAGCCOMPRESSOR_MINONOFF, - EAXAGCCOMPRESSOR_MAXONOFF); -} - -void EaxCompressorEffect::validate_all( - const EAXAGCCOMPRESSORPROPERTIES& eax_all) +void EaxCompressorEffect::set(const EaxCall& call, Props& props) { - validate_on_off(eax_all.ulOnOff); -} - -void EaxCompressorEffect::defer_on_off( - unsigned long ulOnOff) -{ - eax_d_.ulOnOff = ulOnOff; - eax_dirty_flags_.ulOnOff = (eax_.ulOnOff != eax_d_.ulOnOff); -} - -void EaxCompressorEffect::defer_all( - const EAXAGCCOMPRESSORPROPERTIES& eax_all) -{ - defer_on_off(eax_all.ulOnOff); -} - -void EaxCompressorEffect::defer_on_off( - const EaxEaxCall& eax_call) -{ - const auto& on_off = - eax_call.get_value(); - - validate_on_off(on_off); - defer_on_off(on_off); -} - -void EaxCompressorEffect::defer_all( - const EaxEaxCall& eax_call) -{ - const auto& all = - eax_call.get_value(); - - validate_all(all); - defer_all(all); -} - -// [[nodiscard]] -bool EaxCompressorEffect::apply_deferred() -{ - if (eax_dirty_flags_ == EaxCompressorEffectDirtyFlags{}) + switch(call.get_property_id()) { - return false; + case EAXAGCCOMPRESSOR_NONE: break; + case EAXAGCCOMPRESSOR_ALLPARAMETERS: defer(call, props); break; + case EAXAGCCOMPRESSOR_ONOFF: defer(call, props.ulOnOff); break; + default: fail_unknown_property_id(); } +} - eax_ = eax_d_; +bool EaxCompressorEffect::commit_props(const Props& props) +{ + auto is_dirty = false; - if (eax_dirty_flags_.ulOnOff) + if (props_.ulOnOff != props.ulOnOff) { + is_dirty = true; set_efx_on_off(); } - eax_dirty_flags_ = EaxCompressorEffectDirtyFlags{}; - - return true; -} - -void EaxCompressorEffect::set(const EaxEaxCall& eax_call) -{ - switch(eax_call.get_property_id()) - { - case EAXAGCCOMPRESSOR_NONE: - break; - - case EAXAGCCOMPRESSOR_ALLPARAMETERS: - defer_all(eax_call); - break; - - case EAXAGCCOMPRESSOR_ONOFF: - defer_on_off(eax_call); - break; - - default: - throw EaxCompressorEffectException{"Unsupported property id."}; - } + return is_dirty; } } // namespace -EaxEffectUPtr eax_create_eax_compressor_effect() +EaxEffectUPtr eax_create_eax_compressor_effect(const EaxCall& call) { - return std::make_unique(); + return eax_create_eax4_effect(call); } #endif // ALSOFT_EAX diff --git a/modules/openal-soft/al/effects/distortion.cpp b/modules/openal-soft/al/effects/distortion.cpp index 13b1f23..b58412b 100644 --- a/modules/openal-soft/al/effects/distortion.cpp +++ b/modules/openal-soft/al/effects/distortion.cpp @@ -9,9 +9,8 @@ #ifdef ALSOFT_EAX #include "alnumeric.h" - -#include "al/eax_exception.h" -#include "al/eax_utils.h" +#include "al/eax/exception.h" +#include "al/eax/utils.h" #endif // ALSOFT_EAX @@ -123,156 +122,151 @@ const EffectProps DistortionEffectProps{genDefaultProps()}; #ifdef ALSOFT_EAX namespace { -using EaxDistortionEffectDirtyFlagsValue = std::uint_least8_t; - -struct EaxDistortionEffectDirtyFlags +class EaxDistortionEffectException : public EaxException { - using EaxIsBitFieldStruct = bool; - - EaxDistortionEffectDirtyFlagsValue flEdge : 1; - EaxDistortionEffectDirtyFlagsValue lGain : 1; - EaxDistortionEffectDirtyFlagsValue flLowPassCutOff : 1; - EaxDistortionEffectDirtyFlagsValue flEQCenter : 1; - EaxDistortionEffectDirtyFlagsValue flEQBandwidth : 1; -}; // EaxDistortionEffectDirtyFlags - +public: + explicit EaxDistortionEffectException(const char* message) + : EaxException{"EAX_DISTORTION_EFFECT", message} + {} +}; // EaxDistortionEffectException -class EaxDistortionEffect final : - public EaxEffect +class EaxDistortionEffect final : public EaxEffect4 { public: - EaxDistortionEffect(); - - void dispatch(const EaxEaxCall& eax_call) override; - - // [[nodiscard]] - bool apply_deferred() override; + EaxDistortionEffect(const EaxCall& call); private: - EAXDISTORTIONPROPERTIES eax_{}; - EAXDISTORTIONPROPERTIES eax_d_{}; - EaxDistortionEffectDirtyFlags eax_dirty_flags_{}; - - void set_eax_defaults(); - - void set_efx_edge(); - void set_efx_gain(); - void set_efx_lowpass_cutoff(); - void set_efx_eq_center(); - void set_efx_eq_bandwidth(); - void set_efx_defaults(); - - void get(const EaxEaxCall& eax_call); - - void validate_edge(float flEdge); - void validate_gain(long lGain); - void validate_lowpass_cutoff(float flLowPassCutOff); - void validate_eq_center(float flEQCenter); - void validate_eq_bandwidth(float flEQBandwidth); - void validate_all(const EAXDISTORTIONPROPERTIES& eax_all); - - void defer_edge(float flEdge); - void defer_gain(long lGain); - void defer_low_pass_cutoff(float flLowPassCutOff); - void defer_eq_center(float flEQCenter); - void defer_eq_bandwidth(float flEQBandwidth); - void defer_all(const EAXDISTORTIONPROPERTIES& eax_all); - - void defer_edge(const EaxEaxCall& eax_call); - void defer_gain(const EaxEaxCall& eax_call); - void defer_low_pass_cutoff(const EaxEaxCall& eax_call); - void defer_eq_center(const EaxEaxCall& eax_call); - void defer_eq_bandwidth(const EaxEaxCall& eax_call); - void defer_all(const EaxEaxCall& eax_call); - - void set(const EaxEaxCall& eax_call); + struct EdgeValidator { + void operator()(float flEdge) const + { + eax_validate_range( + "Edge", + flEdge, + EAXDISTORTION_MINEDGE, + EAXDISTORTION_MAXEDGE); + } + }; // EdgeValidator + + struct GainValidator { + void operator()(long lGain) const + { + eax_validate_range( + "Gain", + lGain, + EAXDISTORTION_MINGAIN, + EAXDISTORTION_MAXGAIN); + } + }; // GainValidator + + struct LowPassCutOffValidator { + void operator()(float flLowPassCutOff) const + { + eax_validate_range( + "Low-pass Cut-off", + flLowPassCutOff, + EAXDISTORTION_MINLOWPASSCUTOFF, + EAXDISTORTION_MAXLOWPASSCUTOFF); + } + }; // LowPassCutOffValidator + + struct EqCenterValidator { + void operator()(float flEQCenter) const + { + eax_validate_range( + "EQ Center", + flEQCenter, + EAXDISTORTION_MINEQCENTER, + EAXDISTORTION_MAXEQCENTER); + } + }; // EqCenterValidator + + struct EqBandwidthValidator { + void operator()(float flEQBandwidth) const + { + eax_validate_range( + "EQ Bandwidth", + flEQBandwidth, + EAXDISTORTION_MINEQBANDWIDTH, + EAXDISTORTION_MAXEQBANDWIDTH); + } + }; // EqBandwidthValidator + + struct AllValidator { + void operator()(const Props& all) const + { + EdgeValidator{}(all.flEdge); + GainValidator{}(all.lGain); + LowPassCutOffValidator{}(all.flLowPassCutOff); + EqCenterValidator{}(all.flEQCenter); + EqBandwidthValidator{}(all.flEQBandwidth); + } + }; // AllValidator + + void set_defaults(Props& props) override; + + void set_efx_edge() noexcept; + void set_efx_gain() noexcept; + void set_efx_lowpass_cutoff() noexcept; + void set_efx_eq_center() noexcept; + void set_efx_eq_bandwidth() noexcept; + void set_efx_defaults() override; + + void get(const EaxCall& call, const Props& props) override; + void set(const EaxCall& call, Props& props) override; + bool commit_props(const Props& props) override; }; // EaxDistortionEffect +EaxDistortionEffect::EaxDistortionEffect(const EaxCall& call) + : EaxEffect4{AL_EFFECT_DISTORTION, call} +{} -class EaxDistortionEffectException : - public EaxException -{ -public: - explicit EaxDistortionEffectException( - const char* message) - : - EaxException{"EAX_DISTORTION_EFFECT", message} - { - } -}; // EaxDistortionEffectException - - -EaxDistortionEffect::EaxDistortionEffect() - : EaxEffect{AL_EFFECT_DISTORTION} -{ - set_eax_defaults(); - set_efx_defaults(); -} - -void EaxDistortionEffect::dispatch(const EaxEaxCall& eax_call) -{ - eax_call.is_get() ? get(eax_call) : set(eax_call); -} - -void EaxDistortionEffect::set_eax_defaults() +void EaxDistortionEffect::set_defaults(Props& props) { - eax_.flEdge = EAXDISTORTION_DEFAULTEDGE; - eax_.lGain = EAXDISTORTION_DEFAULTGAIN; - eax_.flLowPassCutOff = EAXDISTORTION_DEFAULTLOWPASSCUTOFF; - eax_.flEQCenter = EAXDISTORTION_DEFAULTEQCENTER; - eax_.flEQBandwidth = EAXDISTORTION_DEFAULTEQBANDWIDTH; - - eax_d_ = eax_; + props.flEdge = EAXDISTORTION_DEFAULTEDGE; + props.lGain = EAXDISTORTION_DEFAULTGAIN; + props.flLowPassCutOff = EAXDISTORTION_DEFAULTLOWPASSCUTOFF; + props.flEQCenter = EAXDISTORTION_DEFAULTEQCENTER; + props.flEQBandwidth = EAXDISTORTION_DEFAULTEQBANDWIDTH; } -void EaxDistortionEffect::set_efx_edge() +void EaxDistortionEffect::set_efx_edge() noexcept { - const auto edge = clamp( - eax_.flEdge, + al_effect_props_.Distortion.Edge = clamp( + props_.flEdge, AL_DISTORTION_MIN_EDGE, AL_DISTORTION_MAX_EDGE); - - al_effect_props_.Distortion.Edge = edge; } -void EaxDistortionEffect::set_efx_gain() +void EaxDistortionEffect::set_efx_gain() noexcept { - const auto gain = clamp( - level_mb_to_gain(static_cast(eax_.lGain)), + al_effect_props_.Distortion.Gain = clamp( + level_mb_to_gain(static_cast(props_.lGain)), AL_DISTORTION_MIN_GAIN, AL_DISTORTION_MAX_GAIN); - - al_effect_props_.Distortion.Gain = gain; } -void EaxDistortionEffect::set_efx_lowpass_cutoff() +void EaxDistortionEffect::set_efx_lowpass_cutoff() noexcept { - const auto lowpass_cutoff = clamp( - eax_.flLowPassCutOff, + al_effect_props_.Distortion.LowpassCutoff = clamp( + props_.flLowPassCutOff, AL_DISTORTION_MIN_LOWPASS_CUTOFF, AL_DISTORTION_MAX_LOWPASS_CUTOFF); - - al_effect_props_.Distortion.LowpassCutoff = lowpass_cutoff; } -void EaxDistortionEffect::set_efx_eq_center() +void EaxDistortionEffect::set_efx_eq_center() noexcept { - const auto eq_center = clamp( - eax_.flEQCenter, + al_effect_props_.Distortion.EQCenter = clamp( + props_.flEQCenter, AL_DISTORTION_MIN_EQCENTER, AL_DISTORTION_MAX_EQCENTER); - - al_effect_props_.Distortion.EQCenter = eq_center; } -void EaxDistortionEffect::set_efx_eq_bandwidth() +void EaxDistortionEffect::set_efx_eq_bandwidth() noexcept { - const auto eq_bandwidth = clamp( - eax_.flEdge, + al_effect_props_.Distortion.EQBandwidth = clamp( + props_.flEdge, AL_DISTORTION_MIN_EQBANDWIDTH, AL_DISTORTION_MAX_EQBANDWIDTH); - - al_effect_props_.Distortion.EQBandwidth = eq_bandwidth; } void EaxDistortionEffect::set_efx_defaults() @@ -284,288 +278,78 @@ void EaxDistortionEffect::set_efx_defaults() set_efx_eq_bandwidth(); } -void EaxDistortionEffect::get(const EaxEaxCall& eax_call) +void EaxDistortionEffect::get(const EaxCall& call, const Props& props) { - switch(eax_call.get_property_id()) + switch(call.get_property_id()) { - case EAXDISTORTION_NONE: - break; - - case EAXDISTORTION_ALLPARAMETERS: - eax_call.set_value(eax_); - break; - - case EAXDISTORTION_EDGE: - eax_call.set_value(eax_.flEdge); - break; - - case EAXDISTORTION_GAIN: - eax_call.set_value(eax_.lGain); - break; - - case EAXDISTORTION_LOWPASSCUTOFF: - eax_call.set_value(eax_.flLowPassCutOff); - break; - - case EAXDISTORTION_EQCENTER: - eax_call.set_value(eax_.flEQCenter); - break; - - case EAXDISTORTION_EQBANDWIDTH: - eax_call.set_value(eax_.flEQBandwidth); - break; - - default: - throw EaxDistortionEffectException{"Unsupported property id."}; + case EAXDISTORTION_NONE: break; + case EAXDISTORTION_ALLPARAMETERS: call.set_value(props); break; + case EAXDISTORTION_EDGE: call.set_value(props.flEdge); break; + case EAXDISTORTION_GAIN: call.set_value(props.lGain); break; + case EAXDISTORTION_LOWPASSCUTOFF: call.set_value(props.flLowPassCutOff); break; + case EAXDISTORTION_EQCENTER: call.set_value(props.flEQCenter); break; + case EAXDISTORTION_EQBANDWIDTH: call.set_value(props.flEQBandwidth); break; + default: fail_unknown_property_id(); } } -void EaxDistortionEffect::validate_edge( - float flEdge) -{ - eax_validate_range( - "Edge", - flEdge, - EAXDISTORTION_MINEDGE, - EAXDISTORTION_MAXEDGE); -} - -void EaxDistortionEffect::validate_gain( - long lGain) -{ - eax_validate_range( - "Gain", - lGain, - EAXDISTORTION_MINGAIN, - EAXDISTORTION_MAXGAIN); -} - -void EaxDistortionEffect::validate_lowpass_cutoff( - float flLowPassCutOff) -{ - eax_validate_range( - "Low-pass Cut-off", - flLowPassCutOff, - EAXDISTORTION_MINLOWPASSCUTOFF, - EAXDISTORTION_MAXLOWPASSCUTOFF); -} - -void EaxDistortionEffect::validate_eq_center( - float flEQCenter) -{ - eax_validate_range( - "EQ Center", - flEQCenter, - EAXDISTORTION_MINEQCENTER, - EAXDISTORTION_MAXEQCENTER); -} - -void EaxDistortionEffect::validate_eq_bandwidth( - float flEQBandwidth) -{ - eax_validate_range( - "EQ Bandwidth", - flEQBandwidth, - EAXDISTORTION_MINEQBANDWIDTH, - EAXDISTORTION_MAXEQBANDWIDTH); -} - -void EaxDistortionEffect::validate_all( - const EAXDISTORTIONPROPERTIES& eax_all) -{ - validate_edge(eax_all.flEdge); - validate_gain(eax_all.lGain); - validate_lowpass_cutoff(eax_all.flLowPassCutOff); - validate_eq_center(eax_all.flEQCenter); - validate_eq_bandwidth(eax_all.flEQBandwidth); -} - -void EaxDistortionEffect::defer_edge( - float flEdge) -{ - eax_d_.flEdge = flEdge; - eax_dirty_flags_.flEdge = (eax_.flEdge != eax_d_.flEdge); -} - -void EaxDistortionEffect::defer_gain( - long lGain) +void EaxDistortionEffect::set(const EaxCall& call, Props& props) { - eax_d_.lGain = lGain; - eax_dirty_flags_.lGain = (eax_.lGain != eax_d_.lGain); -} - -void EaxDistortionEffect::defer_low_pass_cutoff( - float flLowPassCutOff) -{ - eax_d_.flLowPassCutOff = flLowPassCutOff; - eax_dirty_flags_.flLowPassCutOff = (eax_.flLowPassCutOff != eax_d_.flLowPassCutOff); -} - -void EaxDistortionEffect::defer_eq_center( - float flEQCenter) -{ - eax_d_.flEQCenter = flEQCenter; - eax_dirty_flags_.flEQCenter = (eax_.flEQCenter != eax_d_.flEQCenter); -} - -void EaxDistortionEffect::defer_eq_bandwidth( - float flEQBandwidth) -{ - eax_d_.flEQBandwidth = flEQBandwidth; - eax_dirty_flags_.flEQBandwidth = (eax_.flEQBandwidth != eax_d_.flEQBandwidth); -} - -void EaxDistortionEffect::defer_all( - const EAXDISTORTIONPROPERTIES& eax_all) -{ - defer_edge(eax_all.flEdge); - defer_gain(eax_all.lGain); - defer_low_pass_cutoff(eax_all.flLowPassCutOff); - defer_eq_center(eax_all.flEQCenter); - defer_eq_bandwidth(eax_all.flEQBandwidth); -} - -void EaxDistortionEffect::defer_edge( - const EaxEaxCall& eax_call) -{ - const auto& edge = - eax_call.get_value(); - - validate_edge(edge); - defer_edge(edge); -} - -void EaxDistortionEffect::defer_gain( - const EaxEaxCall& eax_call) -{ - const auto& gain = - eax_call.get_value(); - - validate_gain(gain); - defer_gain(gain); -} - -void EaxDistortionEffect::defer_low_pass_cutoff( - const EaxEaxCall& eax_call) -{ - const auto& lowpass_cutoff = - eax_call.get_value(); - - validate_lowpass_cutoff(lowpass_cutoff); - defer_low_pass_cutoff(lowpass_cutoff); -} - -void EaxDistortionEffect::defer_eq_center( - const EaxEaxCall& eax_call) -{ - const auto& eq_center = - eax_call.get_value(); - - validate_eq_center(eq_center); - defer_eq_center(eq_center); -} - -void EaxDistortionEffect::defer_eq_bandwidth( - const EaxEaxCall& eax_call) -{ - const auto& eq_bandwidth = - eax_call.get_value(); - - validate_eq_bandwidth(eq_bandwidth); - defer_eq_bandwidth(eq_bandwidth); -} - -void EaxDistortionEffect::defer_all( - const EaxEaxCall& eax_call) -{ - const auto& all = - eax_call.get_value(); - - validate_all(all); - defer_all(all); -} - -// [[nodiscard]] -bool EaxDistortionEffect::apply_deferred() -{ - if (eax_dirty_flags_ == EaxDistortionEffectDirtyFlags{}) + switch(call.get_property_id()) { - return false; + case EAXDISTORTION_NONE: break; + case EAXDISTORTION_ALLPARAMETERS: defer(call, props); break; + case EAXDISTORTION_EDGE: defer(call, props.flEdge); break; + case EAXDISTORTION_GAIN: defer(call, props.lGain); break; + case EAXDISTORTION_LOWPASSCUTOFF: defer(call, props.flLowPassCutOff); break; + case EAXDISTORTION_EQCENTER: defer(call, props.flEQCenter); break; + case EAXDISTORTION_EQBANDWIDTH: defer(call, props.flEQBandwidth); break; + default: fail_unknown_property_id(); } +} - eax_ = eax_d_; +bool EaxDistortionEffect::commit_props(const Props& props) +{ + auto is_dirty = false; - if (eax_dirty_flags_.flEdge) + if (props_.flEdge != props.flEdge) { + is_dirty = true; set_efx_edge(); } - if (eax_dirty_flags_.lGain) + if (props_.lGain != props.lGain) { + is_dirty = true; set_efx_gain(); } - if (eax_dirty_flags_.flLowPassCutOff) + if (props_.flLowPassCutOff != props.flLowPassCutOff) { + is_dirty = true; set_efx_lowpass_cutoff(); } - if (eax_dirty_flags_.flEQCenter) + if (props_.flEQCenter != props.flEQCenter) { + is_dirty = true; set_efx_eq_center(); } - if (eax_dirty_flags_.flEQBandwidth) + if (props_.flEQBandwidth != props.flEQBandwidth) { + is_dirty = true; set_efx_eq_bandwidth(); } - eax_dirty_flags_ = EaxDistortionEffectDirtyFlags{}; - - return true; -} - -void EaxDistortionEffect::set(const EaxEaxCall& eax_call) -{ - switch(eax_call.get_property_id()) - { - case EAXDISTORTION_NONE: - break; - - case EAXDISTORTION_ALLPARAMETERS: - defer_all(eax_call); - break; - - case EAXDISTORTION_EDGE: - defer_edge(eax_call); - break; - - case EAXDISTORTION_GAIN: - defer_gain(eax_call); - break; - - case EAXDISTORTION_LOWPASSCUTOFF: - defer_low_pass_cutoff(eax_call); - break; - - case EAXDISTORTION_EQCENTER: - defer_eq_center(eax_call); - break; - - case EAXDISTORTION_EQBANDWIDTH: - defer_eq_bandwidth(eax_call); - break; - - default: - throw EaxDistortionEffectException{"Unsupported property id."}; - } + return is_dirty; } } // namespace -EaxEffectUPtr eax_create_eax_distortion_effect() +EaxEffectUPtr eax_create_eax_distortion_effect(const EaxCall& call) { - return std::make_unique(); + return eax_create_eax4_effect(call); } #endif // ALSOFT_EAX diff --git a/modules/openal-soft/al/effects/echo.cpp b/modules/openal-soft/al/effects/echo.cpp index 61adad7..f25c94b 100644 --- a/modules/openal-soft/al/effects/echo.cpp +++ b/modules/openal-soft/al/effects/echo.cpp @@ -9,9 +9,8 @@ #ifdef ALSOFT_EAX #include "alnumeric.h" - -#include "al/eax_exception.h" -#include "al/eax_utils.h" +#include "al/eax/exception.h" +#include "al/eax/utils.h" #endif // ALSOFT_EAX @@ -120,157 +119,151 @@ const EffectProps EchoEffectProps{genDefaultProps()}; #ifdef ALSOFT_EAX namespace { -using EaxEchoEffectDirtyFlagsValue = std::uint_least8_t; - -struct EaxEchoEffectDirtyFlags +class EaxEchoEffectException : public EaxException { - using EaxIsBitFieldStruct = bool; - - EaxEchoEffectDirtyFlagsValue flDelay : 1; - EaxEchoEffectDirtyFlagsValue flLRDelay : 1; - EaxEchoEffectDirtyFlagsValue flDamping : 1; - EaxEchoEffectDirtyFlagsValue flFeedback : 1; - EaxEchoEffectDirtyFlagsValue flSpread : 1; -}; // EaxEchoEffectDirtyFlags - +public: + explicit EaxEchoEffectException(const char* message) + : EaxException{"EAX_ECHO_EFFECT", message} + {} +}; // EaxEchoEffectException -class EaxEchoEffect final : - public EaxEffect +class EaxEchoEffect final : public EaxEffect4 { public: - EaxEchoEffect(); - - void dispatch(const EaxEaxCall& eax_call) override; - - // [[nodiscard]] - bool apply_deferred() override; + EaxEchoEffect(const EaxCall& call); private: - EAXECHOPROPERTIES eax_{}; - EAXECHOPROPERTIES eax_d_{}; - EaxEchoEffectDirtyFlags eax_dirty_flags_{}; - - void set_eax_defaults(); - - void set_efx_delay(); - void set_efx_lr_delay(); - void set_efx_damping(); - void set_efx_feedback(); - void set_efx_spread(); - void set_efx_defaults(); - - void get(const EaxEaxCall& eax_call); - - void validate_delay(float flDelay); - void validate_lr_delay(float flLRDelay); - void validate_damping(float flDamping); - void validate_feedback(float flFeedback); - void validate_spread(float flSpread); - void validate_all(const EAXECHOPROPERTIES& all); - - void defer_delay(float flDelay); - void defer_lr_delay(float flLRDelay); - void defer_damping(float flDamping); - void defer_feedback(float flFeedback); - void defer_spread(float flSpread); - void defer_all(const EAXECHOPROPERTIES& all); - - void defer_delay(const EaxEaxCall& eax_call); - void defer_lr_delay(const EaxEaxCall& eax_call); - void defer_damping(const EaxEaxCall& eax_call); - void defer_feedback(const EaxEaxCall& eax_call); - void defer_spread(const EaxEaxCall& eax_call); - void defer_all(const EaxEaxCall& eax_call); - - void set(const EaxEaxCall& eax_call); + struct DelayValidator { + void operator()(float flDelay) const + { + eax_validate_range( + "Delay", + flDelay, + EAXECHO_MINDELAY, + EAXECHO_MAXDELAY); + } + }; // DelayValidator + + struct LrDelayValidator { + void operator()(float flLRDelay) const + { + eax_validate_range( + "LR Delay", + flLRDelay, + EAXECHO_MINLRDELAY, + EAXECHO_MAXLRDELAY); + } + }; // LrDelayValidator + + struct DampingValidator { + void operator()(float flDamping) const + { + eax_validate_range( + "Damping", + flDamping, + EAXECHO_MINDAMPING, + EAXECHO_MAXDAMPING); + } + }; // DampingValidator + + struct FeedbackValidator { + void operator()(float flFeedback) const + { + eax_validate_range( + "Feedback", + flFeedback, + EAXECHO_MINFEEDBACK, + EAXECHO_MAXFEEDBACK); + } + }; // FeedbackValidator + + struct SpreadValidator { + void operator()(float flSpread) const + { + eax_validate_range( + "Spread", + flSpread, + EAXECHO_MINSPREAD, + EAXECHO_MAXSPREAD); + } + }; // SpreadValidator + + struct AllValidator { + void operator()(const Props& all) const + { + DelayValidator{}(all.flDelay); + LrDelayValidator{}(all.flLRDelay); + DampingValidator{}(all.flDamping); + FeedbackValidator{}(all.flFeedback); + SpreadValidator{}(all.flSpread); + } + }; // AllValidator + + void set_defaults(Props& props) override; + + void set_efx_delay() noexcept; + void set_efx_lr_delay() noexcept; + void set_efx_damping() noexcept; + void set_efx_feedback() noexcept; + void set_efx_spread() noexcept; + void set_efx_defaults() override; + + void get(const EaxCall& call, const Props& props) override; + void set(const EaxCall& call, Props& props) override; + bool commit_props(const Props& props) override; }; // EaxEchoEffect +EaxEchoEffect::EaxEchoEffect(const EaxCall& call) + : EaxEffect4{AL_EFFECT_ECHO, call} +{} -class EaxEchoEffectException : - public EaxException -{ -public: - explicit EaxEchoEffectException( - const char* message) - : - EaxException{"EAX_ECHO_EFFECT", message} - { - } -}; // EaxEchoEffectException - - -EaxEchoEffect::EaxEchoEffect() - : EaxEffect{AL_EFFECT_ECHO} -{ - set_eax_defaults(); - set_efx_defaults(); -} - -void EaxEchoEffect::dispatch( - const EaxEaxCall& eax_call) -{ - eax_call.is_get() ? get(eax_call) : set(eax_call); -} - -void EaxEchoEffect::set_eax_defaults() +void EaxEchoEffect::set_defaults(Props& props) { - eax_.flDelay = EAXECHO_DEFAULTDELAY; - eax_.flLRDelay = EAXECHO_DEFAULTLRDELAY; - eax_.flDamping = EAXECHO_DEFAULTDAMPING; - eax_.flFeedback = EAXECHO_DEFAULTFEEDBACK; - eax_.flSpread = EAXECHO_DEFAULTSPREAD; - - eax_d_ = eax_; + props.flDelay = EAXECHO_DEFAULTDELAY; + props.flLRDelay = EAXECHO_DEFAULTLRDELAY; + props.flDamping = EAXECHO_DEFAULTDAMPING; + props.flFeedback = EAXECHO_DEFAULTFEEDBACK; + props.flSpread = EAXECHO_DEFAULTSPREAD; } -void EaxEchoEffect::set_efx_delay() +void EaxEchoEffect::set_efx_delay() noexcept { - const auto delay = clamp( - eax_.flDelay, + al_effect_props_.Echo.Delay = clamp( + props_.flDelay, AL_ECHO_MIN_DELAY, AL_ECHO_MAX_DELAY); - - al_effect_props_.Echo.Delay = delay; } -void EaxEchoEffect::set_efx_lr_delay() +void EaxEchoEffect::set_efx_lr_delay() noexcept { - const auto lr_delay = clamp( - eax_.flLRDelay, + al_effect_props_.Echo.LRDelay = clamp( + props_.flLRDelay, AL_ECHO_MIN_LRDELAY, AL_ECHO_MAX_LRDELAY); - - al_effect_props_.Echo.LRDelay = lr_delay; } -void EaxEchoEffect::set_efx_damping() +void EaxEchoEffect::set_efx_damping() noexcept { - const auto damping = clamp( - eax_.flDamping, + al_effect_props_.Echo.Damping = clamp( + props_.flDamping, AL_ECHO_MIN_DAMPING, AL_ECHO_MAX_DAMPING); - - al_effect_props_.Echo.Damping = damping; } -void EaxEchoEffect::set_efx_feedback() +void EaxEchoEffect::set_efx_feedback() noexcept { - const auto feedback = clamp( - eax_.flFeedback, + al_effect_props_.Echo.Feedback = clamp( + props_.flFeedback, AL_ECHO_MIN_FEEDBACK, AL_ECHO_MAX_FEEDBACK); - - al_effect_props_.Echo.Feedback = feedback; } -void EaxEchoEffect::set_efx_spread() +void EaxEchoEffect::set_efx_spread() noexcept { - const auto spread = clamp( - eax_.flSpread, + al_effect_props_.Echo.Spread = clamp( + props_.flSpread, AL_ECHO_MIN_SPREAD, AL_ECHO_MAX_SPREAD); - - al_effect_props_.Echo.Spread = spread; } void EaxEchoEffect::set_efx_defaults() @@ -282,288 +275,78 @@ void EaxEchoEffect::set_efx_defaults() set_efx_spread(); } -void EaxEchoEffect::get(const EaxEaxCall& eax_call) +void EaxEchoEffect::get(const EaxCall& call, const Props& props) { - switch(eax_call.get_property_id()) + switch(call.get_property_id()) { - case EAXECHO_NONE: - break; - - case EAXECHO_ALLPARAMETERS: - eax_call.set_value(eax_); - break; - - case EAXECHO_DELAY: - eax_call.set_value(eax_.flDelay); - break; - - case EAXECHO_LRDELAY: - eax_call.set_value(eax_.flLRDelay); - break; - - case EAXECHO_DAMPING: - eax_call.set_value(eax_.flDamping); - break; - - case EAXECHO_FEEDBACK: - eax_call.set_value(eax_.flFeedback); - break; - - case EAXECHO_SPREAD: - eax_call.set_value(eax_.flSpread); - break; - - default: - throw EaxEchoEffectException{"Unsupported property id."}; + case EAXECHO_NONE: break; + case EAXECHO_ALLPARAMETERS: call.set_value(props); break; + case EAXECHO_DELAY: call.set_value(props.flDelay); break; + case EAXECHO_LRDELAY: call.set_value(props.flLRDelay); break; + case EAXECHO_DAMPING: call.set_value(props.flDamping); break; + case EAXECHO_FEEDBACK: call.set_value(props.flFeedback); break; + case EAXECHO_SPREAD: call.set_value(props.flSpread); break; + default: fail_unknown_property_id(); } } -void EaxEchoEffect::validate_delay( - float flDelay) -{ - eax_validate_range( - "Delay", - flDelay, - EAXECHO_MINDELAY, - EAXECHO_MAXDELAY); -} - -void EaxEchoEffect::validate_lr_delay( - float flLRDelay) -{ - eax_validate_range( - "LR Delay", - flLRDelay, - EAXECHO_MINLRDELAY, - EAXECHO_MAXLRDELAY); -} - -void EaxEchoEffect::validate_damping( - float flDamping) -{ - eax_validate_range( - "Damping", - flDamping, - EAXECHO_MINDAMPING, - EAXECHO_MAXDAMPING); -} - -void EaxEchoEffect::validate_feedback( - float flFeedback) -{ - eax_validate_range( - "Feedback", - flFeedback, - EAXECHO_MINFEEDBACK, - EAXECHO_MAXFEEDBACK); -} - -void EaxEchoEffect::validate_spread( - float flSpread) -{ - eax_validate_range( - "Spread", - flSpread, - EAXECHO_MINSPREAD, - EAXECHO_MAXSPREAD); -} - -void EaxEchoEffect::validate_all( - const EAXECHOPROPERTIES& all) -{ - validate_delay(all.flDelay); - validate_lr_delay(all.flLRDelay); - validate_damping(all.flDamping); - validate_feedback(all.flFeedback); - validate_spread(all.flSpread); -} - -void EaxEchoEffect::defer_delay( - float flDelay) -{ - eax_d_.flDelay = flDelay; - eax_dirty_flags_.flDelay = (eax_.flDelay != eax_d_.flDelay); -} - -void EaxEchoEffect::defer_lr_delay( - float flLRDelay) +void EaxEchoEffect::set(const EaxCall& call, Props& props) { - eax_d_.flLRDelay = flLRDelay; - eax_dirty_flags_.flLRDelay = (eax_.flLRDelay != eax_d_.flLRDelay); -} - -void EaxEchoEffect::defer_damping( - float flDamping) -{ - eax_d_.flDamping = flDamping; - eax_dirty_flags_.flDamping = (eax_.flDamping != eax_d_.flDamping); -} - -void EaxEchoEffect::defer_feedback( - float flFeedback) -{ - eax_d_.flFeedback = flFeedback; - eax_dirty_flags_.flFeedback = (eax_.flFeedback != eax_d_.flFeedback); -} - -void EaxEchoEffect::defer_spread( - float flSpread) -{ - eax_d_.flSpread = flSpread; - eax_dirty_flags_.flSpread = (eax_.flSpread != eax_d_.flSpread); -} - -void EaxEchoEffect::defer_all( - const EAXECHOPROPERTIES& all) -{ - defer_delay(all.flDelay); - defer_lr_delay(all.flLRDelay); - defer_damping(all.flDamping); - defer_feedback(all.flFeedback); - defer_spread(all.flSpread); -} - -void EaxEchoEffect::defer_delay( - const EaxEaxCall& eax_call) -{ - const auto& delay = - eax_call.get_value(); - - validate_delay(delay); - defer_delay(delay); -} - -void EaxEchoEffect::defer_lr_delay( - const EaxEaxCall& eax_call) -{ - const auto& lr_delay = - eax_call.get_value(); - - validate_lr_delay(lr_delay); - defer_lr_delay(lr_delay); -} - -void EaxEchoEffect::defer_damping( - const EaxEaxCall& eax_call) -{ - const auto& damping = - eax_call.get_value(); - - validate_damping(damping); - defer_damping(damping); -} - -void EaxEchoEffect::defer_feedback( - const EaxEaxCall& eax_call) -{ - const auto& feedback = - eax_call.get_value(); - - validate_feedback(feedback); - defer_feedback(feedback); -} - -void EaxEchoEffect::defer_spread( - const EaxEaxCall& eax_call) -{ - const auto& spread = - eax_call.get_value(); - - validate_spread(spread); - defer_spread(spread); -} - -void EaxEchoEffect::defer_all( - const EaxEaxCall& eax_call) -{ - const auto& all = - eax_call.get_value(); - - validate_all(all); - defer_all(all); -} - -// [[nodiscard]] -bool EaxEchoEffect::apply_deferred() -{ - if (eax_dirty_flags_ == EaxEchoEffectDirtyFlags{}) + switch(call.get_property_id()) { - return false; + case EAXECHO_NONE: break; + case EAXECHO_ALLPARAMETERS: defer(call, props); break; + case EAXECHO_DELAY: defer(call, props.flDelay); break; + case EAXECHO_LRDELAY: defer(call, props.flLRDelay); break; + case EAXECHO_DAMPING: defer(call, props.flDamping); break; + case EAXECHO_FEEDBACK: defer(call, props.flFeedback); break; + case EAXECHO_SPREAD: defer(call, props.flSpread); break; + default: fail_unknown_property_id(); } +} - eax_ = eax_d_; +bool EaxEchoEffect::commit_props(const Props& props) +{ + auto is_dirty = false; - if (eax_dirty_flags_.flDelay) + if (props_.flDelay != props.flDelay) { + is_dirty = true; set_efx_delay(); } - if (eax_dirty_flags_.flLRDelay) + if (props_.flLRDelay != props.flLRDelay) { + is_dirty = true; set_efx_lr_delay(); } - if (eax_dirty_flags_.flDamping) + if (props_.flDamping != props.flDamping) { + is_dirty = true; set_efx_damping(); } - if (eax_dirty_flags_.flFeedback) + if (props_.flFeedback != props.flFeedback) { + is_dirty = true; set_efx_feedback(); } - if (eax_dirty_flags_.flSpread) + if (props_.flSpread != props.flSpread) { + is_dirty = true; set_efx_spread(); } - eax_dirty_flags_ = EaxEchoEffectDirtyFlags{}; - - return true; -} - -void EaxEchoEffect::set(const EaxEaxCall& eax_call) -{ - switch(eax_call.get_property_id()) - { - case EAXECHO_NONE: - break; - - case EAXECHO_ALLPARAMETERS: - defer_all(eax_call); - break; - - case EAXECHO_DELAY: - defer_delay(eax_call); - break; - - case EAXECHO_LRDELAY: - defer_lr_delay(eax_call); - break; - - case EAXECHO_DAMPING: - defer_damping(eax_call); - break; - - case EAXECHO_FEEDBACK: - defer_feedback(eax_call); - break; - - case EAXECHO_SPREAD: - defer_spread(eax_call); - break; - - default: - throw EaxEchoEffectException{"Unsupported property id."}; - } + return is_dirty; } } // namespace -EaxEffectUPtr eax_create_eax_echo_effect() +EaxEffectUPtr eax_create_eax_echo_effect(const EaxCall& call) { - return std::make_unique(); + return eax_create_eax4_effect(call); } #endif // ALSOFT_EAX diff --git a/modules/openal-soft/al/effects/effects.cpp b/modules/openal-soft/al/effects/effects.cpp index faf322d..e4e6123 100644 --- a/modules/openal-soft/al/effects/effects.cpp +++ b/modules/openal-soft/al/effects/effects.cpp @@ -10,7 +10,7 @@ #include "AL/efx.h" -EaxEffectUPtr eax_create_eax_effect(ALenum al_effect_type) +EaxEffectUPtr eax_create_eax_effect(ALenum al_effect_type, const EaxCall& call) { #define EAX_PREFIX "[EAX_MAKE_EAX_EFFECT] " @@ -20,40 +20,40 @@ EaxEffectUPtr eax_create_eax_effect(ALenum al_effect_type) return eax_create_eax_null_effect(); case AL_EFFECT_CHORUS: - return eax_create_eax_chorus_effect(); + return eax_create_eax_chorus_effect(call); case AL_EFFECT_DISTORTION: - return eax_create_eax_distortion_effect(); + return eax_create_eax_distortion_effect(call); case AL_EFFECT_ECHO: - return eax_create_eax_echo_effect(); + return eax_create_eax_echo_effect(call); case AL_EFFECT_FLANGER: - return eax_create_eax_flanger_effect(); + return eax_create_eax_flanger_effect(call); case AL_EFFECT_FREQUENCY_SHIFTER: - return eax_create_eax_frequency_shifter_effect(); + return eax_create_eax_frequency_shifter_effect(call); case AL_EFFECT_VOCAL_MORPHER: - return eax_create_eax_vocal_morpher_effect(); + return eax_create_eax_vocal_morpher_effect(call); case AL_EFFECT_PITCH_SHIFTER: - return eax_create_eax_pitch_shifter_effect(); + return eax_create_eax_pitch_shifter_effect(call); case AL_EFFECT_RING_MODULATOR: - return eax_create_eax_ring_modulator_effect(); + return eax_create_eax_ring_modulator_effect(call); case AL_EFFECT_AUTOWAH: - return eax_create_eax_auto_wah_effect(); + return eax_create_eax_auto_wah_effect(call); case AL_EFFECT_COMPRESSOR: - return eax_create_eax_compressor_effect(); + return eax_create_eax_compressor_effect(call); case AL_EFFECT_EQUALIZER: - return eax_create_eax_equalizer_effect(); + return eax_create_eax_equalizer_effect(call); case AL_EFFECT_EAXREVERB: - return eax_create_eax_reverb_effect(); + return eax_create_eax_reverb_effect(call); default: assert(false && "Unsupported AL effect type."); diff --git a/modules/openal-soft/al/effects/effects.h b/modules/openal-soft/al/effects/effects.h index 830e719..164c0d1 100644 --- a/modules/openal-soft/al/effects/effects.h +++ b/modules/openal-soft/al/effects/effects.h @@ -6,7 +6,8 @@ #include "core/except.h" #ifdef ALSOFT_EAX -#include "al/eax_effect.h" +#include "al/eax/call.h" +#include "al/eax/effect.h" #endif // ALSOFT_EAX union EffectProps; @@ -86,7 +87,7 @@ extern const EffectVtable ConvolutionEffectVtable; #ifdef ALSOFT_EAX -EaxEffectUPtr eax_create_eax_effect(ALenum al_effect_type); +EaxEffectUPtr eax_create_eax_effect(ALenum al_effect_type, const EaxCall& call); #endif // ALSOFT_EAX #endif /* AL_EFFECTS_EFFECTS_H */ diff --git a/modules/openal-soft/al/effects/equalizer.cpp b/modules/openal-soft/al/effects/equalizer.cpp index f829328..80dd1c4 100644 --- a/modules/openal-soft/al/effects/equalizer.cpp +++ b/modules/openal-soft/al/effects/equalizer.cpp @@ -9,9 +9,8 @@ #ifdef ALSOFT_EAX #include "alnumeric.h" - -#include "al/eax_exception.h" -#include "al/eax_utils.h" +#include "al/eax/exception.h" +#include "al/eax/utils.h" #endif // ALSOFT_EAX @@ -178,236 +177,261 @@ const EffectProps EqualizerEffectProps{genDefaultProps()}; #ifdef ALSOFT_EAX namespace { -using EaxEqualizerEffectDirtyFlagsValue = std::uint_least16_t; - -struct EaxEqualizerEffectDirtyFlags -{ - using EaxIsBitFieldStruct = bool; - - EaxEqualizerEffectDirtyFlagsValue lLowGain : 1; - EaxEqualizerEffectDirtyFlagsValue flLowCutOff : 1; - EaxEqualizerEffectDirtyFlagsValue lMid1Gain : 1; - EaxEqualizerEffectDirtyFlagsValue flMid1Center : 1; - EaxEqualizerEffectDirtyFlagsValue flMid1Width : 1; - EaxEqualizerEffectDirtyFlagsValue lMid2Gain : 1; - EaxEqualizerEffectDirtyFlagsValue flMid2Center : 1; - EaxEqualizerEffectDirtyFlagsValue flMid2Width : 1; - EaxEqualizerEffectDirtyFlagsValue lHighGain : 1; - EaxEqualizerEffectDirtyFlagsValue flHighCutOff : 1; -}; // EaxEqualizerEffectDirtyFlags - - -class EaxEqualizerEffect final : - public EaxEffect +class EaxEqualizerEffectException : public EaxException { public: - EaxEqualizerEffect(); - - void dispatch(const EaxEaxCall& eax_call) override; - - // [[nodiscard]] - bool apply_deferred() override; - -private: - EAXEQUALIZERPROPERTIES eax_{}; - EAXEQUALIZERPROPERTIES eax_d_{}; - EaxEqualizerEffectDirtyFlags eax_dirty_flags_{}; - - void set_eax_defaults(); - - void set_efx_low_gain(); - void set_efx_low_cutoff(); - void set_efx_mid1_gain(); - void set_efx_mid1_center(); - void set_efx_mid1_width(); - void set_efx_mid2_gain(); - void set_efx_mid2_center(); - void set_efx_mid2_width(); - void set_efx_high_gain(); - void set_efx_high_cutoff(); - void set_efx_defaults(); - - void get(const EaxEaxCall& eax_call); - - void validate_low_gain(long lLowGain); - void validate_low_cutoff(float flLowCutOff); - void validate_mid1_gain(long lMid1Gain); - void validate_mid1_center(float flMid1Center); - void validate_mid1_width(float flMid1Width); - void validate_mid2_gain(long lMid2Gain); - void validate_mid2_center(float flMid2Center); - void validate_mid2_width(float flMid2Width); - void validate_high_gain(long lHighGain); - void validate_high_cutoff(float flHighCutOff); - void validate_all(const EAXEQUALIZERPROPERTIES& all); - - void defer_low_gain(long lLowGain); - void defer_low_cutoff(float flLowCutOff); - void defer_mid1_gain(long lMid1Gain); - void defer_mid1_center(float flMid1Center); - void defer_mid1_width(float flMid1Width); - void defer_mid2_gain(long lMid2Gain); - void defer_mid2_center(float flMid2Center); - void defer_mid2_width(float flMid2Width); - void defer_high_gain(long lHighGain); - void defer_high_cutoff(float flHighCutOff); - void defer_all(const EAXEQUALIZERPROPERTIES& all); - - void defer_low_gain(const EaxEaxCall& eax_call); - void defer_low_cutoff(const EaxEaxCall& eax_call); - void defer_mid1_gain(const EaxEaxCall& eax_call); - void defer_mid1_center(const EaxEaxCall& eax_call); - void defer_mid1_width(const EaxEaxCall& eax_call); - void defer_mid2_gain(const EaxEaxCall& eax_call); - void defer_mid2_center(const EaxEaxCall& eax_call); - void defer_mid2_width(const EaxEaxCall& eax_call); - void defer_high_gain(const EaxEaxCall& eax_call); - void defer_high_cutoff(const EaxEaxCall& eax_call); - void defer_all(const EaxEaxCall& eax_call); - - void set(const EaxEaxCall& eax_call); -}; // EaxEqualizerEffect - + explicit EaxEqualizerEffectException(const char* message) + : EaxException{"EAX_EQUALIZER_EFFECT", message} + {} +}; // EaxEqualizerEffectException -class EaxEqualizerEffectException : - public EaxException +class EaxEqualizerEffect final : public EaxEffect4 { public: - explicit EaxEqualizerEffectException( - const char* message) - : - EaxException{"EAX_EQUALIZER_EFFECT", message} - { - } -}; // EaxEqualizerEffectException - + EaxEqualizerEffect(const EaxCall& call); -EaxEqualizerEffect::EaxEqualizerEffect() - : EaxEffect{AL_EFFECT_EQUALIZER} -{ - set_eax_defaults(); - set_efx_defaults(); -} +private: + struct LowGainValidator { + void operator()(long lLowGain) const + { + eax_validate_range( + "Low Gain", + lLowGain, + EAXEQUALIZER_MINLOWGAIN, + EAXEQUALIZER_MAXLOWGAIN); + } + }; // LowGainValidator + + struct LowCutOffValidator { + void operator()(float flLowCutOff) const + { + eax_validate_range( + "Low Cutoff", + flLowCutOff, + EAXEQUALIZER_MINLOWCUTOFF, + EAXEQUALIZER_MAXLOWCUTOFF); + } + }; // LowCutOffValidator + + struct Mid1GainValidator { + void operator()(long lMid1Gain) const + { + eax_validate_range( + "Mid1 Gain", + lMid1Gain, + EAXEQUALIZER_MINMID1GAIN, + EAXEQUALIZER_MAXMID1GAIN); + } + }; // Mid1GainValidator + + struct Mid1CenterValidator { + void operator()(float flMid1Center) const + { + eax_validate_range( + "Mid1 Center", + flMid1Center, + EAXEQUALIZER_MINMID1CENTER, + EAXEQUALIZER_MAXMID1CENTER); + } + }; // Mid1CenterValidator + + struct Mid1WidthValidator { + void operator()(float flMid1Width) const + { + eax_validate_range( + "Mid1 Width", + flMid1Width, + EAXEQUALIZER_MINMID1WIDTH, + EAXEQUALIZER_MAXMID1WIDTH); + } + }; // Mid1WidthValidator + + struct Mid2GainValidator { + void operator()(long lMid2Gain) const + { + eax_validate_range( + "Mid2 Gain", + lMid2Gain, + EAXEQUALIZER_MINMID2GAIN, + EAXEQUALIZER_MAXMID2GAIN); + } + }; // Mid2GainValidator + + struct Mid2CenterValidator { + void operator()(float flMid2Center) const + { + eax_validate_range( + "Mid2 Center", + flMid2Center, + EAXEQUALIZER_MINMID2CENTER, + EAXEQUALIZER_MAXMID2CENTER); + } + }; // Mid2CenterValidator + + struct Mid2WidthValidator { + void operator()(float flMid2Width) const + { + eax_validate_range( + "Mid2 Width", + flMid2Width, + EAXEQUALIZER_MINMID2WIDTH, + EAXEQUALIZER_MAXMID2WIDTH); + } + }; // Mid2WidthValidator + + struct HighGainValidator { + void operator()(long lHighGain) const + { + eax_validate_range( + "High Gain", + lHighGain, + EAXEQUALIZER_MINHIGHGAIN, + EAXEQUALIZER_MAXHIGHGAIN); + } + }; // HighGainValidator + + struct HighCutOffValidator { + void operator()(float flHighCutOff) const + { + eax_validate_range( + "High Cutoff", + flHighCutOff, + EAXEQUALIZER_MINHIGHCUTOFF, + EAXEQUALIZER_MAXHIGHCUTOFF); + } + }; // HighCutOffValidator + + struct AllValidator { + void operator()(const Props& all) const + { + LowGainValidator{}(all.lLowGain); + LowCutOffValidator{}(all.flLowCutOff); + Mid1GainValidator{}(all.lMid1Gain); + Mid1CenterValidator{}(all.flMid1Center); + Mid1WidthValidator{}(all.flMid1Width); + Mid2GainValidator{}(all.lMid2Gain); + Mid2CenterValidator{}(all.flMid2Center); + Mid2WidthValidator{}(all.flMid2Width); + HighGainValidator{}(all.lHighGain); + HighCutOffValidator{}(all.flHighCutOff); + } + }; // AllValidator + + void set_defaults(Props& props) override; + + void set_efx_low_gain() noexcept; + void set_efx_low_cutoff() noexcept; + void set_efx_mid1_gain() noexcept; + void set_efx_mid1_center() noexcept; + void set_efx_mid1_width() noexcept; + void set_efx_mid2_gain() noexcept; + void set_efx_mid2_center() noexcept; + void set_efx_mid2_width() noexcept; + void set_efx_high_gain() noexcept; + void set_efx_high_cutoff() noexcept; + void set_efx_defaults() override; + + void get(const EaxCall& call, const Props& props) override; + void set(const EaxCall& call, Props& props) override; + bool commit_props(const Props& props) override; +}; // EaxEqualizerEffect -void EaxEqualizerEffect::dispatch(const EaxEaxCall& eax_call) -{ - eax_call.is_get() ? get(eax_call) : set(eax_call); -} +EaxEqualizerEffect::EaxEqualizerEffect(const EaxCall& call) + : EaxEffect4{AL_EFFECT_EQUALIZER, call} +{} -void EaxEqualizerEffect::set_eax_defaults() +void EaxEqualizerEffect::set_defaults(Props& props) { - eax_.lLowGain = EAXEQUALIZER_DEFAULTLOWGAIN; - eax_.flLowCutOff = EAXEQUALIZER_DEFAULTLOWCUTOFF; - eax_.lMid1Gain = EAXEQUALIZER_DEFAULTMID1GAIN; - eax_.flMid1Center = EAXEQUALIZER_DEFAULTMID1CENTER; - eax_.flMid1Width = EAXEQUALIZER_DEFAULTMID1WIDTH; - eax_.lMid2Gain = EAXEQUALIZER_DEFAULTMID2GAIN; - eax_.flMid2Center = EAXEQUALIZER_DEFAULTMID2CENTER; - eax_.flMid2Width = EAXEQUALIZER_DEFAULTMID2WIDTH; - eax_.lHighGain = EAXEQUALIZER_DEFAULTHIGHGAIN; - eax_.flHighCutOff = EAXEQUALIZER_DEFAULTHIGHCUTOFF; - - eax_d_ = eax_; + props.lLowGain = EAXEQUALIZER_DEFAULTLOWGAIN; + props.flLowCutOff = EAXEQUALIZER_DEFAULTLOWCUTOFF; + props.lMid1Gain = EAXEQUALIZER_DEFAULTMID1GAIN; + props.flMid1Center = EAXEQUALIZER_DEFAULTMID1CENTER; + props.flMid1Width = EAXEQUALIZER_DEFAULTMID1WIDTH; + props.lMid2Gain = EAXEQUALIZER_DEFAULTMID2GAIN; + props.flMid2Center = EAXEQUALIZER_DEFAULTMID2CENTER; + props.flMid2Width = EAXEQUALIZER_DEFAULTMID2WIDTH; + props.lHighGain = EAXEQUALIZER_DEFAULTHIGHGAIN; + props.flHighCutOff = EAXEQUALIZER_DEFAULTHIGHCUTOFF; } -void EaxEqualizerEffect::set_efx_low_gain() +void EaxEqualizerEffect::set_efx_low_gain() noexcept { - const auto low_gain = clamp( - level_mb_to_gain(static_cast(eax_.lLowGain)), + al_effect_props_.Equalizer.LowGain = clamp( + level_mb_to_gain(static_cast(props_.lLowGain)), AL_EQUALIZER_MIN_LOW_GAIN, AL_EQUALIZER_MAX_LOW_GAIN); - - al_effect_props_.Equalizer.LowGain = low_gain; } -void EaxEqualizerEffect::set_efx_low_cutoff() +void EaxEqualizerEffect::set_efx_low_cutoff() noexcept { - const auto low_cutoff = clamp( - eax_.flLowCutOff, + al_effect_props_.Equalizer.LowCutoff = clamp( + props_.flLowCutOff, AL_EQUALIZER_MIN_LOW_CUTOFF, AL_EQUALIZER_MAX_LOW_CUTOFF); - - al_effect_props_.Equalizer.LowCutoff = low_cutoff; } -void EaxEqualizerEffect::set_efx_mid1_gain() +void EaxEqualizerEffect::set_efx_mid1_gain() noexcept { - const auto mid1_gain = clamp( - level_mb_to_gain(static_cast(eax_.lMid1Gain)), + al_effect_props_.Equalizer.Mid1Gain = clamp( + level_mb_to_gain(static_cast(props_.lMid1Gain)), AL_EQUALIZER_MIN_MID1_GAIN, AL_EQUALIZER_MAX_MID1_GAIN); - - al_effect_props_.Equalizer.Mid1Gain = mid1_gain; } -void EaxEqualizerEffect::set_efx_mid1_center() +void EaxEqualizerEffect::set_efx_mid1_center() noexcept { - const auto mid1_center = clamp( - eax_.flMid1Center, + al_effect_props_.Equalizer.Mid1Center = clamp( + props_.flMid1Center, AL_EQUALIZER_MIN_MID1_CENTER, AL_EQUALIZER_MAX_MID1_CENTER); - - al_effect_props_.Equalizer.Mid1Center = mid1_center; } -void EaxEqualizerEffect::set_efx_mid1_width() +void EaxEqualizerEffect::set_efx_mid1_width() noexcept { - const auto mid1_width = clamp( - eax_.flMid1Width, + al_effect_props_.Equalizer.Mid1Width = clamp( + props_.flMid1Width, AL_EQUALIZER_MIN_MID1_WIDTH, AL_EQUALIZER_MAX_MID1_WIDTH); - - al_effect_props_.Equalizer.Mid1Width = mid1_width; } -void EaxEqualizerEffect::set_efx_mid2_gain() +void EaxEqualizerEffect::set_efx_mid2_gain() noexcept { - const auto mid2_gain = clamp( - level_mb_to_gain(static_cast(eax_.lMid2Gain)), + al_effect_props_.Equalizer.Mid2Gain = clamp( + level_mb_to_gain(static_cast(props_.lMid2Gain)), AL_EQUALIZER_MIN_MID2_GAIN, AL_EQUALIZER_MAX_MID2_GAIN); - - al_effect_props_.Equalizer.Mid2Gain = mid2_gain; } -void EaxEqualizerEffect::set_efx_mid2_center() +void EaxEqualizerEffect::set_efx_mid2_center() noexcept { - const auto mid2_center = clamp( - eax_.flMid2Center, + al_effect_props_.Equalizer.Mid2Center = clamp( + props_.flMid2Center, AL_EQUALIZER_MIN_MID2_CENTER, AL_EQUALIZER_MAX_MID2_CENTER); - - al_effect_props_.Equalizer.Mid2Center = mid2_center; } -void EaxEqualizerEffect::set_efx_mid2_width() +void EaxEqualizerEffect::set_efx_mid2_width() noexcept { - const auto mid2_width = clamp( - eax_.flMid2Width, + al_effect_props_.Equalizer.Mid2Width = clamp( + props_.flMid2Width, AL_EQUALIZER_MIN_MID2_WIDTH, AL_EQUALIZER_MAX_MID2_WIDTH); - - al_effect_props_.Equalizer.Mid2Width = mid2_width; } -void EaxEqualizerEffect::set_efx_high_gain() +void EaxEqualizerEffect::set_efx_high_gain() noexcept { - const auto high_gain = clamp( - level_mb_to_gain(static_cast(eax_.lHighGain)), + al_effect_props_.Equalizer.HighGain = clamp( + level_mb_to_gain(static_cast(props_.lHighGain)), AL_EQUALIZER_MIN_HIGH_GAIN, AL_EQUALIZER_MAX_HIGH_GAIN); - - al_effect_props_.Equalizer.HighGain = high_gain; } -void EaxEqualizerEffect::set_efx_high_cutoff() +void EaxEqualizerEffect::set_efx_high_cutoff() noexcept { - const auto high_cutoff = clamp( - eax_.flHighCutOff, + al_effect_props_.Equalizer.HighCutoff = clamp( + props_.flHighCutOff, AL_EQUALIZER_MIN_HIGH_CUTOFF, AL_EQUALIZER_MAX_HIGH_CUTOFF); - - al_effect_props_.Equalizer.HighCutoff = high_cutoff; } void EaxEqualizerEffect::set_efx_defaults() @@ -424,498 +448,118 @@ void EaxEqualizerEffect::set_efx_defaults() set_efx_high_cutoff(); } -void EaxEqualizerEffect::get(const EaxEaxCall& eax_call) +void EaxEqualizerEffect::get(const EaxCall& call, const Props& props) { - switch(eax_call.get_property_id()) + switch(call.get_property_id()) { - case EAXEQUALIZER_NONE: - break; - - case EAXEQUALIZER_ALLPARAMETERS: - eax_call.set_value(eax_); - break; - - case EAXEQUALIZER_LOWGAIN: - eax_call.set_value(eax_.lLowGain); - break; - - case EAXEQUALIZER_LOWCUTOFF: - eax_call.set_value(eax_.flLowCutOff); - break; - - case EAXEQUALIZER_MID1GAIN: - eax_call.set_value(eax_.lMid1Gain); - break; - - case EAXEQUALIZER_MID1CENTER: - eax_call.set_value(eax_.flMid1Center); - break; - - case EAXEQUALIZER_MID1WIDTH: - eax_call.set_value(eax_.flMid1Width); - break; - - case EAXEQUALIZER_MID2GAIN: - eax_call.set_value(eax_.lMid2Gain); - break; - - case EAXEQUALIZER_MID2CENTER: - eax_call.set_value(eax_.flMid2Center); - break; - - case EAXEQUALIZER_MID2WIDTH: - eax_call.set_value(eax_.flMid2Width); - break; - - case EAXEQUALIZER_HIGHGAIN: - eax_call.set_value(eax_.lHighGain); - break; - - case EAXEQUALIZER_HIGHCUTOFF: - eax_call.set_value(eax_.flHighCutOff); - break; - - default: - throw EaxEqualizerEffectException{"Unsupported property id."}; + case EAXEQUALIZER_NONE: break; + case EAXEQUALIZER_ALLPARAMETERS: call.set_value(props); break; + case EAXEQUALIZER_LOWGAIN: call.set_value(props.lLowGain); break; + case EAXEQUALIZER_LOWCUTOFF: call.set_value(props.flLowCutOff); break; + case EAXEQUALIZER_MID1GAIN: call.set_value(props.lMid1Gain); break; + case EAXEQUALIZER_MID1CENTER: call.set_value(props.flMid1Center); break; + case EAXEQUALIZER_MID1WIDTH: call.set_value(props.flMid1Width); break; + case EAXEQUALIZER_MID2GAIN: call.set_value(props.lMid2Gain); break; + case EAXEQUALIZER_MID2CENTER: call.set_value(props.flMid2Center); break; + case EAXEQUALIZER_MID2WIDTH: call.set_value(props.flMid2Width); break; + case EAXEQUALIZER_HIGHGAIN: call.set_value(props.lHighGain); break; + case EAXEQUALIZER_HIGHCUTOFF: call.set_value(props.flHighCutOff); break; + default: fail_unknown_property_id(); } } -void EaxEqualizerEffect::validate_low_gain( - long lLowGain) -{ - eax_validate_range( - "Low Gain", - lLowGain, - EAXEQUALIZER_MINLOWGAIN, - EAXEQUALIZER_MAXLOWGAIN); -} - -void EaxEqualizerEffect::validate_low_cutoff( - float flLowCutOff) -{ - eax_validate_range( - "Low Cutoff", - flLowCutOff, - EAXEQUALIZER_MINLOWCUTOFF, - EAXEQUALIZER_MAXLOWCUTOFF); -} - -void EaxEqualizerEffect::validate_mid1_gain( - long lMid1Gain) -{ - eax_validate_range( - "Mid1 Gain", - lMid1Gain, - EAXEQUALIZER_MINMID1GAIN, - EAXEQUALIZER_MAXMID1GAIN); -} - -void EaxEqualizerEffect::validate_mid1_center( - float flMid1Center) -{ - eax_validate_range( - "Mid1 Center", - flMid1Center, - EAXEQUALIZER_MINMID1CENTER, - EAXEQUALIZER_MAXMID1CENTER); -} - -void EaxEqualizerEffect::validate_mid1_width( - float flMid1Width) -{ - eax_validate_range( - "Mid1 Width", - flMid1Width, - EAXEQUALIZER_MINMID1WIDTH, - EAXEQUALIZER_MAXMID1WIDTH); -} - -void EaxEqualizerEffect::validate_mid2_gain( - long lMid2Gain) -{ - eax_validate_range( - "Mid2 Gain", - lMid2Gain, - EAXEQUALIZER_MINMID2GAIN, - EAXEQUALIZER_MAXMID2GAIN); -} - -void EaxEqualizerEffect::validate_mid2_center( - float flMid2Center) -{ - eax_validate_range( - "Mid2 Center", - flMid2Center, - EAXEQUALIZER_MINMID2CENTER, - EAXEQUALIZER_MAXMID2CENTER); -} - -void EaxEqualizerEffect::validate_mid2_width( - float flMid2Width) -{ - eax_validate_range( - "Mid2 Width", - flMid2Width, - EAXEQUALIZER_MINMID2WIDTH, - EAXEQUALIZER_MAXMID2WIDTH); -} - -void EaxEqualizerEffect::validate_high_gain( - long lHighGain) -{ - eax_validate_range( - "High Gain", - lHighGain, - EAXEQUALIZER_MINHIGHGAIN, - EAXEQUALIZER_MAXHIGHGAIN); -} - -void EaxEqualizerEffect::validate_high_cutoff( - float flHighCutOff) -{ - eax_validate_range( - "High Cutoff", - flHighCutOff, - EAXEQUALIZER_MINHIGHCUTOFF, - EAXEQUALIZER_MAXHIGHCUTOFF); -} - -void EaxEqualizerEffect::validate_all( - const EAXEQUALIZERPROPERTIES& all) -{ - validate_low_gain(all.lLowGain); - validate_low_cutoff(all.flLowCutOff); - validate_mid1_gain(all.lMid1Gain); - validate_mid1_center(all.flMid1Center); - validate_mid1_width(all.flMid1Width); - validate_mid2_gain(all.lMid2Gain); - validate_mid2_center(all.flMid2Center); - validate_mid2_width(all.flMid2Width); - validate_high_gain(all.lHighGain); - validate_high_cutoff(all.flHighCutOff); -} - -void EaxEqualizerEffect::defer_low_gain( - long lLowGain) -{ - eax_d_.lLowGain = lLowGain; - eax_dirty_flags_.lLowGain = (eax_.lLowGain != eax_d_.lLowGain); -} - -void EaxEqualizerEffect::defer_low_cutoff( - float flLowCutOff) -{ - eax_d_.flLowCutOff = flLowCutOff; - eax_dirty_flags_.flLowCutOff = (eax_.flLowCutOff != eax_d_.flLowCutOff); -} - -void EaxEqualizerEffect::defer_mid1_gain( - long lMid1Gain) -{ - eax_d_.lMid1Gain = lMid1Gain; - eax_dirty_flags_.lMid1Gain = (eax_.lMid1Gain != eax_d_.lMid1Gain); -} - -void EaxEqualizerEffect::defer_mid1_center( - float flMid1Center) -{ - eax_d_.flMid1Center = flMid1Center; - eax_dirty_flags_.flMid1Center = (eax_.flMid1Center != eax_d_.flMid1Center); -} - -void EaxEqualizerEffect::defer_mid1_width( - float flMid1Width) -{ - eax_d_.flMid1Width = flMid1Width; - eax_dirty_flags_.flMid1Width = (eax_.flMid1Width != eax_d_.flMid1Width); -} - -void EaxEqualizerEffect::defer_mid2_gain( - long lMid2Gain) -{ - eax_d_.lMid2Gain = lMid2Gain; - eax_dirty_flags_.lMid2Gain = (eax_.lMid2Gain != eax_d_.lMid2Gain); -} - -void EaxEqualizerEffect::defer_mid2_center( - float flMid2Center) -{ - eax_d_.flMid2Center = flMid2Center; - eax_dirty_flags_.flMid2Center = (eax_.flMid2Center != eax_d_.flMid2Center); -} - -void EaxEqualizerEffect::defer_mid2_width( - float flMid2Width) -{ - eax_d_.flMid2Width = flMid2Width; - eax_dirty_flags_.flMid2Width = (eax_.flMid2Width != eax_d_.flMid2Width); -} - -void EaxEqualizerEffect::defer_high_gain( - long lHighGain) -{ - eax_d_.lHighGain = lHighGain; - eax_dirty_flags_.lHighGain = (eax_.lHighGain != eax_d_.lHighGain); -} - -void EaxEqualizerEffect::defer_high_cutoff( - float flHighCutOff) -{ - eax_d_.flHighCutOff = flHighCutOff; - eax_dirty_flags_.flHighCutOff = (eax_.flHighCutOff != eax_d_.flHighCutOff); -} - -void EaxEqualizerEffect::defer_all( - const EAXEQUALIZERPROPERTIES& all) -{ - defer_low_gain(all.lLowGain); - defer_low_cutoff(all.flLowCutOff); - defer_mid1_gain(all.lMid1Gain); - defer_mid1_center(all.flMid1Center); - defer_mid1_width(all.flMid1Width); - defer_mid2_gain(all.lMid2Gain); - defer_mid2_center(all.flMid2Center); - defer_mid2_width(all.flMid2Width); - defer_high_gain(all.lHighGain); - defer_high_cutoff(all.flHighCutOff); -} - -void EaxEqualizerEffect::defer_low_gain( - const EaxEaxCall& eax_call) -{ - const auto& low_gain = - eax_call.get_value(); - - validate_low_gain(low_gain); - defer_low_gain(low_gain); -} - -void EaxEqualizerEffect::defer_low_cutoff( - const EaxEaxCall& eax_call) -{ - const auto& low_cutoff = - eax_call.get_value(); - - validate_low_cutoff(low_cutoff); - defer_low_cutoff(low_cutoff); -} - -void EaxEqualizerEffect::defer_mid1_gain( - const EaxEaxCall& eax_call) -{ - const auto& mid1_gain = - eax_call.get_value(); - - validate_mid1_gain(mid1_gain); - defer_mid1_gain(mid1_gain); -} - -void EaxEqualizerEffect::defer_mid1_center( - const EaxEaxCall& eax_call) -{ - const auto& mid1_center = - eax_call.get_value(); - - validate_mid1_center(mid1_center); - defer_mid1_center(mid1_center); -} - -void EaxEqualizerEffect::defer_mid1_width( - const EaxEaxCall& eax_call) -{ - const auto& mid1_width = - eax_call.get_value(); - - validate_mid1_width(mid1_width); - defer_mid1_width(mid1_width); -} - -void EaxEqualizerEffect::defer_mid2_gain( - const EaxEaxCall& eax_call) -{ - const auto& mid2_gain = - eax_call.get_value(); - - validate_mid2_gain(mid2_gain); - defer_mid2_gain(mid2_gain); -} - -void EaxEqualizerEffect::defer_mid2_center( - const EaxEaxCall& eax_call) -{ - const auto& mid2_center = - eax_call.get_value(); - - validate_mid2_center(mid2_center); - defer_mid2_center(mid2_center); -} - -void EaxEqualizerEffect::defer_mid2_width( - const EaxEaxCall& eax_call) -{ - const auto& mid2_width = - eax_call.get_value(); - - validate_mid2_width(mid2_width); - defer_mid2_width(mid2_width); -} - -void EaxEqualizerEffect::defer_high_gain( - const EaxEaxCall& eax_call) +void EaxEqualizerEffect::set(const EaxCall& call, Props& props) { - const auto& high_gain = - eax_call.get_value(); - - validate_high_gain(high_gain); - defer_high_gain(high_gain); -} - -void EaxEqualizerEffect::defer_high_cutoff( - const EaxEaxCall& eax_call) -{ - const auto& high_cutoff = - eax_call.get_value(); - - validate_high_cutoff(high_cutoff); - defer_high_cutoff(high_cutoff); -} - -void EaxEqualizerEffect::defer_all( - const EaxEaxCall& eax_call) -{ - const auto& all = - eax_call.get_value(); - - validate_all(all); - defer_all(all); -} - -// [[nodiscard]] -bool EaxEqualizerEffect::apply_deferred() -{ - if (eax_dirty_flags_ == EaxEqualizerEffectDirtyFlags{}) + switch(call.get_property_id()) { - return false; + case EAXEQUALIZER_NONE: break; + case EAXEQUALIZER_ALLPARAMETERS: defer(call, props); break; + case EAXEQUALIZER_LOWGAIN: defer(call, props.lLowGain); break; + case EAXEQUALIZER_LOWCUTOFF: defer(call, props.flLowCutOff); break; + case EAXEQUALIZER_MID1GAIN: defer(call, props.lMid1Gain); break; + case EAXEQUALIZER_MID1CENTER: defer(call, props.flMid1Center); break; + case EAXEQUALIZER_MID1WIDTH: defer(call, props.flMid1Width); break; + case EAXEQUALIZER_MID2GAIN: defer(call, props.lMid2Gain); break; + case EAXEQUALIZER_MID2CENTER: defer(call, props.flMid2Center); break; + case EAXEQUALIZER_MID2WIDTH: defer(call, props.flMid2Width); break; + case EAXEQUALIZER_HIGHGAIN: defer(call, props.lHighGain); break; + case EAXEQUALIZER_HIGHCUTOFF: defer(call, props.flHighCutOff); break; + default: fail_unknown_property_id(); } +} - eax_ = eax_d_; +bool EaxEqualizerEffect::commit_props(const Props& props) +{ + auto is_dirty = false; - if (eax_dirty_flags_.lLowGain) + if (props_.lLowGain != props.lLowGain) { + is_dirty = true; set_efx_low_gain(); } - if (eax_dirty_flags_.flLowCutOff) + if (props_.flLowCutOff != props.flLowCutOff) { + is_dirty = true; set_efx_low_cutoff(); } - if (eax_dirty_flags_.lMid1Gain) + if (props_.lMid1Gain != props.lMid1Gain) { + is_dirty = true; set_efx_mid1_gain(); } - if (eax_dirty_flags_.flMid1Center) + if (props_.flMid1Center != props.flMid1Center) { + is_dirty = true; set_efx_mid1_center(); } - if (eax_dirty_flags_.flMid1Width) + if (props_.flMid1Width != props.flMid1Width) { + is_dirty = true; set_efx_mid1_width(); } - if (eax_dirty_flags_.lMid2Gain) + if (props_.lMid2Gain != props.lMid2Gain) { + is_dirty = true; set_efx_mid2_gain(); } - if (eax_dirty_flags_.flMid2Center) + if (props_.flMid2Center != props.flMid2Center) { + is_dirty = true; set_efx_mid2_center(); } - if (eax_dirty_flags_.flMid2Width) + if (props_.flMid2Width != props.flMid2Width) { + is_dirty = true; set_efx_mid2_width(); } - if (eax_dirty_flags_.lHighGain) + if (props_.lHighGain != props.lHighGain) { + is_dirty = true; set_efx_high_gain(); } - if (eax_dirty_flags_.flHighCutOff) + if (props_.flHighCutOff != props.flHighCutOff) { + is_dirty = true; set_efx_high_cutoff(); } - eax_dirty_flags_ = EaxEqualizerEffectDirtyFlags{}; - - return true; -} - -void EaxEqualizerEffect::set(const EaxEaxCall& eax_call) -{ - switch(eax_call.get_property_id()) - { - case EAXEQUALIZER_NONE: - break; - - case EAXEQUALIZER_ALLPARAMETERS: - defer_all(eax_call); - break; - - case EAXEQUALIZER_LOWGAIN: - defer_low_gain(eax_call); - break; - - case EAXEQUALIZER_LOWCUTOFF: - defer_low_cutoff(eax_call); - break; - - case EAXEQUALIZER_MID1GAIN: - defer_mid1_gain(eax_call); - break; - - case EAXEQUALIZER_MID1CENTER: - defer_mid1_center(eax_call); - break; - - case EAXEQUALIZER_MID1WIDTH: - defer_mid1_width(eax_call); - break; - - case EAXEQUALIZER_MID2GAIN: - defer_mid2_gain(eax_call); - break; - - case EAXEQUALIZER_MID2CENTER: - defer_mid2_center(eax_call); - break; - - case EAXEQUALIZER_MID2WIDTH: - defer_mid2_width(eax_call); - break; - - case EAXEQUALIZER_HIGHGAIN: - defer_high_gain(eax_call); - break; - - case EAXEQUALIZER_HIGHCUTOFF: - defer_high_cutoff(eax_call); - break; - - default: - throw EaxEqualizerEffectException{"Unsupported property id."}; - } + return is_dirty; } } // namespace -EaxEffectUPtr eax_create_eax_equalizer_effect() +EaxEffectUPtr eax_create_eax_equalizer_effect(const EaxCall& call) { - return std::make_unique(); + return eax_create_eax4_effect(call); } #endif // ALSOFT_EAX diff --git a/modules/openal-soft/al/effects/fshifter.cpp b/modules/openal-soft/al/effects/fshifter.cpp index d334890..2b1710a 100644 --- a/modules/openal-soft/al/effects/fshifter.cpp +++ b/modules/openal-soft/al/effects/fshifter.cpp @@ -12,11 +12,9 @@ #ifdef ALSOFT_EAX #include - #include "alnumeric.h" - -#include "al/eax_exception.h" -#include "al/eax_utils.h" +#include "al/eax/exception.h" +#include "al/eax/utils.h" #endif // ALSOFT_EAX @@ -141,113 +139,99 @@ const EffectProps FshifterEffectProps{genDefaultProps()}; #ifdef ALSOFT_EAX namespace { -using EaxFrequencyShifterEffectDirtyFlagsValue = std::uint_least8_t; - -struct EaxFrequencyShifterEffectDirtyFlags -{ - using EaxIsBitFieldStruct = bool; - - EaxFrequencyShifterEffectDirtyFlagsValue flFrequency : 1; - EaxFrequencyShifterEffectDirtyFlagsValue ulLeftDirection : 1; - EaxFrequencyShifterEffectDirtyFlagsValue ulRightDirection : 1; -}; // EaxFrequencyShifterEffectDirtyFlags - - -class EaxFrequencyShifterEffect final : - public EaxEffect +class EaxFrequencyShifterEffectException : public EaxException { public: - EaxFrequencyShifterEffect(); - - void dispatch(const EaxEaxCall& eax_call) override; + explicit EaxFrequencyShifterEffectException(const char* message) + : EaxException{"EAX_FREQUENCY_SHIFTER_EFFECT", message} + {} +}; // EaxFrequencyShifterEffectException - // [[nodiscard]] - bool apply_deferred() override; +class EaxFrequencyShifterEffect final : public EaxEffect4 { +public: + EaxFrequencyShifterEffect(const EaxCall& call); private: - EAXFREQUENCYSHIFTERPROPERTIES eax_{}; - EAXFREQUENCYSHIFTERPROPERTIES eax_d_{}; - EaxFrequencyShifterEffectDirtyFlags eax_dirty_flags_{}; - - void set_eax_defaults(); - - void set_efx_frequency(); + struct FrequencyValidator { + void operator()(float flFrequency) const + { + eax_validate_range( + "Frequency", + flFrequency, + EAXFREQUENCYSHIFTER_MINFREQUENCY, + EAXFREQUENCYSHIFTER_MAXFREQUENCY); + } + }; // FrequencyValidator + + struct LeftDirectionValidator { + void operator()(unsigned long ulLeftDirection) const + { + eax_validate_range( + "Left Direction", + ulLeftDirection, + EAXFREQUENCYSHIFTER_MINLEFTDIRECTION, + EAXFREQUENCYSHIFTER_MAXLEFTDIRECTION); + } + }; // LeftDirectionValidator + + struct RightDirectionValidator { + void operator()(unsigned long ulRightDirection) const + { + eax_validate_range( + "Right Direction", + ulRightDirection, + EAXFREQUENCYSHIFTER_MINRIGHTDIRECTION, + EAXFREQUENCYSHIFTER_MAXRIGHTDIRECTION); + } + }; // RightDirectionValidator + + struct AllValidator { + void operator()(const Props& all) const + { + FrequencyValidator{}(all.flFrequency); + LeftDirectionValidator{}(all.ulLeftDirection); + RightDirectionValidator{}(all.ulRightDirection); + } + }; // AllValidator + + void set_defaults(Props& props) override; + + void set_efx_frequency() noexcept; void set_efx_left_direction(); void set_efx_right_direction(); - void set_efx_defaults(); + void set_efx_defaults() override; - void get(const EaxEaxCall& eax_call); - - void validate_frequency(float flFrequency); - void validate_left_direction(unsigned long ulLeftDirection); - void validate_right_direction(unsigned long ulRightDirection); - void validate_all(const EAXFREQUENCYSHIFTERPROPERTIES& all); - - void defer_frequency(float flFrequency); - void defer_left_direction(unsigned long ulLeftDirection); - void defer_right_direction(unsigned long ulRightDirection); - void defer_all(const EAXFREQUENCYSHIFTERPROPERTIES& all); - - void defer_frequency(const EaxEaxCall& eax_call); - void defer_left_direction(const EaxEaxCall& eax_call); - void defer_right_direction(const EaxEaxCall& eax_call); - void defer_all(const EaxEaxCall& eax_call); - - void set(const EaxEaxCall& eax_call); + void get(const EaxCall& call, const Props& props) override; + void set(const EaxCall& call, Props& props) override; + bool commit_props(const Props& props) override; }; // EaxFrequencyShifterEffect -class EaxFrequencyShifterEffectException : - public EaxException -{ -public: - explicit EaxFrequencyShifterEffectException( - const char* message) - : - EaxException{"EAX_FREQUENCY_SHIFTER_EFFECT", message} - { - } -}; // EaxFrequencyShifterEffectException +EaxFrequencyShifterEffect::EaxFrequencyShifterEffect(const EaxCall& call) + : EaxEffect4{AL_EFFECT_FREQUENCY_SHIFTER, call} +{} - -EaxFrequencyShifterEffect::EaxFrequencyShifterEffect() - : EaxEffect{AL_EFFECT_FREQUENCY_SHIFTER} +void EaxFrequencyShifterEffect::set_defaults(Props& props) { - set_eax_defaults(); - set_efx_defaults(); + props.flFrequency = EAXFREQUENCYSHIFTER_DEFAULTFREQUENCY; + props.ulLeftDirection = EAXFREQUENCYSHIFTER_DEFAULTLEFTDIRECTION; + props.ulRightDirection = EAXFREQUENCYSHIFTER_DEFAULTRIGHTDIRECTION; } -void EaxFrequencyShifterEffect::dispatch(const EaxEaxCall& eax_call) +void EaxFrequencyShifterEffect::set_efx_frequency() noexcept { - eax_call.is_get() ? get(eax_call) : set(eax_call); -} - -void EaxFrequencyShifterEffect::set_eax_defaults() -{ - eax_.flFrequency = EAXFREQUENCYSHIFTER_DEFAULTFREQUENCY; - eax_.ulLeftDirection = EAXFREQUENCYSHIFTER_DEFAULTLEFTDIRECTION; - eax_.ulRightDirection = EAXFREQUENCYSHIFTER_DEFAULTRIGHTDIRECTION; - - eax_d_ = eax_; -} - -void EaxFrequencyShifterEffect::set_efx_frequency() -{ - const auto frequency = clamp( - eax_.flFrequency, + al_effect_props_.Fshifter.Frequency = clamp( + props_.flFrequency, AL_FREQUENCY_SHIFTER_MIN_FREQUENCY, AL_FREQUENCY_SHIFTER_MAX_FREQUENCY); - - al_effect_props_.Fshifter.Frequency = frequency; } void EaxFrequencyShifterEffect::set_efx_left_direction() { const auto left_direction = clamp( - static_cast(eax_.ulLeftDirection), + static_cast(props_.ulLeftDirection), AL_FREQUENCY_SHIFTER_MIN_LEFT_DIRECTION, AL_FREQUENCY_SHIFTER_MAX_LEFT_DIRECTION); - const auto efx_left_direction = DirectionFromEmum(left_direction); assert(efx_left_direction.has_value()); al_effect_props_.Fshifter.LeftDirection = *efx_left_direction; @@ -256,10 +240,9 @@ void EaxFrequencyShifterEffect::set_efx_left_direction() void EaxFrequencyShifterEffect::set_efx_right_direction() { const auto right_direction = clamp( - static_cast(eax_.ulRightDirection), + static_cast(props_.ulRightDirection), AL_FREQUENCY_SHIFTER_MIN_RIGHT_DIRECTION, AL_FREQUENCY_SHIFTER_MAX_RIGHT_DIRECTION); - const auto efx_right_direction = DirectionFromEmum(right_direction); assert(efx_right_direction.has_value()); al_effect_props_.Fshifter.RightDirection = *efx_right_direction; @@ -272,208 +255,62 @@ void EaxFrequencyShifterEffect::set_efx_defaults() set_efx_right_direction(); } -void EaxFrequencyShifterEffect::get(const EaxEaxCall& eax_call) +void EaxFrequencyShifterEffect::get(const EaxCall& call, const Props& props) { - switch(eax_call.get_property_id()) + switch(call.get_property_id()) { - case EAXFREQUENCYSHIFTER_NONE: - break; - - case EAXFREQUENCYSHIFTER_ALLPARAMETERS: - eax_call.set_value(eax_); - break; - - case EAXFREQUENCYSHIFTER_FREQUENCY: - eax_call.set_value(eax_.flFrequency); - break; - - case EAXFREQUENCYSHIFTER_LEFTDIRECTION: - eax_call.set_value(eax_.ulLeftDirection); - break; - - case EAXFREQUENCYSHIFTER_RIGHTDIRECTION: - eax_call.set_value(eax_.ulRightDirection); - break; - - default: - throw EaxFrequencyShifterEffectException{"Unsupported property id."}; + case EAXFREQUENCYSHIFTER_NONE: break; + case EAXFREQUENCYSHIFTER_ALLPARAMETERS: call.set_value(props); break; + case EAXFREQUENCYSHIFTER_FREQUENCY: call.set_value(props.flFrequency); break; + case EAXFREQUENCYSHIFTER_LEFTDIRECTION: call.set_value(props.ulLeftDirection); break; + case EAXFREQUENCYSHIFTER_RIGHTDIRECTION: call.set_value(props.ulRightDirection); break; + default: fail_unknown_property_id(); } } -void EaxFrequencyShifterEffect::validate_frequency( - float flFrequency) -{ - eax_validate_range( - "Frequency", - flFrequency, - EAXFREQUENCYSHIFTER_MINFREQUENCY, - EAXFREQUENCYSHIFTER_MAXFREQUENCY); -} - -void EaxFrequencyShifterEffect::validate_left_direction( - unsigned long ulLeftDirection) -{ - eax_validate_range( - "Left Direction", - ulLeftDirection, - EAXFREQUENCYSHIFTER_MINLEFTDIRECTION, - EAXFREQUENCYSHIFTER_MAXLEFTDIRECTION); -} - -void EaxFrequencyShifterEffect::validate_right_direction( - unsigned long ulRightDirection) -{ - eax_validate_range( - "Right Direction", - ulRightDirection, - EAXFREQUENCYSHIFTER_MINRIGHTDIRECTION, - EAXFREQUENCYSHIFTER_MAXRIGHTDIRECTION); -} - -void EaxFrequencyShifterEffect::validate_all( - const EAXFREQUENCYSHIFTERPROPERTIES& all) -{ - validate_frequency(all.flFrequency); - validate_left_direction(all.ulLeftDirection); - validate_right_direction(all.ulRightDirection); -} - -void EaxFrequencyShifterEffect::defer_frequency( - float flFrequency) -{ - eax_d_.flFrequency = flFrequency; - eax_dirty_flags_.flFrequency = (eax_.flFrequency != eax_d_.flFrequency); -} - -void EaxFrequencyShifterEffect::defer_left_direction( - unsigned long ulLeftDirection) -{ - eax_d_.ulLeftDirection = ulLeftDirection; - eax_dirty_flags_.ulLeftDirection = (eax_.ulLeftDirection != eax_d_.ulLeftDirection); -} - -void EaxFrequencyShifterEffect::defer_right_direction( - unsigned long ulRightDirection) +void EaxFrequencyShifterEffect::set(const EaxCall& call, Props& props) { - eax_d_.ulRightDirection = ulRightDirection; - eax_dirty_flags_.ulRightDirection = (eax_.ulRightDirection != eax_d_.ulRightDirection); -} - -void EaxFrequencyShifterEffect::defer_all( - const EAXFREQUENCYSHIFTERPROPERTIES& all) -{ - defer_frequency(all.flFrequency); - defer_left_direction(all.ulLeftDirection); - defer_right_direction(all.ulRightDirection); -} - -void EaxFrequencyShifterEffect::defer_frequency( - const EaxEaxCall& eax_call) -{ - const auto& frequency = - eax_call.get_value< - EaxFrequencyShifterEffectException, const decltype(EAXFREQUENCYSHIFTERPROPERTIES::flFrequency)>(); - - validate_frequency(frequency); - defer_frequency(frequency); -} - -void EaxFrequencyShifterEffect::defer_left_direction( - const EaxEaxCall& eax_call) -{ - const auto& left_direction = - eax_call.get_value< - EaxFrequencyShifterEffectException, const decltype(EAXFREQUENCYSHIFTERPROPERTIES::ulLeftDirection)>(); - - validate_left_direction(left_direction); - defer_left_direction(left_direction); -} - -void EaxFrequencyShifterEffect::defer_right_direction( - const EaxEaxCall& eax_call) -{ - const auto& right_direction = - eax_call.get_value< - EaxFrequencyShifterEffectException, const decltype(EAXFREQUENCYSHIFTERPROPERTIES::ulRightDirection)>(); - - validate_right_direction(right_direction); - defer_right_direction(right_direction); -} - -void EaxFrequencyShifterEffect::defer_all( - const EaxEaxCall& eax_call) -{ - const auto& all = - eax_call.get_value< - EaxFrequencyShifterEffectException, const EAXFREQUENCYSHIFTERPROPERTIES>(); - - validate_all(all); - defer_all(all); -} - -// [[nodiscard]] -bool EaxFrequencyShifterEffect::apply_deferred() -{ - if (eax_dirty_flags_ == EaxFrequencyShifterEffectDirtyFlags{}) + switch(call.get_property_id()) { - return false; + case EAXFREQUENCYSHIFTER_NONE: break; + case EAXFREQUENCYSHIFTER_ALLPARAMETERS: defer(call, props); break; + case EAXFREQUENCYSHIFTER_FREQUENCY: defer(call, props.flFrequency); break; + case EAXFREQUENCYSHIFTER_LEFTDIRECTION: defer(call, props.ulLeftDirection); break; + case EAXFREQUENCYSHIFTER_RIGHTDIRECTION: defer(call, props.ulRightDirection); break; + default: fail_unknown_property_id(); } +} - eax_ = eax_d_; +bool EaxFrequencyShifterEffect::commit_props(const Props& props) +{ + auto is_dirty = false; - if (eax_dirty_flags_.flFrequency) + if (props_.flFrequency != props.flFrequency) { + is_dirty = true; set_efx_frequency(); } - if (eax_dirty_flags_.ulLeftDirection) + if (props_.ulLeftDirection != props.ulLeftDirection) { + is_dirty = true; set_efx_left_direction(); } - if (eax_dirty_flags_.ulRightDirection) + if (props_.ulRightDirection != props.ulRightDirection) { + is_dirty = true; set_efx_right_direction(); } - eax_dirty_flags_ = EaxFrequencyShifterEffectDirtyFlags{}; - - return true; -} - -void EaxFrequencyShifterEffect::set(const EaxEaxCall& eax_call) -{ - switch(eax_call.get_property_id()) - { - case EAXFREQUENCYSHIFTER_NONE: - break; - - case EAXFREQUENCYSHIFTER_ALLPARAMETERS: - defer_all(eax_call); - break; - - case EAXFREQUENCYSHIFTER_FREQUENCY: - defer_frequency(eax_call); - break; - - case EAXFREQUENCYSHIFTER_LEFTDIRECTION: - defer_left_direction(eax_call); - break; - - case EAXFREQUENCYSHIFTER_RIGHTDIRECTION: - defer_right_direction(eax_call); - break; - - default: - throw EaxFrequencyShifterEffectException{"Unsupported property id."}; - } + return is_dirty; } } // namespace -EaxEffectUPtr eax_create_eax_frequency_shifter_effect() +EaxEffectUPtr eax_create_eax_frequency_shifter_effect(const EaxCall& call) { - return std::make_unique(); + return eax_create_eax4_effect(call); } #endif // ALSOFT_EAX diff --git a/modules/openal-soft/al/effects/modulator.cpp b/modules/openal-soft/al/effects/modulator.cpp index 800b892..774fb76 100644 --- a/modules/openal-soft/al/effects/modulator.cpp +++ b/modules/openal-soft/al/effects/modulator.cpp @@ -12,11 +12,9 @@ #ifdef ALSOFT_EAX #include - #include "alnumeric.h" - -#include "al/eax_exception.h" -#include "al/eax_utils.h" +#include "al/eax/exception.h" +#include "al/eax/utils.h" #endif // ALSOFT_EAX @@ -147,123 +145,107 @@ const EffectProps ModulatorEffectProps{genDefaultProps()}; #ifdef ALSOFT_EAX namespace { -using EaxRingModulatorEffectDirtyFlagsValue = std::uint_least8_t; - -struct EaxRingModulatorEffectDirtyFlags +class EaxRingModulatorEffectException : public EaxException { - using EaxIsBitFieldStruct = bool; - - EaxRingModulatorEffectDirtyFlagsValue flFrequency : 1; - EaxRingModulatorEffectDirtyFlagsValue flHighPassCutOff : 1; - EaxRingModulatorEffectDirtyFlagsValue ulWaveform : 1; -}; // EaxPitchShifterEffectDirtyFlags - +public: + explicit EaxRingModulatorEffectException(const char* message) + : EaxException{"EAX_RING_MODULATOR_EFFECT", message} + {} +}; // EaxRingModulatorEffectException -class EaxRingModulatorEffect final : - public EaxEffect +class EaxRingModulatorEffect final : public EaxEffect4 { public: - EaxRingModulatorEffect(); - - void dispatch(const EaxEaxCall& eax_call) override; - - // [[nodiscard]] - bool apply_deferred() override; + EaxRingModulatorEffect(const EaxCall& call); private: - EAXRINGMODULATORPROPERTIES eax_{}; - EAXRINGMODULATORPROPERTIES eax_d_{}; - EaxRingModulatorEffectDirtyFlags eax_dirty_flags_{}; - - void set_eax_defaults(); - - void set_efx_frequency(); - void set_efx_high_pass_cutoff(); + struct FrequencyValidator { + void operator()(float flFrequency) const + { + eax_validate_range( + "Frequency", + flFrequency, + EAXRINGMODULATOR_MINFREQUENCY, + EAXRINGMODULATOR_MAXFREQUENCY); + } + }; // FrequencyValidator + + struct HighPassCutOffValidator { + void operator()(float flHighPassCutOff) const + { + eax_validate_range( + "High-Pass Cutoff", + flHighPassCutOff, + EAXRINGMODULATOR_MINHIGHPASSCUTOFF, + EAXRINGMODULATOR_MAXHIGHPASSCUTOFF); + } + }; // HighPassCutOffValidator + + struct WaveformValidator { + void operator()(unsigned long ulWaveform) const + { + eax_validate_range( + "Waveform", + ulWaveform, + EAXRINGMODULATOR_MINWAVEFORM, + EAXRINGMODULATOR_MAXWAVEFORM); + } + }; // WaveformValidator + + struct AllValidator { + void operator()(const Props& all) const + { + FrequencyValidator{}(all.flFrequency); + HighPassCutOffValidator{}(all.flHighPassCutOff); + WaveformValidator{}(all.ulWaveform); + } + }; // AllValidator + + void set_defaults(Props& props) override; + + void set_efx_frequency() noexcept; + void set_efx_high_pass_cutoff() noexcept; void set_efx_waveform(); - void set_efx_defaults(); - - void get(const EaxEaxCall& eax_call); + void set_efx_defaults() override; - void validate_frequency(float flFrequency); - void validate_high_pass_cutoff(float flHighPassCutOff); - void validate_waveform(unsigned long ulWaveform); - void validate_all(const EAXRINGMODULATORPROPERTIES& all); - - void defer_frequency(float flFrequency); - void defer_high_pass_cutoff(float flHighPassCutOff); - void defer_waveform(unsigned long ulWaveform); - void defer_all(const EAXRINGMODULATORPROPERTIES& all); - - void defer_frequency(const EaxEaxCall& eax_call); - void defer_high_pass_cutoff(const EaxEaxCall& eax_call); - void defer_waveform(const EaxEaxCall& eax_call); - void defer_all(const EaxEaxCall& eax_call); - - void set(const EaxEaxCall& eax_call); + void get(const EaxCall& call, const Props& props) override; + void set(const EaxCall& call, Props& props) override; + bool commit_props(const Props& props) override; }; // EaxRingModulatorEffect +EaxRingModulatorEffect::EaxRingModulatorEffect(const EaxCall& call) + : EaxEffect4{AL_EFFECT_RING_MODULATOR, call} +{} -class EaxRingModulatorEffectException : - public EaxException +void EaxRingModulatorEffect::set_defaults(Props& props) { -public: - explicit EaxRingModulatorEffectException( - const char* message) - : - EaxException{"EAX_RING_MODULATOR_EFFECT", message} - { - } -}; // EaxRingModulatorEffectException - - -EaxRingModulatorEffect::EaxRingModulatorEffect() - : EaxEffect{AL_EFFECT_RING_MODULATOR} -{ - set_eax_defaults(); - set_efx_defaults(); + props.flFrequency = EAXRINGMODULATOR_DEFAULTFREQUENCY; + props.flHighPassCutOff = EAXRINGMODULATOR_DEFAULTHIGHPASSCUTOFF; + props.ulWaveform = EAXRINGMODULATOR_DEFAULTWAVEFORM; } -void EaxRingModulatorEffect::dispatch(const EaxEaxCall& eax_call) +void EaxRingModulatorEffect::set_efx_frequency() noexcept { - eax_call.is_get() ? get(eax_call) : set(eax_call); -} - -void EaxRingModulatorEffect::set_eax_defaults() -{ - eax_.flFrequency = EAXRINGMODULATOR_DEFAULTFREQUENCY; - eax_.flHighPassCutOff = EAXRINGMODULATOR_DEFAULTHIGHPASSCUTOFF; - eax_.ulWaveform = EAXRINGMODULATOR_DEFAULTWAVEFORM; - - eax_d_ = eax_; -} - -void EaxRingModulatorEffect::set_efx_frequency() -{ - const auto frequency = clamp( - eax_.flFrequency, + al_effect_props_.Modulator.Frequency = clamp( + props_.flFrequency, AL_RING_MODULATOR_MIN_FREQUENCY, AL_RING_MODULATOR_MAX_FREQUENCY); - - al_effect_props_.Modulator.Frequency = frequency; } -void EaxRingModulatorEffect::set_efx_high_pass_cutoff() +void EaxRingModulatorEffect::set_efx_high_pass_cutoff() noexcept { - const auto high_pass_cutoff = clamp( - eax_.flHighPassCutOff, + al_effect_props_.Modulator.HighPassCutoff = clamp( + props_.flHighPassCutOff, AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF, AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF); - - al_effect_props_.Modulator.HighPassCutoff = high_pass_cutoff; } void EaxRingModulatorEffect::set_efx_waveform() { const auto waveform = clamp( - static_cast(eax_.ulWaveform), + static_cast(props_.ulWaveform), AL_RING_MODULATOR_MIN_WAVEFORM, AL_RING_MODULATOR_MAX_WAVEFORM); - const auto efx_waveform = WaveformFromEmum(waveform); assert(efx_waveform.has_value()); al_effect_props_.Modulator.Waveform = *efx_waveform; @@ -276,207 +258,62 @@ void EaxRingModulatorEffect::set_efx_defaults() set_efx_waveform(); } -void EaxRingModulatorEffect::get(const EaxEaxCall& eax_call) +void EaxRingModulatorEffect::get(const EaxCall& call, const Props& props) { - switch(eax_call.get_property_id()) + switch(call.get_property_id()) { - case EAXRINGMODULATOR_NONE: - break; - - case EAXRINGMODULATOR_ALLPARAMETERS: - eax_call.set_value(eax_); - break; - - case EAXRINGMODULATOR_FREQUENCY: - eax_call.set_value(eax_.flFrequency); - break; - - case EAXRINGMODULATOR_HIGHPASSCUTOFF: - eax_call.set_value(eax_.flHighPassCutOff); - break; - - case EAXRINGMODULATOR_WAVEFORM: - eax_call.set_value(eax_.ulWaveform); - break; - - default: - throw EaxRingModulatorEffectException{"Unsupported property id."}; + case EAXRINGMODULATOR_NONE: break; + case EAXRINGMODULATOR_ALLPARAMETERS: call.set_value(props); break; + case EAXRINGMODULATOR_FREQUENCY: call.set_value(props.flFrequency); break; + case EAXRINGMODULATOR_HIGHPASSCUTOFF: call.set_value(props.flHighPassCutOff); break; + case EAXRINGMODULATOR_WAVEFORM: call.set_value(props.ulWaveform); break; + default: fail_unknown_property_id(); } } -void EaxRingModulatorEffect::validate_frequency( - float flFrequency) -{ - eax_validate_range( - "Frequency", - flFrequency, - EAXRINGMODULATOR_MINFREQUENCY, - EAXRINGMODULATOR_MAXFREQUENCY); -} - -void EaxRingModulatorEffect::validate_high_pass_cutoff( - float flHighPassCutOff) -{ - eax_validate_range( - "High-Pass Cutoff", - flHighPassCutOff, - EAXRINGMODULATOR_MINHIGHPASSCUTOFF, - EAXRINGMODULATOR_MAXHIGHPASSCUTOFF); -} - -void EaxRingModulatorEffect::validate_waveform( - unsigned long ulWaveform) -{ - eax_validate_range( - "Waveform", - ulWaveform, - EAXRINGMODULATOR_MINWAVEFORM, - EAXRINGMODULATOR_MAXWAVEFORM); -} - -void EaxRingModulatorEffect::validate_all( - const EAXRINGMODULATORPROPERTIES& all) -{ - validate_frequency(all.flFrequency); - validate_high_pass_cutoff(all.flHighPassCutOff); - validate_waveform(all.ulWaveform); -} - -void EaxRingModulatorEffect::defer_frequency( - float flFrequency) -{ - eax_d_.flFrequency = flFrequency; - eax_dirty_flags_.flFrequency = (eax_.flFrequency != eax_d_.flFrequency); -} - -void EaxRingModulatorEffect::defer_high_pass_cutoff( - float flHighPassCutOff) -{ - eax_d_.flHighPassCutOff = flHighPassCutOff; - eax_dirty_flags_.flHighPassCutOff = (eax_.flHighPassCutOff != eax_d_.flHighPassCutOff); -} - -void EaxRingModulatorEffect::defer_waveform( - unsigned long ulWaveform) +void EaxRingModulatorEffect::set(const EaxCall& call, Props& props) { - eax_d_.ulWaveform = ulWaveform; - eax_dirty_flags_.ulWaveform = (eax_.ulWaveform != eax_d_.ulWaveform); -} - -void EaxRingModulatorEffect::defer_all( - const EAXRINGMODULATORPROPERTIES& all) -{ - defer_frequency(all.flFrequency); - defer_high_pass_cutoff(all.flHighPassCutOff); - defer_waveform(all.ulWaveform); -} - -void EaxRingModulatorEffect::defer_frequency( - const EaxEaxCall& eax_call) -{ - const auto& frequency = - eax_call.get_value< - EaxRingModulatorEffectException, const decltype(EAXRINGMODULATORPROPERTIES::flFrequency)>(); - - validate_frequency(frequency); - defer_frequency(frequency); -} - -void EaxRingModulatorEffect::defer_high_pass_cutoff( - const EaxEaxCall& eax_call) -{ - const auto& high_pass_cutoff = - eax_call.get_value< - EaxRingModulatorEffectException, const decltype(EAXRINGMODULATORPROPERTIES::flHighPassCutOff)>(); - - validate_high_pass_cutoff(high_pass_cutoff); - defer_high_pass_cutoff(high_pass_cutoff); -} - -void EaxRingModulatorEffect::defer_waveform( - const EaxEaxCall& eax_call) -{ - const auto& waveform = - eax_call.get_value< - EaxRingModulatorEffectException, const decltype(EAXRINGMODULATORPROPERTIES::ulWaveform)>(); - - validate_waveform(waveform); - defer_waveform(waveform); -} - -void EaxRingModulatorEffect::defer_all( - const EaxEaxCall& eax_call) -{ - const auto& all = - eax_call.get_value(); - - validate_all(all); - defer_all(all); -} - -// [[nodiscard]] -bool EaxRingModulatorEffect::apply_deferred() -{ - if (eax_dirty_flags_ == EaxRingModulatorEffectDirtyFlags{}) + switch (call.get_property_id()) { - return false; + case EAXRINGMODULATOR_NONE: break; + case EAXRINGMODULATOR_ALLPARAMETERS: defer(call, props); break; + case EAXRINGMODULATOR_FREQUENCY: defer(call, props.flFrequency); break; + case EAXRINGMODULATOR_HIGHPASSCUTOFF: defer(call, props.flHighPassCutOff); break; + case EAXRINGMODULATOR_WAVEFORM: defer(call, props.ulWaveform); break; + default: fail_unknown_property_id(); } +} - eax_ = eax_d_; +bool EaxRingModulatorEffect::commit_props(const Props& props) +{ + auto is_dirty = false; - if (eax_dirty_flags_.flFrequency) + if (props_.flFrequency != props.flFrequency) { + is_dirty = true; set_efx_frequency(); } - if (eax_dirty_flags_.flHighPassCutOff) + if (props_.flHighPassCutOff != props.flHighPassCutOff) { + is_dirty = true; set_efx_high_pass_cutoff(); } - if (eax_dirty_flags_.ulWaveform) + if (props_.ulWaveform != props.ulWaveform) { + is_dirty = true; set_efx_waveform(); } - eax_dirty_flags_ = EaxRingModulatorEffectDirtyFlags{}; - - return true; -} - -void EaxRingModulatorEffect::set(const EaxEaxCall& eax_call) -{ - switch (eax_call.get_property_id()) - { - case EAXRINGMODULATOR_NONE: - break; - - case EAXRINGMODULATOR_ALLPARAMETERS: - defer_all(eax_call); - break; - - case EAXRINGMODULATOR_FREQUENCY: - defer_frequency(eax_call); - break; - - case EAXRINGMODULATOR_HIGHPASSCUTOFF: - defer_high_pass_cutoff(eax_call); - break; - - case EAXRINGMODULATOR_WAVEFORM: - defer_waveform(eax_call); - break; - - default: - throw EaxRingModulatorEffectException{"Unsupported property id."}; - } + return is_dirty; } } // namespace -EaxEffectUPtr eax_create_eax_ring_modulator_effect() +EaxEffectUPtr eax_create_eax_ring_modulator_effect(const EaxCall& call) { - return std::make_unique(); + return eax_create_eax4_effect(call); } #endif // ALSOFT_EAX diff --git a/modules/openal-soft/al/effects/null.cpp b/modules/openal-soft/al/effects/null.cpp index a0eb224..2243dfe 100644 --- a/modules/openal-soft/al/effects/null.cpp +++ b/modules/openal-soft/al/effects/null.cpp @@ -8,7 +8,7 @@ #include "effects.h" #ifdef ALSOFT_EAX -#include "al/eax_exception.h" +#include "al/eax/exception.h" #endif // ALSOFT_EAX @@ -100,44 +100,34 @@ const EffectProps NullEffectProps{genDefaultProps()}; #ifdef ALSOFT_EAX namespace { -class EaxNullEffect final : - public EaxEffect -{ +class EaxNullEffect final : public EaxEffect { public: - EaxNullEffect(); - - void dispatch(const EaxEaxCall& eax_call) override; + EaxNullEffect() noexcept; - // [[nodiscard]] - bool apply_deferred() override; + void dispatch(const EaxCall& call) override; + /*[[nodiscard]]*/ bool commit() override; }; // EaxNullEffect -class EaxNullEffectException : - public EaxException +class EaxNullEffectException : public EaxException { public: - explicit EaxNullEffectException( - const char* message) - : - EaxException{"EAX_NULL_EFFECT", message} - { - } + explicit EaxNullEffectException(const char* message) + : EaxException{"EAX_NULL_EFFECT", message} + {} }; // EaxNullEffectException - -EaxNullEffect::EaxNullEffect() +EaxNullEffect::EaxNullEffect() noexcept : EaxEffect{AL_EFFECT_NULL} -{ -} +{} -void EaxNullEffect::dispatch(const EaxEaxCall& eax_call) +void EaxNullEffect::dispatch(const EaxCall& call) { - if(eax_call.get_property_id() != 0) + if(call.get_property_id() != 0) throw EaxNullEffectException{"Unsupported property id."}; } -bool EaxNullEffect::apply_deferred() +bool EaxNullEffect::commit() { return false; } diff --git a/modules/openal-soft/al/effects/pshifter.cpp b/modules/openal-soft/al/effects/pshifter.cpp index 1b2dcff..51dbdd8 100644 --- a/modules/openal-soft/al/effects/pshifter.cpp +++ b/modules/openal-soft/al/effects/pshifter.cpp @@ -9,9 +9,8 @@ #ifdef ALSOFT_EAX #include "alnumeric.h" - -#include "al/eax_exception.h" -#include "al/eax_utils.h" +#include "al/eax/exception.h" +#include "al/eax/utils.h" #endif // ALSOFT_EAX @@ -93,108 +92,84 @@ const EffectProps PshifterEffectProps{genDefaultProps()}; #ifdef ALSOFT_EAX namespace { -using EaxPitchShifterEffectDirtyFlagsValue = std::uint_least8_t; - -struct EaxPitchShifterEffectDirtyFlags -{ - using EaxIsBitFieldStruct = bool; - - EaxPitchShifterEffectDirtyFlagsValue lCoarseTune : 1; - EaxPitchShifterEffectDirtyFlagsValue lFineTune : 1; -}; // EaxPitchShifterEffectDirtyFlags - - -class EaxPitchShifterEffect final : - public EaxEffect +class EaxPitchShifterEffectException : public EaxException { public: - EaxPitchShifterEffect(); - - void dispatch(const EaxEaxCall& eax_call) override; + explicit EaxPitchShifterEffectException(const char* message) + : EaxException{"EAX_PITCH_SHIFTER_EFFECT", message} + {} +}; // EaxPitchShifterEffectException - // [[nodiscard]] - bool apply_deferred() override; +class EaxPitchShifterEffect final : public EaxEffect4 { +public: + EaxPitchShifterEffect(const EaxCall& call); private: - EAXPITCHSHIFTERPROPERTIES eax_{}; - EAXPITCHSHIFTERPROPERTIES eax_d_{}; - EaxPitchShifterEffectDirtyFlags eax_dirty_flags_{}; - - void set_eax_defaults(); - - void set_efx_coarse_tune(); - void set_efx_fine_tune(); - void set_efx_defaults(); - - void get(const EaxEaxCall& eax_call); - - void validate_coarse_tune(long lCoarseTune); - void validate_fine_tune(long lFineTune); - void validate_all(const EAXPITCHSHIFTERPROPERTIES& all); - - void defer_coarse_tune(long lCoarseTune); - void defer_fine_tune(long lFineTune); - void defer_all(const EAXPITCHSHIFTERPROPERTIES& all); - - void defer_coarse_tune(const EaxEaxCall& eax_call); - void defer_fine_tune(const EaxEaxCall& eax_call); - void defer_all(const EaxEaxCall& eax_call); - - void set(const EaxEaxCall& eax_call); + struct CoarseTuneValidator { + void operator()(long lCoarseTune) const + { + eax_validate_range( + "Coarse Tune", + lCoarseTune, + EAXPITCHSHIFTER_MINCOARSETUNE, + EAXPITCHSHIFTER_MAXCOARSETUNE); + } + }; // CoarseTuneValidator + + struct FineTuneValidator { + void operator()(long lFineTune) const + { + eax_validate_range( + "Fine Tune", + lFineTune, + EAXPITCHSHIFTER_MINFINETUNE, + EAXPITCHSHIFTER_MAXFINETUNE); + } + }; // FineTuneValidator + + struct AllValidator { + void operator()(const Props& all) const + { + CoarseTuneValidator{}(all.lCoarseTune); + FineTuneValidator{}(all.lFineTune); + } + }; // AllValidator + + void set_defaults(Props& props) override; + + void set_efx_coarse_tune() noexcept; + void set_efx_fine_tune() noexcept; + void set_efx_defaults() override; + + void get(const EaxCall& call, const Props& props) override; + void set(const EaxCall& call, Props& props) override; + bool commit_props(const Props& old_i) override; }; // EaxPitchShifterEffect +EaxPitchShifterEffect::EaxPitchShifterEffect(const EaxCall& call) + : EaxEffect4{AL_EFFECT_PITCH_SHIFTER, call} +{} -class EaxPitchShifterEffectException : - public EaxException +void EaxPitchShifterEffect::set_defaults(Props& props) { -public: - explicit EaxPitchShifterEffectException( - const char* message) - : - EaxException{"EAX_PITCH_SHIFTER_EFFECT", message} - { - } -}; // EaxPitchShifterEffectException - - -EaxPitchShifterEffect::EaxPitchShifterEffect() - : EaxEffect{AL_EFFECT_PITCH_SHIFTER} -{ - set_eax_defaults(); - set_efx_defaults(); -} - -void EaxPitchShifterEffect::dispatch(const EaxEaxCall& eax_call) -{ - eax_call.is_get() ? get(eax_call) : set(eax_call); -} - -void EaxPitchShifterEffect::set_eax_defaults() -{ - eax_.lCoarseTune = EAXPITCHSHIFTER_DEFAULTCOARSETUNE; - eax_.lFineTune = EAXPITCHSHIFTER_DEFAULTFINETUNE; - - eax_d_ = eax_; + props.lCoarseTune = EAXPITCHSHIFTER_DEFAULTCOARSETUNE; + props.lFineTune = EAXPITCHSHIFTER_DEFAULTFINETUNE; } -void EaxPitchShifterEffect::set_efx_coarse_tune() +void EaxPitchShifterEffect::set_efx_coarse_tune() noexcept { - const auto coarse_tune = clamp( - static_cast(eax_.lCoarseTune), + al_effect_props_.Pshifter.CoarseTune = clamp( + static_cast(props_.lCoarseTune), AL_PITCH_SHIFTER_MIN_COARSE_TUNE, AL_PITCH_SHIFTER_MAX_COARSE_TUNE); - - al_effect_props_.Pshifter.CoarseTune = coarse_tune; } -void EaxPitchShifterEffect::set_efx_fine_tune() +void EaxPitchShifterEffect::set_efx_fine_tune() noexcept { - const auto fine_tune = clamp( - static_cast(eax_.lFineTune), + al_effect_props_.Pshifter.FineTune = clamp( + static_cast(props_.lFineTune), AL_PITCH_SHIFTER_MIN_FINE_TUNE, AL_PITCH_SHIFTER_MAX_FINE_TUNE); - - al_effect_props_.Pshifter.FineTune = fine_tune; } void EaxPitchShifterEffect::set_efx_defaults() @@ -203,162 +178,54 @@ void EaxPitchShifterEffect::set_efx_defaults() set_efx_fine_tune(); } -void EaxPitchShifterEffect::get(const EaxEaxCall& eax_call) +void EaxPitchShifterEffect::get(const EaxCall& call, const Props& props) { - switch(eax_call.get_property_id()) + switch(call.get_property_id()) { - case EAXPITCHSHIFTER_NONE: - break; - - case EAXPITCHSHIFTER_ALLPARAMETERS: - eax_call.set_value(eax_); - break; - - case EAXPITCHSHIFTER_COARSETUNE: - eax_call.set_value(eax_.lCoarseTune); - break; - - case EAXPITCHSHIFTER_FINETUNE: - eax_call.set_value(eax_.lFineTune); - break; - - default: - throw EaxPitchShifterEffectException{"Unsupported property id."}; + case EAXPITCHSHIFTER_NONE: break; + case EAXPITCHSHIFTER_ALLPARAMETERS: call.set_value(props); break; + case EAXPITCHSHIFTER_COARSETUNE: call.set_value(props.lCoarseTune); break; + case EAXPITCHSHIFTER_FINETUNE: call.set_value(props.lFineTune); break; + default: fail_unknown_property_id(); } } -void EaxPitchShifterEffect::validate_coarse_tune( - long lCoarseTune) -{ - eax_validate_range( - "Coarse Tune", - lCoarseTune, - EAXPITCHSHIFTER_MINCOARSETUNE, - EAXPITCHSHIFTER_MAXCOARSETUNE); -} - -void EaxPitchShifterEffect::validate_fine_tune( - long lFineTune) +void EaxPitchShifterEffect::set(const EaxCall& call, Props& props) { - eax_validate_range( - "Fine Tune", - lFineTune, - EAXPITCHSHIFTER_MINFINETUNE, - EAXPITCHSHIFTER_MAXFINETUNE); -} - -void EaxPitchShifterEffect::validate_all( - const EAXPITCHSHIFTERPROPERTIES& all) -{ - validate_coarse_tune(all.lCoarseTune); - validate_fine_tune(all.lFineTune); -} - -void EaxPitchShifterEffect::defer_coarse_tune( - long lCoarseTune) -{ - eax_d_.lCoarseTune = lCoarseTune; - eax_dirty_flags_.lCoarseTune = (eax_.lCoarseTune != eax_d_.lCoarseTune); -} - -void EaxPitchShifterEffect::defer_fine_tune( - long lFineTune) -{ - eax_d_.lFineTune = lFineTune; - eax_dirty_flags_.lFineTune = (eax_.lFineTune != eax_d_.lFineTune); -} - -void EaxPitchShifterEffect::defer_all( - const EAXPITCHSHIFTERPROPERTIES& all) -{ - defer_coarse_tune(all.lCoarseTune); - defer_fine_tune(all.lFineTune); -} - -void EaxPitchShifterEffect::defer_coarse_tune( - const EaxEaxCall& eax_call) -{ - const auto& coarse_tune = - eax_call.get_value(); - - validate_coarse_tune(coarse_tune); - defer_coarse_tune(coarse_tune); -} - -void EaxPitchShifterEffect::defer_fine_tune( - const EaxEaxCall& eax_call) -{ - const auto& fine_tune = - eax_call.get_value(); - - validate_fine_tune(fine_tune); - defer_fine_tune(fine_tune); -} - -void EaxPitchShifterEffect::defer_all( - const EaxEaxCall& eax_call) -{ - const auto& all = - eax_call.get_value(); - - validate_all(all); - defer_all(all); -} - -// [[nodiscard]] -bool EaxPitchShifterEffect::apply_deferred() -{ - if (eax_dirty_flags_ == EaxPitchShifterEffectDirtyFlags{}) + switch(call.get_property_id()) { - return false; + case EAXPITCHSHIFTER_NONE: break; + case EAXPITCHSHIFTER_ALLPARAMETERS: defer(call, props); break; + case EAXPITCHSHIFTER_COARSETUNE: defer(call, props.lCoarseTune); break; + case EAXPITCHSHIFTER_FINETUNE: defer(call, props.lFineTune); break; + default: fail_unknown_property_id(); } +} - eax_ = eax_d_; +bool EaxPitchShifterEffect::commit_props(const Props& props) +{ + auto is_dirty = false; - if (eax_dirty_flags_.lCoarseTune) + if (props_.lCoarseTune != props.lCoarseTune) { + is_dirty = true; set_efx_coarse_tune(); } - if (eax_dirty_flags_.lFineTune) + if (props_.lFineTune != props.lFineTune) { + is_dirty = true; set_efx_fine_tune(); } - eax_dirty_flags_ = EaxPitchShifterEffectDirtyFlags{}; - - return true; -} - -void EaxPitchShifterEffect::set(const EaxEaxCall& eax_call) -{ - switch(eax_call.get_property_id()) - { - case EAXPITCHSHIFTER_NONE: - break; - - case EAXPITCHSHIFTER_ALLPARAMETERS: - defer_all(eax_call); - break; - - case EAXPITCHSHIFTER_COARSETUNE: - defer_coarse_tune(eax_call); - break; - - case EAXPITCHSHIFTER_FINETUNE: - defer_fine_tune(eax_call); - break; - - default: - throw EaxPitchShifterEffectException{"Unsupported property id."}; - } + return is_dirty; } } // namespace -EaxEffectUPtr eax_create_eax_pitch_shifter_effect() +EaxEffectUPtr eax_create_eax_pitch_shifter_effect(const EaxCall& call) { - return std::make_unique(); + return eax_create_eax4_effect(call); } #endif // ALSOFT_EAX diff --git a/modules/openal-soft/al/effects/reverb.cpp b/modules/openal-soft/al/effects/reverb.cpp index 197ea50..07d6dfc 100644 --- a/modules/openal-soft/al/effects/reverb.cpp +++ b/modules/openal-soft/al/effects/reverb.cpp @@ -10,11 +10,11 @@ #include "effects.h" #ifdef ALSOFT_EAX -#include +#include #include "alnumeric.h" #include "AL/efx-presets.h" -#include "al/eax_exception.h" -#include "al/eax_utils.h" +#include "al/eax/exception.h" +#include "al/eax/utils.h" #endif // ALSOFT_EAX @@ -566,1977 +566,1429 @@ const EffectProps StdReverbEffectProps{genDefaultStdProps()}; #ifdef ALSOFT_EAX namespace { -extern const EFXEAXREVERBPROPERTIES eax_efx_reverb_presets[]; - -using EaxReverbEffectDirtyFlagsValue = std::uint_least32_t; - -struct EaxReverbEffectDirtyFlags -{ - using EaxIsBitFieldStruct = bool; - - EaxReverbEffectDirtyFlagsValue ulEnvironment : 1; - EaxReverbEffectDirtyFlagsValue flEnvironmentSize : 1; - EaxReverbEffectDirtyFlagsValue flEnvironmentDiffusion : 1; - EaxReverbEffectDirtyFlagsValue lRoom : 1; - EaxReverbEffectDirtyFlagsValue lRoomHF : 1; - EaxReverbEffectDirtyFlagsValue lRoomLF : 1; - EaxReverbEffectDirtyFlagsValue flDecayTime : 1; - EaxReverbEffectDirtyFlagsValue flDecayHFRatio : 1; - EaxReverbEffectDirtyFlagsValue flDecayLFRatio : 1; - EaxReverbEffectDirtyFlagsValue lReflections : 1; - EaxReverbEffectDirtyFlagsValue flReflectionsDelay : 1; - EaxReverbEffectDirtyFlagsValue vReflectionsPan : 1; - EaxReverbEffectDirtyFlagsValue lReverb : 1; - EaxReverbEffectDirtyFlagsValue flReverbDelay : 1; - EaxReverbEffectDirtyFlagsValue vReverbPan : 1; - EaxReverbEffectDirtyFlagsValue flEchoTime : 1; - EaxReverbEffectDirtyFlagsValue flEchoDepth : 1; - EaxReverbEffectDirtyFlagsValue flModulationTime : 1; - EaxReverbEffectDirtyFlagsValue flModulationDepth : 1; - EaxReverbEffectDirtyFlagsValue flAirAbsorptionHF : 1; - EaxReverbEffectDirtyFlagsValue flHFReference : 1; - EaxReverbEffectDirtyFlagsValue flLFReference : 1; - EaxReverbEffectDirtyFlagsValue flRoomRolloffFactor : 1; - EaxReverbEffectDirtyFlagsValue ulFlags : 1; -}; // EaxReverbEffectDirtyFlags - -struct Eax1ReverbEffectDirtyFlags -{ - using EaxIsBitFieldStruct = bool; - - EaxReverbEffectDirtyFlagsValue ulEnvironment : 1; - EaxReverbEffectDirtyFlagsValue flVolume : 1; - EaxReverbEffectDirtyFlagsValue flDecayTime : 1; - EaxReverbEffectDirtyFlagsValue flDamping : 1; -}; // Eax1ReverbEffectDirtyFlags - -class EaxReverbEffect final : - public EaxEffect -{ -public: - EaxReverbEffect(); - - void dispatch(const EaxEaxCall& eax_call) override; - - // [[nodiscard]] - bool apply_deferred() override; - -private: - EAX_REVERBPROPERTIES eax1_{}; - EAX_REVERBPROPERTIES eax1_d_{}; - Eax1ReverbEffectDirtyFlags eax1_dirty_flags_{}; - EAXREVERBPROPERTIES eax_{}; - EAXREVERBPROPERTIES eax_d_{}; - EaxReverbEffectDirtyFlags eax_dirty_flags_{}; - - [[noreturn]] static void eax_fail(const char* message); - - void set_eax_defaults(); - - void set_efx_density_from_environment_size(); - void set_efx_diffusion(); - void set_efx_gain(); - void set_efx_gain_hf(); - void set_efx_gain_lf(); - void set_efx_decay_time(); - void set_efx_decay_hf_ratio(); - void set_efx_decay_lf_ratio(); - void set_efx_reflections_gain(); - void set_efx_reflections_delay(); - void set_efx_reflections_pan(); - void set_efx_late_reverb_gain(); - void set_efx_late_reverb_delay(); - void set_efx_late_reverb_pan(); - void set_efx_echo_time(); - void set_efx_echo_depth(); - void set_efx_modulation_time(); - void set_efx_modulation_depth(); - void set_efx_air_absorption_gain_hf(); - void set_efx_hf_reference(); - void set_efx_lf_reference(); - void set_efx_room_rolloff_factor(); - void set_efx_flags(); - void set_efx_defaults(); - - void v1_get(const EaxEaxCall& eax_call) const; - - void get_all(const EaxEaxCall& eax_call) const; - - void get(const EaxEaxCall& eax_call) const; - - static void v1_validate_environment(unsigned long environment); - static void v1_validate_volume(float volume); - static void v1_validate_decay_time(float decay_time); - static void v1_validate_damping(float damping); - static void v1_validate_all(const EAX_REVERBPROPERTIES& all); - - void v1_defer_environment(unsigned long environment); - void v1_defer_volume(float volume); - void v1_defer_decay_time(float decay_time); - void v1_defer_damping(float damping); - void v1_defer_all(const EAX_REVERBPROPERTIES& all); - - void v1_defer_environment(const EaxEaxCall& eax_call); - void v1_defer_volume(const EaxEaxCall& eax_call); - void v1_defer_decay_time(const EaxEaxCall& eax_call); - void v1_defer_damping(const EaxEaxCall& eax_call); - void v1_defer_all(const EaxEaxCall& eax_call); - void v1_defer(const EaxEaxCall& eax_call); - - void v1_set_efx(); - - static void validate_environment(unsigned long ulEnvironment, int version, bool is_standalone); - static void validate_environment_size(float flEnvironmentSize); - static void validate_environment_diffusion(float flEnvironmentDiffusion); - static void validate_room(long lRoom); - static void validate_room_hf(long lRoomHF); - static void validate_room_lf(long lRoomLF); - static void validate_decay_time(float flDecayTime); - static void validate_decay_hf_ratio(float flDecayHFRatio); - static void validate_decay_lf_ratio(float flDecayLFRatio); - static void validate_reflections(long lReflections); - static void validate_reflections_delay(float flReflectionsDelay); - static void validate_reflections_pan(const EAXVECTOR& vReflectionsPan); - static void validate_reverb(long lReverb); - static void validate_reverb_delay(float flReverbDelay); - static void validate_reverb_pan(const EAXVECTOR& vReverbPan); - static void validate_echo_time(float flEchoTime); - static void validate_echo_depth(float flEchoDepth); - static void validate_modulation_time(float flModulationTime); - static void validate_modulation_depth(float flModulationDepth); - static void validate_air_absorbtion_hf(float air_absorbtion_hf); - static void validate_hf_reference(float flHFReference); - static void validate_lf_reference(float flLFReference); - static void validate_room_rolloff_factor(float flRoomRolloffFactor); - static void validate_flags(unsigned long ulFlags); - static void validate_all(const EAX20LISTENERPROPERTIES& all, int version); - static void validate_all(const EAXREVERBPROPERTIES& all, int version); - - void defer_environment(unsigned long ulEnvironment); - void defer_environment_size(float flEnvironmentSize); - void defer_environment_diffusion(float flEnvironmentDiffusion); - void defer_room(long lRoom); - void defer_room_hf(long lRoomHF); - void defer_room_lf(long lRoomLF); - void defer_decay_time(float flDecayTime); - void defer_decay_hf_ratio(float flDecayHFRatio); - void defer_decay_lf_ratio(float flDecayLFRatio); - void defer_reflections(long lReflections); - void defer_reflections_delay(float flReflectionsDelay); - void defer_reflections_pan(const EAXVECTOR& vReflectionsPan); - void defer_reverb(long lReverb); - void defer_reverb_delay(float flReverbDelay); - void defer_reverb_pan(const EAXVECTOR& vReverbPan); - void defer_echo_time(float flEchoTime); - void defer_echo_depth(float flEchoDepth); - void defer_modulation_time(float flModulationTime); - void defer_modulation_depth(float flModulationDepth); - void defer_air_absorbtion_hf(float flAirAbsorptionHF); - void defer_hf_reference(float flHFReference); - void defer_lf_reference(float flLFReference); - void defer_room_rolloff_factor(float flRoomRolloffFactor); - void defer_flags(unsigned long ulFlags); - void defer_all(const EAX20LISTENERPROPERTIES& all); - void defer_all(const EAXREVERBPROPERTIES& all); - - void defer_environment(const EaxEaxCall& eax_call); - void defer_environment_size(const EaxEaxCall& eax_call); - void defer_environment_diffusion(const EaxEaxCall& eax_call); - void defer_room(const EaxEaxCall& eax_call); - void defer_room_hf(const EaxEaxCall& eax_call); - void defer_room_lf(const EaxEaxCall& eax_call); - void defer_decay_time(const EaxEaxCall& eax_call); - void defer_decay_hf_ratio(const EaxEaxCall& eax_call); - void defer_decay_lf_ratio(const EaxEaxCall& eax_call); - void defer_reflections(const EaxEaxCall& eax_call); - void defer_reflections_delay(const EaxEaxCall& eax_call); - void defer_reflections_pan(const EaxEaxCall& eax_call); - void defer_reverb(const EaxEaxCall& eax_call); - void defer_reverb_delay(const EaxEaxCall& eax_call); - void defer_reverb_pan(const EaxEaxCall& eax_call); - void defer_echo_time(const EaxEaxCall& eax_call); - void defer_echo_depth(const EaxEaxCall& eax_call); - void defer_modulation_time(const EaxEaxCall& eax_call); - void defer_modulation_depth(const EaxEaxCall& eax_call); - void defer_air_absorbtion_hf(const EaxEaxCall& eax_call); - void defer_hf_reference(const EaxEaxCall& eax_call); - void defer_lf_reference(const EaxEaxCall& eax_call); - void defer_room_rolloff_factor(const EaxEaxCall& eax_call); - void defer_flags(const EaxEaxCall& eax_call); - void defer_all(const EaxEaxCall& eax_call); - - void set(const EaxEaxCall& eax_call); -}; // EaxReverbEffect - - -class EaxReverbEffectException : - public EaxException +class EaxReverbEffectException : public EaxException { public: - explicit EaxReverbEffectException( - const char* message) - : - EaxException{"EAX_REVERB_EFFECT", message} - { - } + explicit EaxReverbEffectException(const char* message) + : EaxException{"EAX_REVERB_EFFECT", message} + {} }; // EaxReverbEffectException - -EaxReverbEffect::EaxReverbEffect() - : EaxEffect{AL_EFFECT_EAXREVERB} -{ - set_eax_defaults(); - set_efx_defaults(); -} - -void EaxReverbEffect::dispatch(const EaxEaxCall& eax_call) -{ - eax_call.is_get() ? get(eax_call) : set(eax_call); -} - -[[noreturn]] void EaxReverbEffect::eax_fail(const char* message) -{ - throw EaxReverbEffectException{message}; -} - -void EaxReverbEffect::set_eax_defaults() -{ - eax1_ = EAX1REVERB_PRESETS[EAX_ENVIRONMENT_GENERIC]; - eax1_d_ = eax1_; - eax_ = EAXREVERB_PRESETS[EAX_ENVIRONMENT_GENERIC]; - /* HACK: EAX2 has a default room volume of -10,000dB (silence), although - * newer versions use -1,000dB. What should be happening is properties for - * each EAX version is tracked separately, with the last version used for - * the properties to apply (presumably v2 or nothing being the default). - */ - eax_.lRoom = EAXREVERB_MINROOM; - eax_d_ = eax_; -} - -void EaxReverbEffect::set_efx_density_from_environment_size() -{ - const auto eax_environment_size = eax_.flEnvironmentSize; - - const auto efx_density = clamp( - (eax_environment_size * eax_environment_size * eax_environment_size) / 16.0F, - AL_EAXREVERB_MIN_DENSITY, - AL_EAXREVERB_MAX_DENSITY); - - al_effect_props_.Reverb.Density = efx_density; -} - -void EaxReverbEffect::set_efx_diffusion() -{ - const auto efx_diffusion = clamp( - eax_.flEnvironmentDiffusion, - AL_EAXREVERB_MIN_DIFFUSION, - AL_EAXREVERB_MAX_DIFFUSION); - - al_effect_props_.Reverb.Diffusion = efx_diffusion; -} - -void EaxReverbEffect::set_efx_gain() -{ - const auto efx_gain = clamp( - level_mb_to_gain(static_cast(eax_.lRoom)), - AL_EAXREVERB_MIN_GAIN, - AL_EAXREVERB_MAX_GAIN); - - al_effect_props_.Reverb.Gain = efx_gain; -} - -void EaxReverbEffect::set_efx_gain_hf() -{ - const auto efx_gain_hf = clamp( - level_mb_to_gain(static_cast(eax_.lRoomHF)), - AL_EAXREVERB_MIN_GAINHF, - AL_EAXREVERB_MAX_GAINHF); - - al_effect_props_.Reverb.GainHF = efx_gain_hf; -} - -void EaxReverbEffect::set_efx_gain_lf() -{ - const auto efx_gain_lf = clamp( - level_mb_to_gain(static_cast(eax_.lRoomLF)), - AL_EAXREVERB_MIN_GAINLF, - AL_EAXREVERB_MAX_GAINLF); - - al_effect_props_.Reverb.GainLF = efx_gain_lf; -} - -void EaxReverbEffect::set_efx_decay_time() -{ - const auto efx_decay_time = clamp( - eax_.flDecayTime, - AL_EAXREVERB_MIN_DECAY_TIME, - AL_EAXREVERB_MAX_DECAY_TIME); - - al_effect_props_.Reverb.DecayTime = efx_decay_time; -} - -void EaxReverbEffect::set_efx_decay_hf_ratio() -{ - const auto efx_decay_hf_ratio = clamp( - eax_.flDecayHFRatio, - AL_EAXREVERB_MIN_DECAY_HFRATIO, - AL_EAXREVERB_MAX_DECAY_HFRATIO); - - al_effect_props_.Reverb.DecayHFRatio = efx_decay_hf_ratio; -} - -void EaxReverbEffect::set_efx_decay_lf_ratio() -{ - const auto efx_decay_lf_ratio = clamp( - eax_.flDecayLFRatio, - AL_EAXREVERB_MIN_DECAY_LFRATIO, - AL_EAXREVERB_MAX_DECAY_LFRATIO); - - al_effect_props_.Reverb.DecayLFRatio = efx_decay_lf_ratio; -} - -void EaxReverbEffect::set_efx_reflections_gain() -{ - const auto efx_reflections_gain = clamp( - level_mb_to_gain(static_cast(eax_.lReflections)), - AL_EAXREVERB_MIN_REFLECTIONS_GAIN, - AL_EAXREVERB_MAX_REFLECTIONS_GAIN); - - al_effect_props_.Reverb.ReflectionsGain = efx_reflections_gain; -} - -void EaxReverbEffect::set_efx_reflections_delay() -{ - const auto efx_reflections_delay = clamp( - eax_.flReflectionsDelay, - AL_EAXREVERB_MIN_REFLECTIONS_DELAY, - AL_EAXREVERB_MAX_REFLECTIONS_DELAY); - - al_effect_props_.Reverb.ReflectionsDelay = efx_reflections_delay; -} - -void EaxReverbEffect::set_efx_reflections_pan() -{ - al_effect_props_.Reverb.ReflectionsPan[0] = eax_.vReflectionsPan.x; - al_effect_props_.Reverb.ReflectionsPan[1] = eax_.vReflectionsPan.y; - al_effect_props_.Reverb.ReflectionsPan[2] = eax_.vReflectionsPan.z; -} - -void EaxReverbEffect::set_efx_late_reverb_gain() -{ - const auto efx_late_reverb_gain = clamp( - level_mb_to_gain(static_cast(eax_.lReverb)), - AL_EAXREVERB_MIN_LATE_REVERB_GAIN, - AL_EAXREVERB_MAX_LATE_REVERB_GAIN); - - al_effect_props_.Reverb.LateReverbGain = efx_late_reverb_gain; -} - -void EaxReverbEffect::set_efx_late_reverb_delay() -{ - const auto efx_late_reverb_delay = clamp( - eax_.flReverbDelay, - AL_EAXREVERB_MIN_LATE_REVERB_DELAY, - AL_EAXREVERB_MAX_LATE_REVERB_DELAY); - - al_effect_props_.Reverb.LateReverbDelay = efx_late_reverb_delay; -} - -void EaxReverbEffect::set_efx_late_reverb_pan() -{ - al_effect_props_.Reverb.LateReverbPan[0] = eax_.vReverbPan.x; - al_effect_props_.Reverb.LateReverbPan[1] = eax_.vReverbPan.y; - al_effect_props_.Reverb.LateReverbPan[2] = eax_.vReverbPan.z; -} - -void EaxReverbEffect::set_efx_echo_time() -{ - const auto efx_echo_time = clamp( - eax_.flEchoTime, - AL_EAXREVERB_MIN_ECHO_TIME, - AL_EAXREVERB_MAX_ECHO_TIME); - - al_effect_props_.Reverb.EchoTime = efx_echo_time; -} - -void EaxReverbEffect::set_efx_echo_depth() -{ - const auto efx_echo_depth = clamp( - eax_.flEchoDepth, - AL_EAXREVERB_MIN_ECHO_DEPTH, - AL_EAXREVERB_MAX_ECHO_DEPTH); - - al_effect_props_.Reverb.EchoDepth = efx_echo_depth; -} - -void EaxReverbEffect::set_efx_modulation_time() -{ - const auto efx_modulation_time = clamp( - eax_.flModulationTime, - AL_EAXREVERB_MIN_MODULATION_TIME, - AL_EAXREVERB_MAX_MODULATION_TIME); - - al_effect_props_.Reverb.ModulationTime = efx_modulation_time; -} - -void EaxReverbEffect::set_efx_modulation_depth() -{ - const auto efx_modulation_depth = clamp( - eax_.flModulationDepth, - AL_EAXREVERB_MIN_MODULATION_DEPTH, - AL_EAXREVERB_MAX_MODULATION_DEPTH); - - al_effect_props_.Reverb.ModulationDepth = efx_modulation_depth; -} - -void EaxReverbEffect::set_efx_air_absorption_gain_hf() -{ - const auto efx_air_absorption_hf = clamp( - level_mb_to_gain(eax_.flAirAbsorptionHF), - AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF, - AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF); - - al_effect_props_.Reverb.AirAbsorptionGainHF = efx_air_absorption_hf; -} - -void EaxReverbEffect::set_efx_hf_reference() +class EaxReverbEffect final : public EaxEffect { - const auto efx_hf_reference = clamp( - eax_.flHFReference, - AL_EAXREVERB_MIN_HFREFERENCE, - AL_EAXREVERB_MAX_HFREFERENCE); - - al_effect_props_.Reverb.HFReference = efx_hf_reference; -} - -void EaxReverbEffect::set_efx_lf_reference() -{ - const auto efx_lf_reference = clamp( - eax_.flLFReference, - AL_EAXREVERB_MIN_LFREFERENCE, - AL_EAXREVERB_MAX_LFREFERENCE); - - al_effect_props_.Reverb.LFReference = efx_lf_reference; -} +public: + EaxReverbEffect(const EaxCall& call) noexcept; -void EaxReverbEffect::set_efx_room_rolloff_factor() -{ - const auto efx_room_rolloff_factor = clamp( - eax_.flRoomRolloffFactor, - AL_EAXREVERB_MIN_ROOM_ROLLOFF_FACTOR, - AL_EAXREVERB_MAX_ROOM_ROLLOFF_FACTOR); + void dispatch(const EaxCall& call) override; + /*[[nodiscard]]*/ bool commit() override; - al_effect_props_.Reverb.RoomRolloffFactor = efx_room_rolloff_factor; -} +private: + static constexpr auto initial_room2 = -10'000L; -void EaxReverbEffect::set_efx_flags() -{ - al_effect_props_.Reverb.DecayHFLimit = ((eax_.ulFlags & EAXREVERBFLAGS_DECAYHFLIMIT) != 0); -} + using Exception = EaxReverbEffectException; -void EaxReverbEffect::set_efx_defaults() -{ - set_efx_density_from_environment_size(); - set_efx_diffusion(); - set_efx_gain(); - set_efx_gain_hf(); - set_efx_gain_lf(); - set_efx_decay_time(); - set_efx_decay_hf_ratio(); - set_efx_decay_lf_ratio(); - set_efx_reflections_gain(); - set_efx_reflections_delay(); - set_efx_reflections_pan(); - set_efx_late_reverb_gain(); - set_efx_late_reverb_delay(); - set_efx_late_reverb_pan(); - set_efx_echo_time(); - set_efx_echo_depth(); - set_efx_modulation_time(); - set_efx_modulation_depth(); - set_efx_air_absorption_gain_hf(); - set_efx_hf_reference(); - set_efx_lf_reference(); - set_efx_room_rolloff_factor(); - set_efx_flags(); -} + using Props1 = EAX_REVERBPROPERTIES; + using Props2 = EAX20LISTENERPROPERTIES; + using Props3 = EAXREVERBPROPERTIES; -void EaxReverbEffect::v1_get(const EaxEaxCall& eax_call) const -{ - switch(eax_call.get_property_id()) + struct State1 { - case DSPROPERTY_EAX_ALL: - eax_call.set_value(eax1_); - break; - - case DSPROPERTY_EAX_ENVIRONMENT: - eax_call.set_value(eax1_.environment); - break; - - case DSPROPERTY_EAX_VOLUME: - eax_call.set_value(eax1_.fVolume); - break; - - case DSPROPERTY_EAX_DECAYTIME: - eax_call.set_value(eax1_.fDecayTime_sec); - break; - - case DSPROPERTY_EAX_DAMPING: - eax_call.set_value(eax1_.fDamping); - break; - - default: - eax_fail("Unsupported property id."); - } -} + Props1 i; // Immediate. + Props1 d; // Deferred. + }; // State1 -void EaxReverbEffect::get_all( - const EaxEaxCall& eax_call) const -{ - if (eax_call.get_version() == 2) - { - auto& eax_reverb = eax_call.get_value(); - eax_reverb.lRoom = eax_.lRoom; - eax_reverb.lRoomHF = eax_.lRoomHF; - eax_reverb.flRoomRolloffFactor = eax_.flRoomRolloffFactor; - eax_reverb.flDecayTime = eax_.flDecayTime; - eax_reverb.flDecayHFRatio = eax_.flDecayHFRatio; - eax_reverb.lReflections = eax_.lReflections; - eax_reverb.flReflectionsDelay = eax_.flReflectionsDelay; - eax_reverb.lReverb = eax_.lReverb; - eax_reverb.flReverbDelay = eax_.flReverbDelay; - eax_reverb.dwEnvironment = eax_.ulEnvironment; - eax_reverb.flEnvironmentSize = eax_.flEnvironmentSize; - eax_reverb.flEnvironmentDiffusion = eax_.flEnvironmentDiffusion; - eax_reverb.flAirAbsorptionHF = eax_.flAirAbsorptionHF; - eax_reverb.dwFlags = eax_.ulFlags; - } - else + struct State2 { - eax_call.set_value(eax_); - } -} + Props2 i; // Immediate. + Props2 d; // Deferred. + }; // State2 -void EaxReverbEffect::get(const EaxEaxCall& eax_call) const -{ - if(eax_call.get_version() == 1) - v1_get(eax_call); - else switch(eax_call.get_property_id()) + struct State3 { - case EAXREVERB_NONE: - break; - - case EAXREVERB_ALLPARAMETERS: - get_all(eax_call); - break; - - case EAXREVERB_ENVIRONMENT: - eax_call.set_value(eax_.ulEnvironment); - break; - - case EAXREVERB_ENVIRONMENTSIZE: - eax_call.set_value(eax_.flEnvironmentSize); - break; - - case EAXREVERB_ENVIRONMENTDIFFUSION: - eax_call.set_value(eax_.flEnvironmentDiffusion); - break; - - case EAXREVERB_ROOM: - eax_call.set_value(eax_.lRoom); - break; - - case EAXREVERB_ROOMHF: - eax_call.set_value(eax_.lRoomHF); - break; - - case EAXREVERB_ROOMLF: - eax_call.set_value(eax_.lRoomLF); - break; - - case EAXREVERB_DECAYTIME: - eax_call.set_value(eax_.flDecayTime); - break; + Props3 i; // Immediate. + Props3 d; // Deferred. + }; // State3 - case EAXREVERB_DECAYHFRATIO: - eax_call.set_value(eax_.flDecayHFRatio); - break; - - case EAXREVERB_DECAYLFRATIO: - eax_call.set_value(eax_.flDecayLFRatio); - break; - - case EAXREVERB_REFLECTIONS: - eax_call.set_value(eax_.lReflections); - break; - - case EAXREVERB_REFLECTIONSDELAY: - eax_call.set_value(eax_.flReflectionsDelay); - break; - - case EAXREVERB_REFLECTIONSPAN: - eax_call.set_value(eax_.vReflectionsPan); - break; - - case EAXREVERB_REVERB: - eax_call.set_value(eax_.lReverb); - break; - - case EAXREVERB_REVERBDELAY: - eax_call.set_value(eax_.flReverbDelay); - break; - - case EAXREVERB_REVERBPAN: - eax_call.set_value(eax_.vReverbPan); - break; - - case EAXREVERB_ECHOTIME: - eax_call.set_value(eax_.flEchoTime); - break; - - case EAXREVERB_ECHODEPTH: - eax_call.set_value(eax_.flEchoDepth); - break; - - case EAXREVERB_MODULATIONTIME: - eax_call.set_value(eax_.flModulationTime); - break; - - case EAXREVERB_MODULATIONDEPTH: - eax_call.set_value(eax_.flModulationDepth); - break; - - case EAXREVERB_AIRABSORPTIONHF: - eax_call.set_value(eax_.flAirAbsorptionHF); - break; - - case EAXREVERB_HFREFERENCE: - eax_call.set_value(eax_.flHFReference); - break; - - case EAXREVERB_LFREFERENCE: - eax_call.set_value(eax_.flLFReference); - break; - - case EAXREVERB_ROOMROLLOFFFACTOR: - eax_call.set_value(eax_.flRoomRolloffFactor); - break; - - case EAXREVERB_FLAGS: - eax_call.set_value(eax_.ulFlags); - break; - - default: - eax_fail("Unsupported property id."); - } -} - -void EaxReverbEffect::v1_validate_environment(unsigned long environment) -{ - validate_environment(environment, 1, true); -} - -void EaxReverbEffect::v1_validate_volume(float volume) -{ - eax_validate_range("Volume", volume, EAX1REVERB_MINVOLUME, EAX1REVERB_MAXVOLUME); -} - -void EaxReverbEffect::v1_validate_decay_time(float decay_time) -{ - validate_decay_time(decay_time); -} - -void EaxReverbEffect::v1_validate_damping(float damping) -{ - eax_validate_range("Damping", damping, EAX1REVERB_MINDAMPING, EAX1REVERB_MAXDAMPING); -} - -void EaxReverbEffect::v1_validate_all(const EAX_REVERBPROPERTIES& all) -{ - v1_validate_environment(all.environment); - v1_validate_volume(all.fVolume); - v1_validate_decay_time(all.fDecayTime_sec); - v1_validate_damping(all.fDamping); -} - -void EaxReverbEffect::validate_environment( - unsigned long ulEnvironment, - int version, - bool is_standalone) -{ - eax_validate_range( - "Environment", - ulEnvironment, - EAXREVERB_MINENVIRONMENT, - (version <= 2 || is_standalone) ? EAX1REVERB_MAXENVIRONMENT : EAX30REVERB_MAXENVIRONMENT); -} - -void EaxReverbEffect::validate_environment_size( - float flEnvironmentSize) -{ - eax_validate_range( - "Environment Size", - flEnvironmentSize, - EAXREVERB_MINENVIRONMENTSIZE, - EAXREVERB_MAXENVIRONMENTSIZE); -} - -void EaxReverbEffect::validate_environment_diffusion( - float flEnvironmentDiffusion) -{ - eax_validate_range( - "Environment Diffusion", - flEnvironmentDiffusion, - EAXREVERB_MINENVIRONMENTDIFFUSION, - EAXREVERB_MAXENVIRONMENTDIFFUSION); -} - -void EaxReverbEffect::validate_room( - long lRoom) -{ - eax_validate_range( - "Room", - lRoom, - EAXREVERB_MINROOM, - EAXREVERB_MAXROOM); -} - -void EaxReverbEffect::validate_room_hf( - long lRoomHF) -{ - eax_validate_range( - "Room HF", - lRoomHF, - EAXREVERB_MINROOMHF, - EAXREVERB_MAXROOMHF); -} - -void EaxReverbEffect::validate_room_lf( - long lRoomLF) -{ - eax_validate_range( - "Room LF", - lRoomLF, - EAXREVERB_MINROOMLF, - EAXREVERB_MAXROOMLF); -} - -void EaxReverbEffect::validate_decay_time( - float flDecayTime) -{ - eax_validate_range( - "Decay Time", - flDecayTime, - EAXREVERB_MINDECAYTIME, - EAXREVERB_MAXDECAYTIME); -} - -void EaxReverbEffect::validate_decay_hf_ratio( - float flDecayHFRatio) -{ - eax_validate_range( - "Decay HF Ratio", - flDecayHFRatio, - EAXREVERB_MINDECAYHFRATIO, - EAXREVERB_MAXDECAYHFRATIO); -} - -void EaxReverbEffect::validate_decay_lf_ratio( - float flDecayLFRatio) -{ - eax_validate_range( - "Decay LF Ratio", - flDecayLFRatio, - EAXREVERB_MINDECAYLFRATIO, - EAXREVERB_MAXDECAYLFRATIO); -} - -void EaxReverbEffect::validate_reflections( - long lReflections) -{ - eax_validate_range( - "Reflections", - lReflections, - EAXREVERB_MINREFLECTIONS, - EAXREVERB_MAXREFLECTIONS); -} - -void EaxReverbEffect::validate_reflections_delay( - float flReflectionsDelay) -{ - eax_validate_range( - "Reflections Delay", - flReflectionsDelay, - EAXREVERB_MINREFLECTIONSDELAY, - EAXREVERB_MAXREFLECTIONSDELAY); -} - -void EaxReverbEffect::validate_reflections_pan( - const EAXVECTOR& vReflectionsPan) -{ - std::ignore = vReflectionsPan; -} - -void EaxReverbEffect::validate_reverb( - long lReverb) -{ - eax_validate_range( - "Reverb", - lReverb, - EAXREVERB_MINREVERB, - EAXREVERB_MAXREVERB); -} - -void EaxReverbEffect::validate_reverb_delay( - float flReverbDelay) -{ - eax_validate_range( - "Reverb Delay", - flReverbDelay, - EAXREVERB_MINREVERBDELAY, - EAXREVERB_MAXREVERBDELAY); -} - -void EaxReverbEffect::validate_reverb_pan( - const EAXVECTOR& vReverbPan) -{ - std::ignore = vReverbPan; -} - -void EaxReverbEffect::validate_echo_time( - float flEchoTime) -{ - eax_validate_range( - "Echo Time", - flEchoTime, - EAXREVERB_MINECHOTIME, - EAXREVERB_MAXECHOTIME); -} - -void EaxReverbEffect::validate_echo_depth( - float flEchoDepth) -{ - eax_validate_range( - "Echo Depth", - flEchoDepth, - EAXREVERB_MINECHODEPTH, - EAXREVERB_MAXECHODEPTH); -} - -void EaxReverbEffect::validate_modulation_time( - float flModulationTime) -{ - eax_validate_range( - "Modulation Time", - flModulationTime, - EAXREVERB_MINMODULATIONTIME, - EAXREVERB_MAXMODULATIONTIME); -} - -void EaxReverbEffect::validate_modulation_depth( - float flModulationDepth) -{ - eax_validate_range( - "Modulation Depth", - flModulationDepth, - EAXREVERB_MINMODULATIONDEPTH, - EAXREVERB_MAXMODULATIONDEPTH); -} - -void EaxReverbEffect::validate_air_absorbtion_hf( - float air_absorbtion_hf) -{ - eax_validate_range( - "Air Absorbtion HF", - air_absorbtion_hf, - EAXREVERB_MINAIRABSORPTIONHF, - EAXREVERB_MAXAIRABSORPTIONHF); -} - -void EaxReverbEffect::validate_hf_reference( - float flHFReference) -{ - eax_validate_range( - "HF Reference", - flHFReference, - EAXREVERB_MINHFREFERENCE, - EAXREVERB_MAXHFREFERENCE); -} - -void EaxReverbEffect::validate_lf_reference( - float flLFReference) -{ - eax_validate_range( - "LF Reference", - flLFReference, - EAXREVERB_MINLFREFERENCE, - EAXREVERB_MAXLFREFERENCE); -} - -void EaxReverbEffect::validate_room_rolloff_factor( - float flRoomRolloffFactor) -{ - eax_validate_range( - "Room Rolloff Factor", - flRoomRolloffFactor, - EAXREVERB_MINROOMROLLOFFFACTOR, - EAXREVERB_MAXROOMROLLOFFFACTOR); -} - -void EaxReverbEffect::validate_flags( - unsigned long ulFlags) -{ - eax_validate_range( - "Flags", - ulFlags, - 0UL, - ~EAXREVERBFLAGS_RESERVED); -} - -void EaxReverbEffect::validate_all( - const EAX20LISTENERPROPERTIES& listener, - int version) -{ - validate_room(listener.lRoom); - validate_room_hf(listener.lRoomHF); - validate_room_rolloff_factor(listener.flRoomRolloffFactor); - validate_decay_time(listener.flDecayTime); - validate_decay_hf_ratio(listener.flDecayHFRatio); - validate_reflections(listener.lReflections); - validate_reflections_delay(listener.flReflectionsDelay); - validate_reverb(listener.lReverb); - validate_reverb_delay(listener.flReverbDelay); - validate_environment(listener.dwEnvironment, version, false); - validate_environment_size(listener.flEnvironmentSize); - validate_environment_diffusion(listener.flEnvironmentDiffusion); - validate_air_absorbtion_hf(listener.flAirAbsorptionHF); - validate_flags(listener.dwFlags); -} - -void EaxReverbEffect::validate_all( - const EAXREVERBPROPERTIES& lReverb, - int version) -{ - validate_environment(lReverb.ulEnvironment, version, false); - validate_environment_size(lReverb.flEnvironmentSize); - validate_environment_diffusion(lReverb.flEnvironmentDiffusion); - validate_room(lReverb.lRoom); - validate_room_hf(lReverb.lRoomHF); - validate_room_lf(lReverb.lRoomLF); - validate_decay_time(lReverb.flDecayTime); - validate_decay_hf_ratio(lReverb.flDecayHFRatio); - validate_decay_lf_ratio(lReverb.flDecayLFRatio); - validate_reflections(lReverb.lReflections); - validate_reflections_delay(lReverb.flReflectionsDelay); - validate_reverb(lReverb.lReverb); - validate_reverb_delay(lReverb.flReverbDelay); - validate_echo_time(lReverb.flEchoTime); - validate_echo_depth(lReverb.flEchoDepth); - validate_modulation_time(lReverb.flModulationTime); - validate_modulation_depth(lReverb.flModulationDepth); - validate_air_absorbtion_hf(lReverb.flAirAbsorptionHF); - validate_hf_reference(lReverb.flHFReference); - validate_lf_reference(lReverb.flLFReference); - validate_room_rolloff_factor(lReverb.flRoomRolloffFactor); - validate_flags(lReverb.ulFlags); -} - -void EaxReverbEffect::v1_defer_environment(unsigned long environment) -{ - eax1_d_ = EAX1REVERB_PRESETS[environment]; - eax1_dirty_flags_.ulEnvironment = true; -} - -void EaxReverbEffect::v1_defer_volume(float volume) -{ - eax1_d_.fVolume = volume; - eax1_dirty_flags_.flVolume = (eax1_.fVolume != eax1_d_.fVolume); -} - -void EaxReverbEffect::v1_defer_decay_time(float decay_time) -{ - eax1_d_.fDecayTime_sec = decay_time; - eax1_dirty_flags_.flDecayTime = (eax1_.fDecayTime_sec != eax1_d_.fDecayTime_sec); -} - -void EaxReverbEffect::v1_defer_damping(float damping) -{ - eax1_d_.fDamping = damping; - eax1_dirty_flags_.flDamping = (eax1_.fDamping != eax1_d_.fDamping); -} - -void EaxReverbEffect::v1_defer_all(const EAX_REVERBPROPERTIES& lReverb) -{ - v1_defer_environment(lReverb.environment); - v1_defer_volume(lReverb.fVolume); - v1_defer_decay_time(lReverb.fDecayTime_sec); - v1_defer_damping(lReverb.fDamping); -} - - -void EaxReverbEffect::v1_set_efx() -{ - auto efx_props = eax_efx_reverb_presets[eax1_.environment]; - efx_props.flGain = eax1_.fVolume; - efx_props.flDecayTime = eax1_.fDecayTime_sec; - efx_props.flDecayHFRatio = clamp(eax1_.fDamping, AL_EAXREVERB_MIN_DECAY_HFRATIO, AL_EAXREVERB_MAX_DECAY_HFRATIO); - - al_effect_props_.Reverb.Density = efx_props.flDensity; - al_effect_props_.Reverb.Diffusion = efx_props.flDiffusion; - al_effect_props_.Reverb.Gain = efx_props.flGain; - al_effect_props_.Reverb.GainHF = efx_props.flGainHF; - al_effect_props_.Reverb.GainLF = efx_props.flGainLF; - al_effect_props_.Reverb.DecayTime = efx_props.flDecayTime; - al_effect_props_.Reverb.DecayHFRatio = efx_props.flDecayHFRatio; - al_effect_props_.Reverb.DecayLFRatio = efx_props.flDecayLFRatio; - al_effect_props_.Reverb.ReflectionsGain = efx_props.flReflectionsGain; - al_effect_props_.Reverb.ReflectionsDelay = efx_props.flReflectionsDelay; - al_effect_props_.Reverb.ReflectionsPan[0] = efx_props.flReflectionsPan[0]; - al_effect_props_.Reverb.ReflectionsPan[1] = efx_props.flReflectionsPan[1]; - al_effect_props_.Reverb.ReflectionsPan[2] = efx_props.flReflectionsPan[2]; - al_effect_props_.Reverb.LateReverbGain = efx_props.flLateReverbGain; - al_effect_props_.Reverb.LateReverbDelay = efx_props.flLateReverbDelay; - al_effect_props_.Reverb.LateReverbPan[0] = efx_props.flLateReverbPan[0]; - al_effect_props_.Reverb.LateReverbPan[1] = efx_props.flLateReverbPan[1]; - al_effect_props_.Reverb.LateReverbPan[2] = efx_props.flLateReverbPan[2]; - al_effect_props_.Reverb.EchoTime = efx_props.flEchoTime; - al_effect_props_.Reverb.EchoDepth = efx_props.flEchoDepth; - al_effect_props_.Reverb.ModulationTime = efx_props.flModulationTime; - al_effect_props_.Reverb.ModulationDepth = efx_props.flModulationDepth; - al_effect_props_.Reverb.HFReference = efx_props.flHFReference; - al_effect_props_.Reverb.LFReference = efx_props.flLFReference; - al_effect_props_.Reverb.RoomRolloffFactor = efx_props.flRoomRolloffFactor; - al_effect_props_.Reverb.AirAbsorptionGainHF = efx_props.flAirAbsorptionGainHF; - al_effect_props_.Reverb.DecayHFLimit = false; -} - -void EaxReverbEffect::defer_environment( - unsigned long ulEnvironment) -{ - eax_d_.ulEnvironment = ulEnvironment; - eax_dirty_flags_.ulEnvironment = (eax_.ulEnvironment != eax_d_.ulEnvironment); -} - -void EaxReverbEffect::defer_environment_size( - float flEnvironmentSize) -{ - eax_d_.flEnvironmentSize = flEnvironmentSize; - eax_dirty_flags_.flEnvironmentSize = (eax_.flEnvironmentSize != eax_d_.flEnvironmentSize); -} - -void EaxReverbEffect::defer_environment_diffusion( - float flEnvironmentDiffusion) -{ - eax_d_.flEnvironmentDiffusion = flEnvironmentDiffusion; - eax_dirty_flags_.flEnvironmentDiffusion = (eax_.flEnvironmentDiffusion != eax_d_.flEnvironmentDiffusion); -} - -void EaxReverbEffect::defer_room( - long lRoom) -{ - eax_d_.lRoom = lRoom; - eax_dirty_flags_.lRoom = (eax_.lRoom != eax_d_.lRoom); -} - -void EaxReverbEffect::defer_room_hf( - long lRoomHF) -{ - eax_d_.lRoomHF = lRoomHF; - eax_dirty_flags_.lRoomHF = (eax_.lRoomHF != eax_d_.lRoomHF); -} - -void EaxReverbEffect::defer_room_lf( - long lRoomLF) -{ - eax_d_.lRoomLF = lRoomLF; - eax_dirty_flags_.lRoomLF = (eax_.lRoomLF != eax_d_.lRoomLF); -} - -void EaxReverbEffect::defer_decay_time( - float flDecayTime) -{ - eax_d_.flDecayTime = flDecayTime; - eax_dirty_flags_.flDecayTime = (eax_.flDecayTime != eax_d_.flDecayTime); -} - -void EaxReverbEffect::defer_decay_hf_ratio( - float flDecayHFRatio) -{ - eax_d_.flDecayHFRatio = flDecayHFRatio; - eax_dirty_flags_.flDecayHFRatio = (eax_.flDecayHFRatio != eax_d_.flDecayHFRatio); -} - -void EaxReverbEffect::defer_decay_lf_ratio( - float flDecayLFRatio) -{ - eax_d_.flDecayLFRatio = flDecayLFRatio; - eax_dirty_flags_.flDecayLFRatio = (eax_.flDecayLFRatio != eax_d_.flDecayLFRatio); -} - -void EaxReverbEffect::defer_reflections( - long lReflections) -{ - eax_d_.lReflections = lReflections; - eax_dirty_flags_.lReflections = (eax_.lReflections != eax_d_.lReflections); -} - -void EaxReverbEffect::defer_reflections_delay( - float flReflectionsDelay) -{ - eax_d_.flReflectionsDelay = flReflectionsDelay; - eax_dirty_flags_.flReflectionsDelay = (eax_.flReflectionsDelay != eax_d_.flReflectionsDelay); -} - -void EaxReverbEffect::defer_reflections_pan( - const EAXVECTOR& vReflectionsPan) -{ - eax_d_.vReflectionsPan = vReflectionsPan; - eax_dirty_flags_.vReflectionsPan = (eax_.vReflectionsPan != eax_d_.vReflectionsPan); -} - -void EaxReverbEffect::defer_reverb( - long lReverb) -{ - eax_d_.lReverb = lReverb; - eax_dirty_flags_.lReverb = (eax_.lReverb != eax_d_.lReverb); -} - -void EaxReverbEffect::defer_reverb_delay( - float flReverbDelay) -{ - eax_d_.flReverbDelay = flReverbDelay; - eax_dirty_flags_.flReverbDelay = (eax_.flReverbDelay != eax_d_.flReverbDelay); -} - -void EaxReverbEffect::defer_reverb_pan( - const EAXVECTOR& vReverbPan) -{ - eax_d_.vReverbPan = vReverbPan; - eax_dirty_flags_.vReverbPan = (eax_.vReverbPan != eax_d_.vReverbPan); -} - -void EaxReverbEffect::defer_echo_time( - float flEchoTime) -{ - eax_d_.flEchoTime = flEchoTime; - eax_dirty_flags_.flEchoTime = (eax_.flEchoTime != eax_d_.flEchoTime); -} - -void EaxReverbEffect::defer_echo_depth( - float flEchoDepth) -{ - eax_d_.flEchoDepth = flEchoDepth; - eax_dirty_flags_.flEchoDepth = (eax_.flEchoDepth != eax_d_.flEchoDepth); -} - -void EaxReverbEffect::defer_modulation_time( - float flModulationTime) -{ - eax_d_.flModulationTime = flModulationTime; - eax_dirty_flags_.flModulationTime = (eax_.flModulationTime != eax_d_.flModulationTime); -} - -void EaxReverbEffect::defer_modulation_depth( - float flModulationDepth) -{ - eax_d_.flModulationDepth = flModulationDepth; - eax_dirty_flags_.flModulationDepth = (eax_.flModulationDepth != eax_d_.flModulationDepth); -} - -void EaxReverbEffect::defer_air_absorbtion_hf( - float flAirAbsorptionHF) -{ - eax_d_.flAirAbsorptionHF = flAirAbsorptionHF; - eax_dirty_flags_.flAirAbsorptionHF = (eax_.flAirAbsorptionHF != eax_d_.flAirAbsorptionHF); -} - -void EaxReverbEffect::defer_hf_reference( - float flHFReference) -{ - eax_d_.flHFReference = flHFReference; - eax_dirty_flags_.flHFReference = (eax_.flHFReference != eax_d_.flHFReference); -} - -void EaxReverbEffect::defer_lf_reference( - float flLFReference) -{ - eax_d_.flLFReference = flLFReference; - eax_dirty_flags_.flLFReference = (eax_.flLFReference != eax_d_.flLFReference); -} + struct EnvironmentValidator1 { + void operator()(unsigned long ulEnvironment) const + { + eax_validate_range( + "Environment", + ulEnvironment, + EAXREVERB_MINENVIRONMENT, + EAX1REVERB_MAXENVIRONMENT); + } + }; // EnvironmentValidator1 -void EaxReverbEffect::defer_room_rolloff_factor( - float flRoomRolloffFactor) -{ - eax_d_.flRoomRolloffFactor = flRoomRolloffFactor; - eax_dirty_flags_.flRoomRolloffFactor = (eax_.flRoomRolloffFactor != eax_d_.flRoomRolloffFactor); -} + struct VolumeValidator { + void operator()(float volume) const + { + eax_validate_range( + "Volume", + volume, + EAX1REVERB_MINVOLUME, + EAX1REVERB_MAXVOLUME); + } + }; // VolumeValidator -void EaxReverbEffect::defer_flags( - unsigned long ulFlags) -{ - eax_d_.ulFlags = ulFlags; - eax_dirty_flags_.ulFlags = (eax_.ulFlags != eax_d_.ulFlags); -} + struct DecayTimeValidator { + void operator()(float flDecayTime) const + { + eax_validate_range( + "Decay Time", + flDecayTime, + EAXREVERB_MINDECAYTIME, + EAXREVERB_MAXDECAYTIME); + } + }; // DecayTimeValidator -void EaxReverbEffect::defer_all( - const EAX20LISTENERPROPERTIES& listener) -{ - defer_room(listener.lRoom); - defer_room_hf(listener.lRoomHF); - defer_room_rolloff_factor(listener.flRoomRolloffFactor); - defer_decay_time(listener.flDecayTime); - defer_decay_hf_ratio(listener.flDecayHFRatio); - defer_reflections(listener.lReflections); - defer_reflections_delay(listener.flReflectionsDelay); - defer_reverb(listener.lReverb); - defer_reverb_delay(listener.flReverbDelay); - defer_environment(listener.dwEnvironment); - defer_environment_size(listener.flEnvironmentSize); - defer_environment_diffusion(listener.flEnvironmentDiffusion); - defer_air_absorbtion_hf(listener.flAirAbsorptionHF); - defer_flags(listener.dwFlags); -} + struct DampingValidator { + void operator()(float damping) const + { + eax_validate_range( + "Damping", + damping, + EAX1REVERB_MINDAMPING, + EAX1REVERB_MAXDAMPING); + } + }; // DampingValidator -void EaxReverbEffect::defer_all( - const EAXREVERBPROPERTIES& lReverb) -{ - defer_environment(lReverb.ulEnvironment); - defer_environment_size(lReverb.flEnvironmentSize); - defer_environment_diffusion(lReverb.flEnvironmentDiffusion); - defer_room(lReverb.lRoom); - defer_room_hf(lReverb.lRoomHF); - defer_room_lf(lReverb.lRoomLF); - defer_decay_time(lReverb.flDecayTime); - defer_decay_hf_ratio(lReverb.flDecayHFRatio); - defer_decay_lf_ratio(lReverb.flDecayLFRatio); - defer_reflections(lReverb.lReflections); - defer_reflections_delay(lReverb.flReflectionsDelay); - defer_reflections_pan(lReverb.vReflectionsPan); - defer_reverb(lReverb.lReverb); - defer_reverb_delay(lReverb.flReverbDelay); - defer_reverb_pan(lReverb.vReverbPan); - defer_echo_time(lReverb.flEchoTime); - defer_echo_depth(lReverb.flEchoDepth); - defer_modulation_time(lReverb.flModulationTime); - defer_modulation_depth(lReverb.flModulationDepth); - defer_air_absorbtion_hf(lReverb.flAirAbsorptionHF); - defer_hf_reference(lReverb.flHFReference); - defer_lf_reference(lReverb.flLFReference); - defer_room_rolloff_factor(lReverb.flRoomRolloffFactor); - defer_flags(lReverb.ulFlags); -} + struct AllValidator1 { + void operator()(const Props1& all) const + { + EnvironmentValidator1{}(all.environment); + VolumeValidator{}(all.fVolume); + DecayTimeValidator{}(all.fDecayTime_sec); + DampingValidator{}(all.fDamping); + } + }; // AllValidator1 + struct RoomValidator { + void operator()(long lRoom) const + { + eax_validate_range( + "Room", + lRoom, + EAXREVERB_MINROOM, + EAXREVERB_MAXROOM); + } + }; // RoomValidator -void EaxReverbEffect::v1_defer_environment(const EaxEaxCall& eax_call) -{ - const auto& environment = eax_call.get_value(); + struct RoomHFValidator { + void operator()(long lRoomHF) const + { + eax_validate_range( + "Room HF", + lRoomHF, + EAXREVERB_MINROOMHF, + EAXREVERB_MAXROOMHF); + } + }; // RoomHFValidator - validate_environment(environment, 1, true); + struct RoomRolloffFactorValidator { + void operator()(float flRoomRolloffFactor) const + { + eax_validate_range( + "Room Rolloff Factor", + flRoomRolloffFactor, + EAXREVERB_MINROOMROLLOFFFACTOR, + EAXREVERB_MAXROOMROLLOFFFACTOR); + } + }; // RoomRolloffFactorValidator - const auto& reverb_preset = EAX1REVERB_PRESETS[environment]; - v1_defer_all(reverb_preset); -} + struct DecayHFRatioValidator { + void operator()(float flDecayHFRatio) const + { + eax_validate_range( + "Decay HF Ratio", + flDecayHFRatio, + EAXREVERB_MINDECAYHFRATIO, + EAXREVERB_MAXDECAYHFRATIO); + } + }; // DecayHFRatioValidator -void EaxReverbEffect::v1_defer_volume(const EaxEaxCall& eax_call) -{ - const auto& volume = eax_call.get_value(); + struct ReflectionsValidator { + void operator()(long lReflections) const + { + eax_validate_range( + "Reflections", + lReflections, + EAXREVERB_MINREFLECTIONS, + EAXREVERB_MAXREFLECTIONS); + } + }; // ReflectionsValidator - v1_validate_volume(volume); - v1_defer_volume(volume); -} + struct ReflectionsDelayValidator { + void operator()(float flReflectionsDelay) const + { + eax_validate_range( + "Reflections Delay", + flReflectionsDelay, + EAXREVERB_MINREFLECTIONSDELAY, + EAXREVERB_MAXREFLECTIONSDELAY); + } + }; // ReflectionsDelayValidator -void EaxReverbEffect::v1_defer_decay_time(const EaxEaxCall& eax_call) -{ - const auto& decay_time = eax_call.get_value(); + struct ReverbValidator { + void operator()(long lReverb) const + { + eax_validate_range( + "Reverb", + lReverb, + EAXREVERB_MINREVERB, + EAXREVERB_MAXREVERB); + } + }; // ReverbValidator - v1_validate_decay_time(decay_time); - v1_defer_decay_time(decay_time); -} + struct ReverbDelayValidator { + void operator()(float flReverbDelay) const + { + eax_validate_range( + "Reverb Delay", + flReverbDelay, + EAXREVERB_MINREVERBDELAY, + EAXREVERB_MAXREVERBDELAY); + } + }; // ReverbDelayValidator -void EaxReverbEffect::v1_defer_damping(const EaxEaxCall& eax_call) -{ - const auto& damping = eax_call.get_value(); + struct EnvironmentSizeValidator { + void operator()(float flEnvironmentSize) const + { + eax_validate_range( + "Environment Size", + flEnvironmentSize, + EAXREVERB_MINENVIRONMENTSIZE, + EAXREVERB_MAXENVIRONMENTSIZE); + } + }; // EnvironmentSizeValidator - v1_validate_damping(damping); - v1_defer_damping(damping); -} + struct EnvironmentDiffusionValidator { + void operator()(float flEnvironmentDiffusion) const + { + eax_validate_range( + "Environment Diffusion", + flEnvironmentDiffusion, + EAXREVERB_MINENVIRONMENTDIFFUSION, + EAXREVERB_MAXENVIRONMENTDIFFUSION); + } + }; // EnvironmentDiffusionValidator -void EaxReverbEffect::v1_defer_all(const EaxEaxCall& eax_call) -{ - const auto& reverb_all = eax_call.get_value(); + struct AirAbsorptionHFValidator { + void operator()(float flAirAbsorptionHF) const + { + eax_validate_range( + "Air Absorbtion HF", + flAirAbsorptionHF, + EAXREVERB_MINAIRABSORPTIONHF, + EAXREVERB_MAXAIRABSORPTIONHF); + } + }; // AirAbsorptionHFValidator - v1_validate_all(reverb_all); - v1_defer_all(reverb_all); -} + struct FlagsValidator2 { + void operator()(unsigned long ulFlags) const + { + eax_validate_range( + "Flags", + ulFlags, + 0UL, + ~EAX2LISTENERFLAGS_RESERVED); + } + }; // FlagsValidator2 + struct AllValidator2 { + void operator()(const Props2& all) const + { + RoomValidator{}(all.lRoom); + RoomHFValidator{}(all.lRoomHF); + RoomRolloffFactorValidator{}(all.flRoomRolloffFactor); + DecayTimeValidator{}(all.flDecayTime); + DecayHFRatioValidator{}(all.flDecayHFRatio); + ReflectionsValidator{}(all.lReflections); + ReflectionsDelayValidator{}(all.flReflectionsDelay); + ReverbValidator{}(all.lReverb); + ReverbDelayValidator{}(all.flReverbDelay); + EnvironmentValidator1{}(all.dwEnvironment); + EnvironmentSizeValidator{}(all.flEnvironmentSize); + EnvironmentDiffusionValidator{}(all.flEnvironmentDiffusion); + AirAbsorptionHFValidator{}(all.flAirAbsorptionHF); + FlagsValidator2{}(all.dwFlags); + } + }; // AllValidator2 -void EaxReverbEffect::defer_environment( - const EaxEaxCall& eax_call) -{ - const auto& ulEnvironment = - eax_call.get_value(); + struct EnvironmentValidator3 { + void operator()(unsigned long ulEnvironment) const + { + eax_validate_range( + "Environment", + ulEnvironment, + EAXREVERB_MINENVIRONMENT, + EAX30REVERB_MAXENVIRONMENT); + } + }; // EnvironmentValidator1 - validate_environment(ulEnvironment, eax_call.get_version(), true); + struct RoomLFValidator { + void operator()(long lRoomLF) const + { + eax_validate_range( + "Room LF", + lRoomLF, + EAXREVERB_MINROOMLF, + EAXREVERB_MAXROOMLF); + } + }; // RoomLFValidator - if (eax_d_.ulEnvironment == ulEnvironment) - { - return; - } + struct DecayLFRatioValidator { + void operator()(float flDecayLFRatio) const + { + eax_validate_range( + "Decay LF Ratio", + flDecayLFRatio, + EAXREVERB_MINDECAYLFRATIO, + EAXREVERB_MAXDECAYLFRATIO); + } + }; // DecayLFRatioValidator - const auto& reverb_preset = EAXREVERB_PRESETS[ulEnvironment]; + struct VectorValidator { + void operator()(const EAXVECTOR&) const + {} + }; // VectorValidator - defer_all(reverb_preset); -} + struct EchoTimeValidator { + void operator()(float flEchoTime) const + { + eax_validate_range( + "Echo Time", + flEchoTime, + EAXREVERB_MINECHOTIME, + EAXREVERB_MAXECHOTIME); + } + }; // EchoTimeValidator -void EaxReverbEffect::defer_environment_size( - const EaxEaxCall& eax_call) -{ - const auto& flEnvironmentSize = - eax_call.get_value(); + struct EchoDepthValidator { + void operator()(float flEchoDepth) const + { + eax_validate_range( + "Echo Depth", + flEchoDepth, + EAXREVERB_MINECHODEPTH, + EAXREVERB_MAXECHODEPTH); + } + }; // EchoDepthValidator - validate_environment_size(flEnvironmentSize); + struct ModulationTimeValidator { + void operator()(float flModulationTime) const + { + eax_validate_range( + "Modulation Time", + flModulationTime, + EAXREVERB_MINMODULATIONTIME, + EAXREVERB_MAXMODULATIONTIME); + } + }; // ModulationTimeValidator - if (eax_d_.flEnvironmentSize == flEnvironmentSize) - { - return; - } + struct ModulationDepthValidator { + void operator()(float flModulationDepth) const + { + eax_validate_range( + "Modulation Depth", + flModulationDepth, + EAXREVERB_MINMODULATIONDEPTH, + EAXREVERB_MAXMODULATIONDEPTH); + } + }; // ModulationDepthValidator - const auto scale = flEnvironmentSize / eax_d_.flEnvironmentSize; + struct HFReferenceValidator { + void operator()(float flHFReference) const + { + eax_validate_range( + "HF Reference", + flHFReference, + EAXREVERB_MINHFREFERENCE, + EAXREVERB_MAXHFREFERENCE); + } + }; // HFReferenceValidator - defer_environment_size(flEnvironmentSize); + struct LFReferenceValidator { + void operator()(float flLFReference) const + { + eax_validate_range( + "LF Reference", + flLFReference, + EAXREVERB_MINLFREFERENCE, + EAXREVERB_MAXLFREFERENCE); + } + }; // LFReferenceValidator - if ((eax_d_.ulFlags & EAXREVERBFLAGS_DECAYTIMESCALE) != 0) - { - const auto flDecayTime = clamp( - scale * eax_d_.flDecayTime, - EAXREVERB_MINDECAYTIME, - EAXREVERB_MAXDECAYTIME); + struct FlagsValidator3 { + void operator()(unsigned long ulFlags) const + { + eax_validate_range( + "Flags", + ulFlags, + 0UL, + ~EAXREVERBFLAGS_RESERVED); + } + }; // FlagsValidator3 - defer_decay_time(flDecayTime); - } + struct AllValidator3 { + void operator()(const Props3& all) const + { + EnvironmentValidator3{}(all.ulEnvironment); + EnvironmentSizeValidator{}(all.flEnvironmentSize); + EnvironmentDiffusionValidator{}(all.flEnvironmentDiffusion); + RoomValidator{}(all.lRoom); + RoomHFValidator{}(all.lRoomHF); + RoomLFValidator{}(all.lRoomLF); + DecayTimeValidator{}(all.flDecayTime); + DecayHFRatioValidator{}(all.flDecayHFRatio); + DecayLFRatioValidator{}(all.flDecayLFRatio); + ReflectionsValidator{}(all.lReflections); + ReflectionsDelayValidator{}(all.flReflectionsDelay); + VectorValidator{}(all.vReflectionsPan); + ReverbValidator{}(all.lReverb); + ReverbDelayValidator{}(all.flReverbDelay); + VectorValidator{}(all.vReverbPan); + EchoTimeValidator{}(all.flEchoTime); + EchoDepthValidator{}(all.flEchoDepth); + ModulationTimeValidator{}(all.flModulationTime); + ModulationDepthValidator{}(all.flModulationDepth); + AirAbsorptionHFValidator{}(all.flAirAbsorptionHF); + HFReferenceValidator{}(all.flHFReference); + LFReferenceValidator{}(all.flLFReference); + RoomRolloffFactorValidator{}(all.flRoomRolloffFactor); + FlagsValidator3{}(all.ulFlags); + } + }; // AllValidator3 - if ((eax_d_.ulFlags & EAXREVERBFLAGS_REFLECTIONSSCALE) != 0) - { - if ((eax_d_.ulFlags & EAXREVERBFLAGS_REFLECTIONSDELAYSCALE) != 0) + struct EnvironmentDeferrer2 { + void operator()(Props2& props, unsigned long dwEnvironment) const { - const auto lReflections = clamp( - eax_d_.lReflections - static_cast(gain_to_level_mb(scale)), - EAXREVERB_MINREFLECTIONS, - EAXREVERB_MAXREFLECTIONS); + props = EAX2REVERB_PRESETS[dwEnvironment]; + } + }; // EnvironmentDeferrer2 - defer_reflections(lReflections); + struct EnvironmentSizeDeferrer2 { + void operator()(Props2& props, float flEnvironmentSize) const + { + if (props.flEnvironmentSize == flEnvironmentSize) + { + return; + } + + const auto scale = flEnvironmentSize / props.flEnvironmentSize; + props.flEnvironmentSize = flEnvironmentSize; + + if ((props.dwFlags & EAX2LISTENERFLAGS_DECAYTIMESCALE) != 0) + { + props.flDecayTime = clamp( + props.flDecayTime * scale, + EAXREVERB_MINDECAYTIME, + EAXREVERB_MAXDECAYTIME); + } + + if ((props.dwFlags & EAX2LISTENERFLAGS_REFLECTIONSSCALE) != 0 && + (props.dwFlags & EAX2LISTENERFLAGS_REFLECTIONSDELAYSCALE) != 0) + { + props.lReflections = clamp( + props.lReflections - static_cast(gain_to_level_mb(scale)), + EAXREVERB_MINREFLECTIONS, + EAXREVERB_MAXREFLECTIONS); + } + + if ((props.dwFlags & EAX2LISTENERFLAGS_REFLECTIONSDELAYSCALE) != 0) + { + props.flReflectionsDelay = clamp( + props.flReflectionsDelay * scale, + EAXREVERB_MINREFLECTIONSDELAY, + EAXREVERB_MAXREFLECTIONSDELAY); + } + + if ((props.dwFlags & EAX2LISTENERFLAGS_REVERBSCALE) != 0) + { + const auto log_scalar = ((props.dwFlags & EAXREVERBFLAGS_DECAYTIMESCALE) != 0) ? 2'000.0F : 3'000.0F; + + props.lReverb = clamp( + props.lReverb - static_cast(std::log10(scale) * log_scalar), + EAXREVERB_MINREVERB, + EAXREVERB_MAXREVERB); + } + + if ((props.dwFlags & EAX2LISTENERFLAGS_REVERBDELAYSCALE) != 0) + { + props.flReverbDelay = clamp( + props.flReverbDelay * scale, + EAXREVERB_MINREVERBDELAY, + EAXREVERB_MAXREVERBDELAY); + } } - } + }; // EnvironmentSizeDeferrer2 - if ((eax_d_.ulFlags & EAXREVERBFLAGS_REFLECTIONSDELAYSCALE) != 0) - { - const auto flReflectionsDelay = clamp( - eax_d_.flReflectionsDelay * scale, - EAXREVERB_MINREFLECTIONSDELAY, - EAXREVERB_MAXREFLECTIONSDELAY); + struct EnvironmentDeferrer3 { + void operator()(Props3& props, unsigned long ulEnvironment) const + { + if (ulEnvironment == EAX_ENVIRONMENT_UNDEFINED) + { + props.ulEnvironment = EAX_ENVIRONMENT_UNDEFINED; + return; + } - defer_reflections_delay(flReflectionsDelay); - } + props = EAXREVERB_PRESETS[ulEnvironment]; + } + }; // EnvironmentDeferrer3 - if ((eax_d_.ulFlags & EAXREVERBFLAGS_REVERBSCALE) != 0) + struct EnvironmentSizeDeferrer3 { + void operator()(Props3& props, float flEnvironmentSize) const + { + if (props.flEnvironmentSize == flEnvironmentSize) + { + return; + } + + const auto scale = flEnvironmentSize / props.flEnvironmentSize; + props.ulEnvironment = EAX_ENVIRONMENT_UNDEFINED; + props.flEnvironmentSize = flEnvironmentSize; + + if ((props.ulFlags & EAXREVERBFLAGS_DECAYTIMESCALE) != 0) + { + props.flDecayTime = clamp( + props.flDecayTime * scale, + EAXREVERB_MINDECAYTIME, + EAXREVERB_MAXDECAYTIME); + } + + if ((props.ulFlags & EAXREVERBFLAGS_REFLECTIONSSCALE) != 0 && + (props.ulFlags & EAXREVERBFLAGS_REFLECTIONSDELAYSCALE) != 0) + { + props.lReflections = clamp( + props.lReflections - static_cast(gain_to_level_mb(scale)), + EAXREVERB_MINREFLECTIONS, + EAXREVERB_MAXREFLECTIONS); + } + + if ((props.ulFlags & EAXREVERBFLAGS_REFLECTIONSDELAYSCALE) != 0) + { + props.flReflectionsDelay = clamp( + props.flReflectionsDelay * scale, + EAXREVERB_MINREFLECTIONSDELAY, + EAXREVERB_MAXREFLECTIONSDELAY); + } + + if ((props.ulFlags & EAXREVERBFLAGS_REVERBSCALE) != 0) + { + const auto log_scalar = ((props.ulFlags & EAXREVERBFLAGS_DECAYTIMESCALE) != 0) ? 2'000.0F : 3'000.0F; + props.lReverb = clamp( + props.lReverb - static_cast(std::log10(scale) * log_scalar), + EAXREVERB_MINREVERB, + EAXREVERB_MAXREVERB); + } + + if ((props.ulFlags & EAXREVERBFLAGS_REVERBDELAYSCALE) != 0) + { + props.flReverbDelay = clamp( + props.flReverbDelay * scale, + EAXREVERB_MINREVERBDELAY, + EAXREVERB_MAXREVERBDELAY); + } + + if ((props.ulFlags & EAXREVERBFLAGS_ECHOTIMESCALE) != 0) + { + props.flEchoTime = clamp( + props.flEchoTime * scale, + EAXREVERB_MINECHOTIME, + EAXREVERB_MAXECHOTIME); + } + + if ((props.ulFlags & EAXREVERBFLAGS_MODULATIONTIMESCALE) != 0) + { + props.flModulationTime = clamp( + props.flModulationTime * scale, + EAXREVERB_MINMODULATIONTIME, + EAXREVERB_MAXMODULATIONTIME); + } + } + }; // EnvironmentSizeDeferrer3 + + int version_; + bool changed_{}; + Props3 props_{}; + State1 state1_{}; + State2 state2_{}; + State3 state3_{}; + State3 state4_{}; + State3 state5_{}; + + [[noreturn]] static void fail(const char* message); + [[noreturn]] static void fail_unknown_property_id(); + [[noreturn]] static void fail_unknown_version(); + + static void set_defaults(State1& state) noexcept; + static void set_defaults(State2& state) noexcept; + static void set_defaults(State3& state) noexcept; + void set_defaults() noexcept; + + void set_current_defaults(); + + void set_efx_density_from_environment_size() noexcept; + void set_efx_diffusion() noexcept; + void set_efx_gain() noexcept; + void set_efx_gain_hf() noexcept; + void set_efx_gain_lf() noexcept; + void set_efx_decay_time() noexcept; + void set_efx_decay_hf_ratio() noexcept; + void set_efx_decay_lf_ratio() noexcept; + void set_efx_reflections_gain() noexcept; + void set_efx_reflections_delay() noexcept; + void set_efx_reflections_pan() noexcept; + void set_efx_late_reverb_gain() noexcept; + void set_efx_late_reverb_delay() noexcept; + void set_efx_late_reverb_pan() noexcept; + void set_efx_echo_time() noexcept; + void set_efx_echo_depth() noexcept; + void set_efx_modulation_time() noexcept; + void set_efx_modulation_depth() noexcept; + void set_efx_air_absorption_gain_hf() noexcept; + void set_efx_hf_reference() noexcept; + void set_efx_lf_reference() noexcept; + void set_efx_room_rolloff_factor() noexcept; + void set_efx_flags() noexcept; + void set_efx_defaults() noexcept; + + static void get1(const EaxCall& call, const Props1& props); + static void get2(const EaxCall& call, const Props2& props); + static void get3(const EaxCall& call, const Props3& props); + void get(const EaxCall& call); + + template + static void defer(const EaxCall& call, TProperty& property) { - const auto log_scalar = ((eax_d_.ulFlags & EAXREVERBFLAGS_DECAYTIMESCALE) != 0) ? 2'000.0F : 3'000.0F; - - const auto lReverb = clamp( - eax_d_.lReverb - static_cast(std::log10(scale) * log_scalar), - EAXREVERB_MINREVERB, - EAXREVERB_MAXREVERB); - - defer_reverb(lReverb); + const auto& value = call.get_value(); + TValidator{}(value); + property = value; } - if ((eax_d_.ulFlags & EAXREVERBFLAGS_REVERBDELAYSCALE) != 0) + template + static void defer(const EaxCall& call, TProperties& properties, TProperty&) { - const auto flReverbDelay = clamp( - scale * eax_d_.flReverbDelay, - EAXREVERB_MINREVERBDELAY, - EAXREVERB_MAXREVERBDELAY); - - defer_reverb_delay(flReverbDelay); + const auto& value = call.get_value(); + TValidator{}(value); + TDeferrer{}(properties, value); } - if ((eax_d_.ulFlags & EAXREVERBFLAGS_ECHOTIMESCALE) != 0) + template + static void defer3(const EaxCall& call, Props3& properties, TProperty& property) { - const auto flEchoTime = clamp( - eax_d_.flEchoTime * scale, - EAXREVERB_MINECHOTIME, - EAXREVERB_MAXECHOTIME); - - defer_echo_time(flEchoTime); + const auto& value = call.get_value(); + TValidator{}(value); + if (value == property) + return; + property = value; + properties.ulEnvironment = EAX_ENVIRONMENT_UNDEFINED; } - if ((eax_d_.ulFlags & EAXREVERBFLAGS_MODULATIONTIMESCALE) != 0) - { - const auto flModulationTime = clamp( - scale * eax_d_.flModulationTime, - EAXREVERB_MINMODULATIONTIME, - EAXREVERB_MAXMODULATIONTIME); + static void set1(const EaxCall& call, Props1& props); + static void set2(const EaxCall& call, Props2& props); + static void set3(const EaxCall& call, Props3& props); + void set(const EaxCall& call); - defer_modulation_time(flModulationTime); - } -} + static void translate(const Props1& src, Props3& dst) noexcept; + static void translate(const Props2& src, Props3& dst) noexcept; +}; // EaxReverbEffect -void EaxReverbEffect::defer_environment_diffusion( - const EaxEaxCall& eax_call) +EaxReverbEffect::EaxReverbEffect(const EaxCall& call) noexcept + : EaxEffect{AL_EFFECT_EAXREVERB}, version_{call.get_version()} { - const auto& flEnvironmentDiffusion = - eax_call.get_value(); - - validate_environment_diffusion(flEnvironmentDiffusion); - defer_environment_diffusion(flEnvironmentDiffusion); + set_defaults(); + set_current_defaults(); + set_efx_defaults(); } -void EaxReverbEffect::defer_room( - const EaxEaxCall& eax_call) +void EaxReverbEffect::dispatch(const EaxCall& call) { - const auto& lRoom = - eax_call.get_value(); - - validate_room(lRoom); - defer_room(lRoom); + call.is_get() ? get(call) : set(call); } -void EaxReverbEffect::defer_room_hf( - const EaxEaxCall& eax_call) +[[noreturn]] void EaxReverbEffect::fail(const char* message) { - const auto& lRoomHF = - eax_call.get_value(); - - validate_room_hf(lRoomHF); - defer_room_hf(lRoomHF); + throw Exception{message}; } -void EaxReverbEffect::defer_room_lf( - const EaxEaxCall& eax_call) +[[noreturn]] void EaxReverbEffect::fail_unknown_property_id() { - const auto& lRoomLF = - eax_call.get_value(); - - validate_room_lf(lRoomLF); - defer_room_lf(lRoomLF); + fail(EaxEffectErrorMessages::unknown_property_id()); } -void EaxReverbEffect::defer_decay_time( - const EaxEaxCall& eax_call) +[[noreturn]] void EaxReverbEffect::fail_unknown_version() { - const auto& flDecayTime = - eax_call.get_value(); - - validate_decay_time(flDecayTime); - defer_decay_time(flDecayTime); + fail(EaxEffectErrorMessages::unknown_version()); } -void EaxReverbEffect::defer_decay_hf_ratio( - const EaxEaxCall& eax_call) +void EaxReverbEffect::set_defaults(State1& state) noexcept { - const auto& flDecayHFRatio = - eax_call.get_value(); - - validate_decay_hf_ratio(flDecayHFRatio); - defer_decay_hf_ratio(flDecayHFRatio); + state.i = EAX1REVERB_PRESETS[EAX_ENVIRONMENT_GENERIC]; + state.d = state.i; } -void EaxReverbEffect::defer_decay_lf_ratio( - const EaxEaxCall& eax_call) +void EaxReverbEffect::set_defaults(State2& state) noexcept { - const auto& flDecayLFRatio = - eax_call.get_value(); - - validate_decay_lf_ratio(flDecayLFRatio); - defer_decay_lf_ratio(flDecayLFRatio); + state.i = EAX2REVERB_PRESETS[EAX2_ENVIRONMENT_GENERIC]; + state.i.lRoom = initial_room2; + state.d = state.i; } -void EaxReverbEffect::defer_reflections( - const EaxEaxCall& eax_call) +void EaxReverbEffect::set_defaults(State3& state) noexcept { - const auto& lReflections = - eax_call.get_value(); - - validate_reflections(lReflections); - defer_reflections(lReflections); + state.i = EAXREVERB_PRESETS[EAX_ENVIRONMENT_GENERIC]; + state.d = state.i; } -void EaxReverbEffect::defer_reflections_delay( - const EaxEaxCall& eax_call) +void EaxReverbEffect::set_defaults() noexcept { - const auto& flReflectionsDelay = - eax_call.get_value(); - - validate_reflections_delay(flReflectionsDelay); - defer_reflections_delay(flReflectionsDelay); + set_defaults(state1_); + set_defaults(state2_); + set_defaults(state3_); + state4_ = state3_; + state5_ = state3_; } -void EaxReverbEffect::defer_reflections_pan( - const EaxEaxCall& eax_call) +void EaxReverbEffect::set_current_defaults() { - const auto& vReflectionsPan = - eax_call.get_value(); - - validate_reflections_pan(vReflectionsPan); - defer_reflections_pan(vReflectionsPan); + switch (version_) + { + case 1: translate(state1_.i, props_); break; + case 2: translate(state2_.i, props_); break; + case 3: props_ = state3_.i; break; + case 4: props_ = state4_.i; break; + case 5: props_ = state5_.i; break; + default: fail_unknown_version(); + } } -void EaxReverbEffect::defer_reverb( - const EaxEaxCall& eax_call) +void EaxReverbEffect::set_efx_density_from_environment_size() noexcept { - const auto& lReverb = - eax_call.get_value(); - - validate_reverb(lReverb); - defer_reverb(lReverb); + const auto size = props_.flEnvironmentSize; + const auto density = (size * size * size) / 16.0F; + al_effect_props_.Reverb.Density = clamp( + density, + AL_EAXREVERB_MIN_DENSITY, + AL_EAXREVERB_MAX_DENSITY); } -void EaxReverbEffect::defer_reverb_delay( - const EaxEaxCall& eax_call) +void EaxReverbEffect::set_efx_diffusion() noexcept { - const auto& flReverbDelay = - eax_call.get_value(); + al_effect_props_.Reverb.Diffusion = clamp( + props_.flEnvironmentDiffusion, + AL_EAXREVERB_MIN_DIFFUSION, + AL_EAXREVERB_MAX_DIFFUSION); +} - validate_reverb_delay(flReverbDelay); - defer_reverb_delay(flReverbDelay); +void EaxReverbEffect::set_efx_gain() noexcept +{ + al_effect_props_.Reverb.Gain = clamp( + level_mb_to_gain(static_cast(props_.lRoom)), + AL_EAXREVERB_MIN_GAIN, + AL_EAXREVERB_MAX_GAIN); } -void EaxReverbEffect::defer_reverb_pan( - const EaxEaxCall& eax_call) +void EaxReverbEffect::set_efx_gain_hf() noexcept { - const auto& vReverbPan = - eax_call.get_value(); + al_effect_props_.Reverb.GainHF = clamp( + level_mb_to_gain(static_cast(props_.lRoomHF)), + AL_EAXREVERB_MIN_GAINHF, + AL_EAXREVERB_MAX_GAINHF); +} - validate_reverb_pan(vReverbPan); - defer_reverb_pan(vReverbPan); +void EaxReverbEffect::set_efx_gain_lf() noexcept +{ + al_effect_props_.Reverb.GainLF = clamp( + level_mb_to_gain(static_cast(props_.lRoomLF)), + AL_EAXREVERB_MIN_GAINLF, + AL_EAXREVERB_MAX_GAINLF); } -void EaxReverbEffect::defer_echo_time( - const EaxEaxCall& eax_call) +void EaxReverbEffect::set_efx_decay_time() noexcept { - const auto& flEchoTime = - eax_call.get_value(); + al_effect_props_.Reverb.DecayTime = clamp( + props_.flDecayTime, + AL_EAXREVERB_MIN_DECAY_TIME, + AL_EAXREVERB_MAX_DECAY_TIME); +} - validate_echo_time(flEchoTime); - defer_echo_time(flEchoTime); +void EaxReverbEffect::set_efx_decay_hf_ratio() noexcept +{ + al_effect_props_.Reverb.DecayHFRatio = clamp( + props_.flDecayHFRatio, + AL_EAXREVERB_MIN_DECAY_HFRATIO, + AL_EAXREVERB_MAX_DECAY_HFRATIO); } -void EaxReverbEffect::defer_echo_depth( - const EaxEaxCall& eax_call) +void EaxReverbEffect::set_efx_decay_lf_ratio() noexcept { - const auto& flEchoDepth = - eax_call.get_value(); + al_effect_props_.Reverb.DecayLFRatio = clamp( + props_.flDecayLFRatio, + AL_EAXREVERB_MIN_DECAY_LFRATIO, + AL_EAXREVERB_MAX_DECAY_LFRATIO); +} - validate_echo_depth(flEchoDepth); - defer_echo_depth(flEchoDepth); +void EaxReverbEffect::set_efx_reflections_gain() noexcept +{ + al_effect_props_.Reverb.ReflectionsGain = clamp( + level_mb_to_gain(static_cast(props_.lReflections)), + AL_EAXREVERB_MIN_REFLECTIONS_GAIN, + AL_EAXREVERB_MAX_REFLECTIONS_GAIN); } -void EaxReverbEffect::defer_modulation_time( - const EaxEaxCall& eax_call) +void EaxReverbEffect::set_efx_reflections_delay() noexcept { - const auto& flModulationTime = - eax_call.get_value(); + al_effect_props_.Reverb.ReflectionsDelay = clamp( + props_.flReflectionsDelay, + AL_EAXREVERB_MIN_REFLECTIONS_DELAY, + AL_EAXREVERB_MAX_REFLECTIONS_DELAY); +} - validate_modulation_time(flModulationTime); - defer_modulation_time(flModulationTime); +void EaxReverbEffect::set_efx_reflections_pan() noexcept +{ + al_effect_props_.Reverb.ReflectionsPan[0] = props_.vReflectionsPan.x; + al_effect_props_.Reverb.ReflectionsPan[1] = props_.vReflectionsPan.y; + al_effect_props_.Reverb.ReflectionsPan[2] = props_.vReflectionsPan.z; } -void EaxReverbEffect::defer_modulation_depth( - const EaxEaxCall& eax_call) +void EaxReverbEffect::set_efx_late_reverb_gain() noexcept { - const auto& flModulationDepth = - eax_call.get_value(); + al_effect_props_.Reverb.LateReverbGain = clamp( + level_mb_to_gain(static_cast(props_.lReverb)), + AL_EAXREVERB_MIN_LATE_REVERB_GAIN, + AL_EAXREVERB_MAX_LATE_REVERB_GAIN); +} - validate_modulation_depth(flModulationDepth); - defer_modulation_depth(flModulationDepth); +void EaxReverbEffect::set_efx_late_reverb_delay() noexcept +{ + al_effect_props_.Reverb.LateReverbDelay = clamp( + props_.flReverbDelay, + AL_EAXREVERB_MIN_LATE_REVERB_DELAY, + AL_EAXREVERB_MAX_LATE_REVERB_DELAY); } -void EaxReverbEffect::defer_air_absorbtion_hf( - const EaxEaxCall& eax_call) +void EaxReverbEffect::set_efx_late_reverb_pan() noexcept { - const auto& air_absorbtion_hf = - eax_call.get_value(); + al_effect_props_.Reverb.LateReverbPan[0] = props_.vReverbPan.x; + al_effect_props_.Reverb.LateReverbPan[1] = props_.vReverbPan.y; + al_effect_props_.Reverb.LateReverbPan[2] = props_.vReverbPan.z; +} - validate_air_absorbtion_hf(air_absorbtion_hf); - defer_air_absorbtion_hf(air_absorbtion_hf); +void EaxReverbEffect::set_efx_echo_time() noexcept +{ + al_effect_props_.Reverb.EchoTime = clamp( + props_.flEchoTime, + AL_EAXREVERB_MIN_ECHO_TIME, + AL_EAXREVERB_MAX_ECHO_TIME); } -void EaxReverbEffect::defer_hf_reference( - const EaxEaxCall& eax_call) +void EaxReverbEffect::set_efx_echo_depth() noexcept { - const auto& flHFReference = - eax_call.get_value(); + al_effect_props_.Reverb.EchoDepth = clamp( + props_.flEchoDepth, + AL_EAXREVERB_MIN_ECHO_DEPTH, + AL_EAXREVERB_MAX_ECHO_DEPTH); +} - validate_hf_reference(flHFReference); - defer_hf_reference(flHFReference); +void EaxReverbEffect::set_efx_modulation_time() noexcept +{ + al_effect_props_.Reverb.ModulationTime = clamp( + props_.flModulationTime, + AL_EAXREVERB_MIN_MODULATION_TIME, + AL_EAXREVERB_MAX_MODULATION_TIME); } -void EaxReverbEffect::defer_lf_reference( - const EaxEaxCall& eax_call) +void EaxReverbEffect::set_efx_modulation_depth() noexcept { - const auto& flLFReference = - eax_call.get_value(); + al_effect_props_.Reverb.ModulationDepth = clamp( + props_.flModulationDepth, + AL_EAXREVERB_MIN_MODULATION_DEPTH, + AL_EAXREVERB_MAX_MODULATION_DEPTH); +} - validate_lf_reference(flLFReference); - defer_lf_reference(flLFReference); +void EaxReverbEffect::set_efx_air_absorption_gain_hf() noexcept +{ + al_effect_props_.Reverb.AirAbsorptionGainHF = clamp( + level_mb_to_gain(props_.flAirAbsorptionHF), + AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF, + AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF); } -void EaxReverbEffect::defer_room_rolloff_factor( - const EaxEaxCall& eax_call) +void EaxReverbEffect::set_efx_hf_reference() noexcept { - const auto& flRoomRolloffFactor = - eax_call.get_value(); + al_effect_props_.Reverb.HFReference = clamp( + props_.flHFReference, + AL_EAXREVERB_MIN_HFREFERENCE, + AL_EAXREVERB_MAX_HFREFERENCE); +} - validate_room_rolloff_factor(flRoomRolloffFactor); - defer_room_rolloff_factor(flRoomRolloffFactor); +void EaxReverbEffect::set_efx_lf_reference() noexcept +{ + al_effect_props_.Reverb.LFReference = clamp( + props_.flLFReference, + AL_EAXREVERB_MIN_LFREFERENCE, + AL_EAXREVERB_MAX_LFREFERENCE); } -void EaxReverbEffect::defer_flags( - const EaxEaxCall& eax_call) +void EaxReverbEffect::set_efx_room_rolloff_factor() noexcept { - const auto& ulFlags = - eax_call.get_value(); + al_effect_props_.Reverb.RoomRolloffFactor = clamp( + props_.flRoomRolloffFactor, + AL_EAXREVERB_MIN_ROOM_ROLLOFF_FACTOR, + AL_EAXREVERB_MAX_ROOM_ROLLOFF_FACTOR); +} - validate_flags(ulFlags); - defer_flags(ulFlags); +void EaxReverbEffect::set_efx_flags() noexcept +{ + al_effect_props_.Reverb.DecayHFLimit = ((props_.ulFlags & EAXREVERBFLAGS_DECAYHFLIMIT) != 0); } -void EaxReverbEffect::defer_all( - const EaxEaxCall& eax_call) +void EaxReverbEffect::set_efx_defaults() noexcept { - const auto eax_version = eax_call.get_version(); + set_efx_density_from_environment_size(); + set_efx_diffusion(); + set_efx_gain(); + set_efx_gain_hf(); + set_efx_gain_lf(); + set_efx_decay_time(); + set_efx_decay_hf_ratio(); + set_efx_decay_lf_ratio(); + set_efx_reflections_gain(); + set_efx_reflections_delay(); + set_efx_reflections_pan(); + set_efx_late_reverb_gain(); + set_efx_late_reverb_delay(); + set_efx_late_reverb_pan(); + set_efx_echo_time(); + set_efx_echo_depth(); + set_efx_modulation_time(); + set_efx_modulation_depth(); + set_efx_air_absorption_gain_hf(); + set_efx_hf_reference(); + set_efx_lf_reference(); + set_efx_room_rolloff_factor(); + set_efx_flags(); +} - if (eax_version == 2) +void EaxReverbEffect::get1(const EaxCall& call, const Props1& props) +{ + switch(call.get_property_id()) { - const auto& listener = - eax_call.get_value(); - - validate_all(listener, eax_version); - defer_all(listener); + case DSPROPERTY_EAX_ALL: call.set_value(props); break; + case DSPROPERTY_EAX_ENVIRONMENT: call.set_value(props.environment); break; + case DSPROPERTY_EAX_VOLUME: call.set_value(props.fVolume); break; + case DSPROPERTY_EAX_DECAYTIME: call.set_value(props.fDecayTime_sec); break; + case DSPROPERTY_EAX_DAMPING: call.set_value(props.fDamping); break; + default: fail_unknown_property_id(); } - else - { - const auto& reverb_all = - eax_call.get_value(); +} - validate_all(reverb_all, eax_version); - defer_all(reverb_all); +void EaxReverbEffect::get2(const EaxCall& call, const Props2& props) +{ + switch(call.get_property_id()) + { + case DSPROPERTY_EAX20LISTENER_NONE: break; + case DSPROPERTY_EAX20LISTENER_ALLPARAMETERS: call.set_value(props); break; + case DSPROPERTY_EAX20LISTENER_ROOM: call.set_value(props.lRoom); break; + case DSPROPERTY_EAX20LISTENER_ROOMHF: call.set_value(props.lRoomHF); break; + case DSPROPERTY_EAX20LISTENER_ROOMROLLOFFFACTOR: call.set_value(props.flRoomRolloffFactor); break; + case DSPROPERTY_EAX20LISTENER_DECAYTIME: call.set_value(props.flDecayTime); break; + case DSPROPERTY_EAX20LISTENER_DECAYHFRATIO: call.set_value(props.flDecayHFRatio); break; + case DSPROPERTY_EAX20LISTENER_REFLECTIONS: call.set_value(props.lReflections); break; + case DSPROPERTY_EAX20LISTENER_REFLECTIONSDELAY: call.set_value(props.flReverbDelay); break; + case DSPROPERTY_EAX20LISTENER_REVERB: call.set_value(props.lReverb); break; + case DSPROPERTY_EAX20LISTENER_REVERBDELAY: call.set_value(props.flReverbDelay); break; + case DSPROPERTY_EAX20LISTENER_ENVIRONMENT: call.set_value(props.dwEnvironment); break; + case DSPROPERTY_EAX20LISTENER_ENVIRONMENTSIZE: call.set_value(props.flEnvironmentSize); break; + case DSPROPERTY_EAX20LISTENER_ENVIRONMENTDIFFUSION: call.set_value(props.flEnvironmentDiffusion); break; + case DSPROPERTY_EAX20LISTENER_AIRABSORPTIONHF: call.set_value(props.flAirAbsorptionHF); break; + case DSPROPERTY_EAX20LISTENER_FLAGS: call.set_value(props.dwFlags); break; + default: fail_unknown_property_id(); } } - -void EaxReverbEffect::v1_defer(const EaxEaxCall& eax_call) +void EaxReverbEffect::get3(const EaxCall& call, const Props3& props) { - switch (eax_call.get_property_id()) + switch(call.get_property_id()) { - case DSPROPERTY_EAX_ALL: return v1_defer_all(eax_call); - case DSPROPERTY_EAX_ENVIRONMENT: return v1_defer_environment(eax_call); - case DSPROPERTY_EAX_VOLUME: return v1_defer_volume(eax_call); - case DSPROPERTY_EAX_DECAYTIME: return v1_defer_decay_time(eax_call); - case DSPROPERTY_EAX_DAMPING: return v1_defer_damping(eax_call); - default: eax_fail("Unsupported property id."); + case EAXREVERB_NONE: break; + case EAXREVERB_ALLPARAMETERS: call.set_value(props); break; + case EAXREVERB_ENVIRONMENT: call.set_value(props.ulEnvironment); break; + case EAXREVERB_ENVIRONMENTSIZE: call.set_value(props.flEnvironmentSize); break; + case EAXREVERB_ENVIRONMENTDIFFUSION: call.set_value(props.flEnvironmentDiffusion); break; + case EAXREVERB_ROOM: call.set_value(props.lRoom); break; + case EAXREVERB_ROOMHF: call.set_value(props.lRoomHF); break; + case EAXREVERB_ROOMLF: call.set_value(props.lRoomLF); break; + case EAXREVERB_DECAYTIME: call.set_value(props.flDecayTime); break; + case EAXREVERB_DECAYHFRATIO: call.set_value(props.flDecayHFRatio); break; + case EAXREVERB_DECAYLFRATIO: call.set_value(props.flDecayLFRatio); break; + case EAXREVERB_REFLECTIONS: call.set_value(props.lReflections); break; + case EAXREVERB_REFLECTIONSDELAY: call.set_value(props.flReflectionsDelay); break; + case EAXREVERB_REFLECTIONSPAN: call.set_value(props.vReflectionsPan); break; + case EAXREVERB_REVERB: call.set_value(props.lReverb); break; + case EAXREVERB_REVERBDELAY: call.set_value(props.flReverbDelay); break; + case EAXREVERB_REVERBPAN: call.set_value(props.vReverbPan); break; + case EAXREVERB_ECHOTIME: call.set_value(props.flEchoTime); break; + case EAXREVERB_ECHODEPTH: call.set_value(props.flEchoDepth); break; + case EAXREVERB_MODULATIONTIME: call.set_value(props.flModulationTime); break; + case EAXREVERB_MODULATIONDEPTH: call.set_value(props.flModulationDepth); break; + case EAXREVERB_AIRABSORPTIONHF: call.set_value(props.flAirAbsorptionHF); break; + case EAXREVERB_HFREFERENCE: call.set_value(props.flHFReference); break; + case EAXREVERB_LFREFERENCE: call.set_value(props.flLFReference); break; + case EAXREVERB_ROOMROLLOFFFACTOR: call.set_value(props.flRoomRolloffFactor); break; + case EAXREVERB_FLAGS: call.set_value(props.ulFlags); break; + default: fail_unknown_property_id(); } } -// [[nodiscard]] -bool EaxReverbEffect::apply_deferred() +void EaxReverbEffect::get(const EaxCall& call) { - bool ret{false}; - - if(unlikely(eax1_dirty_flags_ != Eax1ReverbEffectDirtyFlags{})) + switch(call.get_version()) { - eax1_ = eax1_d_; - - v1_set_efx(); - - eax1_dirty_flags_ = Eax1ReverbEffectDirtyFlags{}; - - ret = true; + case 1: get1(call, state1_.i); break; + case 2: get2(call, state2_.i); break; + case 3: get3(call, state3_.i); break; + case 4: get3(call, state4_.i); break; + case 5: get3(call, state5_.i); break; + default: fail_unknown_version(); } +} - if(eax_dirty_flags_ == EaxReverbEffectDirtyFlags{}) - return ret; - - eax_ = eax_d_; +/*[[nodiscard]]*/ bool EaxReverbEffect::commit() +{ + if(!changed_) + return false; + changed_ = false; - if (eax_dirty_flags_.ulEnvironment) + const auto props = props_; + switch(version_) { + case 1: + state1_.i = state1_.d; + translate(state1_.d, props_); + break; + case 2: + state2_.i = state2_.d; + translate(state2_.d, props_); + break; + case 3: + state3_.i = state3_.d; + props_ = state3_.d; + break; + case 4: + state4_.i = state4_.d; + props_ = state4_.d; + break; + case 5: + state5_.i = state5_.d; + props_ = state5_.d; + break; + + default: + fail_unknown_version(); } - if (eax_dirty_flags_.flEnvironmentSize) + auto is_dirty = false; + + if (props_.flEnvironmentSize != props.flEnvironmentSize) { + is_dirty = true; set_efx_density_from_environment_size(); } - if (eax_dirty_flags_.flEnvironmentDiffusion) + if (props_.flEnvironmentDiffusion != props.flEnvironmentDiffusion) { + is_dirty = true; set_efx_diffusion(); } - if (eax_dirty_flags_.lRoom) + if (props_.lRoom != props.lRoom) { + is_dirty = true; set_efx_gain(); } - if (eax_dirty_flags_.lRoomHF) + if (props_.lRoomHF != props.lRoomHF) { + is_dirty = true; set_efx_gain_hf(); } - if (eax_dirty_flags_.lRoomLF) + if (props_.lRoomLF != props.lRoomLF) { + is_dirty = true; set_efx_gain_lf(); } - if (eax_dirty_flags_.flDecayTime) + if (props_.flDecayTime != props.flDecayTime) { + is_dirty = true; set_efx_decay_time(); } - if (eax_dirty_flags_.flDecayHFRatio) + if (props_.flDecayHFRatio != props.flDecayHFRatio) { + is_dirty = true; set_efx_decay_hf_ratio(); } - if (eax_dirty_flags_.flDecayLFRatio) + if (props_.flDecayLFRatio != props.flDecayLFRatio) { + is_dirty = true; set_efx_decay_lf_ratio(); } - if (eax_dirty_flags_.lReflections) + if (props_.lReflections != props.lReflections) { + is_dirty = true; set_efx_reflections_gain(); } - if (eax_dirty_flags_.flReflectionsDelay) + if (props_.flReflectionsDelay != props.flReflectionsDelay) { + is_dirty = true; set_efx_reflections_delay(); } - if (eax_dirty_flags_.vReflectionsPan) + if (props_.vReflectionsPan != props.vReflectionsPan) { + is_dirty = true; set_efx_reflections_pan(); } - if (eax_dirty_flags_.lReverb) + if (props_.lReverb != props.lReverb) { + is_dirty = true; set_efx_late_reverb_gain(); } - if (eax_dirty_flags_.flReverbDelay) + if (props_.flReverbDelay != props.flReverbDelay) { + is_dirty = true; set_efx_late_reverb_delay(); } - if (eax_dirty_flags_.vReverbPan) + if (props_.vReverbPan != props.vReverbPan) { + is_dirty = true; set_efx_late_reverb_pan(); } - if (eax_dirty_flags_.flEchoTime) + if (props_.flEchoTime != props.flEchoTime) { + is_dirty = true; set_efx_echo_time(); } - if (eax_dirty_flags_.flEchoDepth) + if (props_.flEchoDepth != props.flEchoDepth) { + is_dirty = true; set_efx_echo_depth(); } - if (eax_dirty_flags_.flModulationTime) + if (props_.flModulationTime != props.flModulationTime) { + is_dirty = true; set_efx_modulation_time(); } - if (eax_dirty_flags_.flModulationDepth) + if (props_.flModulationDepth != props.flModulationDepth) { + is_dirty = true; set_efx_modulation_depth(); } - if (eax_dirty_flags_.flAirAbsorptionHF) + if (props_.flAirAbsorptionHF != props.flAirAbsorptionHF) { + is_dirty = true; set_efx_air_absorption_gain_hf(); } - if (eax_dirty_flags_.flHFReference) + if (props_.flHFReference != props.flHFReference) { + is_dirty = true; set_efx_hf_reference(); } - if (eax_dirty_flags_.flLFReference) + if (props_.flLFReference != props.flLFReference) { + is_dirty = true; set_efx_lf_reference(); } - if (eax_dirty_flags_.flRoomRolloffFactor) + if (props_.flRoomRolloffFactor != props.flRoomRolloffFactor) { + is_dirty = true; set_efx_room_rolloff_factor(); } - if (eax_dirty_flags_.ulFlags) + if (props_.ulFlags != props.ulFlags) { + is_dirty = true; set_efx_flags(); } - eax_dirty_flags_ = EaxReverbEffectDirtyFlags{}; + return is_dirty; +} + +void EaxReverbEffect::set1(const EaxCall& call, Props1& props) +{ + switch (call.get_property_id()) + { + case DSPROPERTY_EAX_ALL: defer(call, props); break; + case DSPROPERTY_EAX_ENVIRONMENT: defer(call, props.environment); break; + case DSPROPERTY_EAX_VOLUME: defer(call, props.fVolume); break; + case DSPROPERTY_EAX_DECAYTIME: defer(call, props.fDecayTime_sec); break; + case DSPROPERTY_EAX_DAMPING: defer(call, props.fDamping); break; + default: fail_unknown_property_id(); + } +} + +void EaxReverbEffect::set2(const EaxCall& call, Props2& props) +{ + switch (call.get_property_id()) + { + case DSPROPERTY_EAX20LISTENER_NONE: + break; + + case DSPROPERTY_EAX20LISTENER_ALLPARAMETERS: + defer(call, props); + break; + + case DSPROPERTY_EAX20LISTENER_ROOM: + defer(call, props.lRoom); + break; + + case DSPROPERTY_EAX20LISTENER_ROOMHF: + defer(call, props.lRoomHF); + break; + + case DSPROPERTY_EAX20LISTENER_ROOMROLLOFFFACTOR: + defer(call, props.flRoomRolloffFactor); + break; + + case DSPROPERTY_EAX20LISTENER_DECAYTIME: + defer(call, props.flDecayTime); + break; + + case DSPROPERTY_EAX20LISTENER_DECAYHFRATIO: + defer(call, props.flDecayHFRatio); + break; + + case DSPROPERTY_EAX20LISTENER_REFLECTIONS: + defer(call, props.lReflections); + break; + + case DSPROPERTY_EAX20LISTENER_REFLECTIONSDELAY: + defer(call, props.flReverbDelay); + break; + + case DSPROPERTY_EAX20LISTENER_REVERB: + defer(call, props.lReverb); + break; + + case DSPROPERTY_EAX20LISTENER_REVERBDELAY: + defer(call, props.flReverbDelay); + break; + + case DSPROPERTY_EAX20LISTENER_ENVIRONMENT: + defer(call, props, props.dwEnvironment); + break; + + case DSPROPERTY_EAX20LISTENER_ENVIRONMENTSIZE: + defer(call, props, props.flEnvironmentSize); + break; + + case DSPROPERTY_EAX20LISTENER_ENVIRONMENTDIFFUSION: + defer(call, props.flEnvironmentDiffusion); + break; + + case DSPROPERTY_EAX20LISTENER_AIRABSORPTIONHF: + defer(call, props.flAirAbsorptionHF); + break; + + case DSPROPERTY_EAX20LISTENER_FLAGS: + defer(call, props.dwFlags); + break; - return true; + default: + fail_unknown_property_id(); + } } -void EaxReverbEffect::set(const EaxEaxCall& eax_call) +void EaxReverbEffect::set3(const EaxCall& call, Props3& props) { - if(eax_call.get_version() == 1) - v1_defer(eax_call); - else switch(eax_call.get_property_id()) + switch(call.get_property_id()) { case EAXREVERB_NONE: break; case EAXREVERB_ALLPARAMETERS: - defer_all(eax_call); + defer(call, props); break; case EAXREVERB_ENVIRONMENT: - defer_environment(eax_call); + defer(call, props, props.ulEnvironment); break; case EAXREVERB_ENVIRONMENTSIZE: - defer_environment_size(eax_call); + defer(call, props, props.flEnvironmentSize); break; case EAXREVERB_ENVIRONMENTDIFFUSION: - defer_environment_diffusion(eax_call); + defer3(call, props, props.flEnvironmentDiffusion); break; case EAXREVERB_ROOM: - defer_room(eax_call); + defer3(call, props, props.lRoom); break; case EAXREVERB_ROOMHF: - defer_room_hf(eax_call); + defer3(call, props, props.lRoomHF); break; case EAXREVERB_ROOMLF: - defer_room_lf(eax_call); + defer3(call, props, props.lRoomLF); break; case EAXREVERB_DECAYTIME: - defer_decay_time(eax_call); + defer3(call, props, props.flDecayTime); break; case EAXREVERB_DECAYHFRATIO: - defer_decay_hf_ratio(eax_call); + defer3(call, props, props.flDecayHFRatio); break; case EAXREVERB_DECAYLFRATIO: - defer_decay_lf_ratio(eax_call); + defer3(call, props, props.flDecayLFRatio); break; case EAXREVERB_REFLECTIONS: - defer_reflections(eax_call); + defer3(call, props, props.lReflections); break; case EAXREVERB_REFLECTIONSDELAY: - defer_reflections_delay(eax_call); + defer3(call, props, props.flReflectionsDelay); break; case EAXREVERB_REFLECTIONSPAN: - defer_reflections_pan(eax_call); + defer3(call, props, props.vReflectionsPan); break; case EAXREVERB_REVERB: - defer_reverb(eax_call); + defer3(call, props, props.lReverb); break; case EAXREVERB_REVERBDELAY: - defer_reverb_delay(eax_call); + defer3(call, props, props.flReverbDelay); break; case EAXREVERB_REVERBPAN: - defer_reverb_pan(eax_call); + defer3(call, props, props.vReverbPan); break; case EAXREVERB_ECHOTIME: - defer_echo_time(eax_call); + defer3(call, props, props.flEchoTime); break; case EAXREVERB_ECHODEPTH: - defer_echo_depth(eax_call); + defer3(call, props, props.flEchoDepth); break; case EAXREVERB_MODULATIONTIME: - defer_modulation_time(eax_call); + defer3(call, props, props.flModulationTime); break; case EAXREVERB_MODULATIONDEPTH: - defer_modulation_depth(eax_call); + defer3(call, props, props.flModulationDepth); break; case EAXREVERB_AIRABSORPTIONHF: - defer_air_absorbtion_hf(eax_call); + defer3(call, props, props.flAirAbsorptionHF); break; case EAXREVERB_HFREFERENCE: - defer_hf_reference(eax_call); + defer3(call, props, props.flHFReference); break; case EAXREVERB_LFREFERENCE: - defer_lf_reference(eax_call); + defer3(call, props, props.flLFReference); break; case EAXREVERB_ROOMROLLOFFFACTOR: - defer_room_rolloff_factor(eax_call); + defer3(call, props, props.flRoomRolloffFactor); break; case EAXREVERB_FLAGS: - defer_flags(eax_call); + defer3(call, props, props.ulFlags); break; default: - eax_fail("Unsupported property id."); + fail_unknown_property_id(); } } -const EFXEAXREVERBPROPERTIES eax_efx_reverb_presets[EAX1_ENVIRONMENT_COUNT] = +void EaxReverbEffect::set(const EaxCall& call) { - EFX_REVERB_PRESET_GENERIC, - EFX_REVERB_PRESET_PADDEDCELL, - EFX_REVERB_PRESET_ROOM, - EFX_REVERB_PRESET_BATHROOM, - EFX_REVERB_PRESET_LIVINGROOM, - EFX_REVERB_PRESET_STONEROOM, - EFX_REVERB_PRESET_AUDITORIUM, - EFX_REVERB_PRESET_CONCERTHALL, - EFX_REVERB_PRESET_CAVE, - EFX_REVERB_PRESET_ARENA, - EFX_REVERB_PRESET_HANGAR, - EFX_REVERB_PRESET_CARPETEDHALLWAY, - EFX_REVERB_PRESET_HALLWAY, - EFX_REVERB_PRESET_STONECORRIDOR, - EFX_REVERB_PRESET_ALLEY, - EFX_REVERB_PRESET_FOREST, - EFX_REVERB_PRESET_CITY, - EFX_REVERB_PRESET_MOUNTAINS, - EFX_REVERB_PRESET_QUARRY, - EFX_REVERB_PRESET_PLAIN, - EFX_REVERB_PRESET_PARKINGLOT, - EFX_REVERB_PRESET_SEWERPIPE, - EFX_REVERB_PRESET_UNDERWATER, - EFX_REVERB_PRESET_DRUGGED, - EFX_REVERB_PRESET_DIZZY, - EFX_REVERB_PRESET_PSYCHOTIC, -}; // EFXEAXREVERBPROPERTIES + const auto version = call.get_version(); + switch(version) + { + case 1: set1(call, state1_.d); break; + case 2: set2(call, state2_.d); break; + case 3: set3(call, state3_.d); break; + case 4: set3(call, state4_.d); break; + case 5: set3(call, state5_.d); break; + default: fail_unknown_version(); + } + changed_ = true; + version_ = version; +} + +void EaxReverbEffect::translate(const Props1& src, Props3& dst) noexcept +{ + assert(src.environment <= EAX1REVERB_MAXENVIRONMENT); + dst = EAXREVERB_PRESETS[src.environment]; + dst.flDecayTime = src.fDecayTime_sec; + dst.flDecayHFRatio = src.fDamping; + dst.lReverb = mini(static_cast(gain_to_level_mb(src.fVolume)), 0); +} + +void EaxReverbEffect::translate(const Props2& src, Props3& dst) noexcept +{ + assert(src.dwEnvironment <= EAX1REVERB_MAXENVIRONMENT); + const auto& env = EAXREVERB_PRESETS[src.dwEnvironment]; + dst.ulEnvironment = src.dwEnvironment; + dst.flEnvironmentSize = src.flEnvironmentSize; + dst.flEnvironmentDiffusion = src.flEnvironmentDiffusion; + dst.lRoom = src.lRoom; + dst.lRoomHF = src.lRoomHF; + dst.lRoomLF = env.lRoomLF; + dst.flDecayTime = src.flDecayTime; + dst.flDecayHFRatio = src.flDecayHFRatio; + dst.flDecayLFRatio = env.flDecayLFRatio; + dst.lReflections = src.lReflections; + dst.flReflectionsDelay = src.flReflectionsDelay; + dst.vReflectionsPan = env.vReflectionsPan; + dst.lReverb = src.lReverb; + dst.flReverbDelay = src.flReverbDelay; + dst.vReverbPan = env.vReverbPan; + dst.flEchoTime = env.flEchoTime; + dst.flEchoDepth = env.flEchoDepth; + dst.flModulationTime = env.flModulationTime; + dst.flModulationDepth = env.flModulationDepth; + dst.flAirAbsorptionHF = src.flAirAbsorptionHF; + dst.flHFReference = env.flHFReference; + dst.flLFReference = env.flLFReference; + dst.flRoomRolloffFactor = src.flRoomRolloffFactor; + dst.ulFlags = src.dwFlags; +} } // namespace -EaxEffectUPtr eax_create_eax_reverb_effect() +EaxEffectUPtr eax_create_eax_reverb_effect(const EaxCall& call) { - return std::make_unique(); + return std::make_unique(call); } #endif // ALSOFT_EAX diff --git a/modules/openal-soft/al/effects/vmorpher.cpp b/modules/openal-soft/al/effects/vmorpher.cpp index 8c0b3ad..95f98db 100644 --- a/modules/openal-soft/al/effects/vmorpher.cpp +++ b/modules/openal-soft/al/effects/vmorpher.cpp @@ -12,11 +12,9 @@ #ifdef ALSOFT_EAX #include - #include "alnumeric.h" - -#include "al/eax_exception.h" -#include "al/eax_utils.h" +#include "al/eax/exception.h" +#include "al/eax/utils.h" #endif // ALSOFT_EAX @@ -260,178 +258,181 @@ const EffectProps VmorpherEffectProps{genDefaultProps()}; #ifdef ALSOFT_EAX namespace { -using EaxVocalMorpherEffectDirtyFlagsValue = std::uint_least8_t; - -struct EaxVocalMorpherEffectDirtyFlags -{ - using EaxIsBitFieldStruct = bool; - - EaxVocalMorpherEffectDirtyFlagsValue ulPhonemeA : 1; - EaxVocalMorpherEffectDirtyFlagsValue lPhonemeACoarseTuning : 1; - EaxVocalMorpherEffectDirtyFlagsValue ulPhonemeB : 1; - EaxVocalMorpherEffectDirtyFlagsValue lPhonemeBCoarseTuning : 1; - EaxVocalMorpherEffectDirtyFlagsValue ulWaveform : 1; - EaxVocalMorpherEffectDirtyFlagsValue flRate : 1; -}; // EaxPitchShifterEffectDirtyFlags - - -class EaxVocalMorpherEffect final : - public EaxEffect -{ +class EaxVocalMorpherEffectException : public EaxException { public: - EaxVocalMorpherEffect(); - - void dispatch(const EaxEaxCall& eax_call) override; + explicit EaxVocalMorpherEffectException(const char* message) + : EaxException{"EAX_VOCAL_MORPHER_EFFECT", message} + {} +}; // EaxVocalMorpherEffectException - // [[nodiscard]] - bool apply_deferred() override; +class EaxVocalMorpherEffect final : public EaxEffect4 { +public: + EaxVocalMorpherEffect(const EaxCall& call); private: - EAXVOCALMORPHERPROPERTIES eax_{}; - EAXVOCALMORPHERPROPERTIES eax_d_{}; - EaxVocalMorpherEffectDirtyFlags eax_dirty_flags_{}; - - void set_eax_defaults(); + struct PhonemeAValidator { + void operator()(unsigned long ulPhonemeA) const + { + eax_validate_range( + "Phoneme A", + ulPhonemeA, + EAXVOCALMORPHER_MINPHONEMEA, + EAXVOCALMORPHER_MAXPHONEMEA); + } + }; // PhonemeAValidator + + struct PhonemeACoarseTuningValidator { + void operator()(long lPhonemeACoarseTuning) const + { + eax_validate_range( + "Phoneme A Coarse Tuning", + lPhonemeACoarseTuning, + EAXVOCALMORPHER_MINPHONEMEACOARSETUNING, + EAXVOCALMORPHER_MAXPHONEMEACOARSETUNING); + } + }; // PhonemeACoarseTuningValidator + + struct PhonemeBValidator { + void operator()(unsigned long ulPhonemeB) const + { + eax_validate_range( + "Phoneme B", + ulPhonemeB, + EAXVOCALMORPHER_MINPHONEMEB, + EAXVOCALMORPHER_MAXPHONEMEB); + } + }; // PhonemeBValidator + + struct PhonemeBCoarseTuningValidator { + void operator()(long lPhonemeBCoarseTuning) const + { + eax_validate_range( + "Phoneme B Coarse Tuning", + lPhonemeBCoarseTuning, + EAXVOCALMORPHER_MINPHONEMEBCOARSETUNING, + EAXVOCALMORPHER_MAXPHONEMEBCOARSETUNING); + } + }; // PhonemeBCoarseTuningValidator + + struct WaveformValidator { + void operator()(unsigned long ulWaveform) const + { + eax_validate_range( + "Waveform", + ulWaveform, + EAXVOCALMORPHER_MINWAVEFORM, + EAXVOCALMORPHER_MAXWAVEFORM); + } + }; // WaveformValidator + + struct RateValidator { + void operator()(float flRate) const + { + eax_validate_range( + "Rate", + flRate, + EAXVOCALMORPHER_MINRATE, + EAXVOCALMORPHER_MAXRATE); + } + }; // RateValidator + + struct AllValidator { + void operator()(const Props& all) const + { + PhonemeAValidator{}(all.ulPhonemeA); + PhonemeACoarseTuningValidator{}(all.lPhonemeACoarseTuning); + PhonemeBValidator{}(all.ulPhonemeB); + PhonemeBCoarseTuningValidator{}(all.lPhonemeBCoarseTuning); + WaveformValidator{}(all.ulWaveform); + RateValidator{}(all.flRate); + } + }; // AllValidator + + void set_defaults(Props& props) override; void set_efx_phoneme_a(); - void set_efx_phoneme_a_coarse_tuning(); + void set_efx_phoneme_a_coarse_tuning() noexcept; void set_efx_phoneme_b(); - void set_efx_phoneme_b_coarse_tuning(); + void set_efx_phoneme_b_coarse_tuning() noexcept; void set_efx_waveform(); - void set_efx_rate(); - void set_efx_defaults(); - - void get(const EaxEaxCall& eax_call); - - void validate_phoneme_a(unsigned long ulPhonemeA); - void validate_phoneme_a_coarse_tuning(long lPhonemeACoarseTuning); - void validate_phoneme_b(unsigned long ulPhonemeB); - void validate_phoneme_b_coarse_tuning(long lPhonemeBCoarseTuning); - void validate_waveform(unsigned long ulWaveform); - void validate_rate(float flRate); - void validate_all(const EAXVOCALMORPHERPROPERTIES& all); - - void defer_phoneme_a(unsigned long ulPhonemeA); - void defer_phoneme_a_coarse_tuning(long lPhonemeACoarseTuning); - void defer_phoneme_b(unsigned long ulPhonemeB); - void defer_phoneme_b_coarse_tuning(long lPhonemeBCoarseTuning); - void defer_waveform(unsigned long ulWaveform); - void defer_rate(float flRate); - void defer_all(const EAXVOCALMORPHERPROPERTIES& all); - - void defer_phoneme_a(const EaxEaxCall& eax_call); - void defer_phoneme_a_coarse_tuning(const EaxEaxCall& eax_call); - void defer_phoneme_b(const EaxEaxCall& eax_call); - void defer_phoneme_b_coarse_tuning(const EaxEaxCall& eax_call); - void defer_waveform(const EaxEaxCall& eax_call); - void defer_rate(const EaxEaxCall& eax_call); - void defer_all(const EaxEaxCall& eax_call); - - void set(const EaxEaxCall& eax_call); -}; // EaxVocalMorpherEffect + void set_efx_rate() noexcept; + void set_efx_defaults() override; + void get(const EaxCall& call, const Props& props) override; + void set(const EaxCall& call, Props& props) override; + bool commit_props(const Props& props) override; +}; // EaxVocalMorpherEffect -class EaxVocalMorpherEffectException : - public EaxException -{ -public: - explicit EaxVocalMorpherEffectException( - const char* message) - : - EaxException{"EAX_VOCAL_MORPHER_EFFECT", message} - { - } -}; // EaxVocalMorpherEffectException - +EaxVocalMorpherEffect::EaxVocalMorpherEffect(const EaxCall& call) + : EaxEffect4{AL_EFFECT_VOCAL_MORPHER, call} +{} -EaxVocalMorpherEffect::EaxVocalMorpherEffect() - : EaxEffect{AL_EFFECT_VOCAL_MORPHER} +void EaxVocalMorpherEffect::set_defaults(Props& props) { - set_eax_defaults(); - set_efx_defaults(); -} - -void EaxVocalMorpherEffect::dispatch(const EaxEaxCall& eax_call) -{ - eax_call.is_get() ? get(eax_call) : set(eax_call); -} - -void EaxVocalMorpherEffect::set_eax_defaults() -{ - eax_.ulPhonemeA = EAXVOCALMORPHER_DEFAULTPHONEMEA; - eax_.lPhonemeACoarseTuning = EAXVOCALMORPHER_DEFAULTPHONEMEACOARSETUNING; - eax_.ulPhonemeB = EAXVOCALMORPHER_DEFAULTPHONEMEB; - eax_.lPhonemeBCoarseTuning = EAXVOCALMORPHER_DEFAULTPHONEMEBCOARSETUNING; - eax_.ulWaveform = EAXVOCALMORPHER_DEFAULTWAVEFORM; - eax_.flRate = EAXVOCALMORPHER_DEFAULTRATE; - - eax_d_ = eax_; + props.ulPhonemeA = EAXVOCALMORPHER_DEFAULTPHONEMEA; + props.lPhonemeACoarseTuning = EAXVOCALMORPHER_DEFAULTPHONEMEACOARSETUNING; + props.ulPhonemeB = EAXVOCALMORPHER_DEFAULTPHONEMEB; + props.lPhonemeBCoarseTuning = EAXVOCALMORPHER_DEFAULTPHONEMEBCOARSETUNING; + props.ulWaveform = EAXVOCALMORPHER_DEFAULTWAVEFORM; + props.flRate = EAXVOCALMORPHER_DEFAULTRATE; } void EaxVocalMorpherEffect::set_efx_phoneme_a() { const auto phoneme_a = clamp( - static_cast(eax_.ulPhonemeA), + static_cast(props_.ulPhonemeA), AL_VOCAL_MORPHER_MIN_PHONEMEA, AL_VOCAL_MORPHER_MAX_PHONEMEA); - const auto efx_phoneme_a = PhenomeFromEnum(phoneme_a); assert(efx_phoneme_a.has_value()); al_effect_props_.Vmorpher.PhonemeA = *efx_phoneme_a; } -void EaxVocalMorpherEffect::set_efx_phoneme_a_coarse_tuning() +void EaxVocalMorpherEffect::set_efx_phoneme_a_coarse_tuning() noexcept { const auto phoneme_a_coarse_tuning = clamp( - static_cast(eax_.lPhonemeACoarseTuning), + static_cast(props_.lPhonemeACoarseTuning), AL_VOCAL_MORPHER_MIN_PHONEMEA_COARSE_TUNING, AL_VOCAL_MORPHER_MAX_PHONEMEA_COARSE_TUNING); - al_effect_props_.Vmorpher.PhonemeACoarseTuning = phoneme_a_coarse_tuning; } void EaxVocalMorpherEffect::set_efx_phoneme_b() { const auto phoneme_b = clamp( - static_cast(eax_.ulPhonemeB), + static_cast(props_.ulPhonemeB), AL_VOCAL_MORPHER_MIN_PHONEMEB, AL_VOCAL_MORPHER_MAX_PHONEMEB); - const auto efx_phoneme_b = PhenomeFromEnum(phoneme_b); assert(efx_phoneme_b.has_value()); al_effect_props_.Vmorpher.PhonemeB = *efx_phoneme_b; } -void EaxVocalMorpherEffect::set_efx_phoneme_b_coarse_tuning() +void EaxVocalMorpherEffect::set_efx_phoneme_b_coarse_tuning() noexcept { - const auto phoneme_b_coarse_tuning = clamp( - static_cast(eax_.lPhonemeBCoarseTuning), + al_effect_props_.Vmorpher.PhonemeBCoarseTuning = clamp( + static_cast(props_.lPhonemeBCoarseTuning), AL_VOCAL_MORPHER_MIN_PHONEMEB_COARSE_TUNING, AL_VOCAL_MORPHER_MAX_PHONEMEB_COARSE_TUNING); - - al_effect_props_.Vmorpher.PhonemeBCoarseTuning = phoneme_b_coarse_tuning; } void EaxVocalMorpherEffect::set_efx_waveform() { const auto waveform = clamp( - static_cast(eax_.ulWaveform), + static_cast(props_.ulWaveform), AL_VOCAL_MORPHER_MIN_WAVEFORM, AL_VOCAL_MORPHER_MAX_WAVEFORM); - const auto wfx_waveform = WaveformFromEmum(waveform); assert(wfx_waveform.has_value()); al_effect_props_.Vmorpher.Waveform = *wfx_waveform; } -void EaxVocalMorpherEffect::set_efx_rate() +void EaxVocalMorpherEffect::set_efx_rate() noexcept { - const auto rate = clamp( - eax_.flRate, + al_effect_props_.Vmorpher.Rate = clamp( + props_.flRate, AL_VOCAL_MORPHER_MIN_RATE, AL_VOCAL_MORPHER_MAX_RATE); - - al_effect_props_.Vmorpher.Rate = rate; } void EaxVocalMorpherEffect::set_efx_defaults() @@ -444,343 +445,134 @@ void EaxVocalMorpherEffect::set_efx_defaults() set_efx_rate(); } -void EaxVocalMorpherEffect::get(const EaxEaxCall& eax_call) +void EaxVocalMorpherEffect::get(const EaxCall& call, const Props& props) { - switch(eax_call.get_property_id()) + switch(call.get_property_id()) { case EAXVOCALMORPHER_NONE: break; case EAXVOCALMORPHER_ALLPARAMETERS: - eax_call.set_value(eax_); + call.set_value(props); break; case EAXVOCALMORPHER_PHONEMEA: - eax_call.set_value(eax_.ulPhonemeA); + call.set_value(props.ulPhonemeA); break; case EAXVOCALMORPHER_PHONEMEACOARSETUNING: - eax_call.set_value(eax_.lPhonemeACoarseTuning); + call.set_value(props.lPhonemeACoarseTuning); break; case EAXVOCALMORPHER_PHONEMEB: - eax_call.set_value(eax_.ulPhonemeB); + call.set_value(props.ulPhonemeB); break; case EAXVOCALMORPHER_PHONEMEBCOARSETUNING: - eax_call.set_value(eax_.lPhonemeBCoarseTuning); + call.set_value(props.lPhonemeBCoarseTuning); break; case EAXVOCALMORPHER_WAVEFORM: - eax_call.set_value(eax_.ulWaveform); + call.set_value(props.ulWaveform); break; case EAXVOCALMORPHER_RATE: - eax_call.set_value(eax_.flRate); + call.set_value(props.flRate); break; default: - throw EaxVocalMorpherEffectException{"Unsupported property id."}; + fail_unknown_property_id(); } } -void EaxVocalMorpherEffect::validate_phoneme_a( - unsigned long ulPhonemeA) +void EaxVocalMorpherEffect::set(const EaxCall& call, Props& props) { - eax_validate_range( - "Phoneme A", - ulPhonemeA, - EAXVOCALMORPHER_MINPHONEMEA, - EAXVOCALMORPHER_MAXPHONEMEA); -} - -void EaxVocalMorpherEffect::validate_phoneme_a_coarse_tuning( - long lPhonemeACoarseTuning) -{ - eax_validate_range( - "Phoneme A Coarse Tuning", - lPhonemeACoarseTuning, - EAXVOCALMORPHER_MINPHONEMEACOARSETUNING, - EAXVOCALMORPHER_MAXPHONEMEACOARSETUNING); -} - -void EaxVocalMorpherEffect::validate_phoneme_b( - unsigned long ulPhonemeB) -{ - eax_validate_range( - "Phoneme B", - ulPhonemeB, - EAXVOCALMORPHER_MINPHONEMEB, - EAXVOCALMORPHER_MAXPHONEMEB); -} - -void EaxVocalMorpherEffect::validate_phoneme_b_coarse_tuning( - long lPhonemeBCoarseTuning) -{ - eax_validate_range( - "Phoneme B Coarse Tuning", - lPhonemeBCoarseTuning, - EAXVOCALMORPHER_MINPHONEMEBCOARSETUNING, - EAXVOCALMORPHER_MAXPHONEMEBCOARSETUNING); -} - -void EaxVocalMorpherEffect::validate_waveform( - unsigned long ulWaveform) -{ - eax_validate_range( - "Waveform", - ulWaveform, - EAXVOCALMORPHER_MINWAVEFORM, - EAXVOCALMORPHER_MAXWAVEFORM); -} - -void EaxVocalMorpherEffect::validate_rate( - float flRate) -{ - eax_validate_range( - "Rate", - flRate, - EAXVOCALMORPHER_MINRATE, - EAXVOCALMORPHER_MAXRATE); -} - -void EaxVocalMorpherEffect::validate_all( - const EAXVOCALMORPHERPROPERTIES& all) -{ - validate_phoneme_a(all.ulPhonemeA); - validate_phoneme_a_coarse_tuning(all.lPhonemeACoarseTuning); - validate_phoneme_b(all.ulPhonemeB); - validate_phoneme_b_coarse_tuning(all.lPhonemeBCoarseTuning); - validate_waveform(all.ulWaveform); - validate_rate(all.flRate); -} - -void EaxVocalMorpherEffect::defer_phoneme_a( - unsigned long ulPhonemeA) -{ - eax_d_.ulPhonemeA = ulPhonemeA; - eax_dirty_flags_.ulPhonemeA = (eax_.ulPhonemeA != eax_d_.ulPhonemeA); -} - -void EaxVocalMorpherEffect::defer_phoneme_a_coarse_tuning( - long lPhonemeACoarseTuning) -{ - eax_d_.lPhonemeACoarseTuning = lPhonemeACoarseTuning; - eax_dirty_flags_.lPhonemeACoarseTuning = (eax_.lPhonemeACoarseTuning != eax_d_.lPhonemeACoarseTuning); -} - -void EaxVocalMorpherEffect::defer_phoneme_b( - unsigned long ulPhonemeB) -{ - eax_d_.ulPhonemeB = ulPhonemeB; - eax_dirty_flags_.ulPhonemeB = (eax_.ulPhonemeB != eax_d_.ulPhonemeB); -} - -void EaxVocalMorpherEffect::defer_phoneme_b_coarse_tuning( - long lPhonemeBCoarseTuning) -{ - eax_d_.lPhonemeBCoarseTuning = lPhonemeBCoarseTuning; - eax_dirty_flags_.lPhonemeBCoarseTuning = (eax_.lPhonemeBCoarseTuning != eax_d_.lPhonemeBCoarseTuning); -} - -void EaxVocalMorpherEffect::defer_waveform( - unsigned long ulWaveform) -{ - eax_d_.ulWaveform = ulWaveform; - eax_dirty_flags_.ulWaveform = (eax_.ulWaveform != eax_d_.ulWaveform); -} - -void EaxVocalMorpherEffect::defer_rate( - float flRate) -{ - eax_d_.flRate = flRate; - eax_dirty_flags_.flRate = (eax_.flRate != eax_d_.flRate); -} - -void EaxVocalMorpherEffect::defer_all( - const EAXVOCALMORPHERPROPERTIES& all) -{ - defer_phoneme_a(all.ulPhonemeA); - defer_phoneme_a_coarse_tuning(all.lPhonemeACoarseTuning); - defer_phoneme_b(all.ulPhonemeB); - defer_phoneme_b_coarse_tuning(all.lPhonemeBCoarseTuning); - defer_waveform(all.ulWaveform); - defer_rate(all.flRate); -} - -void EaxVocalMorpherEffect::defer_phoneme_a( - const EaxEaxCall& eax_call) -{ - const auto& phoneme_a = eax_call.get_value(); - - validate_phoneme_a(phoneme_a); - defer_phoneme_a(phoneme_a); -} - -void EaxVocalMorpherEffect::defer_phoneme_a_coarse_tuning( - const EaxEaxCall& eax_call) -{ - const auto& phoneme_a_coarse_tuning = eax_call.get_value< - EaxVocalMorpherEffectException, - const decltype(EAXVOCALMORPHERPROPERTIES::lPhonemeACoarseTuning) - >(); - - validate_phoneme_a_coarse_tuning(phoneme_a_coarse_tuning); - defer_phoneme_a_coarse_tuning(phoneme_a_coarse_tuning); -} - -void EaxVocalMorpherEffect::defer_phoneme_b( - const EaxEaxCall& eax_call) -{ - const auto& phoneme_b = eax_call.get_value< - EaxVocalMorpherEffectException, - const decltype(EAXVOCALMORPHERPROPERTIES::ulPhonemeB) - >(); - - validate_phoneme_b(phoneme_b); - defer_phoneme_b(phoneme_b); -} + switch(call.get_property_id()) + { + case EAXVOCALMORPHER_NONE: + break; -void EaxVocalMorpherEffect::defer_phoneme_b_coarse_tuning( - const EaxEaxCall& eax_call) -{ - const auto& phoneme_b_coarse_tuning = eax_call.get_value< - EaxVocalMorpherEffectException, - const decltype(EAXVOCALMORPHERPROPERTIES::lPhonemeBCoarseTuning) - >(); + case EAXVOCALMORPHER_ALLPARAMETERS: + defer(call, props); + break; - validate_phoneme_b_coarse_tuning(phoneme_b_coarse_tuning); - defer_phoneme_b_coarse_tuning(phoneme_b_coarse_tuning); -} + case EAXVOCALMORPHER_PHONEMEA: + defer(call, props.ulPhonemeA); + break; -void EaxVocalMorpherEffect::defer_waveform( - const EaxEaxCall& eax_call) -{ - const auto& waveform = eax_call.get_value< - EaxVocalMorpherEffectException, - const decltype(EAXVOCALMORPHERPROPERTIES::ulWaveform) - >(); + case EAXVOCALMORPHER_PHONEMEACOARSETUNING: + defer(call, props.lPhonemeACoarseTuning); + break; - validate_waveform(waveform); - defer_waveform(waveform); -} + case EAXVOCALMORPHER_PHONEMEB: + defer(call, props.ulPhonemeB); + break; -void EaxVocalMorpherEffect::defer_rate( - const EaxEaxCall& eax_call) -{ - const auto& rate = eax_call.get_value< - EaxVocalMorpherEffectException, - const decltype(EAXVOCALMORPHERPROPERTIES::flRate) - >(); + case EAXVOCALMORPHER_PHONEMEBCOARSETUNING: + defer(call, props.lPhonemeBCoarseTuning); + break; - validate_rate(rate); - defer_rate(rate); -} + case EAXVOCALMORPHER_WAVEFORM: + defer(call, props.ulWaveform); + break; -void EaxVocalMorpherEffect::defer_all( - const EaxEaxCall& eax_call) -{ - const auto& all = eax_call.get_value< - EaxVocalMorpherEffectException, - const EAXVOCALMORPHERPROPERTIES - >(); + case EAXVOCALMORPHER_RATE: + defer(call, props.flRate); + break; - validate_all(all); - defer_all(all); + default: + fail_unknown_property_id(); + } } -// [[nodiscard]] -bool EaxVocalMorpherEffect::apply_deferred() +bool EaxVocalMorpherEffect::commit_props(const Props& props) { - if (eax_dirty_flags_ == EaxVocalMorpherEffectDirtyFlags{}) - { - return false; - } + auto is_dirty = false; - eax_ = eax_d_; - - if (eax_dirty_flags_.ulPhonemeA) + if (props_.ulPhonemeA != props.ulPhonemeA) { + is_dirty = true; set_efx_phoneme_a(); } - if (eax_dirty_flags_.lPhonemeACoarseTuning) + if (props_.lPhonemeACoarseTuning != props.lPhonemeACoarseTuning) { + is_dirty = true; set_efx_phoneme_a_coarse_tuning(); } - if (eax_dirty_flags_.ulPhonemeB) + if (props_.ulPhonemeB != props.ulPhonemeB) { + is_dirty = true; set_efx_phoneme_b(); } - if (eax_dirty_flags_.lPhonemeBCoarseTuning) + if (props_.lPhonemeBCoarseTuning != props.lPhonemeBCoarseTuning) { + is_dirty = true; set_efx_phoneme_b_coarse_tuning(); } - if (eax_dirty_flags_.ulWaveform) + if (props_.ulWaveform != props.ulWaveform) { + is_dirty = true; set_efx_waveform(); } - if (eax_dirty_flags_.flRate) + if (props_.flRate != props.flRate) { + is_dirty = true; set_efx_rate(); } - eax_dirty_flags_ = EaxVocalMorpherEffectDirtyFlags{}; - - return true; -} - -void EaxVocalMorpherEffect::set(const EaxEaxCall& eax_call) -{ - switch(eax_call.get_property_id()) - { - case EAXVOCALMORPHER_NONE: - break; - - case EAXVOCALMORPHER_ALLPARAMETERS: - defer_all(eax_call); - break; - - case EAXVOCALMORPHER_PHONEMEA: - defer_phoneme_a(eax_call); - break; - - case EAXVOCALMORPHER_PHONEMEACOARSETUNING: - defer_phoneme_a_coarse_tuning(eax_call); - break; - - case EAXVOCALMORPHER_PHONEMEB: - defer_phoneme_b(eax_call); - break; - - case EAXVOCALMORPHER_PHONEMEBCOARSETUNING: - defer_phoneme_b_coarse_tuning(eax_call); - break; - - case EAXVOCALMORPHER_WAVEFORM: - defer_waveform(eax_call); - break; - - case EAXVOCALMORPHER_RATE: - defer_rate(eax_call); - break; - - default: - throw EaxVocalMorpherEffectException{"Unsupported property id."}; - } + return is_dirty; } } // namespace - -EaxEffectUPtr eax_create_eax_vocal_morpher_effect() +EaxEffectUPtr eax_create_eax_vocal_morpher_effect(const EaxCall& call) { - return std::make_unique(); + return eax_create_eax4_effect(call); } #endif // ALSOFT_EAX diff --git a/modules/openal-soft/al/source.cpp b/modules/openal-soft/al/source.cpp index d2ccfe0..e68c5b1 100644 --- a/modules/openal-soft/al/source.cpp +++ b/modules/openal-soft/al/source.cpp @@ -73,7 +73,7 @@ #include "threads.h" #ifdef ALSOFT_EAX -#include "eax_exception.h" +#include #endif // ALSOFT_EAX namespace { @@ -3640,13 +3640,7 @@ void UpdateAllSourceProps(ALCcontext *context) usemask &= ~(1_u64 << idx); ALsource *source{sublist.Sources + idx}; - source->eax_commit(); - - if(Voice *voice{GetSourceVoice(source, context)}) - { - if(std::exchange(source->mPropsDirty, false)) - UpdateSourceProps(source, voice, context); - } + source->eax_commit_and_update(); } } } @@ -3685,161 +3679,316 @@ SourceSubList::~SourceSubList() #ifdef ALSOFT_EAX -class EaxSourceException : - public EaxException -{ -public: - explicit EaxSourceException( - const char* message) - : - EaxException{"EAX_SOURCE", message} +void EaxUpdateSourceVoice(ALsource *source, ALCcontext *context) +{ + if(Voice *voice{GetSourceVoice(source, context)}) { + if(std::exchange(source->mPropsDirty, false)) + UpdateSourceProps(source, voice, context); } -}; // EaxSourceException +} +constexpr const ALsource::EaxFxSlotIds ALsource::eax4_fx_slot_ids; +constexpr const ALsource::EaxFxSlotIds ALsource::eax5_fx_slot_ids; -class EaxSourceActiveFxSlotsException : - public EaxException +void ALsource::eax_initialize(ALCcontext *context) noexcept { -public: - explicit EaxSourceActiveFxSlotsException( - const char* message) - : - EaxException{"EAX_SOURCE_ACTIVE_FX_SLOTS", message} - { - } -}; // EaxSourceActiveFxSlotsException + assert(context != nullptr); + eax_al_context_ = context; + eax_primary_fx_slot_id_ = eax_al_context_->eax_get_primary_fx_slot_index(); + eax_version_ = eax_al_context_->eax_get_version(); + eax_set_defaults(); + eax_commit(EaxCommitType::forced); +} +void ALsource::eax_dispatch(const EaxCall& call) +{ + call.is_get() ? eax_get(call) : eax_set(call); +} -class EaxSourceSendException : - public EaxException +void ALsource::eax_commit_and_update() { -public: - explicit EaxSourceSendException( - const char* message) - : - EaxException{"EAX_SOURCE_SEND", message} - { - } -}; // EaxSourceSendException + eax_commit(); + EaxUpdateSourceVoice(this, eax_al_context_); +} +ALsource* ALsource::eax_lookup_source(ALCcontext& al_context, ALuint source_id) noexcept +{ + return LookupSource(&al_context, source_id); +} -void EaxUpdateSourceVoice(ALsource *source, ALCcontext *context) +[[noreturn]] void ALsource::eax_fail(const char* message) { - if(Voice *voice{GetSourceVoice(source, context)}) - { - if(std::exchange(source->mPropsDirty, false)) - UpdateSourceProps(source, voice, context); + throw Exception{message}; +} + +[[noreturn]] void ALsource::eax_fail_unknown_property_id() +{ + eax_fail("Unknown property id."); +} + +[[noreturn]] void ALsource::eax_fail_unknown_version() +{ + eax_fail("Unknown version."); +} + +[[noreturn]] void ALsource::eax_fail_unknown_active_fx_slot_id() +{ + eax_fail("Unknown active FX slot ID."); +} + +[[noreturn]] void ALsource::eax_fail_unknown_receiving_fx_slot_id() +{ + eax_fail("Unknown receiving FX slot ID."); +} + +void ALsource::eax_set_sends_defaults(EaxSends& sends, const EaxFxSlotIds& ids) noexcept +{ + for (auto i = size_t{}; i < EAX_MAX_FXSLOTS; ++i) { + auto& send = sends[i]; + send.guidReceivingFXSlotID = *(ids[i]); + send.lSend = EAXSOURCE_DEFAULTSEND; + send.lSendHF = EAXSOURCE_DEFAULTSENDHF; + send.lOcclusion = EAXSOURCE_DEFAULTOCCLUSION; + send.flOcclusionLFRatio = EAXSOURCE_DEFAULTOCCLUSIONLFRATIO; + send.flOcclusionRoomRatio = EAXSOURCE_DEFAULTOCCLUSIONROOMRATIO; + send.flOcclusionDirectRatio = EAXSOURCE_DEFAULTOCCLUSIONDIRECTRATIO; + send.lExclusion = EAXSOURCE_DEFAULTEXCLUSION; + send.flExclusionLFRatio = EAXSOURCE_DEFAULTEXCLUSIONLFRATIO; } } +void ALsource::eax1_set_defaults(Eax1Props& props) noexcept +{ + props.fMix = EAX_REVERBMIX_USEDISTANCE; +} -void ALsource::eax_initialize(ALCcontext *context) noexcept +void ALsource::eax1_set_defaults() noexcept { - assert(context); - eax_al_context_ = context; - eax_set_defaults(); - eax_initialize_fx_slots(); + eax1_set_defaults(eax1_.i); + eax1_.d = eax1_.i; +} - eax_d_ = eax_; +void ALsource::eax2_set_defaults(Eax2Props& props) noexcept +{ + props.lDirect = EAXSOURCE_DEFAULTDIRECT; + props.lDirectHF = EAXSOURCE_DEFAULTDIRECTHF; + props.lRoom = EAXSOURCE_DEFAULTROOM; + props.lRoomHF = EAXSOURCE_DEFAULTROOMHF; + props.flRoomRolloffFactor = EAXSOURCE_DEFAULTROOMROLLOFFFACTOR; + props.lObstruction = EAXSOURCE_DEFAULTOBSTRUCTION; + props.flObstructionLFRatio = EAXSOURCE_DEFAULTOBSTRUCTIONLFRATIO; + props.lOcclusion = EAXSOURCE_DEFAULTOCCLUSION; + props.flOcclusionLFRatio = EAXSOURCE_DEFAULTOCCLUSIONLFRATIO; + props.flOcclusionRoomRatio = EAXSOURCE_DEFAULTOCCLUSIONROOMRATIO; + props.lOutsideVolumeHF = EAXSOURCE_DEFAULTOUTSIDEVOLUMEHF; + props.flAirAbsorptionFactor = EAXSOURCE_DEFAULTAIRABSORPTIONFACTOR; + props.dwFlags = EAXSOURCE_DEFAULTFLAGS; } -void ALsource::eax_update_filters() +void ALsource::eax2_set_defaults() noexcept { - eax_update_filters_internal(); + eax2_set_defaults(eax2_.i); + eax2_.d = eax2_.i; } -void ALsource::eax_update(EaxContextSharedDirtyFlags) +void ALsource::eax3_set_defaults(Eax3Props& props) noexcept { - /* NOTE: EaxContextSharedDirtyFlags only has one flag (primary_fx_slot_id), - * which must be true for this to be called. - */ - if(eax_uses_primary_id_) - eax_update_primary_fx_slot_id(); + props.lDirect = EAXSOURCE_DEFAULTDIRECT; + props.lDirectHF = EAXSOURCE_DEFAULTDIRECTHF; + props.lRoom = EAXSOURCE_DEFAULTROOM; + props.lRoomHF = EAXSOURCE_DEFAULTROOMHF; + props.lObstruction = EAXSOURCE_DEFAULTOBSTRUCTION; + props.flObstructionLFRatio = EAXSOURCE_DEFAULTOBSTRUCTIONLFRATIO; + props.lOcclusion = EAXSOURCE_DEFAULTOCCLUSION; + props.flOcclusionLFRatio = EAXSOURCE_DEFAULTOCCLUSIONLFRATIO; + props.flOcclusionRoomRatio = EAXSOURCE_DEFAULTOCCLUSIONROOMRATIO; + props.flOcclusionDirectRatio = EAXSOURCE_DEFAULTOCCLUSIONDIRECTRATIO; + props.lExclusion = EAXSOURCE_DEFAULTEXCLUSION; + props.flExclusionLFRatio = EAXSOURCE_DEFAULTEXCLUSIONLFRATIO; + props.lOutsideVolumeHF = EAXSOURCE_DEFAULTOUTSIDEVOLUMEHF; + props.flDopplerFactor = EAXSOURCE_DEFAULTDOPPLERFACTOR; + props.flRolloffFactor = EAXSOURCE_DEFAULTROLLOFFFACTOR; + props.flRoomRolloffFactor = EAXSOURCE_DEFAULTROOMROLLOFFFACTOR; + props.flAirAbsorptionFactor = EAXSOURCE_DEFAULTAIRABSORPTIONFACTOR; + props.ulFlags = EAXSOURCE_DEFAULTFLAGS; } -void ALsource::eax_commit_and_update() +void ALsource::eax3_set_defaults() noexcept { - eax_apply_deferred(); - EaxUpdateSourceVoice(this, eax_al_context_); + eax3_set_defaults(eax3_.i); + eax3_.d = eax3_.i; } -ALsource* ALsource::eax_lookup_source( - ALCcontext& al_context, - ALuint source_id) noexcept +void ALsource::eax4_set_sends_defaults(EaxSends& sends) noexcept { - return LookupSource(&al_context, source_id); + eax_set_sends_defaults(sends, eax4_fx_slot_ids); } -[[noreturn]] -void ALsource::eax_fail( - const char* message) +void ALsource::eax4_set_active_fx_slots_defaults(EAX40ACTIVEFXSLOTS& slots) noexcept { - throw EaxSourceException{message}; + slots = EAX40SOURCE_DEFAULTACTIVEFXSLOTID; } -void ALsource::eax_set_source_defaults() noexcept +void ALsource::eax4_set_defaults() noexcept { - eax1_.fMix = EAX_REVERBMIX_USEDISTANCE; + eax3_set_defaults(eax4_.i.source); + eax4_set_sends_defaults(eax4_.i.sends); + eax4_set_active_fx_slots_defaults(eax4_.i.active_fx_slots); + eax4_.d = eax4_.i; +} - eax_.source.lDirect = EAXSOURCE_DEFAULTDIRECT; - eax_.source.lDirectHF = EAXSOURCE_DEFAULTDIRECTHF; - eax_.source.lRoom = EAXSOURCE_DEFAULTROOM; - eax_.source.lRoomHF = EAXSOURCE_DEFAULTROOMHF; - eax_.source.lObstruction = EAXSOURCE_DEFAULTOBSTRUCTION; - eax_.source.flObstructionLFRatio = EAXSOURCE_DEFAULTOBSTRUCTIONLFRATIO; - eax_.source.lOcclusion = EAXSOURCE_DEFAULTOCCLUSION; - eax_.source.flOcclusionLFRatio = EAXSOURCE_DEFAULTOCCLUSIONLFRATIO; - eax_.source.flOcclusionRoomRatio = EAXSOURCE_DEFAULTOCCLUSIONROOMRATIO; - eax_.source.flOcclusionDirectRatio = EAXSOURCE_DEFAULTOCCLUSIONDIRECTRATIO; - eax_.source.lExclusion = EAXSOURCE_DEFAULTEXCLUSION; - eax_.source.flExclusionLFRatio = EAXSOURCE_DEFAULTEXCLUSIONLFRATIO; - eax_.source.lOutsideVolumeHF = EAXSOURCE_DEFAULTOUTSIDEVOLUMEHF; - eax_.source.flDopplerFactor = EAXSOURCE_DEFAULTDOPPLERFACTOR; - eax_.source.flRolloffFactor = EAXSOURCE_DEFAULTROLLOFFFACTOR; - eax_.source.flRoomRolloffFactor = EAXSOURCE_DEFAULTROOMROLLOFFFACTOR; - eax_.source.flAirAbsorptionFactor = EAXSOURCE_DEFAULTAIRABSORPTIONFACTOR; - eax_.source.ulFlags = EAXSOURCE_DEFAULTFLAGS; - eax_.source.flMacroFXFactor = EAXSOURCE_DEFAULTMACROFXFACTOR; +void ALsource::eax5_set_source_defaults(EAX50SOURCEPROPERTIES& props) noexcept +{ + eax3_set_defaults(static_cast(props)); + props.flMacroFXFactor = EAXSOURCE_DEFAULTMACROFXFACTOR; } -void ALsource::eax_set_active_fx_slots_defaults() noexcept +void ALsource::eax5_set_sends_defaults(EaxSends& sends) noexcept { - eax_.active_fx_slots = EAX50SOURCE_3DDEFAULTACTIVEFXSLOTID; + eax_set_sends_defaults(sends, eax5_fx_slot_ids); } -void ALsource::eax_set_send_defaults(EAXSOURCEALLSENDPROPERTIES& eax_send) noexcept +void ALsource::eax5_set_active_fx_slots_defaults(EAX50ACTIVEFXSLOTS& slots) noexcept { - eax_send.guidReceivingFXSlotID = EAX_NULL_GUID; - eax_send.lSend = EAXSOURCE_DEFAULTSEND; - eax_send.lSendHF = EAXSOURCE_DEFAULTSENDHF; - eax_send.lOcclusion = EAXSOURCE_DEFAULTOCCLUSION; - eax_send.flOcclusionLFRatio = EAXSOURCE_DEFAULTOCCLUSIONLFRATIO; - eax_send.flOcclusionRoomRatio = EAXSOURCE_DEFAULTOCCLUSIONROOMRATIO; - eax_send.flOcclusionDirectRatio = EAXSOURCE_DEFAULTOCCLUSIONDIRECTRATIO; - eax_send.lExclusion = EAXSOURCE_DEFAULTEXCLUSION; - eax_send.flExclusionLFRatio = EAXSOURCE_DEFAULTEXCLUSIONLFRATIO; + slots = EAX50SOURCE_3DDEFAULTACTIVEFXSLOTID; } -void ALsource::eax_set_sends_defaults() noexcept +void ALsource::eax5_set_speaker_levels_defaults(EaxSpeakerLevels& speaker_levels) noexcept { - for (auto& eax_send : eax_.sends) - { - eax_set_send_defaults(eax_send); + for (auto i = size_t{}; i < eax_max_speakers; ++i) { + auto& speaker_level = speaker_levels[i]; + speaker_level.lSpeakerID = static_cast(EAXSPEAKER_FRONT_LEFT + i); + speaker_level.lLevel = EAXSOURCE_DEFAULTSPEAKERLEVEL; } } -void ALsource::eax_set_speaker_levels_defaults() noexcept +void ALsource::eax5_set_defaults(Eax5Props& props) noexcept +{ + eax5_set_source_defaults(props.source); + eax5_set_sends_defaults(props.sends); + eax5_set_active_fx_slots_defaults(props.active_fx_slots); + eax5_set_speaker_levels_defaults(props.speaker_levels); +} + +void ALsource::eax5_set_defaults() noexcept { - std::fill(eax_.speaker_levels.begin(), eax_.speaker_levels.end(), EAXSOURCE_DEFAULTSPEAKERLEVEL); + eax5_set_defaults(eax5_.i); + eax5_.d = eax5_.i; } void ALsource::eax_set_defaults() noexcept { - eax_set_source_defaults(); - eax_set_active_fx_slots_defaults(); - eax_set_sends_defaults(); - eax_set_speaker_levels_defaults(); + eax1_set_defaults(); + eax2_set_defaults(); + eax3_set_defaults(); + eax4_set_defaults(); + eax5_set_defaults(); +} + +void ALsource::eax1_translate(const Eax1Props& src, Eax5Props& dst) noexcept +{ + eax5_set_defaults(dst); + + if (src.fMix == EAX_REVERBMIX_USEDISTANCE) + dst.source.ulFlags |= EAXSOURCEFLAGS_ROOMAUTO; + else + dst.source.ulFlags &= ~EAXSOURCEFLAGS_ROOMAUTO; + + dst.sends[0].lSendHF = clamp( + static_cast(gain_to_level_mb(src.fMix)), + EAXSOURCE_MINSENDHF, + EAXSOURCE_MAXSENDHF); +} + +void ALsource::eax2_translate(const Eax2Props& src, Eax5Props& dst) noexcept +{ + // Source. + // + dst.source.lDirect = src.lDirect; + dst.source.lDirectHF = src.lDirectHF; + dst.source.lRoom = src.lRoom; + dst.source.lRoomHF = src.lRoomHF; + dst.source.lObstruction = src.lObstruction; + dst.source.flObstructionLFRatio = src.flObstructionLFRatio; + dst.source.lOcclusion = src.lOcclusion; + dst.source.flOcclusionLFRatio = src.flOcclusionLFRatio; + dst.source.flOcclusionRoomRatio = src.flOcclusionRoomRatio; + dst.source.flOcclusionDirectRatio = EAXSOURCE_DEFAULTOCCLUSIONDIRECTRATIO; + dst.source.lExclusion = EAXSOURCE_DEFAULTEXCLUSION; + dst.source.flExclusionLFRatio = EAXSOURCE_DEFAULTEXCLUSIONLFRATIO; + dst.source.lOutsideVolumeHF = src.lOutsideVolumeHF; + dst.source.flDopplerFactor = EAXSOURCE_DEFAULTDOPPLERFACTOR; + dst.source.flRolloffFactor = EAXSOURCE_DEFAULTROLLOFFFACTOR; + dst.source.flRoomRolloffFactor = src.flRoomRolloffFactor; + dst.source.flAirAbsorptionFactor = src.flAirAbsorptionFactor; + dst.source.ulFlags = src.dwFlags; + dst.source.flMacroFXFactor = EAXSOURCE_DEFAULTMACROFXFACTOR; + + // Set everyting else to defaults. + // + eax5_set_sends_defaults(dst.sends); + eax5_set_active_fx_slots_defaults(dst.active_fx_slots); + eax5_set_speaker_levels_defaults(dst.speaker_levels); +} + +void ALsource::eax3_translate(const Eax3Props& src, Eax5Props& dst) noexcept +{ + // Source. + // + static_cast(dst.source) = src; + dst.source.flMacroFXFactor = EAXSOURCE_DEFAULTMACROFXFACTOR; + + // Set everyting else to defaults. + // + eax5_set_sends_defaults(dst.sends); + eax5_set_active_fx_slots_defaults(dst.active_fx_slots); + eax5_set_speaker_levels_defaults(dst.speaker_levels); +} + +void ALsource::eax4_translate(const Eax4Props& src, Eax5Props& dst) noexcept +{ + // Source. + // + static_cast(dst.source) = src.source; + dst.source.flMacroFXFactor = EAXSOURCE_DEFAULTMACROFXFACTOR; + + // Sends. + // + dst.sends = src.sends; + + for (auto i = size_t{}; i < EAX_MAX_FXSLOTS; ++i) + dst.sends[i].guidReceivingFXSlotID = *(eax5_fx_slot_ids[i]); + + // Active FX slots. + // + for (auto i = 0; i < EAX50_MAX_ACTIVE_FXSLOTS; ++i) { + auto& dst_id = dst.active_fx_slots.guidActiveFXSlots[i]; + + if (i < EAX40_MAX_ACTIVE_FXSLOTS) { + const auto& src_id = src.active_fx_slots.guidActiveFXSlots[i]; + + if (src_id == EAX_NULL_GUID) + dst_id = EAX_NULL_GUID; + else if (src_id == EAX_PrimaryFXSlotID) + dst_id = EAX_PrimaryFXSlotID; + else if (src_id == EAXPROPERTYID_EAX40_FXSlot0) + dst_id = EAXPROPERTYID_EAX50_FXSlot0; + else if (src_id == EAXPROPERTYID_EAX40_FXSlot1) + dst_id = EAXPROPERTYID_EAX50_FXSlot1; + else if (src_id == EAXPROPERTYID_EAX40_FXSlot2) + dst_id = EAXPROPERTYID_EAX50_FXSlot2; + else if (src_id == EAXPROPERTYID_EAX40_FXSlot3) + dst_id = EAXPROPERTYID_EAX50_FXSlot3; + else + assert(false && "Unknown active FX slot ID."); + } else + dst_id = EAX_NULL_GUID; + } + + // Speaker levels. + // + eax5_set_speaker_levels_defaults(dst.speaker_levels); } float ALsource::eax_calculate_dst_occlusion_mb( @@ -3851,7 +4000,6 @@ float ALsource::eax_calculate_dst_occlusion_mb( const auto ratio_2 = path_ratio * lf_ratio; const auto ratio = (ratio_2 > ratio_1) ? ratio_2 : ratio_1; const auto dst_occlustion_mb = static_cast(src_occlusion_mb) * ratio; - return dst_occlustion_mb; } @@ -3859,9 +4007,7 @@ EaxAlLowPassParam ALsource::eax_create_direct_filter_param() const noexcept { auto gain_mb = static_cast(eax_.source.lDirect) + - (static_cast(eax_.source.lObstruction) * eax_.source.flObstructionLFRatio) + - eax_calculate_dst_occlusion_mb( eax_.source.lOcclusion, eax_.source.flOcclusionDirectRatio, @@ -3869,31 +4015,29 @@ EaxAlLowPassParam ALsource::eax_create_direct_filter_param() const noexcept auto gain_hf_mb = static_cast(eax_.source.lDirectHF) + - static_cast(eax_.source.lObstruction) + - (static_cast(eax_.source.lOcclusion) * eax_.source.flOcclusionDirectRatio); for (auto i = std::size_t{}; i < EAX_MAX_FXSLOTS; ++i) { - if (eax_active_fx_slots_[i]) + if (!eax_active_fx_slots_[i]) { - const auto& send = eax_.sends[i]; + continue; + } - gain_mb += eax_calculate_dst_occlusion_mb( - send.lOcclusion, - send.flOcclusionDirectRatio, - send.flOcclusionLFRatio); + const auto& send = eax_.sends[i]; - gain_hf_mb += static_cast(send.lOcclusion) * send.flOcclusionDirectRatio; - } + gain_mb += eax_calculate_dst_occlusion_mb( + send.lOcclusion, + send.flOcclusionDirectRatio, + send.flOcclusionLFRatio); + + gain_hf_mb += static_cast(send.lOcclusion) * send.flOcclusionDirectRatio; } - const auto al_low_pass_param = EaxAlLowPassParam - { + const auto al_low_pass_param = EaxAlLowPassParam{ level_mb_to_gain(gain_mb), - minf(level_mb_to_gain(gain_hf_mb), 1.0f) - }; + minf(level_mb_to_gain(gain_hf_mb), 1.0f)}; return al_low_pass_param; } @@ -3905,94 +4049,34 @@ EaxAlLowPassParam ALsource::eax_create_room_filter_param( const auto& fx_slot_eax = fx_slot.eax_get_eax_fx_slot(); const auto gain_mb = - static_cast( - eax_.source.lRoom + - send.lSend) + - + static_cast(eax_.source.lRoom + send.lSend) + eax_calculate_dst_occlusion_mb( eax_.source.lOcclusion, eax_.source.flOcclusionRoomRatio, - eax_.source.flOcclusionLFRatio - ) + - + eax_.source.flOcclusionLFRatio) + eax_calculate_dst_occlusion_mb( send.lOcclusion, send.flOcclusionRoomRatio, - send.flOcclusionLFRatio - ) + - + send.flOcclusionLFRatio) + (static_cast(eax_.source.lExclusion) * eax_.source.flExclusionLFRatio) + - (static_cast(send.lExclusion) * send.flExclusionLFRatio) + - - 0.0F; + (static_cast(send.lExclusion) * send.flExclusionLFRatio); const auto gain_hf_mb = - static_cast( - eax_.source.lRoomHF + - send.lSendHF) + - + static_cast(eax_.source.lRoomHF + send.lSendHF) + (static_cast(fx_slot_eax.lOcclusion + eax_.source.lOcclusion) * eax_.source.flOcclusionRoomRatio) + (static_cast(send.lOcclusion) * send.flOcclusionRoomRatio) + + static_cast(eax_.source.lExclusion + send.lExclusion); - static_cast( - eax_.source.lExclusion + - send.lExclusion) + - - 0.0F; - - const auto al_low_pass_param = EaxAlLowPassParam - { + const auto al_low_pass_param = EaxAlLowPassParam{ level_mb_to_gain(gain_mb), - minf(level_mb_to_gain(gain_hf_mb), 1.0f) - }; + minf(level_mb_to_gain(gain_hf_mb), 1.0f)}; return al_low_pass_param; } -void ALsource::eax_set_fx_slots() -{ - eax_uses_primary_id_ = false; - eax_has_active_fx_slots_ = false; - eax_active_fx_slots_.fill(false); - - for(const auto& eax_active_fx_slot_id : eax_.active_fx_slots.guidActiveFXSlots) - { - auto fx_slot_index = EaxFxSlotIndex{}; - - if(eax_active_fx_slot_id == EAX_PrimaryFXSlotID) - { - eax_uses_primary_id_ = true; - fx_slot_index = eax_al_context_->eax_get_primary_fx_slot_index(); - } - else - { - fx_slot_index = eax_active_fx_slot_id; - } - - if(fx_slot_index.has_value()) - { - eax_has_active_fx_slots_ = true; - eax_active_fx_slots_[*fx_slot_index] = true; - } - } - - for(auto i = 0u;i < eax_active_fx_slots_.size();++i) - { - if(!eax_active_fx_slots_[i]) - eax_set_al_source_send(nullptr, i, EaxAlLowPassParam{1.0f, 1.0f}); - } -} - -void ALsource::eax_initialize_fx_slots() -{ - eax_set_fx_slots(); - eax_update_filters_internal(); -} - -void ALsource::eax_update_direct_filter_internal() +void ALsource::eax_update_direct_filter() { const auto& direct_param = eax_create_direct_filter_param(); - Direct.Gain = direct_param.gain; Direct.GainHF = direct_param.gain_hf; Direct.HFReference = LOWPASSFREQREF; @@ -4001,2051 +4085,757 @@ void ALsource::eax_update_direct_filter_internal() mPropsDirty = true; } -void ALsource::eax_update_room_filters_internal() +void ALsource::eax_update_room_filters() { - if (!eax_has_active_fx_slots_) - { - return; - } - - for (auto i = 0u; i < EAX_MAX_FXSLOTS; ++i) - { - if (eax_active_fx_slots_[i]) - { - auto& fx_slot = eax_al_context_->eax_get_fx_slot(static_cast(i)); - const auto& send = eax_.sends[i]; - const auto& room_param = eax_create_room_filter_param(fx_slot, send); + for (auto i = size_t{}; i < EAX_MAX_FXSLOTS; ++i) { + if (!eax_active_fx_slots_[i]) + continue; - eax_set_al_source_send(&fx_slot, i, room_param); - } + auto& fx_slot = eax_al_context_->eax_get_fx_slot(i); + const auto& send = eax_.sends[i]; + const auto& room_param = eax_create_room_filter_param(fx_slot, send); + eax_set_al_source_send(&fx_slot, i, room_param); } } -void ALsource::eax_update_filters_internal() -{ - eax_update_direct_filter_internal(); - eax_update_room_filters_internal(); -} - -void ALsource::eax_update_primary_fx_slot_id() +void ALsource::eax_set_efx_outer_gain_hf() { - const auto& previous_primary_fx_slot_index = eax_al_context_->eax_get_previous_primary_fx_slot_index(); - const auto& primary_fx_slot_index = eax_al_context_->eax_get_primary_fx_slot_index(); - - if (previous_primary_fx_slot_index == primary_fx_slot_index) - { - return; - } - - if (previous_primary_fx_slot_index.has_value()) - { - const auto fx_slot_index = previous_primary_fx_slot_index.value(); - eax_active_fx_slots_[fx_slot_index] = false; - - eax_set_al_source_send(nullptr, fx_slot_index, EaxAlLowPassParam{1.0f, 1.0f}); - } - - if (primary_fx_slot_index.has_value()) - { - const auto fx_slot_index = primary_fx_slot_index.value(); - eax_active_fx_slots_[fx_slot_index] = true; - - auto& fx_slot = eax_al_context_->eax_get_fx_slot(fx_slot_index); - const auto& send = eax_.sends[fx_slot_index]; - const auto& room_param = eax_create_room_filter_param(fx_slot, send); - - eax_set_al_source_send(&fx_slot, fx_slot_index, room_param); - } - - eax_has_active_fx_slots_ = std::any_of( - eax_active_fx_slots_.cbegin(), - eax_active_fx_slots_.cend(), - [](const auto& item) - { - return item; - } - ); + OuterGainHF = clamp( + level_mb_to_gain(static_cast(eax_.source.lOutsideVolumeHF)), + AL_MIN_CONE_OUTER_GAINHF, + AL_MAX_CONE_OUTER_GAINHF); } -void ALsource::eax_defer_active_fx_slots( - const EaxEaxCall& eax_call) +void ALsource::eax_set_efx_doppler_factor() { - const auto active_fx_slots_span = - eax_call.get_values(); - - const auto fx_slot_count = active_fx_slots_span.size(); - - if (fx_slot_count <= 0 || fx_slot_count > EAX_MAX_FXSLOTS) - { - throw EaxSourceActiveFxSlotsException{"Count out of range."}; - } - - for (auto i = std::size_t{}; i < fx_slot_count; ++i) - { - const auto& fx_slot_guid = active_fx_slots_span[i]; - - if (fx_slot_guid != EAX_NULL_GUID && - fx_slot_guid != EAX_PrimaryFXSlotID && - fx_slot_guid != EAXPROPERTYID_EAX40_FXSlot0 && - fx_slot_guid != EAXPROPERTYID_EAX50_FXSlot0 && - fx_slot_guid != EAXPROPERTYID_EAX40_FXSlot1 && - fx_slot_guid != EAXPROPERTYID_EAX50_FXSlot1 && - fx_slot_guid != EAXPROPERTYID_EAX40_FXSlot2 && - fx_slot_guid != EAXPROPERTYID_EAX50_FXSlot2 && - fx_slot_guid != EAXPROPERTYID_EAX40_FXSlot3 && - fx_slot_guid != EAXPROPERTYID_EAX50_FXSlot3) - { - throw EaxSourceActiveFxSlotsException{"Unsupported GUID."}; - } - } - - for (auto i = std::size_t{}; i < fx_slot_count; ++i) - { - eax_d_.active_fx_slots.guidActiveFXSlots[i] = active_fx_slots_span[i]; - } - - for (auto i = fx_slot_count; i < EAX_MAX_FXSLOTS; ++i) - { - eax_d_.active_fx_slots.guidActiveFXSlots[i] = EAX_NULL_GUID; - } - - eax_are_active_fx_slots_dirty_ = (eax_d_.active_fx_slots != eax_.active_fx_slots); + DopplerFactor = eax_.source.flDopplerFactor; } - -const char* ALsource::eax_get_exclusion_name() noexcept +void ALsource::eax_set_efx_rolloff_factor() { - return "Exclusion"; + RolloffFactor2 = eax_.source.flRolloffFactor; } -const char* ALsource::eax_get_exclusion_lf_ratio_name() noexcept +void ALsource::eax_set_efx_room_rolloff_factor() { - return "Exclusion LF Ratio"; + RoomRolloffFactor = eax_.source.flRoomRolloffFactor; } -const char* ALsource::eax_get_occlusion_name() noexcept +void ALsource::eax_set_efx_air_absorption_factor() { - return "Occlusion"; + AirAbsorptionFactor = eax_.source.flAirAbsorptionFactor; } -const char* ALsource::eax_get_occlusion_lf_ratio_name() noexcept +void ALsource::eax_set_efx_dry_gain_hf_auto() { - return "Occlusion LF Ratio"; + DryGainHFAuto = ((eax_.source.ulFlags & EAXSOURCEFLAGS_DIRECTHFAUTO) != 0); } -const char* ALsource::eax_get_occlusion_direct_ratio_name() noexcept +void ALsource::eax_set_efx_wet_gain_auto() { - return "Occlusion Direct Ratio"; + WetGainAuto = ((eax_.source.ulFlags & EAXSOURCEFLAGS_ROOMAUTO) != 0); } -const char* ALsource::eax_get_occlusion_room_ratio_name() noexcept +void ALsource::eax_set_efx_wet_gain_hf_auto() { - return "Occlusion Room Ratio"; + WetGainHFAuto = ((eax_.source.ulFlags & EAXSOURCEFLAGS_ROOMHFAUTO) != 0); } -void ALsource::eax1_validate_reverb_mix(float reverb_mix) +void ALsource::eax1_set(const EaxCall& call, Eax1Props& props) { - if (reverb_mix == EAX_REVERBMIX_USEDISTANCE) - return; + switch (call.get_property_id()) { + case DSPROPERTY_EAXBUFFER_ALL: + eax_defer(call, props); + break; - eax_validate_range("Reverb Mix", reverb_mix, EAX_BUFFER_MINREVERBMIX, EAX_BUFFER_MAXREVERBMIX); -} + case DSPROPERTY_EAXBUFFER_REVERBMIX: + eax_defer(call, props.fMix); + break; -void ALsource::eax_validate_send_receiving_fx_slot_guid( - const GUID& guidReceivingFXSlotID) -{ - if (guidReceivingFXSlotID != EAXPROPERTYID_EAX40_FXSlot0 && - guidReceivingFXSlotID != EAXPROPERTYID_EAX50_FXSlot0 && - guidReceivingFXSlotID != EAXPROPERTYID_EAX40_FXSlot1 && - guidReceivingFXSlotID != EAXPROPERTYID_EAX50_FXSlot1 && - guidReceivingFXSlotID != EAXPROPERTYID_EAX40_FXSlot2 && - guidReceivingFXSlotID != EAXPROPERTYID_EAX50_FXSlot2 && - guidReceivingFXSlotID != EAXPROPERTYID_EAX40_FXSlot3 && - guidReceivingFXSlotID != EAXPROPERTYID_EAX50_FXSlot3) - { - throw EaxSourceSendException{"Unsupported receiving FX slot GUID."}; + default: + eax_fail_unknown_property_id(); } } -void ALsource::eax_validate_send_send( - long lSend) -{ - eax_validate_range( - "Send", - lSend, - EAXSOURCE_MINSEND, - EAXSOURCE_MAXSEND); -} - -void ALsource::eax_validate_send_send_hf( - long lSendHF) +void ALsource::eax2_set(const EaxCall& call, Eax2Props& props) { - eax_validate_range( - "Send HF", - lSendHF, - EAXSOURCE_MINSENDHF, - EAXSOURCE_MAXSENDHF); -} + switch (call.get_property_id()) { + case DSPROPERTY_EAX20BUFFER_NONE: + break; -void ALsource::eax_validate_send_occlusion( - long lOcclusion) -{ - eax_validate_range( - eax_get_occlusion_name(), - lOcclusion, - EAXSOURCE_MINOCCLUSION, - EAXSOURCE_MAXOCCLUSION); -} + case DSPROPERTY_EAX20BUFFER_ALLPARAMETERS: + eax_defer(call, props); + break; -void ALsource::eax_validate_send_occlusion_lf_ratio( - float flOcclusionLFRatio) -{ - eax_validate_range( - eax_get_occlusion_lf_ratio_name(), - flOcclusionLFRatio, - EAXSOURCE_MINOCCLUSIONLFRATIO, - EAXSOURCE_MAXOCCLUSIONLFRATIO); -} + case DSPROPERTY_EAX20BUFFER_DIRECT: + eax_defer(call, props.lDirect); + break; -void ALsource::eax_validate_send_occlusion_room_ratio( - float flOcclusionRoomRatio) -{ - eax_validate_range( - eax_get_occlusion_room_ratio_name(), - flOcclusionRoomRatio, - EAXSOURCE_MINOCCLUSIONROOMRATIO, - EAXSOURCE_MAXOCCLUSIONROOMRATIO); -} + case DSPROPERTY_EAX20BUFFER_DIRECTHF: + eax_defer(call, props.lDirectHF); + break; -void ALsource::eax_validate_send_occlusion_direct_ratio( - float flOcclusionDirectRatio) -{ - eax_validate_range( - eax_get_occlusion_direct_ratio_name(), - flOcclusionDirectRatio, - EAXSOURCE_MINOCCLUSIONDIRECTRATIO, - EAXSOURCE_MAXOCCLUSIONDIRECTRATIO); -} + case DSPROPERTY_EAX20BUFFER_ROOM: + eax_defer(call, props.lRoom); + break; -void ALsource::eax_validate_send_exclusion( - long lExclusion) -{ - eax_validate_range( - eax_get_exclusion_name(), - lExclusion, - EAXSOURCE_MINEXCLUSION, - EAXSOURCE_MAXEXCLUSION); -} + case DSPROPERTY_EAX20BUFFER_ROOMHF: + eax_defer(call, props.lRoomHF); + break; -void ALsource::eax_validate_send_exclusion_lf_ratio( - float flExclusionLFRatio) -{ - eax_validate_range( - eax_get_exclusion_lf_ratio_name(), - flExclusionLFRatio, - EAXSOURCE_MINEXCLUSIONLFRATIO, - EAXSOURCE_MAXEXCLUSIONLFRATIO); -} + case DSPROPERTY_EAX20BUFFER_ROOMROLLOFFFACTOR: + eax_defer(call, props.flRoomRolloffFactor); + break; -void ALsource::eax_validate_send( - const EAXSOURCESENDPROPERTIES& all) -{ - eax_validate_send_receiving_fx_slot_guid(all.guidReceivingFXSlotID); - eax_validate_send_send(all.lSend); - eax_validate_send_send_hf(all.lSendHF); -} + case DSPROPERTY_EAX20BUFFER_OBSTRUCTION: + eax_defer(call, props.lObstruction); + break; -void ALsource::eax_validate_send_exclusion_all( - const EAXSOURCEEXCLUSIONSENDPROPERTIES& all) -{ - eax_validate_send_receiving_fx_slot_guid(all.guidReceivingFXSlotID); - eax_validate_send_exclusion(all.lExclusion); - eax_validate_send_exclusion_lf_ratio(all.flExclusionLFRatio); -} + case DSPROPERTY_EAX20BUFFER_OBSTRUCTIONLFRATIO: + eax_defer(call, props.flObstructionLFRatio); + break; -void ALsource::eax_validate_send_occlusion_all( - const EAXSOURCEOCCLUSIONSENDPROPERTIES& all) -{ - eax_validate_send_receiving_fx_slot_guid(all.guidReceivingFXSlotID); - eax_validate_send_occlusion(all.lOcclusion); - eax_validate_send_occlusion_lf_ratio(all.flOcclusionLFRatio); - eax_validate_send_occlusion_room_ratio(all.flOcclusionRoomRatio); - eax_validate_send_occlusion_direct_ratio(all.flOcclusionDirectRatio); -} + case DSPROPERTY_EAX20BUFFER_OCCLUSION: + eax_defer(call, props.lOcclusion); + break; -void ALsource::eax_validate_send_all( - const EAXSOURCEALLSENDPROPERTIES& all) -{ - eax_validate_send_receiving_fx_slot_guid(all.guidReceivingFXSlotID); - eax_validate_send_send(all.lSend); - eax_validate_send_send_hf(all.lSendHF); - eax_validate_send_occlusion(all.lOcclusion); - eax_validate_send_occlusion_lf_ratio(all.flOcclusionLFRatio); - eax_validate_send_occlusion_room_ratio(all.flOcclusionRoomRatio); - eax_validate_send_occlusion_direct_ratio(all.flOcclusionDirectRatio); - eax_validate_send_exclusion(all.lExclusion); - eax_validate_send_exclusion_lf_ratio(all.flExclusionLFRatio); -} + case DSPROPERTY_EAX20BUFFER_OCCLUSIONLFRATIO: + eax_defer(call, props.flOcclusionLFRatio); + break; -EaxFxSlotIndexValue ALsource::eax_get_send_index( - const GUID& send_guid) -{ - if (false) - { - } - else if (send_guid == EAXPROPERTYID_EAX40_FXSlot0 || send_guid == EAXPROPERTYID_EAX50_FXSlot0) - { - return 0; - } - else if (send_guid == EAXPROPERTYID_EAX40_FXSlot1 || send_guid == EAXPROPERTYID_EAX50_FXSlot1) - { - return 1; - } - else if (send_guid == EAXPROPERTYID_EAX40_FXSlot2 || send_guid == EAXPROPERTYID_EAX50_FXSlot2) - { - return 2; - } - else if (send_guid == EAXPROPERTYID_EAX40_FXSlot3 || send_guid == EAXPROPERTYID_EAX50_FXSlot3) - { - return 3; - } - else - { - throw EaxSourceSendException{"Unsupported receiving FX slot GUID."}; - } -} + case DSPROPERTY_EAX20BUFFER_OCCLUSIONROOMRATIO: + eax_defer(call, props.flOcclusionRoomRatio); + break; -void ALsource::eax_defer_send_send( - long lSend, - EaxFxSlotIndexValue index) -{ - eax_d_.sends[index].lSend = lSend; + case DSPROPERTY_EAX20BUFFER_OUTSIDEVOLUMEHF: + eax_defer(call, props.lOutsideVolumeHF); + break; - eax_sends_dirty_flags_.sends[index].lSend = - (eax_.sends[index].lSend != eax_d_.sends[index].lSend); -} + case DSPROPERTY_EAX20BUFFER_AIRABSORPTIONFACTOR: + eax_defer(call, props.flAirAbsorptionFactor); + break; -void ALsource::eax_defer_send_send_hf( - long lSendHF, - EaxFxSlotIndexValue index) -{ - eax_d_.sends[index].lSendHF = lSendHF; + case DSPROPERTY_EAX20BUFFER_FLAGS: + eax_defer(call, props.dwFlags); + break; - eax_sends_dirty_flags_.sends[index].lSendHF = - (eax_.sends[index].lSendHF != eax_d_.sends[index].lSendHF); + default: + eax_fail_unknown_property_id(); + } } -void ALsource::eax_defer_send_occlusion( - long lOcclusion, - EaxFxSlotIndexValue index) +void ALsource::eax3_set(const EaxCall& call, Eax3Props& props) { - eax_d_.sends[index].lOcclusion = lOcclusion; + switch (call.get_property_id()) { + case EAXSOURCE_NONE: + break; - eax_sends_dirty_flags_.sends[index].lOcclusion = - (eax_.sends[index].lOcclusion != eax_d_.sends[index].lOcclusion); -} + case EAXSOURCE_ALLPARAMETERS: + eax_defer(call, props); + break; -void ALsource::eax_defer_send_occlusion_lf_ratio( - float flOcclusionLFRatio, - EaxFxSlotIndexValue index) -{ - eax_d_.sends[index].flOcclusionLFRatio = flOcclusionLFRatio; + case EAXSOURCE_OBSTRUCTIONPARAMETERS: + eax_defer_sub(call, props.lObstruction); + break; - eax_sends_dirty_flags_.sends[index].flOcclusionLFRatio = - (eax_.sends[index].flOcclusionLFRatio != eax_d_.sends[index].flOcclusionLFRatio); -} - -void ALsource::eax_defer_send_occlusion_room_ratio( - float flOcclusionRoomRatio, - EaxFxSlotIndexValue index) -{ - eax_d_.sends[index].flOcclusionRoomRatio = flOcclusionRoomRatio; - - eax_sends_dirty_flags_.sends[index].flOcclusionRoomRatio = - (eax_.sends[index].flOcclusionRoomRatio != eax_d_.sends[index].flOcclusionRoomRatio); -} - -void ALsource::eax_defer_send_occlusion_direct_ratio( - float flOcclusionDirectRatio, - EaxFxSlotIndexValue index) -{ - eax_d_.sends[index].flOcclusionDirectRatio = flOcclusionDirectRatio; - - eax_sends_dirty_flags_.sends[index].flOcclusionDirectRatio = - (eax_.sends[index].flOcclusionDirectRatio != eax_d_.sends[index].flOcclusionDirectRatio); -} - -void ALsource::eax_defer_send_exclusion( - long lExclusion, - EaxFxSlotIndexValue index) -{ - eax_d_.sends[index].lExclusion = lExclusion; - - eax_sends_dirty_flags_.sends[index].lExclusion = - (eax_.sends[index].lExclusion != eax_d_.sends[index].lExclusion); -} - -void ALsource::eax_defer_send_exclusion_lf_ratio( - float flExclusionLFRatio, - EaxFxSlotIndexValue index) -{ - eax_d_.sends[index].flExclusionLFRatio = flExclusionLFRatio; - - eax_sends_dirty_flags_.sends[index].flExclusionLFRatio = - (eax_.sends[index].flExclusionLFRatio != eax_d_.sends[index].flExclusionLFRatio); -} - -void ALsource::eax_defer_send( - const EAXSOURCESENDPROPERTIES& all, - EaxFxSlotIndexValue index) -{ - eax_defer_send_send(all.lSend, index); - eax_defer_send_send_hf(all.lSendHF, index); -} - -void ALsource::eax_defer_send_exclusion_all( - const EAXSOURCEEXCLUSIONSENDPROPERTIES& all, - EaxFxSlotIndexValue index) -{ - eax_defer_send_exclusion(all.lExclusion, index); - eax_defer_send_exclusion_lf_ratio(all.flExclusionLFRatio, index); -} - -void ALsource::eax_defer_send_occlusion_all( - const EAXSOURCEOCCLUSIONSENDPROPERTIES& all, - EaxFxSlotIndexValue index) -{ - eax_defer_send_occlusion(all.lOcclusion, index); - eax_defer_send_occlusion_lf_ratio(all.flOcclusionLFRatio, index); - eax_defer_send_occlusion_room_ratio(all.flOcclusionRoomRatio, index); - eax_defer_send_occlusion_direct_ratio(all.flOcclusionDirectRatio, index); -} - -void ALsource::eax_defer_send_all( - const EAXSOURCEALLSENDPROPERTIES& all, - EaxFxSlotIndexValue index) -{ - eax_defer_send_send(all.lSend, index); - eax_defer_send_send_hf(all.lSendHF, index); - eax_defer_send_occlusion(all.lOcclusion, index); - eax_defer_send_occlusion_lf_ratio(all.flOcclusionLFRatio, index); - eax_defer_send_occlusion_room_ratio(all.flOcclusionRoomRatio, index); - eax_defer_send_occlusion_direct_ratio(all.flOcclusionDirectRatio, index); - eax_defer_send_exclusion(all.lExclusion, index); - eax_defer_send_exclusion_lf_ratio(all.flExclusionLFRatio, index); -} - -void ALsource::eax_defer_send( - const EaxEaxCall& eax_call) -{ - const auto eax_all_span = - eax_call.get_values(); - - const auto count = eax_all_span.size(); - - if (count <= 0 || count > EAX_MAX_FXSLOTS) - { - throw EaxSourceSendException{"Send count out of range."}; - } - - for (auto i = std::size_t{}; i < count; ++i) - { - const auto& all = eax_all_span[i]; - eax_validate_send(all); - } - - for (auto i = std::size_t{}; i < count; ++i) - { - const auto& all = eax_all_span[i]; - const auto send_index = eax_get_send_index(all.guidReceivingFXSlotID); - eax_defer_send(all, send_index); - } -} - -void ALsource::eax_defer_send_exclusion_all( - const EaxEaxCall& eax_call) -{ - const auto eax_all_span = - eax_call.get_values(); - - const auto count = eax_all_span.size(); - - if (count <= 0 || count > EAX_MAX_FXSLOTS) - { - throw EaxSourceSendException{"Send exclusion all count out of range."}; - } - - for (auto i = std::size_t{}; i < count; ++i) - { - const auto& all = eax_all_span[i]; - eax_validate_send_exclusion_all(all); - } - - for (auto i = std::size_t{}; i < count; ++i) - { - const auto& all = eax_all_span[i]; - const auto send_index = eax_get_send_index(all.guidReceivingFXSlotID); - eax_defer_send_exclusion_all(all, send_index); - } -} - -void ALsource::eax_defer_send_occlusion_all( - const EaxEaxCall& eax_call) -{ - const auto eax_all_span = - eax_call.get_values(); - - const auto count = eax_all_span.size(); - - if (count <= 0 || count > EAX_MAX_FXSLOTS) - { - throw EaxSourceSendException{"Send occlusion all count out of range."}; - } - - for (auto i = std::size_t{}; i < count; ++i) - { - const auto& all = eax_all_span[i]; - eax_validate_send_occlusion_all(all); - } - - for (auto i = std::size_t{}; i < count; ++i) - { - const auto& all = eax_all_span[i]; - const auto send_index = eax_get_send_index(all.guidReceivingFXSlotID); - eax_defer_send_occlusion_all(all, send_index); - } -} - -void ALsource::eax_defer_send_all( - const EaxEaxCall& eax_call) -{ - const auto eax_all_span = - eax_call.get_values(); - - const auto count = eax_all_span.size(); - - if (count <= 0 || count > EAX_MAX_FXSLOTS) - { - throw EaxSourceSendException{"Send all count out of range."}; - } - - for (auto i = std::size_t{}; i < count; ++i) - { - const auto& all = eax_all_span[i]; - eax_validate_send_all(all); - } - - for (auto i = std::size_t{}; i < count; ++i) - { - const auto& all = eax_all_span[i]; - const auto send_index = eax_get_send_index(all.guidReceivingFXSlotID); - eax_defer_send_all(all, send_index); - } -} - - -void ALsource::eax_validate_source_direct( - long direct) -{ - eax_validate_range( - "Direct", - direct, - EAXSOURCE_MINDIRECT, - EAXSOURCE_MAXDIRECT); -} - -void ALsource::eax_validate_source_direct_hf( - long direct_hf) -{ - eax_validate_range( - "Direct HF", - direct_hf, - EAXSOURCE_MINDIRECTHF, - EAXSOURCE_MAXDIRECTHF); -} - -void ALsource::eax_validate_source_room( - long room) -{ - eax_validate_range( - "Room", - room, - EAXSOURCE_MINROOM, - EAXSOURCE_MAXROOM); -} - -void ALsource::eax_validate_source_room_hf( - long room_hf) -{ - eax_validate_range( - "Room HF", - room_hf, - EAXSOURCE_MINROOMHF, - EAXSOURCE_MAXROOMHF); -} - -void ALsource::eax_validate_source_obstruction( - long obstruction) -{ - eax_validate_range( - "Obstruction", - obstruction, - EAXSOURCE_MINOBSTRUCTION, - EAXSOURCE_MAXOBSTRUCTION); -} - -void ALsource::eax_validate_source_obstruction_lf_ratio( - float obstruction_lf_ratio) -{ - eax_validate_range( - "Obstruction LF Ratio", - obstruction_lf_ratio, - EAXSOURCE_MINOBSTRUCTIONLFRATIO, - EAXSOURCE_MAXOBSTRUCTIONLFRATIO); -} - -void ALsource::eax_validate_source_occlusion( - long occlusion) -{ - eax_validate_range( - eax_get_occlusion_name(), - occlusion, - EAXSOURCE_MINOCCLUSION, - EAXSOURCE_MAXOCCLUSION); -} - -void ALsource::eax_validate_source_occlusion_lf_ratio( - float occlusion_lf_ratio) -{ - eax_validate_range( - eax_get_occlusion_lf_ratio_name(), - occlusion_lf_ratio, - EAXSOURCE_MINOCCLUSIONLFRATIO, - EAXSOURCE_MAXOCCLUSIONLFRATIO); -} - -void ALsource::eax_validate_source_occlusion_room_ratio( - float occlusion_room_ratio) -{ - eax_validate_range( - eax_get_occlusion_room_ratio_name(), - occlusion_room_ratio, - EAXSOURCE_MINOCCLUSIONROOMRATIO, - EAXSOURCE_MAXOCCLUSIONROOMRATIO); -} - -void ALsource::eax_validate_source_occlusion_direct_ratio( - float occlusion_direct_ratio) -{ - eax_validate_range( - eax_get_occlusion_direct_ratio_name(), - occlusion_direct_ratio, - EAXSOURCE_MINOCCLUSIONDIRECTRATIO, - EAXSOURCE_MAXOCCLUSIONDIRECTRATIO); -} - -void ALsource::eax_validate_source_exclusion( - long exclusion) -{ - eax_validate_range( - eax_get_exclusion_name(), - exclusion, - EAXSOURCE_MINEXCLUSION, - EAXSOURCE_MAXEXCLUSION); -} - -void ALsource::eax_validate_source_exclusion_lf_ratio( - float exclusion_lf_ratio) -{ - eax_validate_range( - eax_get_exclusion_lf_ratio_name(), - exclusion_lf_ratio, - EAXSOURCE_MINEXCLUSIONLFRATIO, - EAXSOURCE_MAXEXCLUSIONLFRATIO); -} - -void ALsource::eax_validate_source_outside_volume_hf( - long outside_volume_hf) -{ - eax_validate_range( - "Outside Volume HF", - outside_volume_hf, - EAXSOURCE_MINOUTSIDEVOLUMEHF, - EAXSOURCE_MAXOUTSIDEVOLUMEHF); -} - -void ALsource::eax_validate_source_doppler_factor( - float doppler_factor) -{ - eax_validate_range( - "Doppler Factor", - doppler_factor, - EAXSOURCE_MINDOPPLERFACTOR, - EAXSOURCE_MAXDOPPLERFACTOR); -} - -void ALsource::eax_validate_source_rolloff_factor( - float rolloff_factor) -{ - eax_validate_range( - "Rolloff Factor", - rolloff_factor, - EAXSOURCE_MINROLLOFFFACTOR, - EAXSOURCE_MAXROLLOFFFACTOR); -} - -void ALsource::eax_validate_source_room_rolloff_factor( - float room_rolloff_factor) -{ - eax_validate_range( - "Room Rolloff Factor", - room_rolloff_factor, - EAXSOURCE_MINROOMROLLOFFFACTOR, - EAXSOURCE_MAXROOMROLLOFFFACTOR); -} - -void ALsource::eax_validate_source_air_absorption_factor( - float air_absorption_factor) -{ - eax_validate_range( - "Air Absorption Factor", - air_absorption_factor, - EAXSOURCE_MINAIRABSORPTIONFACTOR, - EAXSOURCE_MAXAIRABSORPTIONFACTOR); -} - -void ALsource::eax_validate_source_flags( - unsigned long flags, - int eax_version) -{ - eax_validate_range( - "Flags", - flags, - 0UL, - ~((eax_version == 5) ? EAX50SOURCEFLAGS_RESERVED : EAX20SOURCEFLAGS_RESERVED)); -} - -void ALsource::eax_validate_source_macro_fx_factor( - float macro_fx_factor) -{ - eax_validate_range( - "Macro FX Factor", - macro_fx_factor, - EAXSOURCE_MINMACROFXFACTOR, - EAXSOURCE_MAXMACROFXFACTOR); -} - -void ALsource::eax_validate_source_2d_all( - const EAXSOURCE2DPROPERTIES& all, - int eax_version) -{ - eax_validate_source_direct(all.lDirect); - eax_validate_source_direct_hf(all.lDirectHF); - eax_validate_source_room(all.lRoom); - eax_validate_source_room_hf(all.lRoomHF); - eax_validate_source_flags(all.ulFlags, eax_version); -} - -void ALsource::eax_validate_source_obstruction_all( - const EAXOBSTRUCTIONPROPERTIES& all) -{ - eax_validate_source_obstruction(all.lObstruction); - eax_validate_source_obstruction_lf_ratio(all.flObstructionLFRatio); -} - -void ALsource::eax_validate_source_exclusion_all( - const EAXEXCLUSIONPROPERTIES& all) -{ - eax_validate_source_exclusion(all.lExclusion); - eax_validate_source_exclusion_lf_ratio(all.flExclusionLFRatio); -} - -void ALsource::eax_validate_source_occlusion_all( - const EAXOCCLUSIONPROPERTIES& all) -{ - eax_validate_source_occlusion(all.lOcclusion); - eax_validate_source_occlusion_lf_ratio(all.flOcclusionLFRatio); - eax_validate_source_occlusion_room_ratio(all.flOcclusionRoomRatio); - eax_validate_source_occlusion_direct_ratio(all.flOcclusionDirectRatio); -} - -void ALsource::eax_validate_source_all( - const EAX20BUFFERPROPERTIES& all, - int eax_version) -{ - eax_validate_source_direct(all.lDirect); - eax_validate_source_direct_hf(all.lDirectHF); - eax_validate_source_room(all.lRoom); - eax_validate_source_room_hf(all.lRoomHF); - eax_validate_source_obstruction(all.lObstruction); - eax_validate_source_obstruction_lf_ratio(all.flObstructionLFRatio); - eax_validate_source_occlusion(all.lOcclusion); - eax_validate_source_occlusion_lf_ratio(all.flOcclusionLFRatio); - eax_validate_source_occlusion_room_ratio(all.flOcclusionRoomRatio); - eax_validate_source_outside_volume_hf(all.lOutsideVolumeHF); - eax_validate_source_room_rolloff_factor(all.flRoomRolloffFactor); - eax_validate_source_air_absorption_factor(all.flAirAbsorptionFactor); - eax_validate_source_flags(all.dwFlags, eax_version); -} - -void ALsource::eax_validate_source_all( - const EAX30SOURCEPROPERTIES& all, - int eax_version) -{ - eax_validate_source_direct(all.lDirect); - eax_validate_source_direct_hf(all.lDirectHF); - eax_validate_source_room(all.lRoom); - eax_validate_source_room_hf(all.lRoomHF); - eax_validate_source_obstruction(all.lObstruction); - eax_validate_source_obstruction_lf_ratio(all.flObstructionLFRatio); - eax_validate_source_occlusion(all.lOcclusion); - eax_validate_source_occlusion_lf_ratio(all.flOcclusionLFRatio); - eax_validate_source_occlusion_room_ratio(all.flOcclusionRoomRatio); - eax_validate_source_occlusion_direct_ratio(all.flOcclusionDirectRatio); - eax_validate_source_exclusion(all.lExclusion); - eax_validate_source_exclusion_lf_ratio(all.flExclusionLFRatio); - eax_validate_source_outside_volume_hf(all.lOutsideVolumeHF); - eax_validate_source_doppler_factor(all.flDopplerFactor); - eax_validate_source_rolloff_factor(all.flRolloffFactor); - eax_validate_source_room_rolloff_factor(all.flRoomRolloffFactor); - eax_validate_source_air_absorption_factor(all.flAirAbsorptionFactor); - eax_validate_source_flags(all.ulFlags, eax_version); -} - -void ALsource::eax_validate_source_all( - const EAX50SOURCEPROPERTIES& all, - int eax_version) -{ - eax_validate_source_all(static_cast(all), eax_version); - eax_validate_source_macro_fx_factor(all.flMacroFXFactor); -} - -void ALsource::eax_validate_source_speaker_id( - long speaker_id) -{ - eax_validate_range( - "Speaker Id", - speaker_id, - static_cast(EAXSPEAKER_FRONT_LEFT), - static_cast(EAXSPEAKER_LOW_FREQUENCY)); -} - -void ALsource::eax_validate_source_speaker_level( - long speaker_level) -{ - eax_validate_range( - "Speaker Level", - speaker_level, - EAXSOURCE_MINSPEAKERLEVEL, - EAXSOURCE_MAXSPEAKERLEVEL); -} - -void ALsource::eax_validate_source_speaker_level_all( - const EAXSPEAKERLEVELPROPERTIES& all) -{ - eax_validate_source_speaker_id(all.lSpeakerID); - eax_validate_source_speaker_level(all.lLevel); -} - -void ALsource::eax_defer_source_direct( - long lDirect) -{ - eax_d_.source.lDirect = lDirect; - eax_source_dirty_filter_flags_.lDirect = (eax_.source.lDirect != eax_d_.source.lDirect); -} - -void ALsource::eax_defer_source_direct_hf( - long lDirectHF) -{ - eax_d_.source.lDirectHF = lDirectHF; - eax_source_dirty_filter_flags_.lDirectHF = (eax_.source.lDirectHF != eax_d_.source.lDirectHF); -} - -void ALsource::eax_defer_source_room( - long lRoom) -{ - eax_d_.source.lRoom = lRoom; - eax_source_dirty_filter_flags_.lRoom = (eax_.source.lRoom != eax_d_.source.lRoom); -} - -void ALsource::eax_defer_source_room_hf( - long lRoomHF) -{ - eax_d_.source.lRoomHF = lRoomHF; - eax_source_dirty_filter_flags_.lRoomHF = (eax_.source.lRoomHF != eax_d_.source.lRoomHF); -} - -void ALsource::eax_defer_source_obstruction( - long lObstruction) -{ - eax_d_.source.lObstruction = lObstruction; - eax_source_dirty_filter_flags_.lObstruction = (eax_.source.lObstruction != eax_d_.source.lObstruction); -} - -void ALsource::eax_defer_source_obstruction_lf_ratio( - float flObstructionLFRatio) -{ - eax_d_.source.flObstructionLFRatio = flObstructionLFRatio; - eax_source_dirty_filter_flags_.flObstructionLFRatio = (eax_.source.flObstructionLFRatio != eax_d_.source.flObstructionLFRatio); -} - -void ALsource::eax_defer_source_occlusion( - long lOcclusion) -{ - eax_d_.source.lOcclusion = lOcclusion; - eax_source_dirty_filter_flags_.lOcclusion = (eax_.source.lOcclusion != eax_d_.source.lOcclusion); -} - -void ALsource::eax_defer_source_occlusion_lf_ratio( - float flOcclusionLFRatio) -{ - eax_d_.source.flOcclusionLFRatio = flOcclusionLFRatio; - eax_source_dirty_filter_flags_.flOcclusionLFRatio = (eax_.source.flOcclusionLFRatio != eax_d_.source.flOcclusionLFRatio); -} - -void ALsource::eax_defer_source_occlusion_room_ratio( - float flOcclusionRoomRatio) -{ - eax_d_.source.flOcclusionRoomRatio = flOcclusionRoomRatio; - eax_source_dirty_filter_flags_.flOcclusionRoomRatio = (eax_.source.flOcclusionRoomRatio != eax_d_.source.flOcclusionRoomRatio); -} - -void ALsource::eax_defer_source_occlusion_direct_ratio( - float flOcclusionDirectRatio) -{ - eax_d_.source.flOcclusionDirectRatio = flOcclusionDirectRatio; - eax_source_dirty_filter_flags_.flOcclusionDirectRatio = (eax_.source.flOcclusionDirectRatio != eax_d_.source.flOcclusionDirectRatio); -} - -void ALsource::eax_defer_source_exclusion( - long lExclusion) -{ - eax_d_.source.lExclusion = lExclusion; - eax_source_dirty_filter_flags_.lExclusion = (eax_.source.lExclusion != eax_d_.source.lExclusion); -} - -void ALsource::eax_defer_source_exclusion_lf_ratio( - float flExclusionLFRatio) -{ - eax_d_.source.flExclusionLFRatio = flExclusionLFRatio; - eax_source_dirty_filter_flags_.flExclusionLFRatio = (eax_.source.flExclusionLFRatio != eax_d_.source.flExclusionLFRatio); -} - -void ALsource::eax_defer_source_outside_volume_hf( - long lOutsideVolumeHF) -{ - eax_d_.source.lOutsideVolumeHF = lOutsideVolumeHF; - eax_source_dirty_misc_flags_.lOutsideVolumeHF = (eax_.source.lOutsideVolumeHF != eax_d_.source.lOutsideVolumeHF); -} - -void ALsource::eax_defer_source_doppler_factor( - float flDopplerFactor) -{ - eax_d_.source.flDopplerFactor = flDopplerFactor; - eax_source_dirty_misc_flags_.flDopplerFactor = (eax_.source.flDopplerFactor != eax_d_.source.flDopplerFactor); -} - -void ALsource::eax_defer_source_rolloff_factor( - float flRolloffFactor) -{ - eax_d_.source.flRolloffFactor = flRolloffFactor; - eax_source_dirty_misc_flags_.flRolloffFactor = (eax_.source.flRolloffFactor != eax_d_.source.flRolloffFactor); -} - -void ALsource::eax_defer_source_room_rolloff_factor( - float flRoomRolloffFactor) -{ - eax_d_.source.flRoomRolloffFactor = flRoomRolloffFactor; - eax_source_dirty_misc_flags_.flRoomRolloffFactor = (eax_.source.flRoomRolloffFactor != eax_d_.source.flRoomRolloffFactor); -} - -void ALsource::eax_defer_source_air_absorption_factor( - float flAirAbsorptionFactor) -{ - eax_d_.source.flAirAbsorptionFactor = flAirAbsorptionFactor; - eax_source_dirty_misc_flags_.flAirAbsorptionFactor = (eax_.source.flAirAbsorptionFactor != eax_d_.source.flAirAbsorptionFactor); -} - -void ALsource::eax_defer_source_flags( - unsigned long ulFlags) -{ - eax_d_.source.ulFlags = ulFlags; - eax_source_dirty_misc_flags_.ulFlags = (eax_.source.ulFlags != eax_d_.source.ulFlags); -} - -void ALsource::eax_defer_source_macro_fx_factor( - float flMacroFXFactor) -{ - eax_d_.source.flMacroFXFactor = flMacroFXFactor; - eax_source_dirty_misc_flags_.flMacroFXFactor = (eax_.source.flMacroFXFactor != eax_d_.source.flMacroFXFactor); -} - -void ALsource::eax_defer_source_2d_all( - const EAXSOURCE2DPROPERTIES& all) -{ - eax_defer_source_direct(all.lDirect); - eax_defer_source_direct_hf(all.lDirectHF); - eax_defer_source_room(all.lRoom); - eax_defer_source_room_hf(all.lRoomHF); - eax_defer_source_flags(all.ulFlags); -} - -void ALsource::eax_defer_source_obstruction_all( - const EAXOBSTRUCTIONPROPERTIES& all) -{ - eax_defer_source_obstruction(all.lObstruction); - eax_defer_source_obstruction_lf_ratio(all.flObstructionLFRatio); -} - -void ALsource::eax_defer_source_exclusion_all( - const EAXEXCLUSIONPROPERTIES& all) -{ - eax_defer_source_exclusion(all.lExclusion); - eax_defer_source_exclusion_lf_ratio(all.flExclusionLFRatio); -} - -void ALsource::eax_defer_source_occlusion_all( - const EAXOCCLUSIONPROPERTIES& all) -{ - eax_defer_source_occlusion(all.lOcclusion); - eax_defer_source_occlusion_lf_ratio(all.flOcclusionLFRatio); - eax_defer_source_occlusion_room_ratio(all.flOcclusionRoomRatio); - eax_defer_source_occlusion_direct_ratio(all.flOcclusionDirectRatio); -} - -void ALsource::eax_defer_source_all( - const EAX20BUFFERPROPERTIES& all) -{ - eax_defer_source_direct(all.lDirect); - eax_defer_source_direct_hf(all.lDirectHF); - eax_defer_source_room(all.lRoom); - eax_defer_source_room_hf(all.lRoomHF); - eax_defer_source_obstruction(all.lObstruction); - eax_defer_source_obstruction_lf_ratio(all.flObstructionLFRatio); - eax_defer_source_occlusion(all.lOcclusion); - eax_defer_source_occlusion_lf_ratio(all.flOcclusionLFRatio); - eax_defer_source_occlusion_room_ratio(all.flOcclusionRoomRatio); - eax_defer_source_outside_volume_hf(all.lOutsideVolumeHF); - eax_defer_source_room_rolloff_factor(all.flRoomRolloffFactor); - eax_defer_source_air_absorption_factor(all.flAirAbsorptionFactor); - eax_defer_source_flags(all.dwFlags); -} - -void ALsource::eax_defer_source_all( - const EAX30SOURCEPROPERTIES& all) -{ - eax_defer_source_direct(all.lDirect); - eax_defer_source_direct_hf(all.lDirectHF); - eax_defer_source_room(all.lRoom); - eax_defer_source_room_hf(all.lRoomHF); - eax_defer_source_obstruction(all.lObstruction); - eax_defer_source_obstruction_lf_ratio(all.flObstructionLFRatio); - eax_defer_source_occlusion(all.lOcclusion); - eax_defer_source_occlusion_lf_ratio(all.flOcclusionLFRatio); - eax_defer_source_occlusion_room_ratio(all.flOcclusionRoomRatio); - eax_defer_source_occlusion_direct_ratio(all.flOcclusionDirectRatio); - eax_defer_source_exclusion(all.lExclusion); - eax_defer_source_exclusion_lf_ratio(all.flExclusionLFRatio); - eax_defer_source_outside_volume_hf(all.lOutsideVolumeHF); - eax_defer_source_doppler_factor(all.flDopplerFactor); - eax_defer_source_rolloff_factor(all.flRolloffFactor); - eax_defer_source_room_rolloff_factor(all.flRoomRolloffFactor); - eax_defer_source_air_absorption_factor(all.flAirAbsorptionFactor); - eax_defer_source_flags(all.ulFlags); -} - -void ALsource::eax_defer_source_all( - const EAX50SOURCEPROPERTIES& all) -{ - eax_defer_source_all(static_cast(all)); - eax_defer_source_macro_fx_factor(all.flMacroFXFactor); -} - -void ALsource::eax_defer_source_speaker_level_all( - const EAXSPEAKERLEVELPROPERTIES& all) -{ - const auto speaker_index = static_cast(all.lSpeakerID - 1); - auto& speaker_level_d = eax_d_.speaker_levels[speaker_index]; - const auto& speaker_level = eax_.speaker_levels[speaker_index]; - - if (speaker_level != speaker_level_d) - { - eax_source_dirty_misc_flags_.speaker_levels = true; - } -} - -void ALsource::eax1_set_efx() -{ - const auto primary_fx_slot_index = eax_al_context_->eax_get_primary_fx_slot_index(); - - if (!primary_fx_slot_index.has_value()) - return; - - WetGainAuto = (eax1_.fMix == EAX_REVERBMIX_USEDISTANCE); - const auto filter_gain = (WetGainAuto ? 1.0F : eax1_.fMix); - auto& fx_slot = eax_al_context_->eax_get_fx_slot(*primary_fx_slot_index); - eax_set_al_source_send(&fx_slot, *primary_fx_slot_index, EaxAlLowPassParam{filter_gain, 1.0F}); - mPropsDirty = true; -} - -void ALsource::eax1_set_reverb_mix(const EaxEaxCall& eax_call) -{ - const auto reverb_mix = eax_call.get_value(); - eax1_validate_reverb_mix(reverb_mix); - - if (eax1_.fMix == reverb_mix) - return; - - eax1_.fMix = reverb_mix; - eax1_set_efx(); -} - -void ALsource::eax_defer_source_direct( - const EaxEaxCall& eax_call) -{ - const auto direct = - eax_call.get_value(); - - eax_validate_source_direct(direct); - eax_defer_source_direct(direct); -} - -void ALsource::eax_defer_source_direct_hf( - const EaxEaxCall& eax_call) -{ - const auto direct_hf = - eax_call.get_value(); - - eax_validate_source_direct_hf(direct_hf); - eax_defer_source_direct_hf(direct_hf); -} - -void ALsource::eax_defer_source_room( - const EaxEaxCall& eax_call) -{ - const auto room = - eax_call.get_value(); - - eax_validate_source_room(room); - eax_defer_source_room(room); -} - -void ALsource::eax_defer_source_room_hf( - const EaxEaxCall& eax_call) -{ - const auto room_hf = - eax_call.get_value(); - - eax_validate_source_room_hf(room_hf); - eax_defer_source_room_hf(room_hf); -} - -void ALsource::eax_defer_source_obstruction( - const EaxEaxCall& eax_call) -{ - const auto obstruction = - eax_call.get_value(); - - eax_validate_source_obstruction(obstruction); - eax_defer_source_obstruction(obstruction); -} - -void ALsource::eax_defer_source_obstruction_lf_ratio( - const EaxEaxCall& eax_call) -{ - const auto obstruction_lf_ratio = - eax_call.get_value(); - - eax_validate_source_obstruction_lf_ratio(obstruction_lf_ratio); - eax_defer_source_obstruction_lf_ratio(obstruction_lf_ratio); -} - -void ALsource::eax_defer_source_occlusion( - const EaxEaxCall& eax_call) -{ - const auto occlusion = - eax_call.get_value(); - - eax_validate_source_occlusion(occlusion); - eax_defer_source_occlusion(occlusion); -} - -void ALsource::eax_defer_source_occlusion_lf_ratio( - const EaxEaxCall& eax_call) -{ - const auto occlusion_lf_ratio = - eax_call.get_value(); - - eax_validate_source_occlusion_lf_ratio(occlusion_lf_ratio); - eax_defer_source_occlusion_lf_ratio(occlusion_lf_ratio); -} - -void ALsource::eax_defer_source_occlusion_room_ratio( - const EaxEaxCall& eax_call) -{ - const auto occlusion_room_ratio = - eax_call.get_value(); - - eax_validate_source_occlusion_room_ratio(occlusion_room_ratio); - eax_defer_source_occlusion_room_ratio(occlusion_room_ratio); -} - -void ALsource::eax_defer_source_occlusion_direct_ratio( - const EaxEaxCall& eax_call) -{ - const auto occlusion_direct_ratio = - eax_call.get_value(); - - eax_validate_source_occlusion_direct_ratio(occlusion_direct_ratio); - eax_defer_source_occlusion_direct_ratio(occlusion_direct_ratio); -} - -void ALsource::eax_defer_source_exclusion( - const EaxEaxCall& eax_call) -{ - const auto exclusion = - eax_call.get_value(); - - eax_validate_source_exclusion(exclusion); - eax_defer_source_exclusion(exclusion); -} - -void ALsource::eax_defer_source_exclusion_lf_ratio( - const EaxEaxCall& eax_call) -{ - const auto exclusion_lf_ratio = - eax_call.get_value(); - - eax_validate_source_exclusion_lf_ratio(exclusion_lf_ratio); - eax_defer_source_exclusion_lf_ratio(exclusion_lf_ratio); -} - -void ALsource::eax_defer_source_outside_volume_hf( - const EaxEaxCall& eax_call) -{ - const auto outside_volume_hf = - eax_call.get_value(); - - eax_validate_source_outside_volume_hf(outside_volume_hf); - eax_defer_source_outside_volume_hf(outside_volume_hf); -} - -void ALsource::eax_defer_source_doppler_factor( - const EaxEaxCall& eax_call) -{ - const auto doppler_factor = - eax_call.get_value(); - - eax_validate_source_doppler_factor(doppler_factor); - eax_defer_source_doppler_factor(doppler_factor); -} - -void ALsource::eax_defer_source_rolloff_factor( - const EaxEaxCall& eax_call) -{ - const auto rolloff_factor = - eax_call.get_value(); - - eax_validate_source_rolloff_factor(rolloff_factor); - eax_defer_source_rolloff_factor(rolloff_factor); -} - -void ALsource::eax_defer_source_room_rolloff_factor( - const EaxEaxCall& eax_call) -{ - const auto room_rolloff_factor = - eax_call.get_value(); - - eax_validate_source_room_rolloff_factor(room_rolloff_factor); - eax_defer_source_room_rolloff_factor(room_rolloff_factor); -} - -void ALsource::eax_defer_source_air_absorption_factor( - const EaxEaxCall& eax_call) -{ - const auto air_absorption_factor = - eax_call.get_value(); - - eax_validate_source_air_absorption_factor(air_absorption_factor); - eax_defer_source_air_absorption_factor(air_absorption_factor); -} - -void ALsource::eax_defer_source_flags( - const EaxEaxCall& eax_call) -{ - const auto flags = - eax_call.get_value(); - - eax_validate_source_flags(flags, eax_call.get_version()); - eax_defer_source_flags(flags); -} - -void ALsource::eax_defer_source_macro_fx_factor( - const EaxEaxCall& eax_call) -{ - const auto macro_fx_factor = - eax_call.get_value(); - - eax_validate_source_macro_fx_factor(macro_fx_factor); - eax_defer_source_macro_fx_factor(macro_fx_factor); -} - -void ALsource::eax_defer_source_2d_all( - const EaxEaxCall& eax_call) -{ - const auto all = eax_call.get_value(); - - eax_validate_source_2d_all(all, eax_call.get_version()); - eax_defer_source_2d_all(all); -} - -void ALsource::eax_defer_source_obstruction_all( - const EaxEaxCall& eax_call) -{ - const auto all = eax_call.get_value(); - - eax_validate_source_obstruction_all(all); - eax_defer_source_obstruction_all(all); -} - -void ALsource::eax_defer_source_exclusion_all( - const EaxEaxCall& eax_call) -{ - const auto all = eax_call.get_value(); - - eax_validate_source_exclusion_all(all); - eax_defer_source_exclusion_all(all); -} - -void ALsource::eax_defer_source_occlusion_all( - const EaxEaxCall& eax_call) -{ - const auto all = eax_call.get_value(); - - eax_validate_source_occlusion_all(all); - eax_defer_source_occlusion_all(all); -} - -void ALsource::eax_defer_source_all( - const EaxEaxCall& eax_call) -{ - const auto eax_version = eax_call.get_version(); - - if (eax_version == 2) - { - const auto all = eax_call.get_value(); - - eax_validate_source_all(all, eax_version); - eax_defer_source_all(all); - } - else if (eax_version < 5) - { - const auto all = eax_call.get_value(); - - eax_validate_source_all(all, eax_version); - eax_defer_source_all(all); - } - else - { - const auto all = eax_call.get_value(); + case EAXSOURCE_OCCLUSIONPARAMETERS: + eax_defer_sub(call, props.lOcclusion); + break; - eax_validate_source_all(all, eax_version); - eax_defer_source_all(all); - } -} + case EAXSOURCE_EXCLUSIONPARAMETERS: + eax_defer_sub(call, props.lExclusion); + break; -void ALsource::eax_defer_source_speaker_level_all( - const EaxEaxCall& eax_call) -{ - const auto speaker_level_properties = eax_call.get_value(); + case EAXSOURCE_DIRECT: + eax_defer(call, props.lDirect); + break; - eax_validate_source_speaker_level_all(speaker_level_properties); - eax_defer_source_speaker_level_all(speaker_level_properties); -} + case EAXSOURCE_DIRECTHF: + eax_defer(call, props.lDirectHF); + break; -void ALsource::eax_set_outside_volume_hf() -{ - const auto efx_gain_hf = clamp( - level_mb_to_gain(static_cast(eax_.source.lOutsideVolumeHF)), - AL_MIN_CONE_OUTER_GAINHF, - AL_MAX_CONE_OUTER_GAINHF - ); + case EAXSOURCE_ROOM: + eax_defer(call, props.lRoom); + break; - OuterGainHF = efx_gain_hf; -} + case EAXSOURCE_ROOMHF: + eax_defer(call, props.lRoomHF); + break; -void ALsource::eax_set_doppler_factor() -{ - DopplerFactor = eax_.source.flDopplerFactor; -} + case EAXSOURCE_OBSTRUCTION: + eax_defer(call, props.lObstruction); + break; -void ALsource::eax_set_rolloff_factor() -{ - RolloffFactor2 = eax_.source.flRolloffFactor; -} + case EAXSOURCE_OBSTRUCTIONLFRATIO: + eax_defer(call, props.flObstructionLFRatio); + break; -void ALsource::eax_set_room_rolloff_factor() -{ - RoomRolloffFactor = eax_.source.flRoomRolloffFactor; -} + case EAXSOURCE_OCCLUSION: + eax_defer(call, props.lOcclusion); + break; -void ALsource::eax_set_air_absorption_factor() -{ - AirAbsorptionFactor = eax_.source.flAirAbsorptionFactor; -} + case EAXSOURCE_OCCLUSIONLFRATIO: + eax_defer(call, props.flOcclusionLFRatio); + break; -void ALsource::eax_set_direct_hf_auto_flag() -{ - const auto is_enable = (eax_.source.ulFlags & EAXSOURCEFLAGS_DIRECTHFAUTO) != 0; + case EAXSOURCE_OCCLUSIONROOMRATIO: + eax_defer(call, props.flOcclusionRoomRatio); + break; - DryGainHFAuto = is_enable; -} + case EAXSOURCE_OCCLUSIONDIRECTRATIO: + eax_defer(call, props.flOcclusionDirectRatio); + break; -void ALsource::eax_set_room_auto_flag() -{ - const auto is_enable = (eax_.source.ulFlags & EAXSOURCEFLAGS_ROOMAUTO) != 0; + case EAXSOURCE_EXCLUSION: + eax_defer(call, props.lExclusion); + break; - WetGainAuto = is_enable; -} + case EAXSOURCE_EXCLUSIONLFRATIO: + eax_defer(call, props.flExclusionLFRatio); + break; -void ALsource::eax_set_room_hf_auto_flag() -{ - const auto is_enable = (eax_.source.ulFlags & EAXSOURCEFLAGS_ROOMHFAUTO) != 0; + case EAXSOURCE_OUTSIDEVOLUMEHF: + eax_defer(call, props.lOutsideVolumeHF); + break; - WetGainHFAuto = is_enable; -} + case EAXSOURCE_DOPPLERFACTOR: + eax_defer(call, props.flDopplerFactor); + break; -void ALsource::eax_set_flags() -{ - eax_set_direct_hf_auto_flag(); - eax_set_room_auto_flag(); - eax_set_room_hf_auto_flag(); - eax_set_speaker_levels(); -} + case EAXSOURCE_ROLLOFFFACTOR: + eax_defer(call, props.flRolloffFactor); + break; -void ALsource::eax_set_macro_fx_factor() -{ - // TODO -} + case EAXSOURCE_ROOMROLLOFFFACTOR: + eax_defer(call, props.flRoomRolloffFactor); + break; -void ALsource::eax_set_speaker_levels() -{ - // TODO -} + case EAXSOURCE_AIRABSORPTIONFACTOR: + eax_defer(call, props.flAirAbsorptionFactor); + break; -void ALsource::eax1_set(const EaxEaxCall& eax_call) -{ - switch (eax_call.get_property_id()) - { - case DSPROPERTY_EAXBUFFER_ALL: - case DSPROPERTY_EAXBUFFER_REVERBMIX: - eax1_set_reverb_mix(eax_call); + case EAXSOURCE_FLAGS: + eax_defer(call, props.ulFlags); break; default: - eax_fail("Unsupported property id."); + eax_fail_unknown_property_id(); } } -void ALsource::eax_apply_deferred() +void ALsource::eax4_set(const EaxCall& call, Eax4Props& props) { - if (!eax_are_active_fx_slots_dirty_ && - eax_sends_dirty_flags_ == EaxSourceSendsDirtyFlags{} && - eax_source_dirty_filter_flags_ == EaxSourceSourceFilterDirtyFlags{} && - eax_source_dirty_misc_flags_ == EaxSourceSourceMiscDirtyFlags{}) - { - return; - } - - eax_ = eax_d_; - - if (eax_are_active_fx_slots_dirty_) - { - eax_are_active_fx_slots_dirty_ = false; - eax_set_fx_slots(); - eax_update_filters_internal(); - } - else if (eax_has_active_fx_slots_) - { - if (eax_source_dirty_filter_flags_ != EaxSourceSourceFilterDirtyFlags{}) - { - eax_update_filters_internal(); - } - else if (eax_sends_dirty_flags_ != EaxSourceSendsDirtyFlags{}) - { - for (auto i = std::size_t{}; i < EAX_MAX_FXSLOTS; ++i) - { - if (eax_active_fx_slots_[i]) - { - if (eax_sends_dirty_flags_.sends[i] != EaxSourceSendDirtyFlags{}) - { - eax_update_filters_internal(); - break; - } - } - } - } - } - - if (eax_source_dirty_misc_flags_ != EaxSourceSourceMiscDirtyFlags{}) - { - if (eax_source_dirty_misc_flags_.lOutsideVolumeHF) - { - eax_set_outside_volume_hf(); - } - - if (eax_source_dirty_misc_flags_.flDopplerFactor) - { - eax_set_doppler_factor(); - } - - if (eax_source_dirty_misc_flags_.flRolloffFactor) - { - eax_set_rolloff_factor(); - } + switch (call.get_property_id()) { + case EAXSOURCE_NONE: + case EAXSOURCE_ALLPARAMETERS: + case EAXSOURCE_OBSTRUCTIONPARAMETERS: + case EAXSOURCE_OCCLUSIONPARAMETERS: + case EAXSOURCE_EXCLUSIONPARAMETERS: + case EAXSOURCE_DIRECT: + case EAXSOURCE_DIRECTHF: + case EAXSOURCE_ROOM: + case EAXSOURCE_ROOMHF: + case EAXSOURCE_OBSTRUCTION: + case EAXSOURCE_OBSTRUCTIONLFRATIO: + case EAXSOURCE_OCCLUSION: + case EAXSOURCE_OCCLUSIONLFRATIO: + case EAXSOURCE_OCCLUSIONROOMRATIO: + case EAXSOURCE_OCCLUSIONDIRECTRATIO: + case EAXSOURCE_EXCLUSION: + case EAXSOURCE_EXCLUSIONLFRATIO: + case EAXSOURCE_OUTSIDEVOLUMEHF: + case EAXSOURCE_DOPPLERFACTOR: + case EAXSOURCE_ROLLOFFFACTOR: + case EAXSOURCE_ROOMROLLOFFFACTOR: + case EAXSOURCE_AIRABSORPTIONFACTOR: + case EAXSOURCE_FLAGS: + eax3_set(call, props.source); + break; - if (eax_source_dirty_misc_flags_.flRoomRolloffFactor) - { - eax_set_room_rolloff_factor(); - } + case EAXSOURCE_SENDPARAMETERS: + eax4_defer_sends(call, props.sends); + break; - if (eax_source_dirty_misc_flags_.flAirAbsorptionFactor) - { - eax_set_air_absorption_factor(); - } + case EAXSOURCE_ALLSENDPARAMETERS: + eax4_defer_sends(call, props.sends); + break; - if (eax_source_dirty_misc_flags_.ulFlags) - { - eax_set_flags(); - } + case EAXSOURCE_OCCLUSIONSENDPARAMETERS: + eax4_defer_sends(call, props.sends); + break; - if (eax_source_dirty_misc_flags_.flMacroFXFactor) - { - eax_set_macro_fx_factor(); - } + case EAXSOURCE_EXCLUSIONSENDPARAMETERS: + eax4_defer_sends(call, props.sends); + break; - mPropsDirty = true; + case EAXSOURCE_ACTIVEFXSLOTID: + eax4_defer_active_fx_slot_id(call, props.active_fx_slots.guidActiveFXSlots); + break; - eax_source_dirty_misc_flags_ = EaxSourceSourceMiscDirtyFlags{}; + default: + eax_fail_unknown_property_id(); } +} - eax_sends_dirty_flags_ = EaxSourceSendsDirtyFlags{}; - eax_source_dirty_filter_flags_ = EaxSourceSourceFilterDirtyFlags{}; +void ALsource::eax5_defer_all_2d(const EaxCall& call, EAX50SOURCEPROPERTIES& props) +{ + const auto& src_props = call.get_value(); + Eax5SourceAll2dValidator{}(src_props); + props.lDirect = src_props.lDirect; + props.lDirectHF = src_props.lDirectHF; + props.lRoom = src_props.lRoom; + props.lRoomHF = src_props.lRoomHF; + props.ulFlags = src_props.ulFlags; } -void ALsource::eax_set( - const EaxEaxCall& eax_call) +void ALsource::eax5_defer_speaker_levels(const EaxCall& call, EaxSpeakerLevels& props) { - if (eax_call.get_version() == 1) - { - eax1_set(eax_call); - return; + const auto values = call.get_values(eax_max_speakers); + std::for_each(values.cbegin(), values.cend(), Eax5SpeakerAllValidator{}); + + for (const auto& value : values) { + const auto index = static_cast(value.lSpeakerID - EAXSPEAKER_FRONT_LEFT); + props[index].lLevel = value.lLevel; } +} - switch (eax_call.get_property_id()) - { +void ALsource::eax5_set(const EaxCall& call, Eax5Props& props) +{ + switch (call.get_property_id()) { case EAXSOURCE_NONE: break; case EAXSOURCE_ALLPARAMETERS: - eax_defer_source_all(eax_call); + eax_defer(call, props.source); break; case EAXSOURCE_OBSTRUCTIONPARAMETERS: - eax_defer_source_obstruction_all(eax_call); - break; - case EAXSOURCE_OCCLUSIONPARAMETERS: - eax_defer_source_occlusion_all(eax_call); - break; - case EAXSOURCE_EXCLUSIONPARAMETERS: - eax_defer_source_exclusion_all(eax_call); - break; - case EAXSOURCE_DIRECT: - eax_defer_source_direct(eax_call); - break; - case EAXSOURCE_DIRECTHF: - eax_defer_source_direct_hf(eax_call); - break; - case EAXSOURCE_ROOM: - eax_defer_source_room(eax_call); - break; - case EAXSOURCE_ROOMHF: - eax_defer_source_room_hf(eax_call); - break; - case EAXSOURCE_OBSTRUCTION: - eax_defer_source_obstruction(eax_call); - break; - case EAXSOURCE_OBSTRUCTIONLFRATIO: - eax_defer_source_obstruction_lf_ratio(eax_call); - break; - case EAXSOURCE_OCCLUSION: - eax_defer_source_occlusion(eax_call); - break; - case EAXSOURCE_OCCLUSIONLFRATIO: - eax_defer_source_occlusion_lf_ratio(eax_call); - break; - case EAXSOURCE_OCCLUSIONROOMRATIO: - eax_defer_source_occlusion_room_ratio(eax_call); - break; - case EAXSOURCE_OCCLUSIONDIRECTRATIO: - eax_defer_source_occlusion_direct_ratio(eax_call); - break; - case EAXSOURCE_EXCLUSION: - eax_defer_source_exclusion(eax_call); - break; - case EAXSOURCE_EXCLUSIONLFRATIO: - eax_defer_source_exclusion_lf_ratio(eax_call); - break; - case EAXSOURCE_OUTSIDEVOLUMEHF: - eax_defer_source_outside_volume_hf(eax_call); - break; - case EAXSOURCE_DOPPLERFACTOR: - eax_defer_source_doppler_factor(eax_call); - break; - case EAXSOURCE_ROLLOFFFACTOR: - eax_defer_source_rolloff_factor(eax_call); - break; - case EAXSOURCE_ROOMROLLOFFFACTOR: - eax_defer_source_room_rolloff_factor(eax_call); - break; - case EAXSOURCE_AIRABSORPTIONFACTOR: - eax_defer_source_air_absorption_factor(eax_call); - break; - case EAXSOURCE_FLAGS: - eax_defer_source_flags(eax_call); + eax3_set(call, props.source); break; case EAXSOURCE_SENDPARAMETERS: - eax_defer_send(eax_call); + eax5_defer_sends(call, props.sends); break; case EAXSOURCE_ALLSENDPARAMETERS: - eax_defer_send_all(eax_call); + eax5_defer_sends(call, props.sends); break; case EAXSOURCE_OCCLUSIONSENDPARAMETERS: - eax_defer_send_occlusion_all(eax_call); + eax5_defer_sends(call, props.sends); break; case EAXSOURCE_EXCLUSIONSENDPARAMETERS: - eax_defer_send_exclusion_all(eax_call); + eax5_defer_sends(call, props.sends); break; case EAXSOURCE_ACTIVEFXSLOTID: - eax_defer_active_fx_slots(eax_call); + eax5_defer_active_fx_slot_id(call, props.active_fx_slots.guidActiveFXSlots); break; case EAXSOURCE_MACROFXFACTOR: - eax_defer_source_macro_fx_factor(eax_call); + eax_defer(call, props.source.flMacroFXFactor); break; case EAXSOURCE_SPEAKERLEVELS: - eax_defer_source_speaker_level_all(eax_call); + eax5_defer_speaker_levels(call, props.speaker_levels); break; case EAXSOURCE_ALL2DPARAMETERS: - eax_defer_source_2d_all(eax_call); + eax5_defer_all_2d(call, props.source); break; default: - eax_fail("Unsupported property id."); + eax_fail_unknown_property_id(); } } -const GUID& ALsource::eax_get_send_fx_slot_guid( - int eax_version, - EaxFxSlotIndexValue fx_slot_index) +void ALsource::eax_set(const EaxCall& call) { - switch (eax_version) + const auto eax_version = call.get_version(); + switch(eax_version) { - case 4: - switch (fx_slot_index) - { - case 0: - return EAXPROPERTYID_EAX40_FXSlot0; - - case 1: - return EAXPROPERTYID_EAX40_FXSlot1; - - case 2: - return EAXPROPERTYID_EAX40_FXSlot2; - - case 3: - return EAXPROPERTYID_EAX40_FXSlot3; - - default: - eax_fail("FX slot index out of range."); - } - - case 5: - switch (fx_slot_index) - { - case 0: - return EAXPROPERTYID_EAX50_FXSlot0; - - case 1: - return EAXPROPERTYID_EAX50_FXSlot1; - - case 2: - return EAXPROPERTYID_EAX50_FXSlot2; - - case 3: - return EAXPROPERTYID_EAX50_FXSlot3; - - default: - eax_fail("FX slot index out of range."); - } - - default: - eax_fail("Unsupported EAX version."); + case 1: eax1_set(call, eax1_.d); break; + case 2: eax2_set(call, eax2_.d); break; + case 3: eax3_set(call, eax3_.d); break; + case 4: eax4_set(call, eax4_.d); break; + case 5: eax5_set(call, eax5_.d); break; + default: eax_fail_unknown_property_id(); } + eax_changed_ = true; + eax_version_ = eax_version; } -void ALsource::eax_copy_send( - const EAXSOURCEALLSENDPROPERTIES& src_send, - EAXSOURCESENDPROPERTIES& dst_send) -{ - dst_send.lSend = src_send.lSend; - dst_send.lSendHF = src_send.lSendHF; -} - -void ALsource::eax_copy_send( - const EAXSOURCEALLSENDPROPERTIES& src_send, - EAXSOURCEALLSENDPROPERTIES& dst_send) -{ - dst_send = src_send; -} - -void ALsource::eax_copy_send( - const EAXSOURCEALLSENDPROPERTIES& src_send, - EAXSOURCEOCCLUSIONSENDPROPERTIES& dst_send) -{ - dst_send.lOcclusion = src_send.lOcclusion; - dst_send.flOcclusionLFRatio = src_send.flOcclusionLFRatio; - dst_send.flOcclusionRoomRatio = src_send.flOcclusionRoomRatio; - dst_send.flOcclusionDirectRatio = src_send.flOcclusionDirectRatio; -} - -void ALsource::eax_copy_send( - const EAXSOURCEALLSENDPROPERTIES& src_send, - EAXSOURCEEXCLUSIONSENDPROPERTIES& dst_send) -{ - dst_send.lExclusion = src_send.lExclusion; - dst_send.flExclusionLFRatio = src_send.flExclusionLFRatio; -} - -void ALsource::eax1_get(const EaxEaxCall& eax_call) +void ALsource::eax1_get(const EaxCall& call, const Eax1Props& props) { - switch (eax_call.get_property_id()) - { + switch (call.get_property_id()) { case DSPROPERTY_EAXBUFFER_ALL: case DSPROPERTY_EAXBUFFER_REVERBMIX: - eax_call.set_value(eax1_); + call.set_value(props.fMix); break; default: - eax_fail("Unsupported property id."); + eax_fail_unknown_property_id(); } } -void ALsource::eax_api_get_source_all_v2( - const EaxEaxCall& eax_call) +void ALsource::eax2_get(const EaxCall& call, const Eax2Props& props) { - auto eax_2_all = EAX20BUFFERPROPERTIES{}; - eax_2_all.lDirect = eax_.source.lDirect; - eax_2_all.lDirectHF = eax_.source.lDirectHF; - eax_2_all.lRoom = eax_.source.lRoom; - eax_2_all.lRoomHF = eax_.source.lRoomHF; - eax_2_all.flRoomRolloffFactor = eax_.source.flRoomRolloffFactor; - eax_2_all.lObstruction = eax_.source.lObstruction; - eax_2_all.flObstructionLFRatio = eax_.source.flObstructionLFRatio; - eax_2_all.lOcclusion = eax_.source.lOcclusion; - eax_2_all.flOcclusionLFRatio = eax_.source.flOcclusionLFRatio; - eax_2_all.flOcclusionRoomRatio = eax_.source.flOcclusionRoomRatio; - eax_2_all.lOutsideVolumeHF = eax_.source.lOutsideVolumeHF; - eax_2_all.flAirAbsorptionFactor = eax_.source.flAirAbsorptionFactor; - eax_2_all.dwFlags = eax_.source.ulFlags; - - eax_call.set_value(eax_2_all); -} + switch (call.get_property_id()) { + case DSPROPERTY_EAX20BUFFER_NONE: + break; -void ALsource::eax_api_get_source_all_v3( - const EaxEaxCall& eax_call) -{ - eax_call.set_value(static_cast(eax_.source)); -} + case DSPROPERTY_EAX20BUFFER_ALLPARAMETERS: + call.set_value(props); + break; -void ALsource::eax_api_get_source_all_v5( - const EaxEaxCall& eax_call) -{ - eax_call.set_value(eax_.source); -} + case DSPROPERTY_EAX20BUFFER_DIRECT: + call.set_value(props.lDirect); + break; -void ALsource::eax_api_get_source_all( - const EaxEaxCall& eax_call) -{ - switch (eax_call.get_version()) - { - case 2: - eax_api_get_source_all_v2(eax_call); + case DSPROPERTY_EAX20BUFFER_DIRECTHF: + call.set_value(props.lDirectHF); break; - case 3: - case 4: - eax_api_get_source_all_v3(eax_call); + case DSPROPERTY_EAX20BUFFER_ROOM: + call.set_value(props.lRoom); break; - case 5: - eax_api_get_source_all_v5(eax_call); + case DSPROPERTY_EAX20BUFFER_ROOMHF: + call.set_value(props.lRoomHF); break; - default: - eax_fail("Unsupported EAX version."); - } -} + case DSPROPERTY_EAX20BUFFER_ROOMROLLOFFFACTOR: + call.set_value(props.flRoomRolloffFactor); + break; -void ALsource::eax_api_get_source_all_obstruction( - const EaxEaxCall& eax_call) -{ - auto eax_obstruction_all = EAXOBSTRUCTIONPROPERTIES{}; - eax_obstruction_all.lObstruction = eax_.source.lObstruction; - eax_obstruction_all.flObstructionLFRatio = eax_.source.flObstructionLFRatio; + case DSPROPERTY_EAX20BUFFER_OBSTRUCTION: + call.set_value(props.lObstruction); + break; - eax_call.set_value(eax_obstruction_all); -} + case DSPROPERTY_EAX20BUFFER_OBSTRUCTIONLFRATIO: + call.set_value(props.flObstructionLFRatio); + break; -void ALsource::eax_api_get_source_all_occlusion( - const EaxEaxCall& eax_call) -{ - auto eax_occlusion_all = EAXOCCLUSIONPROPERTIES{}; - eax_occlusion_all.lOcclusion = eax_.source.lOcclusion; - eax_occlusion_all.flOcclusionLFRatio = eax_.source.flOcclusionLFRatio; - eax_occlusion_all.flOcclusionRoomRatio = eax_.source.flOcclusionRoomRatio; - eax_occlusion_all.flOcclusionDirectRatio = eax_.source.flOcclusionDirectRatio; + case DSPROPERTY_EAX20BUFFER_OCCLUSION: + call.set_value(props.lOcclusion); + break; - eax_call.set_value(eax_occlusion_all); -} + case DSPROPERTY_EAX20BUFFER_OCCLUSIONLFRATIO: + call.set_value(props.flOcclusionLFRatio); + break; -void ALsource::eax_api_get_source_all_exclusion( - const EaxEaxCall& eax_call) -{ - auto eax_exclusion_all = EAXEXCLUSIONPROPERTIES{}; - eax_exclusion_all.lExclusion = eax_.source.lExclusion; - eax_exclusion_all.flExclusionLFRatio = eax_.source.flExclusionLFRatio; + case DSPROPERTY_EAX20BUFFER_OCCLUSIONROOMRATIO: + call.set_value(props.flOcclusionRoomRatio); + break; - eax_call.set_value(eax_exclusion_all); -} + case DSPROPERTY_EAX20BUFFER_OUTSIDEVOLUMEHF: + call.set_value(props.lOutsideVolumeHF); + break; -void ALsource::eax_api_get_source_active_fx_slot_id( - const EaxEaxCall& eax_call) -{ - switch (eax_call.get_version()) - { - case 4: - { - const auto& active_fx_slots = reinterpret_cast(eax_.active_fx_slots); - eax_call.set_value(active_fx_slots); - } + case DSPROPERTY_EAX20BUFFER_AIRABSORPTIONFACTOR: + call.set_value(props.flAirAbsorptionFactor); break; - case 5: - { - const auto& active_fx_slots = reinterpret_cast(eax_.active_fx_slots); - eax_call.set_value(active_fx_slots); - } + case DSPROPERTY_EAX20BUFFER_FLAGS: + call.set_value(props.dwFlags); break; default: - eax_fail("Unsupported EAX version."); + eax_fail_unknown_property_id(); } } -void ALsource::eax_api_get_source_all_2d( - const EaxEaxCall& eax_call) +void ALsource::eax3_get_obstruction(const EaxCall& call, const Eax3Props& props) { - auto eax_2d_all = EAXSOURCE2DPROPERTIES{}; - eax_2d_all.lDirect = eax_.source.lDirect; - eax_2d_all.lDirectHF = eax_.source.lDirectHF; - eax_2d_all.lRoom = eax_.source.lRoom; - eax_2d_all.lRoomHF = eax_.source.lRoomHF; - eax_2d_all.ulFlags = eax_.source.ulFlags; - - eax_call.set_value(eax_2d_all); + const auto& subprops = reinterpret_cast(props.lObstruction); + call.set_value(subprops); } -void ALsource::eax_api_get_source_speaker_level_all( - const EaxEaxCall& eax_call) +void ALsource::eax3_get_occlusion(const EaxCall& call, const Eax3Props& props) { - auto& all = eax_call.get_value(); - - eax_validate_source_speaker_id(all.lSpeakerID); - const auto speaker_index = static_cast(all.lSpeakerID - 1); - all.lLevel = eax_.speaker_levels[speaker_index]; + const auto& subprops = reinterpret_cast(props.lOcclusion); + call.set_value(subprops); } -void ALsource::eax_get( - const EaxEaxCall& eax_call) +void ALsource::eax3_get_exclusion(const EaxCall& call, const Eax3Props& props) { - if (eax_call.get_version() == 1) - { - eax1_get(eax_call); - return; - } + const auto& subprops = reinterpret_cast(props.lExclusion); + call.set_value(subprops); +} - switch (eax_call.get_property_id()) - { +void ALsource::eax3_get(const EaxCall& call, const Eax3Props& props) +{ + switch (call.get_property_id()) { case EAXSOURCE_NONE: break; case EAXSOURCE_ALLPARAMETERS: - eax_api_get_source_all(eax_call); + call.set_value(props); break; case EAXSOURCE_OBSTRUCTIONPARAMETERS: - eax_api_get_source_all_obstruction(eax_call); + eax3_get_obstruction(call, props); break; case EAXSOURCE_OCCLUSIONPARAMETERS: - eax_api_get_source_all_occlusion(eax_call); + eax3_get_occlusion(call, props); break; case EAXSOURCE_EXCLUSIONPARAMETERS: - eax_api_get_source_all_exclusion(eax_call); + eax3_get_exclusion(call, props); break; case EAXSOURCE_DIRECT: - eax_call.set_value(eax_.source.lDirect); + call.set_value(props.lDirect); break; case EAXSOURCE_DIRECTHF: - eax_call.set_value(eax_.source.lDirectHF); + call.set_value(props.lDirectHF); break; case EAXSOURCE_ROOM: - eax_call.set_value(eax_.source.lRoom); + call.set_value(props.lRoom); break; case EAXSOURCE_ROOMHF: - eax_call.set_value(eax_.source.lRoomHF); + call.set_value(props.lRoomHF); break; case EAXSOURCE_OBSTRUCTION: - eax_call.set_value(eax_.source.lObstruction); + call.set_value(props.lObstruction); break; case EAXSOURCE_OBSTRUCTIONLFRATIO: - eax_call.set_value(eax_.source.flObstructionLFRatio); + call.set_value(props.flObstructionLFRatio); break; case EAXSOURCE_OCCLUSION: - eax_call.set_value(eax_.source.lOcclusion); + call.set_value(props.lOcclusion); break; case EAXSOURCE_OCCLUSIONLFRATIO: - eax_call.set_value(eax_.source.flOcclusionLFRatio); + call.set_value(props.flOcclusionLFRatio); break; case EAXSOURCE_OCCLUSIONROOMRATIO: - eax_call.set_value(eax_.source.flOcclusionRoomRatio); + call.set_value(props.flOcclusionRoomRatio); break; case EAXSOURCE_OCCLUSIONDIRECTRATIO: - eax_call.set_value(eax_.source.flOcclusionDirectRatio); + call.set_value(props.flOcclusionDirectRatio); break; case EAXSOURCE_EXCLUSION: - eax_call.set_value(eax_.source.lExclusion); + call.set_value(props.lExclusion); break; case EAXSOURCE_EXCLUSIONLFRATIO: - eax_call.set_value(eax_.source.flExclusionLFRatio); + call.set_value(props.flExclusionLFRatio); break; case EAXSOURCE_OUTSIDEVOLUMEHF: - eax_call.set_value(eax_.source.lOutsideVolumeHF); + call.set_value(props.lOutsideVolumeHF); break; case EAXSOURCE_DOPPLERFACTOR: - eax_call.set_value(eax_.source.flDopplerFactor); + call.set_value(props.flDopplerFactor); break; case EAXSOURCE_ROLLOFFFACTOR: - eax_call.set_value(eax_.source.flRolloffFactor); + call.set_value(props.flRolloffFactor); break; case EAXSOURCE_ROOMROLLOFFFACTOR: - eax_call.set_value(eax_.source.flRoomRolloffFactor); + call.set_value(props.flRoomRolloffFactor); + break; + + case EAXSOURCE_AIRABSORPTIONFACTOR: + call.set_value(props.flAirAbsorptionFactor); + break; + + case EAXSOURCE_FLAGS: + call.set_value(props.ulFlags); break; + default: + eax_fail_unknown_property_id(); + } +} + +void ALsource::eax4_get(const EaxCall& call, const Eax4Props& props) +{ + switch (call.get_property_id()) { + case EAXSOURCE_NONE: + break; + + case EAXSOURCE_ALLPARAMETERS: + case EAXSOURCE_OBSTRUCTIONPARAMETERS: + case EAXSOURCE_OCCLUSIONPARAMETERS: + case EAXSOURCE_EXCLUSIONPARAMETERS: + case EAXSOURCE_DIRECT: + case EAXSOURCE_DIRECTHF: + case EAXSOURCE_ROOM: + case EAXSOURCE_ROOMHF: + case EAXSOURCE_OBSTRUCTION: + case EAXSOURCE_OBSTRUCTIONLFRATIO: + case EAXSOURCE_OCCLUSION: + case EAXSOURCE_OCCLUSIONLFRATIO: + case EAXSOURCE_OCCLUSIONROOMRATIO: + case EAXSOURCE_OCCLUSIONDIRECTRATIO: + case EAXSOURCE_EXCLUSION: + case EAXSOURCE_EXCLUSIONLFRATIO: + case EAXSOURCE_OUTSIDEVOLUMEHF: + case EAXSOURCE_DOPPLERFACTOR: + case EAXSOURCE_ROLLOFFFACTOR: + case EAXSOURCE_ROOMROLLOFFFACTOR: case EAXSOURCE_AIRABSORPTIONFACTOR: - eax_call.set_value(eax_.source.flAirAbsorptionFactor); + case EAXSOURCE_FLAGS: + eax3_get(call, props.source); + break; + + case EAXSOURCE_SENDPARAMETERS: + eax_get_sends(call, props.sends); + break; + + case EAXSOURCE_ALLSENDPARAMETERS: + eax_get_sends(call, props.sends); + break; + + case EAXSOURCE_OCCLUSIONSENDPARAMETERS: + eax_get_sends(call, props.sends); + break; + + case EAXSOURCE_EXCLUSIONSENDPARAMETERS: + eax_get_sends(call, props.sends); + break; + + case EAXSOURCE_ACTIVEFXSLOTID: + call.set_value(props.active_fx_slots); + break; + + default: + eax_fail_unknown_property_id(); + } +} + +void ALsource::eax5_get_all_2d(const EaxCall& call, const EAX50SOURCEPROPERTIES& props) +{ + auto& subprops = call.get_value(); + subprops.lDirect = props.lDirect; + subprops.lDirectHF = props.lDirectHF; + subprops.lRoom = props.lRoom; + subprops.lRoomHF = props.lRoomHF; + subprops.ulFlags = props.ulFlags; +} + +void ALsource::eax5_get_speaker_levels(const EaxCall& call, const EaxSpeakerLevels& props) +{ + const auto subprops = call.get_values(eax_max_speakers); + std::uninitialized_copy_n(props.cbegin(), subprops.size(), subprops.begin()); +} + +void ALsource::eax5_get(const EaxCall& call, const Eax5Props& props) +{ + switch (call.get_property_id()) { + case EAXSOURCE_NONE: break; + case EAXSOURCE_ALLPARAMETERS: + case EAXSOURCE_OBSTRUCTIONPARAMETERS: + case EAXSOURCE_OCCLUSIONPARAMETERS: + case EAXSOURCE_EXCLUSIONPARAMETERS: + case EAXSOURCE_DIRECT: + case EAXSOURCE_DIRECTHF: + case EAXSOURCE_ROOM: + case EAXSOURCE_ROOMHF: + case EAXSOURCE_OBSTRUCTION: + case EAXSOURCE_OBSTRUCTIONLFRATIO: + case EAXSOURCE_OCCLUSION: + case EAXSOURCE_OCCLUSIONLFRATIO: + case EAXSOURCE_OCCLUSIONROOMRATIO: + case EAXSOURCE_OCCLUSIONDIRECTRATIO: + case EAXSOURCE_EXCLUSION: + case EAXSOURCE_EXCLUSIONLFRATIO: + case EAXSOURCE_OUTSIDEVOLUMEHF: + case EAXSOURCE_DOPPLERFACTOR: + case EAXSOURCE_ROLLOFFFACTOR: + case EAXSOURCE_ROOMROLLOFFFACTOR: + case EAXSOURCE_AIRABSORPTIONFACTOR: case EAXSOURCE_FLAGS: - eax_call.set_value(eax_.source.ulFlags); + eax3_get(call, props.source); break; case EAXSOURCE_SENDPARAMETERS: - eax_api_get_send_properties(eax_call); + eax_get_sends(call, props.sends); break; case EAXSOURCE_ALLSENDPARAMETERS: - eax_api_get_send_properties(eax_call); + eax_get_sends(call, props.sends); break; case EAXSOURCE_OCCLUSIONSENDPARAMETERS: - eax_api_get_send_properties(eax_call); + eax_get_sends(call, props.sends); break; case EAXSOURCE_EXCLUSIONSENDPARAMETERS: - eax_api_get_send_properties(eax_call); + eax_get_sends(call, props.sends); break; case EAXSOURCE_ACTIVEFXSLOTID: - eax_api_get_source_active_fx_slot_id(eax_call); + call.set_value(props.active_fx_slots); break; case EAXSOURCE_MACROFXFACTOR: - eax_call.set_value(eax_.source.flMacroFXFactor); + call.set_value(props.source.flMacroFXFactor); break; case EAXSOURCE_SPEAKERLEVELS: - eax_api_get_source_speaker_level_all(eax_call); + call.set_value(props.speaker_levels); break; case EAXSOURCE_ALL2DPARAMETERS: - eax_api_get_source_all_2d(eax_call); + eax5_get_all_2d(call, props.source); break; default: - eax_fail("Unsupported property id."); + eax_fail_unknown_property_id(); + } +} + +void ALsource::eax_get(const EaxCall& call) +{ + switch (call.get_version()) { + case 1: eax1_get(call, eax1_.i); break; + case 2: eax2_get(call, eax2_.i); break; + case 3: eax3_get(call, eax3_.i); break; + case 4: eax4_get(call, eax4_.i); break; + case 5: eax5_get(call, eax5_.i); break; + default: eax_fail_unknown_version(); } } -void ALsource::eax_set_al_source_send( - ALeffectslot *slot, - size_t sendidx, - const EaxAlLowPassParam &filter) +void ALsource::eax_set_al_source_send(ALeffectslot *slot, size_t sendidx, const EaxAlLowPassParam &filter) { if(sendidx >= EAX_MAX_FXSLOTS) return; @@ -6057,12 +4847,98 @@ void ALsource::eax_set_al_source_send( send.GainLF = 1.0f; send.LFReference = HIGHPASSFREQREF; - if(slot) IncrementRef(slot->ref); + if(slot != nullptr) + IncrementRef(slot->ref); if(auto *oldslot = send.Slot) DecrementRef(oldslot->ref); - send.Slot = slot; + send.Slot = slot; mPropsDirty = true; } +void ALsource::eax_commit_active_fx_slots() +{ + // Mark all slots as non-active. + eax_active_fx_slots_.fill(false); + + // Mark primary FX slot as active. + if (eax_primary_fx_slot_id_.has_value()) + eax_active_fx_slots_[*eax_primary_fx_slot_id_] = true; + + // Mark the other FX slots as active. + for (const auto& slot_id : eax_.active_fx_slots.guidActiveFXSlots) { + if (slot_id == EAXPROPERTYID_EAX50_FXSlot0) + eax_active_fx_slots_[0] = true; + else if (slot_id == EAXPROPERTYID_EAX50_FXSlot1) + eax_active_fx_slots_[1] = true; + else if (slot_id == EAXPROPERTYID_EAX50_FXSlot2) + eax_active_fx_slots_[2] = true; + else if (slot_id == EAXPROPERTYID_EAX50_FXSlot3) + eax_active_fx_slots_[3] = true; + } + + // Deactivate EFX auxiliary effect slots. + for (auto i = size_t{}; i < EAX_MAX_FXSLOTS; ++i) { + if (!eax_active_fx_slots_[i]) + eax_set_al_source_send(nullptr, i, EaxAlLowPassParam{1.0f, 1.0f}); + } +} + +void ALsource::eax_commit_filters() +{ + eax_update_direct_filter(); + eax_update_room_filters(); +} + +void ALsource::eax_commit(EaxCommitType commit_type) +{ + const auto primary_fx_slot_id = eax_al_context_->eax_get_primary_fx_slot_index(); + const auto is_primary_fx_slot_id_changed = (eax_primary_fx_slot_id_ != primary_fx_slot_id); + + if(commit_type != EaxCommitType::forced && !is_primary_fx_slot_id_changed && !eax_changed_) + return; + + eax_primary_fx_slot_id_ = primary_fx_slot_id; + eax_changed_ = false; + + switch(eax_version_) + { + case 1: + eax1_.i = eax1_.d; + eax1_translate(eax1_.i, eax_); + break; + case 2: + eax2_.i = eax2_.d; + eax2_translate(eax2_.i, eax_); + break; + case 3: + eax3_.i = eax3_.d; + eax3_translate(eax3_.i, eax_); + break; + case 4: + eax4_.i = eax4_.d; + eax4_translate(eax4_.i, eax_); + break; + case 5: + eax5_.i = eax5_.d; + eax_ = eax5_.d; + break; + + default: + eax_fail_unknown_version(); + } + + eax_set_efx_outer_gain_hf(); + eax_set_efx_doppler_factor(); + eax_set_efx_rolloff_factor(); + eax_set_efx_room_rolloff_factor(); + eax_set_efx_air_absorption_factor(); + eax_set_efx_dry_gain_hf_auto(); + eax_set_efx_wet_gain_auto(); + eax_set_efx_wet_gain_hf_auto(); + + eax_commit_active_fx_slots(); + eax_commit_filters(); +} + #endif // ALSOFT_EAX diff --git a/modules/openal-soft/al/source.h b/modules/openal-soft/al/source.h index 6db6bfa..a1efd52 100644 --- a/modules/openal-soft/al/source.h +++ b/modules/openal-soft/al/source.h @@ -22,9 +22,10 @@ #include "vector.h" #ifdef ALSOFT_EAX -#include "eax_eax_call.h" -#include "eax_fx_slot_index.h" -#include "eax_utils.h" +#include "eax/call.h" +#include "eax/exception.h" +#include "eax/fx_slot_index.h" +#include "eax/utils.h" #endif // ALSOFT_EAX struct ALbuffer; @@ -48,67 +49,12 @@ struct ALbufferQueueItem : public VoiceBufferItem { #ifdef ALSOFT_EAX -using EaxSourceSourceFilterDirtyFlagsValue = std::uint_least16_t; - -struct EaxSourceSourceFilterDirtyFlags -{ - using EaxIsBitFieldStruct = bool; - - EaxSourceSourceFilterDirtyFlagsValue lDirect : 1; - EaxSourceSourceFilterDirtyFlagsValue lDirectHF : 1; - EaxSourceSourceFilterDirtyFlagsValue lRoom : 1; - EaxSourceSourceFilterDirtyFlagsValue lRoomHF : 1; - EaxSourceSourceFilterDirtyFlagsValue lObstruction : 1; - EaxSourceSourceFilterDirtyFlagsValue flObstructionLFRatio : 1; - EaxSourceSourceFilterDirtyFlagsValue lOcclusion : 1; - EaxSourceSourceFilterDirtyFlagsValue flOcclusionLFRatio : 1; - EaxSourceSourceFilterDirtyFlagsValue flOcclusionRoomRatio : 1; - EaxSourceSourceFilterDirtyFlagsValue flOcclusionDirectRatio : 1; - EaxSourceSourceFilterDirtyFlagsValue lExclusion : 1; - EaxSourceSourceFilterDirtyFlagsValue flExclusionLFRatio : 1; -}; // EaxSourceSourceFilterDirtyFlags - - -using EaxSourceSourceMiscDirtyFlagsValue = std::uint_least8_t; - -struct EaxSourceSourceMiscDirtyFlags -{ - using EaxIsBitFieldStruct = bool; - - EaxSourceSourceMiscDirtyFlagsValue lOutsideVolumeHF : 1; - EaxSourceSourceMiscDirtyFlagsValue flDopplerFactor : 1; - EaxSourceSourceMiscDirtyFlagsValue flRolloffFactor : 1; - EaxSourceSourceMiscDirtyFlagsValue flRoomRolloffFactor : 1; - EaxSourceSourceMiscDirtyFlagsValue flAirAbsorptionFactor : 1; - EaxSourceSourceMiscDirtyFlagsValue ulFlags : 1; - EaxSourceSourceMiscDirtyFlagsValue flMacroFXFactor : 1; - EaxSourceSourceMiscDirtyFlagsValue speaker_levels : 1; -}; // EaxSourceSourceMiscDirtyFlags - - -using EaxSourceSendDirtyFlagsValue = std::uint_least8_t; - -struct EaxSourceSendDirtyFlags -{ - using EaxIsBitFieldStruct = bool; - - EaxSourceSendDirtyFlagsValue lSend : 1; - EaxSourceSendDirtyFlagsValue lSendHF : 1; - EaxSourceSendDirtyFlagsValue lOcclusion : 1; - EaxSourceSendDirtyFlagsValue flOcclusionLFRatio : 1; - EaxSourceSendDirtyFlagsValue flOcclusionRoomRatio : 1; - EaxSourceSendDirtyFlagsValue flOcclusionDirectRatio : 1; - EaxSourceSendDirtyFlagsValue lExclusion : 1; - EaxSourceSendDirtyFlagsValue flExclusionLFRatio : 1; -}; // EaxSourceSendDirtyFlags - - -struct EaxSourceSendsDirtyFlags -{ - using EaxIsBitFieldStruct = bool; - - EaxSourceSendDirtyFlags sends[EAX_MAX_FXSLOTS]; -}; // EaxSourceSendsDirtyFlags +class EaxSourceException : public EaxException { +public: + explicit EaxSourceException(const char* message) + : EaxException{"EAX_SOURCE", message} + {} +}; #endif // ALSOFT_EAX struct ALsource { @@ -214,593 +160,889 @@ struct ALsource { #ifdef ALSOFT_EAX public: void eax_initialize(ALCcontext *context) noexcept; - - - void eax_dispatch(const EaxEaxCall& eax_call) - { eax_call.is_get() ? eax_get(eax_call) : eax_set(eax_call); } - - - void eax_update_filters(); - - void eax_update( - EaxContextSharedDirtyFlags dirty_flags); - - void eax_commit() { eax_apply_deferred(); } + void eax_dispatch(const EaxCall& call); + void eax_commit() { eax_commit(EaxCommitType::normal); } void eax_commit_and_update(); + bool eax_is_initialized() const noexcept { return eax_al_context_ != nullptr; } - bool eax_is_initialized() const noexcept { return eax_al_context_; } - - - static ALsource* eax_lookup_source( - ALCcontext& al_context, - ALuint source_id) noexcept; - + static ALsource* eax_lookup_source(ALCcontext& al_context, ALuint source_id) noexcept; private: - static constexpr auto eax_max_speakers = 9; - - - using EaxActiveFxSlots = std::array; - using EaxSpeakerLevels = std::array; - - struct Eax - { - using Sends = std::array; - - EAX50ACTIVEFXSLOTS active_fx_slots{}; - EAX50SOURCEPROPERTIES source{}; - Sends sends{}; - EaxSpeakerLevels speaker_levels{}; - }; // Eax - - - bool eax_uses_primary_id_{}; - bool eax_has_active_fx_slots_{}; - bool eax_are_active_fx_slots_dirty_{}; - - ALCcontext* eax_al_context_{}; - - EAXBUFFER_REVERBPROPERTIES eax1_{}; - Eax eax_{}; - Eax eax_d_{}; - EaxActiveFxSlots eax_active_fx_slots_{}; - - EaxSourceSendsDirtyFlags eax_sends_dirty_flags_{}; - EaxSourceSourceFilterDirtyFlags eax_source_dirty_filter_flags_{}; - EaxSourceSourceMiscDirtyFlags eax_source_dirty_misc_flags_{}; - - - [[noreturn]] - static void eax_fail( - const char* message); - - - void eax_set_source_defaults() noexcept; - void eax_set_active_fx_slots_defaults() noexcept; - void eax_set_send_defaults(EAXSOURCEALLSENDPROPERTIES& eax_send) noexcept; - void eax_set_sends_defaults() noexcept; - void eax_set_speaker_levels_defaults() noexcept; - void eax_set_defaults() noexcept; - - - static float eax_calculate_dst_occlusion_mb( - long src_occlusion_mb, - float path_ratio, - float lf_ratio) noexcept; - - EaxAlLowPassParam eax_create_direct_filter_param() const noexcept; - - EaxAlLowPassParam eax_create_room_filter_param( - const ALeffectslot& fx_slot, - const EAXSOURCEALLSENDPROPERTIES& send) const noexcept; - - void eax_set_fx_slots(); - - void eax_initialize_fx_slots(); - - void eax_update_direct_filter_internal(); - - void eax_update_room_filters_internal(); - - void eax_update_filters_internal(); - - void eax_update_primary_fx_slot_id(); - - - void eax_defer_active_fx_slots( - const EaxEaxCall& eax_call); - - - static const char* eax_get_exclusion_name() noexcept; - - static const char* eax_get_exclusion_lf_ratio_name() noexcept; - - - static const char* eax_get_occlusion_name() noexcept; - - static const char* eax_get_occlusion_lf_ratio_name() noexcept; - - static const char* eax_get_occlusion_direct_ratio_name() noexcept; - - static const char* eax_get_occlusion_room_ratio_name() noexcept; - - - static void eax1_validate_reverb_mix(float reverb_mix); - - static void eax_validate_send_receiving_fx_slot_guid( - const GUID& guidReceivingFXSlotID); - - static void eax_validate_send_send( - long lSend); - - static void eax_validate_send_send_hf( - long lSendHF); - - static void eax_validate_send_occlusion( - long lOcclusion); - - static void eax_validate_send_occlusion_lf_ratio( - float flOcclusionLFRatio); - - static void eax_validate_send_occlusion_room_ratio( - float flOcclusionRoomRatio); - - static void eax_validate_send_occlusion_direct_ratio( - float flOcclusionDirectRatio); - - static void eax_validate_send_exclusion( - long lExclusion); - - static void eax_validate_send_exclusion_lf_ratio( - float flExclusionLFRatio); - - static void eax_validate_send( - const EAXSOURCESENDPROPERTIES& all); - - static void eax_validate_send_exclusion_all( - const EAXSOURCEEXCLUSIONSENDPROPERTIES& all); - - static void eax_validate_send_occlusion_all( - const EAXSOURCEOCCLUSIONSENDPROPERTIES& all); - - static void eax_validate_send_all( - const EAXSOURCEALLSENDPROPERTIES& all); - - - static EaxFxSlotIndexValue eax_get_send_index( - const GUID& send_guid); - - - void eax_defer_send_send( - long lSend, - EaxFxSlotIndexValue index); - - void eax_defer_send_send_hf( - long lSendHF, - EaxFxSlotIndexValue index); - - void eax_defer_send_occlusion( - long lOcclusion, - EaxFxSlotIndexValue index); - - void eax_defer_send_occlusion_lf_ratio( - float flOcclusionLFRatio, - EaxFxSlotIndexValue index); - - void eax_defer_send_occlusion_room_ratio( - float flOcclusionRoomRatio, - EaxFxSlotIndexValue index); - - void eax_defer_send_occlusion_direct_ratio( - float flOcclusionDirectRatio, - EaxFxSlotIndexValue index); - - void eax_defer_send_exclusion( - long lExclusion, - EaxFxSlotIndexValue index); - - void eax_defer_send_exclusion_lf_ratio( - float flExclusionLFRatio, - EaxFxSlotIndexValue index); - - void eax_defer_send( - const EAXSOURCESENDPROPERTIES& all, - EaxFxSlotIndexValue index); - - void eax_defer_send_exclusion_all( - const EAXSOURCEEXCLUSIONSENDPROPERTIES& all, - EaxFxSlotIndexValue index); - - void eax_defer_send_occlusion_all( - const EAXSOURCEOCCLUSIONSENDPROPERTIES& all, - EaxFxSlotIndexValue index); - - void eax_defer_send_all( - const EAXSOURCEALLSENDPROPERTIES& all, - EaxFxSlotIndexValue index); - - - void eax_defer_send( - const EaxEaxCall& eax_call); - - void eax_defer_send_exclusion_all( - const EaxEaxCall& eax_call); - - void eax_defer_send_occlusion_all( - const EaxEaxCall& eax_call); - - void eax_defer_send_all( - const EaxEaxCall& eax_call); - - - static void eax_validate_source_direct( - long direct); - - static void eax_validate_source_direct_hf( - long direct_hf); - - static void eax_validate_source_room( - long room); - - static void eax_validate_source_room_hf( - long room_hf); - - static void eax_validate_source_obstruction( - long obstruction); - - static void eax_validate_source_obstruction_lf_ratio( - float obstruction_lf_ratio); - - static void eax_validate_source_occlusion( - long occlusion); - - static void eax_validate_source_occlusion_lf_ratio( - float occlusion_lf_ratio); - - static void eax_validate_source_occlusion_room_ratio( - float occlusion_room_ratio); - - static void eax_validate_source_occlusion_direct_ratio( - float occlusion_direct_ratio); - - static void eax_validate_source_exclusion( - long exclusion); - - static void eax_validate_source_exclusion_lf_ratio( - float exclusion_lf_ratio); - - static void eax_validate_source_outside_volume_hf( - long outside_volume_hf); - - static void eax_validate_source_doppler_factor( - float doppler_factor); - - static void eax_validate_source_rolloff_factor( - float rolloff_factor); - - static void eax_validate_source_room_rolloff_factor( - float room_rolloff_factor); - - static void eax_validate_source_air_absorption_factor( - float air_absorption_factor); - - static void eax_validate_source_flags( - unsigned long flags, - int eax_version); - - static void eax_validate_source_macro_fx_factor( - float macro_fx_factor); - - static void eax_validate_source_2d_all( - const EAXSOURCE2DPROPERTIES& all, - int eax_version); - - static void eax_validate_source_obstruction_all( - const EAXOBSTRUCTIONPROPERTIES& all); - - static void eax_validate_source_exclusion_all( - const EAXEXCLUSIONPROPERTIES& all); - - static void eax_validate_source_occlusion_all( - const EAXOCCLUSIONPROPERTIES& all); - - static void eax_validate_source_all( - const EAX20BUFFERPROPERTIES& all, - int eax_version); - - static void eax_validate_source_all( - const EAX30SOURCEPROPERTIES& all, - int eax_version); - - static void eax_validate_source_all( - const EAX50SOURCEPROPERTIES& all, - int eax_version); - - static void eax_validate_source_speaker_id( - long speaker_id); - - static void eax_validate_source_speaker_level( - long speaker_level); - - static void eax_validate_source_speaker_level_all( - const EAXSPEAKERLEVELPROPERTIES& all); + using Exception = EaxSourceException; + enum class EaxCommitType { + normal, + forced, + }; - void eax_defer_source_direct( - long lDirect); + static constexpr auto eax_max_speakers = 9; - void eax_defer_source_direct_hf( - long lDirectHF); + using EaxFxSlotIds = const GUID* [EAX_MAX_FXSLOTS]; - void eax_defer_source_room( - long lRoom); + static constexpr const EaxFxSlotIds eax4_fx_slot_ids = { + &EAXPROPERTYID_EAX40_FXSlot0, + &EAXPROPERTYID_EAX40_FXSlot1, + &EAXPROPERTYID_EAX40_FXSlot2, + &EAXPROPERTYID_EAX40_FXSlot3, + }; - void eax_defer_source_room_hf( - long lRoomHF); + static constexpr const EaxFxSlotIds eax5_fx_slot_ids = { + &EAXPROPERTYID_EAX50_FXSlot0, + &EAXPROPERTYID_EAX50_FXSlot1, + &EAXPROPERTYID_EAX50_FXSlot2, + &EAXPROPERTYID_EAX50_FXSlot3, + }; - void eax_defer_source_obstruction( - long lObstruction); + using EaxActiveFxSlots = std::array; + using EaxSpeakerLevels = std::array; + using EaxSends = std::array; - void eax_defer_source_obstruction_lf_ratio( - float flObstructionLFRatio); + using Eax1Props = EAXBUFFER_REVERBPROPERTIES; - void eax_defer_source_occlusion( - long lOcclusion); + struct Eax1State { + Eax1Props i; // Immediate. + Eax1Props d; // Deferred. + }; - void eax_defer_source_occlusion_lf_ratio( - float flOcclusionLFRatio); + using Eax2Props = EAX20BUFFERPROPERTIES; - void eax_defer_source_occlusion_room_ratio( - float flOcclusionRoomRatio); + struct Eax2State { + Eax2Props i; // Immediate. + Eax2Props d; // Deferred. + }; - void eax_defer_source_occlusion_direct_ratio( - float flOcclusionDirectRatio); + using Eax3Props = EAX30SOURCEPROPERTIES; - void eax_defer_source_exclusion( - long lExclusion); + struct Eax3State { + Eax3Props i; // Immediate. + Eax3Props d; // Deferred. + }; - void eax_defer_source_exclusion_lf_ratio( - float flExclusionLFRatio); + struct Eax4Props { + Eax3Props source; + EaxSends sends; + EAX40ACTIVEFXSLOTS active_fx_slots; - void eax_defer_source_outside_volume_hf( - long lOutsideVolumeHF); + bool operator==(const Eax4Props& rhs) noexcept + { + return std::memcmp(this, &rhs, sizeof(Eax4Props)) == 0; + } + }; - void eax_defer_source_doppler_factor( - float flDopplerFactor); + struct Eax4State { + Eax4Props i; // Immediate. + Eax4Props d; // Deferred. + }; - void eax_defer_source_rolloff_factor( - float flRolloffFactor); + struct Eax5Props { + EAX50SOURCEPROPERTIES source; + EaxSends sends; + EAX50ACTIVEFXSLOTS active_fx_slots; + EaxSpeakerLevels speaker_levels; - void eax_defer_source_room_rolloff_factor( - float flRoomRolloffFactor); + bool operator==(const Eax5Props& rhs) noexcept + { + return std::memcmp(this, &rhs, sizeof(Eax5Props)) == 0; + } + }; - void eax_defer_source_air_absorption_factor( - float flAirAbsorptionFactor); + struct Eax5State { + Eax5Props i; // Immediate. + Eax5Props d; // Deferred. + }; - void eax_defer_source_flags( - unsigned long ulFlags); + ALCcontext* eax_al_context_{}; + EaxFxSlotIndex eax_primary_fx_slot_id_{}; + EaxActiveFxSlots eax_active_fx_slots_{}; + int eax_version_{}; + bool eax_changed_{}; + Eax1State eax1_{}; + Eax2State eax2_{}; + Eax3State eax3_{}; + Eax4State eax4_{}; + Eax5State eax5_{}; + Eax5Props eax_{}; + + // ---------------------------------------------------------------------- + // Source validators + + struct Eax1SourceReverbMixValidator { + void operator()(float reverb_mix) const + { + if (reverb_mix == EAX_REVERBMIX_USEDISTANCE) + return; + + eax_validate_range( + "Reverb Mix", + reverb_mix, + EAX_BUFFER_MINREVERBMIX, + EAX_BUFFER_MAXREVERBMIX); + } + }; - void eax_defer_source_macro_fx_factor( - float flMacroFXFactor); + struct Eax2SourceDirectValidator { + void operator()(long lDirect) const + { + eax_validate_range( + "Direct", + lDirect, + EAXSOURCE_MINDIRECT, + EAXSOURCE_MAXDIRECT); + } + }; - void eax_defer_source_2d_all( - const EAXSOURCE2DPROPERTIES& all); + struct Eax2SourceDirectHfValidator { + void operator()(long lDirectHF) const + { + eax_validate_range( + "Direct HF", + lDirectHF, + EAXSOURCE_MINDIRECTHF, + EAXSOURCE_MAXDIRECTHF); + } + }; - void eax_defer_source_obstruction_all( - const EAXOBSTRUCTIONPROPERTIES& all); + struct Eax2SourceRoomValidator { + void operator()(long lRoom) const + { + eax_validate_range( + "Room", + lRoom, + EAXSOURCE_MINROOM, + EAXSOURCE_MAXROOM); + } + }; - void eax_defer_source_exclusion_all( - const EAXEXCLUSIONPROPERTIES& all); + struct Eax2SourceRoomHfValidator { + void operator()(long lRoomHF) const + { + eax_validate_range( + "Room HF", + lRoomHF, + EAXSOURCE_MINROOMHF, + EAXSOURCE_MAXROOMHF); + } + }; - void eax_defer_source_occlusion_all( - const EAXOCCLUSIONPROPERTIES& all); + struct Eax2SourceRoomRolloffFactorValidator { + void operator()(float flRoomRolloffFactor) const + { + eax_validate_range( + "Room Rolloff Factor", + flRoomRolloffFactor, + EAXSOURCE_MINROOMROLLOFFFACTOR, + EAXSOURCE_MAXROOMROLLOFFFACTOR); + } + }; - void eax_defer_source_all( - const EAX20BUFFERPROPERTIES& all); + struct Eax2SourceObstructionValidator { + void operator()(long lObstruction) const + { + eax_validate_range( + "Obstruction", + lObstruction, + EAXSOURCE_MINOBSTRUCTION, + EAXSOURCE_MAXOBSTRUCTION); + } + }; - void eax_defer_source_all( - const EAX30SOURCEPROPERTIES& all); + struct Eax2SourceObstructionLfRatioValidator { + void operator()(float flObstructionLFRatio) const + { + eax_validate_range( + "Obstruction LF Ratio", + flObstructionLFRatio, + EAXSOURCE_MINOBSTRUCTIONLFRATIO, + EAXSOURCE_MAXOBSTRUCTIONLFRATIO); + } + }; - void eax_defer_source_all( - const EAX50SOURCEPROPERTIES& all); + struct Eax2SourceOcclusionValidator { + void operator()(long lOcclusion) const + { + eax_validate_range( + "Occlusion", + lOcclusion, + EAXSOURCE_MINOCCLUSION, + EAXSOURCE_MAXOCCLUSION); + } + }; - void eax_defer_source_speaker_level_all( - const EAXSPEAKERLEVELPROPERTIES& all); + struct Eax2SourceOcclusionLfRatioValidator { + void operator()(float flOcclusionLFRatio) const + { + eax_validate_range( + "Occlusion LF Ratio", + flOcclusionLFRatio, + EAXSOURCE_MINOCCLUSIONLFRATIO, + EAXSOURCE_MAXOCCLUSIONLFRATIO); + } + }; + struct Eax2SourceOcclusionRoomRatioValidator { + void operator()(float flOcclusionRoomRatio) const + { + eax_validate_range( + "Occlusion Room Ratio", + flOcclusionRoomRatio, + EAXSOURCE_MINOCCLUSIONROOMRATIO, + EAXSOURCE_MAXOCCLUSIONROOMRATIO); + } + }; - void eax_defer_source_direct( - const EaxEaxCall& eax_call); + struct Eax2SourceOutsideVolumeHfValidator { + void operator()(long lOutsideVolumeHF) const + { + eax_validate_range( + "Outside Volume HF", + lOutsideVolumeHF, + EAXSOURCE_MINOUTSIDEVOLUMEHF, + EAXSOURCE_MAXOUTSIDEVOLUMEHF); + } + }; - void eax_defer_source_direct_hf( - const EaxEaxCall& eax_call); + struct Eax2SourceAirAbsorptionFactorValidator { + void operator()(float flAirAbsorptionFactor) const + { + eax_validate_range( + "Air Absorption Factor", + flAirAbsorptionFactor, + EAXSOURCE_MINAIRABSORPTIONFACTOR, + EAXSOURCE_MAXAIRABSORPTIONFACTOR); + } + }; - void eax_defer_source_room( - const EaxEaxCall& eax_call); + struct Eax2SourceFlagsValidator { + void operator()(unsigned long dwFlags) const + { + eax_validate_range( + "Flags", + dwFlags, + 0UL, + ~EAX20SOURCEFLAGS_RESERVED); + } + }; - void eax_defer_source_room_hf( - const EaxEaxCall& eax_call); + struct Eax3SourceOcclusionDirectRatioValidator { + void operator()(float flOcclusionDirectRatio) const + { + eax_validate_range( + "Occlusion Direct Ratio", + flOcclusionDirectRatio, + EAXSOURCE_MINOCCLUSIONDIRECTRATIO, + EAXSOURCE_MAXOCCLUSIONDIRECTRATIO); + } + }; - void eax_defer_source_obstruction( - const EaxEaxCall& eax_call); + struct Eax3SourceExclusionValidator { + void operator()(long lExclusion) const + { + eax_validate_range( + "Exclusion", + lExclusion, + EAXSOURCE_MINEXCLUSION, + EAXSOURCE_MAXEXCLUSION); + } + }; - void eax_defer_source_obstruction_lf_ratio( - const EaxEaxCall& eax_call); + struct Eax3SourceExclusionLfRatioValidator { + void operator()(float flExclusionLFRatio) const + { + eax_validate_range( + "Exclusion LF Ratio", + flExclusionLFRatio, + EAXSOURCE_MINEXCLUSIONLFRATIO, + EAXSOURCE_MAXEXCLUSIONLFRATIO); + } + }; - void eax_defer_source_occlusion( - const EaxEaxCall& eax_call); + struct Eax3SourceDopplerFactorValidator { + void operator()(float flDopplerFactor) const + { + eax_validate_range( + "Doppler Factor", + flDopplerFactor, + EAXSOURCE_MINDOPPLERFACTOR, + EAXSOURCE_MAXDOPPLERFACTOR); + } + }; - void eax_defer_source_occlusion_lf_ratio( - const EaxEaxCall& eax_call); + struct Eax3SourceRolloffFactorValidator { + void operator()(float flRolloffFactor) const + { + eax_validate_range( + "Rolloff Factor", + flRolloffFactor, + EAXSOURCE_MINROLLOFFFACTOR, + EAXSOURCE_MAXROLLOFFFACTOR); + } + }; - void eax_defer_source_occlusion_room_ratio( - const EaxEaxCall& eax_call); + struct Eax5SourceMacroFXFactorValidator { + void operator()(float flMacroFXFactor) const + { + eax_validate_range( + "Macro FX Factor", + flMacroFXFactor, + EAXSOURCE_MINMACROFXFACTOR, + EAXSOURCE_MAXMACROFXFACTOR); + } + }; - void eax_defer_source_occlusion_direct_ratio( - const EaxEaxCall& eax_call); + struct Eax5SourceFlagsValidator { + void operator()(unsigned long dwFlags) const + { + eax_validate_range( + "Flags", + dwFlags, + 0UL, + ~EAX50SOURCEFLAGS_RESERVED); + } + }; - void eax_defer_source_exclusion( - const EaxEaxCall& eax_call); + struct Eax1SourceAllValidator { + void operator()(const Eax1Props& props) const + { + Eax1SourceReverbMixValidator{}(props.fMix); + } + }; - void eax_defer_source_exclusion_lf_ratio( - const EaxEaxCall& eax_call); + struct Eax2SourceAllValidator { + void operator()(const Eax2Props& props) const + { + Eax2SourceDirectValidator{}(props.lDirect); + Eax2SourceDirectHfValidator{}(props.lDirectHF); + Eax2SourceRoomValidator{}(props.lRoom); + Eax2SourceRoomHfValidator{}(props.lRoomHF); + Eax2SourceRoomRolloffFactorValidator{}(props.flRoomRolloffFactor); + Eax2SourceObstructionValidator{}(props.lObstruction); + Eax2SourceObstructionLfRatioValidator{}(props.flObstructionLFRatio); + Eax2SourceOcclusionValidator{}(props.lOcclusion); + Eax2SourceOcclusionLfRatioValidator{}(props.flOcclusionLFRatio); + Eax2SourceOcclusionRoomRatioValidator{}(props.flOcclusionRoomRatio); + Eax2SourceOutsideVolumeHfValidator{}(props.lOutsideVolumeHF); + Eax2SourceAirAbsorptionFactorValidator{}(props.flAirAbsorptionFactor); + Eax2SourceFlagsValidator{}(props.dwFlags); + } + }; - void eax_defer_source_outside_volume_hf( - const EaxEaxCall& eax_call); + struct Eax3SourceAllValidator { + void operator()(const Eax3Props& props) const + { + Eax2SourceDirectValidator{}(props.lDirect); + Eax2SourceDirectHfValidator{}(props.lDirectHF); + Eax2SourceRoomValidator{}(props.lRoom); + Eax2SourceRoomHfValidator{}(props.lRoomHF); + Eax2SourceObstructionValidator{}(props.lObstruction); + Eax2SourceObstructionLfRatioValidator{}(props.flObstructionLFRatio); + Eax2SourceOcclusionValidator{}(props.lOcclusion); + Eax2SourceOcclusionLfRatioValidator{}(props.flOcclusionLFRatio); + Eax2SourceOcclusionRoomRatioValidator{}(props.flOcclusionRoomRatio); + Eax3SourceOcclusionDirectRatioValidator{}(props.flOcclusionDirectRatio); + Eax3SourceExclusionValidator{}(props.lExclusion); + Eax3SourceExclusionLfRatioValidator{}(props.flExclusionLFRatio); + Eax2SourceOutsideVolumeHfValidator{}(props.lOutsideVolumeHF); + Eax3SourceDopplerFactorValidator{}(props.flDopplerFactor); + Eax3SourceRolloffFactorValidator{}(props.flRolloffFactor); + Eax2SourceRoomRolloffFactorValidator{}(props.flRoomRolloffFactor); + Eax2SourceAirAbsorptionFactorValidator{}(props.flAirAbsorptionFactor); + Eax2SourceFlagsValidator{}(props.ulFlags); + } + }; - void eax_defer_source_doppler_factor( - const EaxEaxCall& eax_call); + struct Eax5SourceAllValidator { + void operator()(const EAX50SOURCEPROPERTIES& props) const + { + Eax3SourceAllValidator{}(static_cast(props)); + Eax5SourceMacroFXFactorValidator{}(props.flMacroFXFactor); + } + }; - void eax_defer_source_rolloff_factor( - const EaxEaxCall& eax_call); + struct Eax5SourceAll2dValidator { + void operator()(const EAXSOURCE2DPROPERTIES& props) const + { + Eax2SourceDirectValidator{}(props.lDirect); + Eax2SourceDirectHfValidator{}(props.lDirectHF); + Eax2SourceRoomValidator{}(props.lRoom); + Eax2SourceRoomHfValidator{}(props.lRoomHF); + Eax5SourceFlagsValidator{}(props.ulFlags); + } + }; - void eax_defer_source_room_rolloff_factor( - const EaxEaxCall& eax_call); + struct Eax4ObstructionValidator { + void operator()(const EAXOBSTRUCTIONPROPERTIES& props) const + { + Eax2SourceObstructionValidator{}(props.lObstruction); + Eax2SourceObstructionLfRatioValidator{}(props.flObstructionLFRatio); + } + }; - void eax_defer_source_air_absorption_factor( - const EaxEaxCall& eax_call); + struct Eax4OcclusionValidator { + void operator()(const EAXOCCLUSIONPROPERTIES& props) const + { + Eax2SourceOcclusionValidator{}(props.lOcclusion); + Eax2SourceOcclusionLfRatioValidator{}(props.flOcclusionLFRatio); + Eax2SourceOcclusionRoomRatioValidator{}(props.flOcclusionRoomRatio); + Eax3SourceOcclusionDirectRatioValidator{}(props.flOcclusionDirectRatio); + } + }; - void eax_defer_source_flags( - const EaxEaxCall& eax_call); + struct Eax4ExclusionValidator { + void operator()(const EAXEXCLUSIONPROPERTIES& props) const + { + Eax3SourceExclusionValidator{}(props.lExclusion); + Eax3SourceExclusionLfRatioValidator{}(props.flExclusionLFRatio); + } + }; - void eax_defer_source_macro_fx_factor( - const EaxEaxCall& eax_call); + // Source validators + // ---------------------------------------------------------------------- + // Send validators - void eax_defer_source_2d_all( - const EaxEaxCall& eax_call); + struct Eax4SendReceivingFxSlotIdValidator { + void operator()(const GUID& guidReceivingFXSlotID) const + { + if (guidReceivingFXSlotID != EAXPROPERTYID_EAX40_FXSlot0 && + guidReceivingFXSlotID != EAXPROPERTYID_EAX40_FXSlot1 && + guidReceivingFXSlotID != EAXPROPERTYID_EAX40_FXSlot2 && + guidReceivingFXSlotID != EAXPROPERTYID_EAX40_FXSlot3) + { + eax_fail_unknown_receiving_fx_slot_id(); + } + } + }; - void eax_defer_source_obstruction_all( - const EaxEaxCall& eax_call); + struct Eax5SendReceivingFxSlotIdValidator { + void operator()(const GUID& guidReceivingFXSlotID) const + { + if (guidReceivingFXSlotID != EAXPROPERTYID_EAX50_FXSlot0 && + guidReceivingFXSlotID != EAXPROPERTYID_EAX50_FXSlot1 && + guidReceivingFXSlotID != EAXPROPERTYID_EAX50_FXSlot2 && + guidReceivingFXSlotID != EAXPROPERTYID_EAX50_FXSlot3) + { + eax_fail_unknown_receiving_fx_slot_id(); + } + } + }; - void eax_defer_source_exclusion_all( - const EaxEaxCall& eax_call); + struct Eax4SendSendValidator { + void operator()(long lSend) const + { + eax_validate_range( + "Send", + lSend, + EAXSOURCE_MINSEND, + EAXSOURCE_MAXSEND); + } + }; - void eax_defer_source_occlusion_all( - const EaxEaxCall& eax_call); + struct Eax4SendSendHfValidator { + void operator()(long lSendHF) const + { + eax_validate_range( + "Send HF", + lSendHF, + EAXSOURCE_MINSENDHF, + EAXSOURCE_MAXSENDHF); + } + }; - void eax_defer_source_all( - const EaxEaxCall& eax_call); + template + struct EaxSendValidator { + void operator()(const EAXSOURCESENDPROPERTIES& props) const + { + TIdValidator{}(props.guidReceivingFXSlotID); + Eax4SendSendValidator{}(props.lSend); + Eax4SendSendHfValidator{}(props.lSendHF); + } + }; - void eax_defer_source_speaker_level_all( - const EaxEaxCall& eax_call); + struct Eax4SendValidator : EaxSendValidator {}; + struct Eax5SendValidator : EaxSendValidator {}; + template + struct EaxOcclusionSendValidator { + void operator()(const EAXSOURCEOCCLUSIONSENDPROPERTIES& props) const + { + TIdValidator{}(props.guidReceivingFXSlotID); + Eax2SourceOcclusionValidator{}(props.lOcclusion); + Eax2SourceOcclusionLfRatioValidator{}(props.flOcclusionLFRatio); + Eax2SourceOcclusionRoomRatioValidator{}(props.flOcclusionRoomRatio); + Eax3SourceOcclusionDirectRatioValidator{}(props.flOcclusionDirectRatio); + } + }; - void eax_set_outside_volume_hf(); + struct Eax4OcclusionSendValidator : EaxOcclusionSendValidator {}; + struct Eax5OcclusionSendValidator : EaxOcclusionSendValidator {}; - void eax_set_doppler_factor(); + template + struct EaxExclusionSendValidator { + void operator()(const EAXSOURCEEXCLUSIONSENDPROPERTIES& props) const + { + TIdValidator{}(props.guidReceivingFXSlotID); + Eax3SourceExclusionValidator{}(props.lExclusion); + Eax3SourceExclusionLfRatioValidator{}(props.flExclusionLFRatio); + } + }; - void eax_set_rolloff_factor(); + struct Eax4ExclusionSendValidator : EaxExclusionSendValidator {}; + struct Eax5ExclusionSendValidator : EaxExclusionSendValidator {}; - void eax_set_room_rolloff_factor(); + template + struct EaxAllSendValidator { + void operator()(const EAXSOURCEALLSENDPROPERTIES& props) const + { + TIdValidator{}(props.guidReceivingFXSlotID); + Eax4SendSendValidator{}(props.lSend); + Eax4SendSendHfValidator{}(props.lSendHF); + Eax2SourceOcclusionValidator{}(props.lOcclusion); + Eax2SourceOcclusionLfRatioValidator{}(props.flOcclusionLFRatio); + Eax2SourceOcclusionRoomRatioValidator{}(props.flOcclusionRoomRatio); + Eax3SourceOcclusionDirectRatioValidator{}(props.flOcclusionDirectRatio); + Eax3SourceExclusionValidator{}(props.lExclusion); + Eax3SourceExclusionLfRatioValidator{}(props.flExclusionLFRatio); + } + }; - void eax_set_air_absorption_factor(); + struct Eax4AllSendValidator : EaxAllSendValidator {}; + struct Eax5AllSendValidator : EaxAllSendValidator {}; + // Send validators + // ---------------------------------------------------------------------- + // Active FX slot ID validators - void eax_set_direct_hf_auto_flag(); + struct Eax4ActiveFxSlotIdValidator { + void operator()(const GUID &guid) const + { + if(guid != EAX_NULL_GUID && guid != EAX_PrimaryFXSlotID + && guid != EAXPROPERTYID_EAX40_FXSlot0 && guid != EAXPROPERTYID_EAX40_FXSlot1 + && guid != EAXPROPERTYID_EAX40_FXSlot2 && guid != EAXPROPERTYID_EAX40_FXSlot3) + { + eax_fail_unknown_active_fx_slot_id(); + } + } + }; - void eax_set_room_auto_flag(); + struct Eax5ActiveFxSlotIdValidator { + void operator()(const GUID &guid) const + { + if(guid != EAX_NULL_GUID && guid != EAX_PrimaryFXSlotID + && guid != EAXPROPERTYID_EAX50_FXSlot0 && guid != EAXPROPERTYID_EAX50_FXSlot1 + && guid != EAXPROPERTYID_EAX50_FXSlot2 && guid != EAXPROPERTYID_EAX50_FXSlot3) + { + eax_fail_unknown_active_fx_slot_id(); + } + } + }; - void eax_set_room_hf_auto_flag(); + // Active FX slot ID validators + // ---------------------------------------------------------------------- + // Speaker level validators. - void eax_set_flags(); + struct Eax5SpeakerIdValidator { + void operator()(long lSpeakerID) const + { + switch (lSpeakerID) { + case EAXSPEAKER_FRONT_LEFT: + case EAXSPEAKER_FRONT_CENTER: + case EAXSPEAKER_FRONT_RIGHT: + case EAXSPEAKER_SIDE_RIGHT: + case EAXSPEAKER_REAR_RIGHT: + case EAXSPEAKER_REAR_CENTER: + case EAXSPEAKER_REAR_LEFT: + case EAXSPEAKER_SIDE_LEFT: + case EAXSPEAKER_LOW_FREQUENCY: + break; + + default: + eax_fail("Unknown speaker ID."); + } + } + }; + struct Eax5SpeakerLevelValidator { + void operator()(long lLevel) const + { + // TODO Use a range when the feature will be implemented. + if (lLevel != EAXSOURCE_DEFAULTSPEAKERLEVEL) + eax_fail("Speaker level out of range."); + } + }; - void eax_set_macro_fx_factor(); + struct Eax5SpeakerAllValidator { + void operator()(const EAXSPEAKERLEVELPROPERTIES& all) const + { + Eax5SpeakerIdValidator{}(all.lSpeakerID); + Eax5SpeakerLevelValidator{}(all.lLevel); + } + }; - void eax_set_speaker_levels(); + // Speaker level validators. + // ---------------------------------------------------------------------- + struct Eax4SendIndexGetter { + EaxFxSlotIndexValue operator()(const GUID &guid) const + { + if(guid == EAXPROPERTYID_EAX40_FXSlot0) + return 0; + if(guid == EAXPROPERTYID_EAX40_FXSlot1) + return 1; + if(guid == EAXPROPERTYID_EAX40_FXSlot2) + return 2; + if(guid == EAXPROPERTYID_EAX40_FXSlot3) + return 3; + eax_fail_unknown_receiving_fx_slot_id(); + } + }; - void eax1_set_efx(); - void eax1_set_reverb_mix(const EaxEaxCall& eax_call); - void eax1_set(const EaxEaxCall& eax_call); + struct Eax5SendIndexGetter { + EaxFxSlotIndexValue operator()(const GUID &guid) const + { + if(guid == EAXPROPERTYID_EAX50_FXSlot0) + return 0; + if(guid == EAXPROPERTYID_EAX50_FXSlot1) + return 1; + if(guid == EAXPROPERTYID_EAX50_FXSlot2) + return 2; + if(guid == EAXPROPERTYID_EAX50_FXSlot3) + return 3; + eax_fail_unknown_receiving_fx_slot_id(); + } + }; - void eax_apply_deferred(); + [[noreturn]] static void eax_fail(const char* message); + [[noreturn]] static void eax_fail_unknown_property_id(); + [[noreturn]] static void eax_fail_unknown_version(); + [[noreturn]] static void eax_fail_unknown_active_fx_slot_id(); + [[noreturn]] static void eax_fail_unknown_receiving_fx_slot_id(); + + void eax_set_sends_defaults(EaxSends& sends, const EaxFxSlotIds& ids) noexcept; + void eax1_set_defaults(Eax1Props& props) noexcept; + void eax1_set_defaults() noexcept; + void eax2_set_defaults(Eax2Props& props) noexcept; + void eax2_set_defaults() noexcept; + void eax3_set_defaults(Eax3Props& props) noexcept; + void eax3_set_defaults() noexcept; + void eax4_set_sends_defaults(EaxSends& sends) noexcept; + void eax4_set_active_fx_slots_defaults(EAX40ACTIVEFXSLOTS& slots) noexcept; + void eax4_set_defaults() noexcept; + void eax5_set_source_defaults(EAX50SOURCEPROPERTIES& props) noexcept; + void eax5_set_sends_defaults(EaxSends& sends) noexcept; + void eax5_set_active_fx_slots_defaults(EAX50ACTIVEFXSLOTS& slots) noexcept; + void eax5_set_speaker_levels_defaults(EaxSpeakerLevels& speaker_levels) noexcept; + void eax5_set_defaults(Eax5Props& props) noexcept; + void eax5_set_defaults() noexcept; + void eax_set_defaults() noexcept; - void eax_set( - const EaxEaxCall& eax_call); + void eax1_translate(const Eax1Props& src, Eax5Props& dst) noexcept; + void eax2_translate(const Eax2Props& src, Eax5Props& dst) noexcept; + void eax3_translate(const Eax3Props& src, Eax5Props& dst) noexcept; + void eax4_translate(const Eax4Props& src, Eax5Props& dst) noexcept; + static float eax_calculate_dst_occlusion_mb( + long src_occlusion_mb, + float path_ratio, + float lf_ratio) noexcept; - static const GUID& eax_get_send_fx_slot_guid( - int eax_version, - EaxFxSlotIndexValue fx_slot_index); + EaxAlLowPassParam eax_create_direct_filter_param() const noexcept; - static void eax_copy_send( - const EAXSOURCEALLSENDPROPERTIES& src_send, - EAXSOURCESENDPROPERTIES& dst_send); + EaxAlLowPassParam eax_create_room_filter_param( + const ALeffectslot& fx_slot, + const EAXSOURCEALLSENDPROPERTIES& send) const noexcept; - static void eax_copy_send( - const EAXSOURCEALLSENDPROPERTIES& src_send, - EAXSOURCEALLSENDPROPERTIES& dst_send); + void eax_update_direct_filter(); + void eax_update_room_filters(); + void eax_commit_filters(); - static void eax_copy_send( - const EAXSOURCEALLSENDPROPERTIES& src_send, - EAXSOURCEOCCLUSIONSENDPROPERTIES& dst_send); + static void eax_copy_send_for_get( + const EAXSOURCEALLSENDPROPERTIES& src, + EAXSOURCESENDPROPERTIES& dst) noexcept + { + dst = reinterpret_cast(src); + } - static void eax_copy_send( - const EAXSOURCEALLSENDPROPERTIES& src_send, - EAXSOURCEEXCLUSIONSENDPROPERTIES& dst_send); + static void eax_copy_send_for_get( + const EAXSOURCEALLSENDPROPERTIES& src, + EAXSOURCEALLSENDPROPERTIES& dst) noexcept + { + dst = src; + } - template< - typename TException, - typename TSrcSend - > - void eax_api_get_send_properties( - const EaxEaxCall& eax_call) const + static void eax_copy_send_for_get( + const EAXSOURCEALLSENDPROPERTIES& src, + EAXSOURCEOCCLUSIONSENDPROPERTIES& dst) noexcept { - const auto eax_version = eax_call.get_version(); - const auto dst_sends = eax_call.get_values(); - const auto send_count = dst_sends.size(); + dst.guidReceivingFXSlotID = src.guidReceivingFXSlotID; + dst.lOcclusion = src.lOcclusion; + dst.flOcclusionLFRatio = src.flOcclusionLFRatio; + dst.flOcclusionRoomRatio = src.flOcclusionRoomRatio; + dst.flOcclusionDirectRatio = src.flOcclusionDirectRatio; + } - for (auto fx_slot_index = EaxFxSlotIndexValue{}; fx_slot_index < send_count; ++fx_slot_index) - { - auto& dst_send = dst_sends[fx_slot_index]; - const auto& src_send = eax_.sends[fx_slot_index]; + static void eax_copy_send_for_get( + const EAXSOURCEALLSENDPROPERTIES& src, + EAXSOURCEEXCLUSIONSENDPROPERTIES& dst) noexcept + { + dst.guidReceivingFXSlotID = src.guidReceivingFXSlotID; + dst.lExclusion = src.lExclusion; + dst.flExclusionLFRatio = src.flExclusionLFRatio; + } - eax_copy_send(src_send, dst_send); + template + void eax_get_sends(const EaxCall& call, const EaxSends& src_sends) + { + const auto dst_sends = call.get_values(EAX_MAX_FXSLOTS); + const auto count = dst_sends.size(); - dst_send.guidReceivingFXSlotID = eax_get_send_fx_slot_guid(eax_version, fx_slot_index); + for (auto i = decltype(count){}; i < count; ++i) { + const auto& src_send = src_sends[i]; + auto& dst_send = dst_sends[i]; + eax_copy_send_for_get(src_send, dst_send); } } + void eax1_get(const EaxCall& call, const Eax1Props& props); + void eax2_get(const EaxCall& call, const Eax2Props& props); + void eax3_get_obstruction(const EaxCall& call, const Eax3Props& props); + void eax3_get_occlusion(const EaxCall& call, const Eax3Props& props); + void eax3_get_exclusion(const EaxCall& call, const Eax3Props& props); + void eax3_get(const EaxCall& call, const Eax3Props& props); + void eax4_get(const EaxCall& call, const Eax4Props& props); + void eax5_get_all_2d(const EaxCall& call, const EAX50SOURCEPROPERTIES& props); + void eax5_get_speaker_levels(const EaxCall& call, const EaxSpeakerLevels& props); + void eax5_get(const EaxCall& call, const Eax5Props& props); + void eax_get(const EaxCall& call); + + static void eax_copy_send_for_set( + const EAXSOURCESENDPROPERTIES& src, + EAXSOURCEALLSENDPROPERTIES& dst) noexcept + { + dst.lSend = src.lSend; + dst.lSendHF = src.lSendHF; + } - void eax1_get(const EaxEaxCall& eax_call); - - void eax_api_get_source_all_v2( - const EaxEaxCall& eax_call); + static void eax_copy_send_for_set( + const EAXSOURCEALLSENDPROPERTIES& src, + EAXSOURCEALLSENDPROPERTIES& dst) noexcept + { + dst.lSend = src.lSend; + dst.lSendHF = src.lSendHF; + dst.lOcclusion = src.lOcclusion; + dst.flOcclusionLFRatio = src.flOcclusionLFRatio; + dst.flOcclusionRoomRatio = src.flOcclusionRoomRatio; + dst.flOcclusionDirectRatio = src.flOcclusionDirectRatio; + dst.lExclusion = src.lExclusion; + dst.flExclusionLFRatio = src.flExclusionLFRatio; + } - void eax_api_get_source_all_v3( - const EaxEaxCall& eax_call); + static void eax_copy_send_for_set( + const EAXSOURCEOCCLUSIONSENDPROPERTIES& src, + EAXSOURCEALLSENDPROPERTIES& dst) noexcept + { + dst.lOcclusion = src.lOcclusion; + dst.flOcclusionLFRatio = src.flOcclusionLFRatio; + dst.flOcclusionRoomRatio = src.flOcclusionRoomRatio; + dst.flOcclusionDirectRatio = src.flOcclusionDirectRatio; + } - void eax_api_get_source_all_v5( - const EaxEaxCall& eax_call); + static void eax_copy_send_for_set( + const EAXSOURCEEXCLUSIONSENDPROPERTIES& src, + EAXSOURCEALLSENDPROPERTIES& dst) noexcept + { + dst.lExclusion = src.lExclusion; + dst.flExclusionLFRatio = src.flExclusionLFRatio; + } - void eax_api_get_source_all( - const EaxEaxCall& eax_call); + template + void eax_defer_sends(const EaxCall& call, EaxSends& dst_sends) + { + const auto src_sends = call.get_values(EAX_MAX_FXSLOTS); + std::for_each(src_sends.cbegin(), src_sends.cend(), TValidator{}); + const auto count = src_sends.size(); + const auto index_getter = TIndexGetter{}; + + for (auto i = decltype(count){}; i < count; ++i) { + const auto& src_send = src_sends[i]; + const auto dst_index = index_getter(src_send.guidReceivingFXSlotID); + auto& dst_send = dst_sends[dst_index]; + eax_copy_send_for_set(src_send, dst_send); + } + } - void eax_api_get_source_all_obstruction( - const EaxEaxCall& eax_call); + template + void eax4_defer_sends(const EaxCall& call, EaxSends& dst_sends) + { + eax_defer_sends(call, dst_sends); + } - void eax_api_get_source_all_occlusion( - const EaxEaxCall& eax_call); + template + void eax5_defer_sends(const EaxCall& call, EaxSends& dst_sends) + { + eax_defer_sends(call, dst_sends); + } - void eax_api_get_source_all_exclusion( - const EaxEaxCall& eax_call); + template + void eax_defer_active_fx_slot_id(const EaxCall& call, GUID (&dst_ids)[TIdCount]) + { + const auto src_ids = call.get_values(TIdCount); + std::for_each(src_ids.cbegin(), src_ids.cend(), TValidator{}); + std::uninitialized_copy(src_ids.cbegin(), src_ids.cend(), dst_ids); + } - void eax_api_get_source_active_fx_slot_id( - const EaxEaxCall& eax_call); + template + void eax4_defer_active_fx_slot_id(const EaxCall& call, GUID (&dst_ids)[TIdCount]) + { + eax_defer_active_fx_slot_id(call, dst_ids); + } - void eax_api_get_source_all_2d( - const EaxEaxCall& eax_call); + template + void eax5_defer_active_fx_slot_id(const EaxCall& call, GUID (&dst_ids)[TIdCount]) + { + eax_defer_active_fx_slot_id(call, dst_ids); + } - void eax_api_get_source_speaker_level_all( - const EaxEaxCall& eax_call); + template + static void eax_defer(const EaxCall& call, TProperty& property) + { + const auto& value = call.get_value(); + TValidator{}(value); + property = value; + } - void eax_get( - const EaxEaxCall& eax_call); + // Defers source's sub-properties (obstruction, occlusion, exclusion). + template + void eax_defer_sub(const EaxCall& call, TProperty& property) + { + const auto& src_props = call.get_value(); + TValidator{}(src_props); + auto& dst_props = reinterpret_cast(property); + dst_props = src_props; + } + void eax_set_efx_outer_gain_hf(); + void eax_set_efx_doppler_factor(); + void eax_set_efx_rolloff_factor(); + void eax_set_efx_room_rolloff_factor(); + void eax_set_efx_air_absorption_factor(); + void eax_set_efx_dry_gain_hf_auto(); + void eax_set_efx_wet_gain_auto(); + void eax_set_efx_wet_gain_hf_auto(); + + void eax1_set(const EaxCall& call, Eax1Props& props); + void eax2_set(const EaxCall& call, Eax2Props& props); + void eax3_set(const EaxCall& call, Eax3Props& props); + void eax4_set(const EaxCall& call, Eax4Props& props); + void eax5_defer_all_2d(const EaxCall& call, EAX50SOURCEPROPERTIES& props); + void eax5_defer_speaker_levels(const EaxCall& call, EaxSpeakerLevels& props); + void eax5_set(const EaxCall& call, Eax5Props& props); + void eax_set(const EaxCall& call); // `alSource3i(source, AL_AUXILIARY_SEND_FILTER, ...)` void eax_set_al_source_send(ALeffectslot *slot, size_t sendidx, const EaxAlLowPassParam &filter); + + void eax_commit_active_fx_slots(); + void eax_commit(EaxCommitType commit_type); #endif // ALSOFT_EAX }; diff --git a/modules/openal-soft/al/state.cpp b/modules/openal-soft/al/state.cpp index 8142890..f41016d 100644 --- a/modules/openal-soft/al/state.cpp +++ b/modules/openal-soft/al/state.cpp @@ -49,8 +49,8 @@ #ifdef ALSOFT_EAX #include "alc/device.h" -#include "eax_globals.h" -#include "eax_x_ram.h" +#include "eax/globals.h" +#include "eax/x_ram.h" #endif // ALSOFT_EAX @@ -943,6 +943,7 @@ void UpdateContextProps(ALCcontext *context) props->Gain = listener.Gain; props->MetersPerUnit = listener.mMetersPerUnit; + props->AirAbsorptionGainHF = context->mAirAbsorptionGainHF; props->DopplerFactor = context->mDopplerFactor; props->DopplerVelocity = context->mDopplerVelocity; props->SpeedOfSound = context->mSpeedOfSound; diff --git a/modules/openal-soft/alsoftrc.sample b/modules/openal-soft/alsoftrc.sample index 7333899..f2b1798 100644 --- a/modules/openal-soft/alsoftrc.sample +++ b/modules/openal-soft/alsoftrc.sample @@ -55,10 +55,10 @@ ## channels: # Sets the output channel configuration. If left unspecified, one will try to # be detected from the system, and defaulting to stereo. The available values -# are: mono, stereo, quad, surround51, surround61, surround71, ambi1, ambi2, -# ambi3. Note that the ambi* configurations provide ambisonic channels of the -# given order (using ACN ordering and SN3D normalization by default), which -# need to be decoded to play correctly on speakers. +# are: mono, stereo, quad, surround51, surround61, surround71, surround3d71, +# ambi1, ambi2, ambi3. Note that the ambi* configurations provide ambisonic +# channels of the given order (using ACN ordering and SN3D normalization by +# default), which need to be decoded to play correctly on speakers. #channels = ## sample-type: @@ -339,11 +339,15 @@ ## surround71: # Decoder configuration file for 7.1 Surround channel output. See -# docs/ambdec.txt for a description of the file format. Note: This can be used -# to enable 3D7.1 with the appropriate configuration and speaker placement, -# see docs/3D7.1.txt. +# docs/ambdec.txt for a description of the file format. #surround71 = +## surround3d71: +# Decoder configuration file for 3D7.1 Surround channel output. See +# docs/ambdec.txt for a description of the file format. See also +# docs/3D7.1.txt for information about 3D7.1. +#surround3d71 = + ## ## Reverb effect stuff (includes EAX reverb) ## diff --git a/modules/openal-soft/appveyor.yml b/modules/openal-soft/appveyor.yml index c468d4e..b75fbd7 100644 --- a/modules/openal-soft/appveyor.yml +++ b/modules/openal-soft/appveyor.yml @@ -1,4 +1,4 @@ -version: 1.22.0.{build} +version: 1.22.2.{build} environment: APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 diff --git a/modules/openal-soft/common/almalloc.h b/modules/openal-soft/common/almalloc.h index 711d02f..295107d 100644 --- a/modules/openal-soft/common/almalloc.h +++ b/modules/openal-soft/common/almalloc.h @@ -29,9 +29,11 @@ void *al_calloc(size_t alignment, size_t size); #define DEF_NEWDEL(T) \ void *operator new(size_t size) \ { \ - void *ret = al_malloc(alignof(T), size); \ - if(!ret) throw std::bad_alloc(); \ - return ret; \ + static_assert(&operator new == &T::operator new, \ + "Incorrect container type specified"); \ + if(void *ret{al_malloc(alignof(T), size)}) \ + return ret; \ + throw std::bad_alloc(); \ } \ void *operator new[](size_t size) { return operator new(size); } \ void operator delete(void *block) noexcept { al_free(block); } \ @@ -50,6 +52,8 @@ enum FamCount : size_t { }; #define DEF_FAM_NEWDEL(T, FamMem) \ static constexpr size_t Sizeof(size_t count) noexcept \ { \ + static_assert(&Sizeof == &T::Sizeof, \ + "Incorrect container type specified"); \ return std::max(decltype(FamMem)::Sizeof(count, offsetof(T, FamMem)), \ sizeof(T)); \ } \ diff --git a/modules/openal-soft/common/aloptional.h b/modules/openal-soft/common/aloptional.h index 6180d16..6de1679 100644 --- a/modules/openal-soft/common/aloptional.h +++ b/modules/openal-soft/common/aloptional.h @@ -310,10 +310,10 @@ public: template constexpr T value_or(U&& defval) const& - { return bool{*this} ? **this : static_cast(std::forward(defval)); } + { return bool(*this) ? **this : static_cast(std::forward(defval)); } template constexpr T value_or(U&& defval) && - { return bool{*this} ? std::move(**this) : static_cast(std::forward(defval)); } + { return bool(*this) ? std::move(**this) : static_cast(std::forward(defval)); } template constexpr T& emplace(Args&& ...args) diff --git a/modules/openal-soft/common/alstring.h b/modules/openal-soft/common/alstring.h index f5127ae..6c5004e 100644 --- a/modules/openal-soft/common/alstring.h +++ b/modules/openal-soft/common/alstring.h @@ -2,6 +2,7 @@ #define AL_STRING_H #include +#include namespace al { diff --git a/modules/openal-soft/common/polyphase_resampler.h b/modules/openal-soft/common/polyphase_resampler.h index e9833d1..0b343d5 100644 --- a/modules/openal-soft/common/polyphase_resampler.h +++ b/modules/openal-soft/common/polyphase_resampler.h @@ -4,6 +4,8 @@ #include +using uint = unsigned int; + /* This is a polyphase sinc-filtered resampler. It is built for very high * quality results, rather than real-time performance. * @@ -32,8 +34,6 @@ */ struct PPhaseResampler { - using uint = unsigned int; - void init(const uint srcRate, const uint dstRate); void process(const uint inN, const double *in, const uint outN, double *out); diff --git a/modules/openal-soft/config.h.in b/modules/openal-soft/config.h.in index 416b87d..477d8c7 100644 --- a/modules/openal-soft/config.h.in +++ b/modules/openal-soft/config.h.in @@ -114,3 +114,6 @@ /* Define if we have pthread_set_name_np() */ #cmakedefine HAVE_PTHREAD_SET_NAME_NP + +/* Define the installation data directory */ +#cmakedefine ALSOFT_INSTALL_DATADIR "@ALSOFT_INSTALL_DATADIR@" diff --git a/modules/openal-soft/core/cpu_caps.cpp b/modules/openal-soft/core/cpu_caps.cpp index 8211b33..0325cd4 100644 --- a/modules/openal-soft/core/cpu_caps.cpp +++ b/modules/openal-soft/core/cpu_caps.cpp @@ -11,11 +11,10 @@ #endif #endif -#ifdef HAVE_INTRIN_H -#include -#endif -#ifdef HAVE_CPUID_H +#if defined(HAVE_CPUID_H) #include +#elif defined(HAVE_INTRIN_H) +#include #endif #include diff --git a/modules/openal-soft/core/devformat.cpp b/modules/openal-soft/core/devformat.cpp index c841b63..cbe8eaf 100644 --- a/modules/openal-soft/core/devformat.cpp +++ b/modules/openal-soft/core/devformat.cpp @@ -28,6 +28,7 @@ uint ChannelsFromDevFmt(DevFmtChannels chans, uint ambiorder) noexcept case DevFmtX51: return 6; case DevFmtX61: return 7; case DevFmtX71: return 8; + case DevFmtX3D71: return 8; case DevFmtAmbi3D: return (ambiorder+1) * (ambiorder+1); } return 0; @@ -57,6 +58,7 @@ const char *DevFmtChannelsString(DevFmtChannels chans) noexcept case DevFmtX51: return "5.1 Surround"; case DevFmtX61: return "6.1 Surround"; case DevFmtX71: return "7.1 Surround"; + case DevFmtX3D71: return "3D7.1 Surround"; case DevFmtAmbi3D: return "Ambisonic 3D"; } return "(unknown channels)"; diff --git a/modules/openal-soft/core/devformat.h b/modules/openal-soft/core/devformat.h index e6d3092..f2a372c 100644 --- a/modules/openal-soft/core/devformat.h +++ b/modules/openal-soft/core/devformat.h @@ -25,6 +25,23 @@ enum Channel : unsigned char { TopBackCenter, TopBackRight, + Aux0, + Aux1, + Aux2, + Aux3, + Aux4, + Aux5, + Aux6, + Aux7, + Aux8, + Aux9, + Aux10, + Aux11, + Aux12, + Aux13, + Aux14, + Aux15, + MaxChannels }; @@ -48,6 +65,7 @@ enum DevFmtChannels : unsigned char { DevFmtX51, DevFmtX61, DevFmtX71, + DevFmtX3D71, DevFmtAmbi3D, DevFmtChannelsDefault = DevFmtStereo diff --git a/modules/openal-soft/core/helpers.cpp b/modules/openal-soft/core/helpers.cpp index e4a94fe..6d0863c 100644 --- a/modules/openal-soft/core/helpers.cpp +++ b/modules/openal-soft/core/helpers.cpp @@ -408,6 +408,20 @@ al::vector SearchDataFiles(const char *ext, const char *subdir) DirectorySearch(path.c_str(), ext, &results); } +#ifdef ALSOFT_INSTALL_DATADIR + // Search the installation data directory + { + std::string path{ALSOFT_INSTALL_DATADIR}; + if(!path.empty()) + { + if(path.back() != '/') + path += '/'; + path += subdir; + DirectorySearch(path.c_str(), ext, &results); + } + } +#endif + return results; } @@ -461,6 +475,17 @@ bool SetRTPriorityRTKit(int prio) /* Don't stupidly exit if the connection dies while doing this. */ dbus_connection_set_exit_on_disconnect(conn.get(), false); + int nicemin{}; + int err{rtkit_get_min_nice_level(conn.get(), &nicemin)}; + if(err == -ENOENT) + { + err = std::abs(err); + ERR("Could not query RTKit: %s (%d)\n", std::strerror(err), err); + return false; + } + int rtmax{rtkit_get_max_realtime_priority(conn.get())}; + TRACE("Maximum real-time priority: %d, minimum niceness: %d\n", rtmax, nicemin); + auto limit_rttime = [](DBusConnection *c) -> int { using ulonglong = unsigned long long; @@ -483,18 +508,6 @@ bool SetRTPriorityRTKit(int prio) } return 0; }; - - int nicemin{}; - int err{rtkit_get_min_nice_level(conn.get(), &nicemin)}; - if(err == -ENOENT) - { - err = std::abs(err); - ERR("Could not query RTKit: %s (%d)\n", std::strerror(err), err); - return false; - } - int rtmax{rtkit_get_max_realtime_priority(conn.get())}; - TRACE("Maximum real-time priority: %d, minimum niceness: %d\n", rtmax, nicemin); - if(rtmax > 0) { if(AllowRTTimeLimit) diff --git a/modules/openal-soft/core/uhjfilter.cpp b/modules/openal-soft/core/uhjfilter.cpp index 7a68f1b..6cdc294 100644 --- a/modules/openal-soft/core/uhjfilter.cpp +++ b/modules/openal-soft/core/uhjfilter.cpp @@ -36,17 +36,17 @@ const PhaseShifterT PShift{}; * impulse with the desired shift. */ -void UhjEncoder::encode(float *LeftOut, float *RightOut, const FloatBufferLine *InSamples, - const size_t SamplesToDo) +void UhjEncoder::encode(float *LeftOut, float *RightOut, + const al::span InSamples, const size_t SamplesToDo) { ASSUME(SamplesToDo > 0); float *RESTRICT left{al::assume_aligned<16>(LeftOut)}; float *RESTRICT right{al::assume_aligned<16>(RightOut)}; - const float *RESTRICT winput{al::assume_aligned<16>(InSamples[0].data())}; - const float *RESTRICT xinput{al::assume_aligned<16>(InSamples[1].data())}; - const float *RESTRICT yinput{al::assume_aligned<16>(InSamples[2].data())}; + const float *RESTRICT winput{al::assume_aligned<16>(InSamples[0])}; + const float *RESTRICT xinput{al::assume_aligned<16>(InSamples[1])}; + const float *RESTRICT yinput{al::assume_aligned<16>(InSamples[2])}; /* Combine the previously delayed S/D signal with the input. Include any * existing direct signal with it. @@ -174,7 +174,7 @@ void UhjDecoder::decode(const al::span samples, const size_t samplesToDo * where j is a +90 degree phase shift. w is a variable control for the * resulting stereo width, with the range 0 <= w <= 0.7. */ -void UhjDecoder::decodeStereo(const al::span samples, const size_t samplesToDo, +void UhjStereoDecoder::decode(const al::span samples, const size_t samplesToDo, const size_t forwardSamples) { ASSUME(samplesToDo > 0); diff --git a/modules/openal-soft/core/uhjfilter.h b/modules/openal-soft/core/uhjfilter.h index 0453def..eeabb6d 100644 --- a/modules/openal-soft/core/uhjfilter.h +++ b/modules/openal-soft/core/uhjfilter.h @@ -4,10 +4,27 @@ #include #include "almalloc.h" +#include "alspan.h" #include "bufferline.h" #include "resampler_limits.h" +struct DecoderBase { + virtual ~DecoderBase() = default; + + virtual void decode(const al::span samples, const size_t samplesToDo, + const size_t forwardSamples) = 0; + + /** + * The width factor for Super Stereo processing. Can be changed in between + * calls to decode, with valid values being between 0...0.7. + */ + float mWidthControl{0.593f}; + + float mCurrentWidth{-1.0f}; +}; + + struct UhjFilterBase { /* The filter delay is half it's effective size, so a delay of 128 has a * FIR length of 256. @@ -30,14 +47,18 @@ struct UhjEncoder : public UhjFilterBase { * signal. The input must use FuMa channel ordering and UHJ scaling (FuMa * with an additional +3dB boost). */ - void encode(float *LeftOut, float *RightOut, const FloatBufferLine *InSamples, + void encode(float *LeftOut, float *RightOut, const al::span InSamples, const size_t SamplesToDo); DEF_NEWDEL(UhjEncoder) }; -struct UhjDecoder : public UhjFilterBase { +struct UhjDecoder : public DecoderBase, public UhjFilterBase { + /* For 2-channel UHJ, shelf filters should use these LF responses. */ + static constexpr float sWLFScale{0.661f}; + static constexpr float sXYLFScale{1.293f}; + alignas(16) std::array mS{}; alignas(16) std::array mD{}; alignas(16) std::array mT{}; @@ -47,14 +68,6 @@ struct UhjDecoder : public UhjFilterBase { alignas(16) std::array mTemp{}; - float mCurrentWidth{-1.0f}; - - /** - * The width factor for Super Stereo processing. Can be changed in between - * calls to decodeStereo, with valid values being between 0...0.7. - */ - float mWidthControl{0.593f}; - /** * Decodes a 3- or 4-channel UHJ signal into a B-Format signal with FuMa * channel ordering and UHJ scaling. For 3-channel, the 3rd channel may be @@ -64,21 +77,22 @@ struct UhjDecoder : public UhjFilterBase { * B-Format decoder, as it needs different shelf filters. */ void decode(const al::span samples, const size_t samplesToDo, - const size_t forwardSamples); + const size_t forwardSamples) override; + DEF_NEWDEL(UhjDecoder) +}; + +struct UhjStereoDecoder : public UhjDecoder { /** * Applies Super Stereo processing on a stereo signal to create a B-Format * signal with FuMa channel ordering and UHJ scaling. The samples span * should contain 3 channels, the first two being the left and right stereo * channels, and the third left empty. */ - void decodeStereo(const al::span samples, const size_t samplesToDo, - const size_t forwardSamples); - - using DecoderFunc = void (UhjDecoder::*)(const al::span samples, - const size_t samplesToDo, const size_t forwardSamples); + void decode(const al::span samples, const size_t samplesToDo, + const size_t forwardSamples) override; - DEF_NEWDEL(UhjDecoder) + DEF_NEWDEL(UhjStereoDecoder) }; #endif /* CORE_UHJFILTER_H */ diff --git a/modules/openal-soft/core/voice.cpp b/modules/openal-soft/core/voice.cpp index e269c4a..ed6c9bf 100644 --- a/modules/openal-soft/core/voice.cpp +++ b/modules/openal-soft/core/voice.cpp @@ -514,8 +514,7 @@ void Voice::mix(const State vstate, ContextBase *Context, const uint SamplesToDo std::transform(Device->mSampleData.end() - mChans.size(), Device->mSampleData.end(), MixingSamples.begin(), offset_bufferline); - const uint PostPadding{MaxResamplerEdge + - (mDecoder ? uint{UhjDecoder::sFilterDelay} : 0u)}; + const uint PostPadding{MaxResamplerEdge + mDecoderPadding}; uint buffers_done{0u}; uint OutPos{0u}; do { @@ -637,8 +636,8 @@ void Voice::mix(const State vstate, ContextBase *Context, const uint SamplesToDo if(mDecoder) { SrcBufferSize = SrcBufferSize - PostPadding + MaxResamplerEdge; - ((*mDecoder).*mDecoderFunc)(MixingSamples, SrcBufferSize, - srcOffset * likely(vstate == Playing)); + mDecoder->decode(MixingSamples, SrcBufferSize, + likely(vstate == Playing) ? srcOffset : 0); } /* Store the last source samples used for next time. */ if(likely(vstate == Playing)) @@ -853,16 +852,20 @@ void Voice::prepare(DeviceBase *device) mPrevSamples.reserve(maxu(2, num_channels)); mPrevSamples.resize(num_channels); - if(IsUHJ(mFmtChannels)) + if(mFmtChannels == FmtSuperStereo) + { + mDecoder = std::make_unique(); + mDecoderPadding = UhjStereoDecoder::sFilterDelay; + } + else if(IsUHJ(mFmtChannels)) { mDecoder = std::make_unique(); - mDecoderFunc = (mFmtChannels == FmtSuperStereo) ? &UhjDecoder::decodeStereo - : &UhjDecoder::decode; + mDecoderPadding = UhjDecoder::sFilterDelay; } else { mDecoder = nullptr; - mDecoderFunc = nullptr; + mDecoderPadding = 0; } /* Clear the stepping value explicitly so the mixer knows not to mix this @@ -905,9 +908,9 @@ void Voice::prepare(DeviceBase *device) */ if(mFmtChannels == FmtUHJ2) { - mChans[0].mAmbiLFScale = 0.661f; - mChans[1].mAmbiLFScale = 1.293f; - mChans[2].mAmbiLFScale = 1.293f; + mChans[0].mAmbiLFScale = UhjDecoder::sWLFScale; + mChans[1].mAmbiLFScale = UhjDecoder::sXYLFScale; + mChans[2].mAmbiLFScale = UhjDecoder::sXYLFScale; } mFlags.set(VoiceIsAmbisonic); } @@ -927,9 +930,9 @@ void Voice::prepare(DeviceBase *device) chandata.mDryParams.NFCtrlFilter = device->mNFCtrlFilter; std::fill_n(chandata.mWetParams.begin(), device->NumAuxSends, SendParams{}); } - mChans[0].mAmbiLFScale = 0.661f; - mChans[1].mAmbiLFScale = 1.293f; - mChans[2].mAmbiLFScale = 1.293f; + mChans[0].mAmbiLFScale = UhjDecoder::sWLFScale; + mChans[1].mAmbiLFScale = UhjDecoder::sXYLFScale; + mChans[2].mAmbiLFScale = UhjDecoder::sXYLFScale; mFlags.set(VoiceIsAmbisonic); } else diff --git a/modules/openal-soft/core/voice.h b/modules/openal-soft/core/voice.h index 70b8084..25560cb 100644 --- a/modules/openal-soft/core/voice.h +++ b/modules/openal-soft/core/voice.h @@ -219,8 +219,8 @@ struct Voice { AmbiScaling mAmbiScaling; uint mAmbiOrder; - std::unique_ptr mDecoder; - UhjDecoder::DecoderFunc mDecoderFunc{}; + std::unique_ptr mDecoder; + uint mDecoderPadding{}; /** Current target parameters used for mixing. */ uint mStep{0}; diff --git a/modules/openal-soft/docs/3D7.1.txt b/modules/openal-soft/docs/3D7.1.txt index 1d40bec..b7249c2 100644 --- a/modules/openal-soft/docs/3D7.1.txt +++ b/modules/openal-soft/docs/3D7.1.txt @@ -58,17 +58,10 @@ Software Setup ============== To enable 3D7.1 on OpenAL Soft, first make sure the audio device is configured -for 7.1 output. Then in the alsoft-config utility, under the Renderer tab, -select the 3D7.1.ambdec preset for the 7.1 Surround decoder configuration. And -that's it. Any applications using OpenAL Soft can take advantage of fully 3D -audio, and multi-channel sounds will be properly remixed for the speaker -layout. - -Playback can be improved by (copying and) modifying the 3D7.1.ambdec preset, -changing the specified speaker distances to match the the real distance (in -meters) from the center of the speaker array, then enable High Quality Mode in -alsoft-config. That will improve the quality when the speakers are not all -equidistant. +for 7.1 output. Then in the alsoft-config utility, for the Channels setting +choose "3D7.1 Surround" from the drop-down list. And that's it. Any application +using OpenAL Soft can take advantage of fully 3D audio, and multi-channel +sounds will be properly remixed for the speaker layout. Note that care must be taken that the audio device is not treated as a "true" 7.1 device by non-3D7.1-capable applications. In particular, the audio server diff --git a/modules/openal-soft/examples/alffplay.cpp b/modules/openal-soft/examples/alffplay.cpp index c3f4c50..177d508 100644 --- a/modules/openal-soft/examples/alffplay.cpp +++ b/modules/openal-soft/examples/alffplay.cpp @@ -28,12 +28,12 @@ #include #include -extern "C" { #ifdef __GNUC__ _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wconversion\"") _Pragma("GCC diagnostic ignored \"-Wold-style-cast\"") #endif +extern "C" { #include "libavcodec/avcodec.h" #include "libavformat/avformat.h" #include "libavformat/avio.h" @@ -55,12 +55,12 @@ constexpr auto AVNoPtsValue = AV_NOPTS_VALUE; constexpr auto AVErrorEOF = AVERROR_EOF; struct SwsContext; -#ifdef __GNUC__ -_Pragma("GCC diagnostic pop") -#endif } #include "SDL.h" +#ifdef __GNUC__ +_Pragma("GCC diagnostic pop") +#endif #include "AL/alc.h" #include "AL/al.h" @@ -89,6 +89,7 @@ const std::string AppName{"alffplay"}; ALenum DirectOutMode{AL_FALSE}; bool EnableWideStereo{false}; +bool EnableUhj{false}; bool EnableSuperStereo{false}; bool DisableVideo{false}; LPALGETSOURCEI64VSOFT alGetSourcei64vSOFT; @@ -97,9 +98,6 @@ LPALEVENTCONTROLSOFT alEventControlSOFT; LPALEVENTCALLBACKSOFT alEventCallbackSOFT; LPALBUFFERCALLBACKSOFT alBufferCallbackSOFT; -ALenum FormatStereo8{AL_FORMAT_STEREO8}; -ALenum FormatStereo16{AL_FORMAT_STEREO16}; -ALenum FormatStereo32F{AL_FORMAT_STEREO_FLOAT32}; const seconds AVNoSyncThreshold{10}; @@ -696,24 +694,29 @@ static void sample_dup(uint8_t *out, const uint8_t *in, size_t count, size_t fra { auto *sample = reinterpret_cast(in); auto *dst = reinterpret_cast(out); - if(frame_size == sizeof(T)) + + /* NOTE: frame_size is a multiple of sizeof(T). */ + size_t type_mult{frame_size / sizeof(T)}; + if(type_mult == 1) std::fill_n(dst, count, *sample); - else + else for(size_t i{0};i < count;++i) { - /* NOTE: frame_size is a multiple of sizeof(T). */ - size_t type_mult{frame_size / sizeof(T)}; - size_t i{0}; - std::generate_n(dst, count*type_mult, - [sample,type_mult,&i]() -> T - { - T ret = sample[i]; - i = (i+1)%type_mult; - return ret; - } - ); + for(size_t j{0};j < type_mult;++j) + dst[i*type_mult + j] = sample[j]; } } +static void sample_dup(uint8_t *out, const uint8_t *in, size_t count, size_t frame_size) +{ + if((frame_size&7) == 0) + sample_dup(out, in, count, frame_size); + else if((frame_size&3) == 0) + sample_dup(out, in, count, frame_size); + else if((frame_size&1) == 0) + sample_dup(out, in, count, frame_size); + else + sample_dup(out, in, count, frame_size); +} bool AudioState::readAudio(uint8_t *samples, unsigned int length, int &sample_skip) { @@ -737,14 +740,7 @@ bool AudioState::readAudio(uint8_t *samples, unsigned int length, int &sample_sk rem = std::min(rem, static_cast(-mSamplesPos)); /* Add samples by copying the first sample */ - if((mFrameSize&7) == 0) - sample_dup(samples, mSamples, rem, mFrameSize); - else if((mFrameSize&3) == 0) - sample_dup(samples, mSamples, rem, mFrameSize); - else if((mFrameSize&1) == 0) - sample_dup(samples, mSamples, rem, mFrameSize); - else - sample_dup(samples, mSamples, rem, mFrameSize); + sample_dup(samples, mSamples, rem, mFrameSize); } mSamplesPos += rem; @@ -766,7 +762,6 @@ bool AudioState::readAudio(uint8_t *samples, unsigned int length, int &sample_sk auto skip = nanoseconds{seconds{mSamplesPos}} / mCodecCtx->sample_rate; mDeviceStartTime -= skip; mCurrentPts += skip; - continue; } } if(audio_size <= 0) @@ -785,71 +780,42 @@ bool AudioState::readAudio(uint8_t *samples, unsigned int length, int &sample_sk bool AudioState::readAudio(int sample_skip) { size_t woffset{mWritePos.load(std::memory_order_acquire)}; + const size_t roffset{mReadPos.load(std::memory_order_relaxed)}; while(mSamplesLen > 0) { - const size_t roffset{mReadPos.load(std::memory_order_relaxed)}; + const size_t nsamples{((roffset > woffset) ? roffset-woffset-1 + : (roffset == 0) ? (mBufferDataSize-woffset-1) + : (mBufferDataSize-woffset)) / mFrameSize}; + if(!nsamples) break; if(mSamplesPos < 0) { - size_t rem{(((roffset > woffset) ? roffset-1 - : ((roffset == 0) ? mBufferDataSize-1 - : mBufferDataSize)) - woffset) / mFrameSize}; - rem = std::min(rem, static_cast(-mSamplesPos)); - if(rem == 0) break; - - auto *splout{&mBufferData[woffset]}; - if((mFrameSize&7) == 0) - sample_dup(splout, mSamples, rem, mFrameSize); - else if((mFrameSize&3) == 0) - sample_dup(splout, mSamples, rem, mFrameSize); - else if((mFrameSize&1) == 0) - sample_dup(splout, mSamples, rem, mFrameSize); - else - sample_dup(splout, mSamples, rem, mFrameSize); + const size_t rem{std::min(nsamples, static_cast(-mSamplesPos))}; + + sample_dup(&mBufferData[woffset], mSamples, rem, mFrameSize); woffset += rem * mFrameSize; - if(woffset == mBufferDataSize) - woffset = 0; + if(woffset == mBufferDataSize) woffset = 0; mWritePos.store(woffset, std::memory_order_release); - mSamplesPos += static_cast(rem); + mCurrentPts += nanoseconds{seconds{rem}} / mCodecCtx->sample_rate; + mSamplesPos += static_cast(rem); continue; } + const size_t rem{std::min(nsamples, static_cast(mSamplesLen-mSamplesPos))}; const size_t boffset{static_cast(mSamplesPos) * size_t{mFrameSize}}; - const size_t nbytes{static_cast(mSamplesLen)*size_t{mFrameSize} - - boffset}; - if(roffset > woffset) - { - const size_t writable{roffset-woffset-1}; - if(writable < nbytes) break; - - memcpy(&mBufferData[woffset], mSamples+boffset, nbytes); - woffset += nbytes; - } - else - { - const size_t writable{mBufferDataSize+roffset-woffset-1}; - if(writable < nbytes) break; + const size_t nbytes{rem * mFrameSize}; - const size_t todo1{std::min(nbytes, mBufferDataSize-woffset)}; - const size_t todo2{nbytes - todo1}; - - memcpy(&mBufferData[woffset], mSamples+boffset, todo1); - woffset += todo1; - if(woffset == mBufferDataSize) - { - woffset = 0; - if(todo2 > 0) - { - memcpy(&mBufferData[woffset], mSamples+boffset+todo1, todo2); - woffset += todo2; - } - } - } + memcpy(&mBufferData[woffset], mSamples + boffset, nbytes); + woffset += nbytes; + if(woffset == mBufferDataSize) woffset = 0; mWritePos.store(woffset, std::memory_order_release); - mCurrentPts += nanoseconds{seconds{mSamplesLen-mSamplesPos}} / mCodecCtx->sample_rate; - do { + mCurrentPts += nanoseconds{seconds{rem}} / mCodecCtx->sample_rate; + mSamplesPos += static_cast(rem); + + while(mSamplesPos >= mSamplesLen) + { mSamplesLen = decodeFrame(); mSamplesPos = std::min(mSamplesLen, sample_skip); if(mSamplesLen <= 0) return false; @@ -859,7 +825,7 @@ bool AudioState::readAudio(int sample_skip) auto skip = nanoseconds{seconds{mSamplesPos}} / mCodecCtx->sample_rate; mDeviceStartTime -= skip; mCurrentPts += skip; - } while(mSamplesPos >= mSamplesLen); + } } return true; @@ -1040,7 +1006,7 @@ int AudioState::handler() { mDstChanLayout = AV_CH_LAYOUT_STEREO; mFrameSize *= 2; - mFormat = FormatStereo32F; + mFormat = EnableUhj ? AL_FORMAT_UHJ2CHN_FLOAT32_SOFT : AL_FORMAT_STEREO_FLOAT32; } } if(mCodecCtx->sample_fmt == AV_SAMPLE_FMT_U8 || mCodecCtx->sample_fmt == AV_SAMPLE_FMT_U8P) @@ -1090,7 +1056,7 @@ int AudioState::handler() { mDstChanLayout = AV_CH_LAYOUT_STEREO; mFrameSize *= 2; - mFormat = FormatStereo8; + mFormat = EnableUhj ? AL_FORMAT_UHJ2CHN8_SOFT : AL_FORMAT_STEREO8; } } if(!mFormat || mFormat == -1) @@ -1140,7 +1106,7 @@ int AudioState::handler() { mDstChanLayout = AV_CH_LAYOUT_STEREO; mFrameSize *= 2; - mFormat = FormatStereo16; + mFormat = EnableUhj ? AL_FORMAT_UHJ2CHN16_SOFT : AL_FORMAT_STEREO16; } } @@ -1299,19 +1265,28 @@ int AudioState::handler() while(1) { + if(mMovie.mQuit.load(std::memory_order_relaxed)) + { + /* If mQuit is set, drain frames until we can't get more audio, + * indicating we've reached the flush packet and the packet sender + * will also quit. + */ + do { + mSamplesLen = decodeFrame(); + mSamplesPos = mSamplesLen; + } while(mSamplesLen > 0); + goto finish; + } + ALenum state; if(mBufferDataSize > 0) { alGetSourcei(mSource, AL_SOURCE_STATE, &state); - /* If mQuit is set, don't actually quit until we can't get more - * audio, indicating we've reached the flush packet and the packet - * sender will also quit. - * - * If mQuit is not set, don't quit even if there's no more audio, + + /* If mQuit is not set, don't quit even if there's no more audio, * so what's buffered has a chance to play to the real end. */ - if(!readAudio(getSync()) && mMovie.mQuit.load(std::memory_order_relaxed)) - goto finish; + readAudio(getSync()); } else { @@ -1334,14 +1309,8 @@ int AudioState::handler() /* Read the next chunk of data, filling the buffer, and queue * it on the source. */ - const bool got_audio{readAudio(samples.get(), static_cast(buffer_len), - sync_skip)}; - if(!got_audio) - { - if(mMovie.mQuit.load(std::memory_order_relaxed)) - goto finish; + if(!readAudio(samples.get(), static_cast(buffer_len), sync_skip)) break; - } const ALuint bufid{mBuffers[mBufferIdx]}; mBufferIdx = static_cast((mBufferIdx+1) % mBuffers.size()); @@ -2046,9 +2015,7 @@ int main(int argc, char *argv[]) else { std::cout<< "Found AL_SOFT_UHJ" < alcFunctions{{ DECL(alDopplerVelocity), DECL(alSpeedOfSound), DECL(alDistanceModel), + + /* EFX 1.0 */ + DECL(alGenFilters), + DECL(alDeleteFilters), + DECL(alIsFilter), + DECL(alFilterf), + DECL(alFilterfv), + DECL(alFilteri), + DECL(alFilteriv), + DECL(alGetFilterf), + DECL(alGetFilterfv), + DECL(alGetFilteri), + DECL(alGetFilteriv), + DECL(alGenEffects), + DECL(alDeleteEffects), + DECL(alIsEffect), + DECL(alEffectf), + DECL(alEffectfv), + DECL(alEffecti), + DECL(alEffectiv), + DECL(alGetEffectf), + DECL(alGetEffectfv), + DECL(alGetEffecti), + DECL(alGetEffectiv), + DECL(alGenAuxiliaryEffectSlots), + DECL(alDeleteAuxiliaryEffectSlots), + DECL(alIsAuxiliaryEffectSlot), + DECL(alAuxiliaryEffectSlotf), + DECL(alAuxiliaryEffectSlotfv), + DECL(alAuxiliaryEffectSloti), + DECL(alAuxiliaryEffectSlotiv), + DECL(alGetAuxiliaryEffectSlotf), + DECL(alGetAuxiliaryEffectSlotfv), + DECL(alGetAuxiliaryEffectSloti), + DECL(alGetAuxiliaryEffectSlotiv), }}; #undef DECL @@ -309,6 +344,56 @@ static ALint GetDriverIndexForName(const EnumeratedList *list, const ALCchar *na } +static void InitCtxFuncs(DriverIface &iface) +{ + ALCdevice *device{iface.alcGetContextsDevice(iface.alcGetCurrentContext())}; + +#define LOAD_PROC(x) do { \ + iface.x = reinterpret_cast(iface.alGetProcAddress(#x));\ + if(!iface.x) \ + ERR("Failed to find entry point for %s in %ls\n", #x, \ + iface.Name.c_str()); \ +} while(0) + if(iface.alcIsExtensionPresent(device, "ALC_EXT_EFX")) + { + LOAD_PROC(alGenFilters); + LOAD_PROC(alDeleteFilters); + LOAD_PROC(alIsFilter); + LOAD_PROC(alFilterf); + LOAD_PROC(alFilterfv); + LOAD_PROC(alFilteri); + LOAD_PROC(alFilteriv); + LOAD_PROC(alGetFilterf); + LOAD_PROC(alGetFilterfv); + LOAD_PROC(alGetFilteri); + LOAD_PROC(alGetFilteriv); + LOAD_PROC(alGenEffects); + LOAD_PROC(alDeleteEffects); + LOAD_PROC(alIsEffect); + LOAD_PROC(alEffectf); + LOAD_PROC(alEffectfv); + LOAD_PROC(alEffecti); + LOAD_PROC(alEffectiv); + LOAD_PROC(alGetEffectf); + LOAD_PROC(alGetEffectfv); + LOAD_PROC(alGetEffecti); + LOAD_PROC(alGetEffectiv); + LOAD_PROC(alGenAuxiliaryEffectSlots); + LOAD_PROC(alDeleteAuxiliaryEffectSlots); + LOAD_PROC(alIsAuxiliaryEffectSlot); + LOAD_PROC(alAuxiliaryEffectSlotf); + LOAD_PROC(alAuxiliaryEffectSlotfv); + LOAD_PROC(alAuxiliaryEffectSloti); + LOAD_PROC(alAuxiliaryEffectSlotiv); + LOAD_PROC(alGetAuxiliaryEffectSlotf); + LOAD_PROC(alGetAuxiliaryEffectSlotfv); + LOAD_PROC(alGetAuxiliaryEffectSloti); + LOAD_PROC(alGetAuxiliaryEffectSlotiv); + } +#undef LOAD_PROC +} + + ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename) { ALCdevice *device = nullptr; @@ -345,17 +430,17 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename) return nullptr; } TRACE("Found driver %d for name \"%s\"\n", idx, devicename); - device = DriverList[idx].alcOpenDevice(devicename); + device = DriverList[idx]->alcOpenDevice(devicename); } else { for(const auto &drv : DriverList) { - if(drv.ALCVer >= MAKE_ALC_VER(1, 1) || - drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT")) + if(drv->ALCVer >= MAKE_ALC_VER(1, 1) + || drv->alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT")) { TRACE("Using default device from driver %d\n", idx); - device = drv.alcOpenDevice(nullptr); + device = drv->alcOpenDevice(nullptr); break; } ++idx; @@ -366,7 +451,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename) { if(DeviceIfaceMap.insert(device, idx) != ALC_NO_ERROR) { - DriverList[idx].alcCloseDevice(device); + DriverList[idx]->alcCloseDevice(device); device = nullptr; } } @@ -383,7 +468,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) LastError.store(ALC_INVALID_DEVICE); return ALC_FALSE; } - if(!DriverList[idx].alcCloseDevice(device)) + if(!DriverList[idx]->alcCloseDevice(device)) return ALC_FALSE; DeviceIfaceMap.removeByKey(device); return ALC_TRUE; @@ -400,12 +485,12 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin LastError.store(ALC_INVALID_DEVICE); return nullptr; } - context = DriverList[idx].alcCreateContext(device, attrlist); + context = DriverList[idx]->alcCreateContext(device, attrlist); if(context) { if(ContextIfaceMap.insert(context, idx) != ALC_NO_ERROR) { - DriverList[idx].alcDestroyContext(context); + DriverList[idx]->alcDestroyContext(context); context = nullptr; } } @@ -426,8 +511,11 @@ ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context) LastError.store(ALC_INVALID_CONTEXT); return ALC_FALSE; } - if(!DriverList[idx].alcMakeContextCurrent(context)) + if(!DriverList[idx]->alcMakeContextCurrent(context)) return ALC_FALSE; + + auto do_init = [idx]() { InitCtxFuncs(*DriverList[idx]); }; + std::call_once(DriverList[idx]->InitOnceCtx, do_init); } /* Unset the context from the old driver if it's different from the new @@ -443,10 +531,10 @@ ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context) else { DriverIface *oldiface = GetThreadDriver(); - if(oldiface && oldiface != &DriverList[idx]) + if(oldiface && oldiface != DriverList[idx].get()) oldiface->alcSetThreadContext(nullptr); - oldiface = CurrentCtxDriver.exchange(&DriverList[idx]); - if(oldiface && oldiface != &DriverList[idx]) + oldiface = CurrentCtxDriver.exchange(DriverList[idx].get()); + if(oldiface && oldiface != DriverList[idx].get()) oldiface->alcMakeContextCurrent(nullptr); } SetThreadDriver(nullptr); @@ -460,7 +548,7 @@ ALC_API void ALC_APIENTRY alcProcessContext(ALCcontext *context) { ALint idx = ContextIfaceMap.lookupByKey(context); if(idx >= 0) - return DriverList[idx].alcProcessContext(context); + return DriverList[idx]->alcProcessContext(context); } LastError.store(ALC_INVALID_CONTEXT); } @@ -471,7 +559,7 @@ ALC_API void ALC_APIENTRY alcSuspendContext(ALCcontext *context) { ALint idx = ContextIfaceMap.lookupByKey(context); if(idx >= 0) - return DriverList[idx].alcSuspendContext(context); + return DriverList[idx]->alcSuspendContext(context); } LastError.store(ALC_INVALID_CONTEXT); } @@ -486,7 +574,7 @@ ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context) return; } - DriverList[idx].alcDestroyContext(context); + DriverList[idx]->alcDestroyContext(context); ContextIfaceMap.removeByKey(context); } @@ -503,7 +591,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *context) { ALint idx = ContextIfaceMap.lookupByKey(context); if(idx >= 0) - return DriverList[idx].alcGetContextsDevice(context); + return DriverList[idx]->alcGetContextsDevice(context); } LastError.store(ALC_INVALID_CONTEXT); return nullptr; @@ -516,7 +604,7 @@ ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device) { ALint idx = DeviceIfaceMap.lookupByKey(device); if(idx < 0) return ALC_INVALID_DEVICE; - return DriverList[idx].alcGetError(device); + return DriverList[idx]->alcGetError(device); } return LastError.exchange(ALC_NO_ERROR); } @@ -534,7 +622,7 @@ ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const A LastError.store(ALC_INVALID_DEVICE); return ALC_FALSE; } - return DriverList[idx].alcIsExtensionPresent(device, extname); + return DriverList[idx]->alcIsExtensionPresent(device, extname); } len = strlen(extname); @@ -563,7 +651,7 @@ ALC_API void* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *f LastError.store(ALC_INVALID_DEVICE); return nullptr; } - return DriverList[idx].alcGetProcAddress(device, funcname); + return DriverList[idx]->alcGetProcAddress(device, funcname); } auto iter = std::find_if(alcFunctions.cbegin(), alcFunctions.cend(), @@ -583,7 +671,7 @@ ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *e LastError.store(ALC_INVALID_DEVICE); return 0; } - return DriverList[idx].alcGetEnumValue(device, enumname); + return DriverList[idx]->alcGetEnumValue(device, enumname); } auto iter = std::find_if(alcEnumerations.cbegin(), alcEnumerations.cend(), @@ -603,7 +691,7 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum para LastError.store(ALC_INVALID_DEVICE); return nullptr; } - return DriverList[idx].alcGetString(device, param); + return DriverList[idx]->alcGetString(device, param); } switch(param) @@ -631,10 +719,10 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum para for(const auto &drv : DriverList) { /* Only enumerate names from drivers that support it. */ - if(drv.ALCVer >= MAKE_ALC_VER(1, 1) - || drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT")) + if(drv->ALCVer >= MAKE_ALC_VER(1, 1) + || drv->alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT")) AppendDeviceList(&DevicesList, - drv.alcGetString(nullptr, ALC_DEVICE_SPECIFIER), idx); + drv->alcGetString(nullptr, ALC_DEVICE_SPECIFIER), idx); ++idx; } /* Ensure the list is double-null termianted. */ @@ -654,13 +742,13 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum para /* If the driver doesn't support ALC_ENUMERATE_ALL_EXT, substitute * standard enumeration. */ - if(drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT")) + if(drv->alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT")) AppendDeviceList(&AllDevicesList, - drv.alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER), idx); - else if(drv.ALCVer >= MAKE_ALC_VER(1, 1) - || drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT")) + drv->alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER), idx); + else if(drv->ALCVer >= MAKE_ALC_VER(1, 1) + || drv->alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT")) AppendDeviceList(&AllDevicesList, - drv.alcGetString(nullptr, ALC_DEVICE_SPECIFIER), idx); + drv->alcGetString(nullptr, ALC_DEVICE_SPECIFIER), idx); ++idx; } /* Ensure the list is double-null termianted. */ @@ -677,10 +765,10 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum para ALint idx{0}; for(const auto &drv : DriverList) { - if(drv.ALCVer >= MAKE_ALC_VER(1, 1) - || drv.alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE")) + if(drv->ALCVer >= MAKE_ALC_VER(1, 1) + || drv->alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE")) AppendDeviceList(&CaptureDevicesList, - drv.alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER), idx); + drv->alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER), idx); ++idx; } /* Ensure the list is double-null termianted. */ @@ -692,39 +780,33 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum para case ALC_DEFAULT_DEVICE_SPECIFIER: { - auto iter = std::find_if(DriverList.cbegin(), DriverList.cend(), - [](const DriverIface &drv) -> bool - { - return drv.ALCVer >= MAKE_ALC_VER(1, 1) - || drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"); - } - ); - if(iter != DriverList.cend()) - return iter->alcGetString(nullptr, ALC_DEFAULT_DEVICE_SPECIFIER); + for(const auto &drv : DriverList) + { + if(drv->ALCVer >= MAKE_ALC_VER(1, 1) + || drv->alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT")) + return drv->alcGetString(nullptr, ALC_DEFAULT_DEVICE_SPECIFIER); + } return ""; } case ALC_DEFAULT_ALL_DEVICES_SPECIFIER: { - auto iter = std::find_if(DriverList.cbegin(), DriverList.cend(), - [](const DriverIface &drv) -> bool - { return drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT") != ALC_FALSE; }); - if(iter != DriverList.cend()) - return iter->alcGetString(nullptr, ALC_DEFAULT_ALL_DEVICES_SPECIFIER); + for(const auto &drv : DriverList) + { + if(drv->alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT") != ALC_FALSE) + return drv->alcGetString(nullptr, ALC_DEFAULT_ALL_DEVICES_SPECIFIER); + } return ""; } case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER: { - auto iter = std::find_if(DriverList.cbegin(), DriverList.cend(), - [](const DriverIface &drv) -> bool - { - return drv.ALCVer >= MAKE_ALC_VER(1, 1) - || drv.alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE"); - } - ); - if(iter != DriverList.cend()) - return iter->alcGetString(nullptr, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER); + for(const auto &drv : DriverList) + { + if(drv->ALCVer >= MAKE_ALC_VER(1, 1) + || drv->alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE")) + return drv->alcGetString(nullptr, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER); + } return ""; } @@ -745,7 +827,7 @@ ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsi LastError.store(ALC_INVALID_DEVICE); return; } - return DriverList[idx].alcGetIntegerv(device, param, size, values); + return DriverList[idx]->alcGetIntegerv(device, param, size, values); } if(size <= 0 || values == nullptr) @@ -813,17 +895,17 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *devicename, return nullptr; } TRACE("Found driver %d for name \"%s\"\n", idx, devicename); - device = DriverList[idx].alcCaptureOpenDevice(devicename, frequency, format, buffersize); + device = DriverList[idx]->alcCaptureOpenDevice(devicename, frequency, format, buffersize); } else { for(const auto &drv : DriverList) { - if(drv.ALCVer >= MAKE_ALC_VER(1, 1) - || drv.alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE")) + if(drv->ALCVer >= MAKE_ALC_VER(1, 1) + || drv->alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE")) { TRACE("Using default capture device from driver %d\n", idx); - device = drv.alcCaptureOpenDevice(nullptr, frequency, format, buffersize); + device = drv->alcCaptureOpenDevice(nullptr, frequency, format, buffersize); break; } ++idx; @@ -834,7 +916,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *devicename, { if(DeviceIfaceMap.insert(device, idx) != ALC_NO_ERROR) { - DriverList[idx].alcCaptureCloseDevice(device); + DriverList[idx]->alcCaptureCloseDevice(device); device = nullptr; } } @@ -851,7 +933,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) LastError.store(ALC_INVALID_DEVICE); return ALC_FALSE; } - if(!DriverList[idx].alcCaptureCloseDevice(device)) + if(!DriverList[idx]->alcCaptureCloseDevice(device)) return ALC_FALSE; DeviceIfaceMap.removeByKey(device); return ALC_TRUE; @@ -863,7 +945,7 @@ ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device) { ALint idx = DeviceIfaceMap.lookupByKey(device); if(idx >= 0) - return DriverList[idx].alcCaptureStart(device); + return DriverList[idx]->alcCaptureStart(device); } LastError.store(ALC_INVALID_DEVICE); } @@ -874,7 +956,7 @@ ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device) { ALint idx = DeviceIfaceMap.lookupByKey(device); if(idx >= 0) - return DriverList[idx].alcCaptureStop(device); + return DriverList[idx]->alcCaptureStop(device); } LastError.store(ALC_INVALID_DEVICE); } @@ -885,7 +967,7 @@ ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, { ALint idx = DeviceIfaceMap.lookupByKey(device); if(idx >= 0) - return DriverList[idx].alcCaptureSamples(device, buffer, samples); + return DriverList[idx]->alcCaptureSamples(device, buffer, samples); } LastError.store(ALC_INVALID_DEVICE); } @@ -908,17 +990,20 @@ ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context) idx = ContextIfaceMap.lookupByKey(context); if(idx >= 0) { - if(DriverList[idx].alcSetThreadContext(context)) + if(DriverList[idx]->alcSetThreadContext(context)) { + auto do_init = [idx]() { InitCtxFuncs(*DriverList[idx]); }; + std::call_once(DriverList[idx]->InitOnceCtx, do_init); + DriverIface *oldiface = GetThreadDriver(); - if(oldiface != &DriverList[idx]) + if(oldiface != DriverList[idx].get()) { - SetThreadDriver(&DriverList[idx]); + SetThreadDriver(DriverList[idx].get()); if(oldiface) oldiface->alcSetThreadContext(nullptr); } return ALC_TRUE; } - err = DriverList[idx].alcGetError(nullptr); + err = DriverList[idx]->alcGetError(nullptr); } LastError.store(err); return ALC_FALSE; diff --git a/modules/openal-soft/router/router.cpp b/modules/openal-soft/router/router.cpp index 67c3481..a0ce165 100644 --- a/modules/openal-soft/router/router.cpp +++ b/modules/openal-soft/router/router.cpp @@ -17,7 +17,7 @@ #include "version.h" -std::vector DriverList; +std::vector DriverList; thread_local DriverIface *ThreadCtxDriver; @@ -84,13 +84,13 @@ static void AddModule(HMODULE module, const WCHAR *name) { for(auto &drv : DriverList) { - if(drv.Module == module) + if(drv->Module == module) { TRACE("Skipping already-loaded module %p\n", decltype(std::declval()){module}); FreeLibrary(module); return; } - if(drv.Name == name) + if(drv->Name == name) { TRACE("Skipping similarly-named module %ls\n", name); FreeLibrary(module); @@ -98,8 +98,8 @@ static void AddModule(HMODULE module, const WCHAR *name) } } - DriverList.emplace_back(name, module); - DriverIface &newdrv = DriverList.back(); + DriverList.emplace_back(std::make_unique(name, module)); + DriverIface &newdrv = *DriverList.back(); /* Load required functions. */ int err = 0; diff --git a/modules/openal-soft/router/router.h b/modules/openal-soft/router/router.h index f49a96e..2a126d4 100644 --- a/modules/openal-soft/router/router.h +++ b/modules/openal-soft/router/router.h @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -24,6 +25,7 @@ struct DriverIface { std::wstring Name; HMODULE Module{nullptr}; int ALCVer{0}; + std::once_flag InitOnceCtx{}; LPALCCREATECONTEXT alcCreateContext{nullptr}; LPALCMAKECONTEXTCURRENT alcMakeContextCurrent{nullptr}; @@ -123,6 +125,41 @@ struct DriverIface { LPALSPEEDOFSOUND alSpeedOfSound{nullptr}; LPALDISTANCEMODEL alDistanceModel{nullptr}; + /* Functions to load after first context creation. */ + LPALGENFILTERS alGenFilters{nullptr}; + LPALDELETEFILTERS alDeleteFilters{nullptr}; + LPALISFILTER alIsFilter{nullptr}; + LPALFILTERF alFilterf{nullptr}; + LPALFILTERFV alFilterfv{nullptr}; + LPALFILTERI alFilteri{nullptr}; + LPALFILTERIV alFilteriv{nullptr}; + LPALGETFILTERF alGetFilterf{nullptr}; + LPALGETFILTERFV alGetFilterfv{nullptr}; + LPALGETFILTERI alGetFilteri{nullptr}; + LPALGETFILTERIV alGetFilteriv{nullptr}; + LPALGENEFFECTS alGenEffects{nullptr}; + LPALDELETEEFFECTS alDeleteEffects{nullptr}; + LPALISEFFECT alIsEffect{nullptr}; + LPALEFFECTF alEffectf{nullptr}; + LPALEFFECTFV alEffectfv{nullptr}; + LPALEFFECTI alEffecti{nullptr}; + LPALEFFECTIV alEffectiv{nullptr}; + LPALGETEFFECTF alGetEffectf{nullptr}; + LPALGETEFFECTFV alGetEffectfv{nullptr}; + LPALGETEFFECTI alGetEffecti{nullptr}; + LPALGETEFFECTIV alGetEffectiv{nullptr}; + LPALGENAUXILIARYEFFECTSLOTS alGenAuxiliaryEffectSlots{nullptr}; + LPALDELETEAUXILIARYEFFECTSLOTS alDeleteAuxiliaryEffectSlots{nullptr}; + LPALISAUXILIARYEFFECTSLOT alIsAuxiliaryEffectSlot{nullptr}; + LPALAUXILIARYEFFECTSLOTF alAuxiliaryEffectSlotf{nullptr}; + LPALAUXILIARYEFFECTSLOTFV alAuxiliaryEffectSlotfv{nullptr}; + LPALAUXILIARYEFFECTSLOTI alAuxiliaryEffectSloti{nullptr}; + LPALAUXILIARYEFFECTSLOTIV alAuxiliaryEffectSlotiv{nullptr}; + LPALGETAUXILIARYEFFECTSLOTF alGetAuxiliaryEffectSlotf{nullptr}; + LPALGETAUXILIARYEFFECTSLOTFV alGetAuxiliaryEffectSlotfv{nullptr}; + LPALGETAUXILIARYEFFECTSLOTI alGetAuxiliaryEffectSloti{nullptr}; + LPALGETAUXILIARYEFFECTSLOTIV alGetAuxiliaryEffectSlotiv{nullptr}; + template DriverIface(T&& name, HMODULE mod) : Name(std::forward(name)), Module(mod) @@ -134,8 +171,9 @@ struct DriverIface { Module = nullptr; } }; +using DriverIfacePtr = std::unique_ptr; -extern std::vector DriverList; +extern std::vector DriverList; extern thread_local DriverIface *ThreadCtxDriver; extern std::atomic CurrentCtxDriver; diff --git a/modules/openal-soft/utils/alsoft-config/mainwindow.cpp b/modules/openal-soft/utils/alsoft-config/mainwindow.cpp index baecf52..3565493 100644 --- a/modules/openal-soft/utils/alsoft-config/mainwindow.cpp +++ b/modules/openal-soft/utils/alsoft-config/mainwindow.cpp @@ -86,6 +86,7 @@ static const struct NameValuePair { { "5.1 Surround", "surround51" }, { "6.1 Surround", "surround61" }, { "7.1 Surround", "surround71" }, + { "3D7.1 Surround", "surround3d71" }, { "Ambisonic, 1st Order", "ambi1" }, { "Ambisonic, 2nd Order", "ambi2" }, @@ -347,6 +348,12 @@ MainWindow::MainWindow(QWidget *parent) : ui->enableSSE41CheckBox->setVisible(false); #endif /* !SSE4.1 */ +#endif + +#ifndef ALSOFT_EAX + ui->enableEaxCheck->setChecked(Qt::Unchecked); + ui->enableEaxCheck->setEnabled(false); + ui->enableEaxCheck->setVisible(false); #endif mPeriodSizeValidator = new QIntValidator{64, 8192, this}; @@ -406,6 +413,8 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->decoder61Button, &QPushButton::clicked, this, &MainWindow::select61DecoderFile); connect(ui->decoder71LineEdit, &QLineEdit::textChanged, this, &MainWindow::enableApplyButton); connect(ui->decoder71Button, &QPushButton::clicked, this, &MainWindow::select71DecoderFile); + connect(ui->decoder3D71LineEdit, &QLineEdit::textChanged, this, &MainWindow::enableApplyButton); + connect(ui->decoder3D71Button, &QPushButton::clicked, this, &MainWindow::select3D71DecoderFile); connect(ui->preferredHrtfComboBox, qcb_cicint, this, &MainWindow::enableApplyButton); connect(ui->hrtfStateComboBox, qcb_cicint, this, &MainWindow::enableApplyButton); @@ -448,6 +457,7 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->enableDedicatedCheck, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); connect(ui->enablePitchShifterCheck, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); connect(ui->enableVocalMorpherCheck, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); + connect(ui->enableEaxCheck, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); connect(ui->pulseAutospawnCheckBox, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); connect(ui->pulseAllowMovesCheckBox, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); @@ -922,6 +932,8 @@ void MainWindow::loadConfig(const QString &fname) ui->enableDedicatedCheck->setChecked(!excludefx.contains("dedicated", Qt::CaseInsensitive)); ui->enablePitchShifterCheck->setChecked(!excludefx.contains("pshifter", Qt::CaseInsensitive)); ui->enableVocalMorpherCheck->setChecked(!excludefx.contains("vmorpher", Qt::CaseInsensitive)); + if(ui->enableEaxCheck->isEnabled()) + ui->enableEaxCheck->setChecked(getCheckState(settings.value("eax/enable")) != Qt::Unchecked); ui->pulseAutospawnCheckBox->setCheckState(getCheckState(settings.value("pulse/spawn-server"))); ui->pulseAllowMovesCheckBox->setCheckState(getCheckState(settings.value("pulse/allow-moves"))); @@ -1134,6 +1146,9 @@ void MainWindow::saveConfig(const QString &fname) const if(!ui->enableVocalMorpherCheck->isChecked()) strlist.append("vmorpher"); settings.setValue("excludefx", strlist.join(QChar{','})); + settings.setValue("eax/enable", + (!ui->enableEaxCheck->isEnabled() || ui->enableEaxCheck->isChecked()) + ? QString{/*"true"*/} : QString{"false"}); settings.setValue("pulse/spawn-server", getCheckValue(ui->pulseAutospawnCheckBox)); settings.setValue("pulse/allow-moves", getCheckValue(ui->pulseAllowMovesCheckBox)); @@ -1240,6 +1255,8 @@ void MainWindow::select61DecoderFile() { selectDecoderFile(ui->decoder61LineEdit, "Select 6.1 Surround Decoder");} void MainWindow::select71DecoderFile() { selectDecoderFile(ui->decoder71LineEdit, "Select 7.1 Surround Decoder");} +void MainWindow::select3D71DecoderFile() +{ selectDecoderFile(ui->decoder3D71LineEdit, "Select 3D7.1 Surround Decoder");} void MainWindow::selectDecoderFile(QLineEdit *line, const char *caption) { QString dir{line->text()}; diff --git a/modules/openal-soft/utils/alsoft-config/mainwindow.h b/modules/openal-soft/utils/alsoft-config/mainwindow.h index ca53582..f7af8ea 100644 --- a/modules/openal-soft/utils/alsoft-config/mainwindow.h +++ b/modules/openal-soft/utils/alsoft-config/mainwindow.h @@ -39,6 +39,7 @@ private slots: void select51DecoderFile(); void select61DecoderFile(); void select71DecoderFile(); + void select3D71DecoderFile(); void updateJackBufferSizeEdit(int size); void updateJackBufferSizeSlider(); diff --git a/modules/openal-soft/utils/alsoft-config/mainwindow.ui b/modules/openal-soft/utils/alsoft-config/mainwindow.ui index ba8f83f..8d05767 100644 --- a/modules/openal-soft/utils/alsoft-config/mainwindow.ui +++ b/modules/openal-soft/utils/alsoft-config/mainwindow.ui @@ -625,9 +625,7 @@ quantization with low-level whitenoise. Enables high-quality ambisonic rendering. This mode is capable of frequency-dependent processing, creating a better reproduction of 3D sound rendering over -surround sound speakers. Enabling this also requires -specifying decoder configuration files for the -appropriate speaker configuration you intend to use. +surround sound speakers. Qt::RightToLeft @@ -670,9 +668,9 @@ configuration file. -10 - 160 + 140 551 - 161 + 231 @@ -684,10 +682,10 @@ configuration file. - 120 + 130 30 - 311 - 21 + 301 + 25 @@ -696,8 +694,8 @@ configuration file. 20 30 - 91 - 21 + 101 + 25 @@ -713,7 +711,7 @@ configuration file. 440 30 91 - 21 + 25 @@ -723,10 +721,10 @@ configuration file. - 120 - 60 - 311 - 21 + 130 + 70 + 301 + 25 @@ -734,9 +732,9 @@ configuration file. 440 - 60 + 70 91 - 21 + 25 @@ -747,9 +745,9 @@ configuration file. 20 - 60 - 91 - 21 + 70 + 101 + 25 @@ -763,9 +761,9 @@ configuration file. 20 - 90 - 91 - 21 + 110 + 101 + 25 @@ -778,10 +776,10 @@ configuration file. - 120 - 90 - 311 - 21 + 130 + 110 + 301 + 25 @@ -789,9 +787,9 @@ configuration file. 440 - 90 + 110 91 - 21 + 25 @@ -802,9 +800,9 @@ configuration file. 440 - 120 + 150 91 - 21 + 25 @@ -814,10 +812,10 @@ configuration file. - 120 - 120 - 311 - 21 + 130 + 150 + 301 + 25 @@ -825,9 +823,9 @@ configuration file. 20 - 120 - 91 - 21 + 150 + 101 + 25 @@ -837,6 +835,45 @@ configuration file. Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + 20 + 190 + 101 + 25 + + + + 3D7.1 Surround: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 130 + 190 + 301 + 25 + + + + + + + 440 + 190 + 91 + 25 + + + + Browse... + + @@ -2110,7 +2147,7 @@ be useful for preventing those extensions from being used. 10 - 100 + 60 511 241 @@ -2516,6 +2553,22 @@ added by the ALC_EXT_DEDICATED extension. + + + + 30 + 320 + 231 + 21 + + + + Enables legacy EAX API support. + + + Enable EAX API support + + diff --git a/modules/openal-soft/utils/makemhr/loaddef.cpp b/modules/openal-soft/utils/makemhr/loaddef.cpp index d325eda..ab505f4 100644 --- a/modules/openal-soft/utils/makemhr/loaddef.cpp +++ b/modules/openal-soft/utils/makemhr/loaddef.cpp @@ -37,8 +37,11 @@ #include #include "alfstream.h" +#include "aloptional.h" +#include "alspan.h" #include "alstring.h" #include "makemhr.h" +#include "polyphase_resampler.h" #include "mysofa.h" @@ -1707,14 +1710,11 @@ static int MatchTargetEar(const char *ident) // Calculate the onset time of an HRIR and average it with any existing // timing for its field, elevation, azimuth, and ear. -static double AverageHrirOnset(const uint rate, const uint n, const double *hrir, const double f, const double onset) +static constexpr int OnsetRateMultiple{10}; +static double AverageHrirOnset(PPhaseResampler &rs, al::span upsampled, const uint rate, + const uint n, const double *hrir, const double f, const double onset) { - std::vector upsampled(10 * n); - { - PPhaseResampler rs; - rs.init(rate, 10 * rate); - rs.process(n, hrir, 10 * n, upsampled.data()); - } + rs.process(n, hrir, static_cast(upsampled.size()), upsampled.data()); auto abs_lt = [](const double &lhs, const double &rhs) -> bool { return std::abs(lhs) < std::abs(rhs); }; @@ -1731,9 +1731,9 @@ static void AverageHrirMagnitude(const uint points, const uint n, const double * std::vector r(n); for(i = 0;i < points;i++) - h[i] = complex_d{hrir[i], 0.0}; + h[i] = hrir[i]; for(;i < n;i++) - h[i] = complex_d{0.0, 0.0}; + h[i] = 0.0; FftForward(n, h.data()); MagnitudeResponse(n, h.data(), r.data()); for(i = 0;i < m;i++) @@ -1741,15 +1741,27 @@ static void AverageHrirMagnitude(const uint points, const uint n, const double * } // Process the list of sources in the data set definition. -static int ProcessSources(TokenReaderT *tr, HrirDataT *hData) +static int ProcessSources(TokenReaderT *tr, HrirDataT *hData, const uint outRate) { uint channels = (hData->mChannelType == CT_STEREO) ? 2 : 1; hData->mHrirsBase.resize(channels * hData->mIrCount * hData->mIrSize); double *hrirs = hData->mHrirsBase.data(); - std::vector hrir(hData->mIrPoints); + auto hrir = std::make_unique(hData->mIrSize); uint line, col, fi, ei, ai; int count; + std::vector onsetSamples(OnsetRateMultiple * hData->mIrPoints); + PPhaseResampler onsetResampler; + onsetResampler.init(hData->mIrRate, OnsetRateMultiple*hData->mIrRate); + + al::optional resampler; + if(outRate && outRate != hData->mIrRate) + resampler.emplace().init(hData->mIrRate, outRate); + const double rateScale{outRate ? static_cast(outRate) / hData->mIrRate : 1.0}; + const uint irPoints{outRate + ? std::min(static_cast(std::ceil(hData->mIrPoints*rateScale)), hData->mIrPoints) + : hData->mIrPoints}; + printf("Loading sources..."); fflush(stdout); count = 0; @@ -1862,17 +1874,24 @@ static int ProcessSources(TokenReaderT *tr, HrirDataT *hData) return 0; } - ExtractSofaHrir(sofa, si, 0, src.mOffset, hData->mIrPoints, hrir.data()); + ExtractSofaHrir(sofa, si, 0, src.mOffset, hData->mIrPoints, hrir.get()); azd->mIrs[0] = &hrirs[hData->mIrSize * azd->mIndex]; - azd->mDelays[0] = AverageHrirOnset(hData->mIrRate, hData->mIrPoints, hrir.data(), 1.0, azd->mDelays[0]); - AverageHrirMagnitude(hData->mIrPoints, hData->mFftSize, hrir.data(), 1.0, azd->mIrs[0]); + azd->mDelays[0] = AverageHrirOnset(onsetResampler, onsetSamples, hData->mIrRate, + hData->mIrPoints, hrir.get(), 1.0, azd->mDelays[0]); + if(resampler) + resampler->process(hData->mIrPoints, hrir.get(), hData->mIrSize, hrir.get()); + AverageHrirMagnitude(irPoints, hData->mFftSize, hrir.get(), 1.0, azd->mIrs[0]); if(src.mChannel == 1) { - ExtractSofaHrir(sofa, si, 1, src.mOffset, hData->mIrPoints, hrir.data()); + ExtractSofaHrir(sofa, si, 1, src.mOffset, hData->mIrPoints, hrir.get()); azd->mIrs[1] = &hrirs[hData->mIrSize * (hData->mIrCount + azd->mIndex)]; - azd->mDelays[1] = AverageHrirOnset(hData->mIrRate, hData->mIrPoints, hrir.data(), 1.0, azd->mDelays[1]); - AverageHrirMagnitude(hData->mIrPoints, hData->mFftSize, hrir.data(), 1.0, azd->mIrs[1]); + azd->mDelays[1] = AverageHrirOnset(onsetResampler, onsetSamples, + hData->mIrRate, hData->mIrPoints, hrir.get(), 1.0, azd->mDelays[1]); + if(resampler) + resampler->process(hData->mIrPoints, hrir.get(), hData->mIrSize, + hrir.get()); + AverageHrirMagnitude(irPoints, hData->mFftSize, hrir.get(), 1.0, azd->mIrs[1]); } // TODO: Since some SOFA files contain minimum phase HRIRs, @@ -1911,7 +1930,7 @@ static int ProcessSources(TokenReaderT *tr, HrirDataT *hData) printf("\rLoading sources... %d file%s", count, (count==1)?"":"s"); fflush(stdout); - if(!LoadSource(&src, hData->mIrRate, hData->mIrPoints, hrir.data())) + if(!LoadSource(&src, hData->mIrRate, hData->mIrPoints, hrir.get())) return 0; uint ti{0}; @@ -1929,8 +1948,12 @@ static int ProcessSources(TokenReaderT *tr, HrirDataT *hData) } } azd->mIrs[ti] = &hrirs[hData->mIrSize * (ti * hData->mIrCount + azd->mIndex)]; - azd->mDelays[ti] = AverageHrirOnset(hData->mIrRate, hData->mIrPoints, hrir.data(), 1.0 / factor[ti], azd->mDelays[ti]); - AverageHrirMagnitude(hData->mIrPoints, hData->mFftSize, hrir.data(), 1.0 / factor[ti], azd->mIrs[ti]); + azd->mDelays[ti] = AverageHrirOnset(onsetResampler, onsetSamples, hData->mIrRate, + hData->mIrPoints, hrir.get(), 1.0 / factor[ti], azd->mDelays[ti]); + if(resampler) + resampler->process(hData->mIrPoints, hrir.get(), hData->mIrSize, hrir.get()); + AverageHrirMagnitude(irPoints, hData->mFftSize, hrir.get(), 1.0 / factor[ti], + azd->mIrs[ti]); factor[ti] += 1.0; if(!TrIsOperator(tr, "+")) break; @@ -1951,6 +1974,13 @@ static int ProcessSources(TokenReaderT *tr, HrirDataT *hData) } } printf("\n"); + hrir = nullptr; + if(resampler) + { + hData->mIrRate = outRate; + hData->mIrPoints = irPoints; + resampler.reset(); + } for(fi = 0;fi < hData->mFdCount;fi++) { for(ei = 0;ei < hData->mFds[fi].mEvCount;ei++) @@ -2012,14 +2042,14 @@ static int ProcessSources(TokenReaderT *tr, HrirDataT *hData) bool LoadDefInput(std::istream &istream, const char *startbytes, std::streamsize startbytecount, - const char *filename, const uint fftSize, const uint truncSize, const ChannelModeT chanMode, - HrirDataT *hData) + const char *filename, const uint fftSize, const uint truncSize, const uint outRate, + const ChannelModeT chanMode, HrirDataT *hData) { TokenReaderT tr{istream}; TrSetup(startbytes, startbytecount, filename, &tr); if(!ProcessMetrics(&tr, fftSize, truncSize, chanMode, hData) - || !ProcessSources(&tr, hData)) + || !ProcessSources(&tr, hData, outRate)) return false; return true; diff --git a/modules/openal-soft/utils/makemhr/loaddef.h b/modules/openal-soft/utils/makemhr/loaddef.h index 34fbb83..63600dc 100644 --- a/modules/openal-soft/utils/makemhr/loaddef.h +++ b/modules/openal-soft/utils/makemhr/loaddef.h @@ -7,7 +7,7 @@ bool LoadDefInput(std::istream &istream, const char *startbytes, std::streamsize startbytecount, - const char *filename, const uint fftSize, const uint truncSize, const ChannelModeT chanMode, - HrirDataT *hData); + const char *filename, const uint fftSize, const uint truncSize, const uint outRate, + const ChannelModeT chanMode, HrirDataT *hData); #endif /* LOADDEF_H */ diff --git a/modules/openal-soft/utils/makemhr/loadsofa.cpp b/modules/openal-soft/utils/makemhr/loadsofa.cpp index 7d091be..18e8463 100644 --- a/modules/openal-soft/utils/makemhr/loadsofa.cpp +++ b/modules/openal-soft/utils/makemhr/loadsofa.cpp @@ -37,6 +37,8 @@ #include #include +#include "aloptional.h" +#include "alspan.h" #include "makemhr.h" #include "polyphase_resampler.h" #include "sofa-support.h" @@ -234,7 +236,7 @@ bool CheckIrData(MYSOFA_HRTF *sofaHrtf) /* Calculate the onset time of a HRIR. */ static constexpr int OnsetRateMultiple{10}; static double CalcHrirOnset(PPhaseResampler &rs, const uint rate, const uint n, - std::vector &upsampled, const double *hrir) + al::span upsampled, const double *hrir) { rs.process(n, hrir, static_cast(upsampled.size()), upsampled.data()); @@ -246,8 +248,7 @@ static double CalcHrirOnset(PPhaseResampler &rs, const uint rate, const uint n, } /* Calculate the magnitude response of a HRIR. */ -static void CalcHrirMagnitude(const uint points, const uint n, std::vector &h, - double *hrir) +static void CalcHrirMagnitude(const uint points, const uint n, al::span h, double *hrir) { auto iter = std::copy_n(hrir, points, h.begin()); std::fill(iter, h.end(), complex_d{0.0, 0.0}); @@ -256,16 +257,24 @@ static void CalcHrirMagnitude(const uint points, const uint n, std::vector loaded_count{0u}; - auto load_proc = [sofaHrtf,hData,&loaded_count]() -> bool + auto load_proc = [sofaHrtf,hData,outRate,&loaded_count]() -> bool { const uint channels{(hData->mChannelType == CT_STEREO) ? 2u : 1u}; hData->mHrirsBase.resize(channels * hData->mIrCount * hData->mIrSize, 0.0); double *hrirs = hData->mHrirsBase.data(); + std::unique_ptr restmp; + al::optional resampler; + if(outRate && outRate != hData->mIrRate) + { + resampler.emplace().init(hData->mIrRate, outRate); + restmp = std::make_unique(sofaHrtf->N); + } + for(uint si{0u};si < sofaHrtf->M;++si) { loaded_count.fetch_add(1u); @@ -313,8 +322,15 @@ static bool LoadResponses(MYSOFA_HRTF *sofaHrtf, HrirDataT *hData) for(uint ti{0u};ti < channels;++ti) { azd->mIrs[ti] = &hrirs[hData->mIrSize * (hData->mIrCount*ti + azd->mIndex)]; - std::copy_n(&sofaHrtf->DataIR.values[(si*sofaHrtf->R + ti)*sofaHrtf->N], - hData->mIrPoints, azd->mIrs[ti]); + if(!resampler) + std::copy_n(&sofaHrtf->DataIR.values[(si*sofaHrtf->R + ti)*sofaHrtf->N], + sofaHrtf->N, azd->mIrs[ti]); + else + { + std::copy_n(&sofaHrtf->DataIR.values[(si*sofaHrtf->R + ti)*sofaHrtf->N], + sofaHrtf->N, restmp.get()); + resampler->process(sofaHrtf->N, restmp.get(), hData->mIrSize, azd->mIrs[ti]); + } } /* TODO: Since some SOFA files contain minimum phase HRIRs, @@ -322,6 +338,14 @@ static bool LoadResponses(MYSOFA_HRTF *sofaHrtf, HrirDataT *hData) * (when available) to reconstruct the HRTDs. */ } + + if(outRate && outRate != hData->mIrRate) + { + const double scale{static_cast(outRate) / hData->mIrRate}; + hData->mIrRate = outRate; + hData->mIrPoints = std::min(static_cast(std::ceil(hData->mIrPoints*scale)), + hData->mIrSize); + } return true; }; @@ -376,7 +400,7 @@ struct MagCalculator { }; bool LoadSofaFile(const char *filename, const uint numThreads, const uint fftSize, - const uint truncSize, const ChannelModeT chanMode, HrirDataT *hData) + const uint truncSize, const uint outRate, const ChannelModeT chanMode, HrirDataT *hData) { int err; MySofaHrtfPtr sofaHrtf{mysofa_load(filename, &err)}; @@ -435,7 +459,7 @@ bool LoadSofaFile(const char *filename, const uint numThreads, const uint fftSiz if(!PrepareLayout(sofaHrtf->M, sofaHrtf->SourcePosition.values, hData)) return false; - if(!LoadResponses(sofaHrtf.get(), hData)) + if(!LoadResponses(sofaHrtf.get(), hData, outRate)) return false; sofaHrtf = nullptr; diff --git a/modules/openal-soft/utils/makemhr/loadsofa.h b/modules/openal-soft/utils/makemhr/loadsofa.h index 803bcf8..82dce85 100644 --- a/modules/openal-soft/utils/makemhr/loadsofa.h +++ b/modules/openal-soft/utils/makemhr/loadsofa.h @@ -5,6 +5,6 @@ bool LoadSofaFile(const char *filename, const uint numThreads, const uint fftSize, - const uint truncSize, const ChannelModeT chanMode, HrirDataT *hData); + const uint truncSize, const uint outRate, const ChannelModeT chanMode, HrirDataT *hData); #endif /* LOADSOFA_H */ diff --git a/modules/openal-soft/utils/makemhr/makemhr.cpp b/modules/openal-soft/utils/makemhr/makemhr.cpp index 554bdfe..8f7ae63 100644 --- a/modules/openal-soft/utils/makemhr/makemhr.cpp +++ b/modules/openal-soft/utils/makemhr/makemhr.cpp @@ -1392,7 +1392,7 @@ static int ProcessDefinition(const char *inName, const uint outRate, const Chann { inName = "stdin"; fprintf(stdout, "Reading HRIR definition from %s...\n", inName); - if(!LoadDefInput(std::cin, nullptr, 0, inName, fftSize, truncSize, chanMode, &hData)) + if(!LoadDefInput(std::cin, nullptr, 0, inName, fftSize, truncSize, outRate, chanMode, &hData)) return 0; } else @@ -1418,13 +1418,13 @@ static int ProcessDefinition(const char *inName, const uint outRate, const Chann { input = nullptr; fprintf(stdout, "Reading HRTF data from %s...\n", inName); - if(!LoadSofaFile(inName, numThreads, fftSize, truncSize, chanMode, &hData)) + if(!LoadSofaFile(inName, numThreads, fftSize, truncSize, outRate, chanMode, &hData)) return 0; } else { fprintf(stdout, "Reading HRIR definition from %s...\n", inName); - if(!LoadDefInput(*input, startbytes, startbytecount, inName, fftSize, truncSize, chanMode, &hData)) + if(!LoadDefInput(*input, startbytes, startbytecount, inName, fftSize, truncSize, outRate, chanMode, &hData)) return 0; } }