Browse Source

Update OpenAL Soft module

master
C. J. Howard 1 year ago
parent
commit
7d35d66e7d
99 changed files with 7128 additions and 10297 deletions
  1. +3
    -0
      CMakeLists.txt
  2. +1
    -1
      modules/antkeeper-source
  3. +19
    -1
      modules/openal-soft/.github/workflows/ci.yml
  4. +47
    -23
      modules/openal-soft/Alc/alc.cpp
  5. +56
    -58
      modules/openal-soft/Alc/alu.cpp
  6. +20
    -54
      modules/openal-soft/Alc/backends/base.cpp
  7. +0
    -5
      modules/openal-soft/Alc/backends/base.h
  8. +25
    -22
      modules/openal-soft/Alc/backends/coreaudio.cpp
  9. +47
    -43
      modules/openal-soft/Alc/backends/dsound.cpp
  10. +24
    -66
      modules/openal-soft/Alc/backends/oboe.cpp
  11. +33
    -18
      modules/openal-soft/Alc/backends/opensl.cpp
  12. +108
    -47
      modules/openal-soft/Alc/backends/pipewire.cpp
  13. +2
    -0
      modules/openal-soft/Alc/backends/pulseaudio.cpp
  14. +4
    -1
      modules/openal-soft/Alc/backends/sdl2.cpp
  15. +66
    -17
      modules/openal-soft/Alc/backends/wasapi.cpp
  16. +2
    -0
      modules/openal-soft/Alc/backends/wave.cpp
  17. +2
    -8
      modules/openal-soft/Alc/backends/winmm.cpp
  18. +107
    -135
      modules/openal-soft/Alc/context.cpp
  19. +29
    -62
      modules/openal-soft/Alc/context.h
  20. +1
    -0
      modules/openal-soft/Alc/device.cpp
  21. +2
    -2
      modules/openal-soft/Alc/device.h
  22. +18
    -11
      modules/openal-soft/Alc/effects/reverb.cpp
  23. +54
    -4
      modules/openal-soft/Alc/panning.cpp
  24. +73
    -56
      modules/openal-soft/CMakeLists.txt
  25. +29
    -0
      modules/openal-soft/ChangeLog
  26. +86
    -112
      modules/openal-soft/al/auxeffectslot.cpp
  27. +33
    -70
      modules/openal-soft/al/auxeffectslot.h
  28. +2
    -2
      modules/openal-soft/al/buffer.cpp
  29. +1
    -1
      modules/openal-soft/al/buffer.h
  30. +564
    -157
      modules/openal-soft/al/eax/api.cpp
  31. +175
    -241
      modules/openal-soft/al/eax/api.h
  32. +212
    -0
      modules/openal-soft/al/eax/call.cpp
  33. +97
    -0
      modules/openal-soft/al/eax/call.h
  34. +173
    -0
      modules/openal-soft/al/eax/effect.h
  35. +1
    -2
      modules/openal-soft/al/eax/exception.cpp
  36. +0
    -0
      modules/openal-soft/al/eax/exception.h
  37. +2
    -2
      modules/openal-soft/al/eax/fx_slot_index.cpp
  38. +1
    -1
      modules/openal-soft/al/eax/fx_slot_index.h
  39. +7
    -6
      modules/openal-soft/al/eax/fx_slots.cpp
  40. +5
    -3
      modules/openal-soft/al/eax/fx_slots.h
  41. +1
    -1
      modules/openal-soft/al/eax/globals.cpp
  42. +0
    -0
      modules/openal-soft/al/eax/globals.h
  43. +1
    -1
      modules/openal-soft/al/eax/utils.cpp
  44. +15
    -54
      modules/openal-soft/al/eax/utils.h
  45. +0
    -0
      modules/openal-soft/al/eax/x_ram.h
  46. +0
    -324
      modules/openal-soft/al/eax_eax_call.cpp
  47. +0
    -117
      modules/openal-soft/al/eax_eax_call.h
  48. +0
    -3
      modules/openal-soft/al/eax_effect.cpp
  49. +0
    -44
      modules/openal-soft/al/eax_effect.h
  50. +0
    -3
      modules/openal-soft/al/eax_x_ram.cpp
  51. +1
    -1
      modules/openal-soft/al/effect.cpp
  52. +128
    -358
      modules/openal-soft/al/effects/autowah.cpp
  53. +390
    -1013
      modules/openal-soft/al/effects/chorus.cpp
  54. +64
    -170
      modules/openal-soft/al/effects/compressor.cpp
  55. +149
    -365
      modules/openal-soft/al/effects/distortion.cpp
  56. +149
    -366
      modules/openal-soft/al/effects/echo.cpp
  57. +13
    -13
      modules/openal-soft/al/effects/effects.cpp
  58. +3
    -2
      modules/openal-soft/al/effects/effects.h
  59. +255
    -611
      modules/openal-soft/al/effects/equalizer.cpp
  60. +100
    -263
      modules/openal-soft/al/effects/fshifter.cpp
  61. +103
    -266
      modules/openal-soft/al/effects/modulator.cpp
  62. +14
    -24
      modules/openal-soft/al/effects/null.cpp
  63. +86
    -219
      modules/openal-soft/al/effects/pshifter.cpp
  64. +1081
    -1629
      modules/openal-soft/al/effects/reverb.cpp
  65. +174
    -382
      modules/openal-soft/al/effects/vmorpher.cpp
  66. +822
    -1946
      modules/openal-soft/al/source.cpp
  67. +787
    -545
      modules/openal-soft/al/source.h
  68. +3
    -2
      modules/openal-soft/al/state.cpp
  69. +11
    -7
      modules/openal-soft/alsoftrc.sample
  70. +1
    -1
      modules/openal-soft/appveyor.yml
  71. +7
    -3
      modules/openal-soft/common/almalloc.h
  72. +2
    -2
      modules/openal-soft/common/aloptional.h
  73. +1
    -0
      modules/openal-soft/common/alstring.h
  74. +2
    -2
      modules/openal-soft/common/polyphase_resampler.h
  75. +3
    -0
      modules/openal-soft/config.h.in
  76. +3
    -4
      modules/openal-soft/core/cpu_caps.cpp
  77. +2
    -0
      modules/openal-soft/core/devformat.cpp
  78. +18
    -0
      modules/openal-soft/core/devformat.h
  79. +25
    -12
      modules/openal-soft/core/helpers.cpp
  80. +6
    -6
      modules/openal-soft/core/uhjfilter.cpp
  81. +31
    -17
      modules/openal-soft/core/uhjfilter.h
  82. +17
    -14
      modules/openal-soft/core/voice.cpp
  83. +2
    -2
      modules/openal-soft/core/voice.h
  84. +4
    -11
      modules/openal-soft/docs/3D7.1.txt
  85. +67
    -100
      modules/openal-soft/examples/alffplay.cpp
  86. +13
    -8
      modules/openal-soft/presets/3D7.1.ambdec
  87. +4
    -3
      modules/openal-soft/presets/presets.txt
  88. +39
    -0
      modules/openal-soft/router/al.cpp
  89. +154
    -69
      modules/openal-soft/router/alc.cpp
  90. +5
    -5
      modules/openal-soft/router/router.cpp
  91. +39
    -1
      modules/openal-soft/router/router.h
  92. +17
    -0
      modules/openal-soft/utils/alsoft-config/mainwindow.cpp
  93. +1
    -0
      modules/openal-soft/utils/alsoft-config/mainwindow.h
  94. +92
    -39
      modules/openal-soft/utils/alsoft-config/mainwindow.ui
  95. +53
    -23
      modules/openal-soft/utils/makemhr/loaddef.cpp
  96. +2
    -2
      modules/openal-soft/utils/makemhr/loaddef.h
  97. +33
    -9
      modules/openal-soft/utils/makemhr/loadsofa.cpp
  98. +1
    -1
      modules/openal-soft/utils/makemhr/loadsofa.h
  99. +3
    -3
      modules/openal-soft/utils/makemhr/makemhr.cpp

+ 3
- 0
CMakeLists.txt View File

@ -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"

+ 1
- 1
modules/antkeeper-source

@ -1 +1 @@
Subproject commit 96c678e5fc141df2440e8000d47dcf5cb942cd7c
Subproject commit 30dc77ef0a2d478c519acd78474b26d630b1bc14

+ 19
- 1
modules/openal-soft/.github/workflows/ci.yml View File

@ -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

+ 47
- 23
modules/openal-soft/Alc/alc.cpp View File

@ -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<std::recursive_mutex> _{ListLock};
if(!PlaybackFactory)
@ -1329,7 +1335,7 @@ void ProbeAllDevicesList()
}
void ProbeCaptureDeviceList()
{
DO_INITCONFIG();
InitConfig();
std::lock_guard<std::recursive_mutex> _{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<int>(nullptr, "sends"))
device->NumAuxSends = minu(DEFAULT_SENDS,
static_cast<uint>(clampi(*sendsopt, 0, MAX_SENDS)));
{
const int max_sends{clampi(*sendsopt, 0, MAX_SENDS)};
device->NumAuxSends = minu(DefaultSends, static_cast<uint>(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<uint>(clampi(*sendsopt, 0, MAX_SENDS)));
{
const int max_sends{clampi(*sendsopt, 0, MAX_SENDS)};
device->NumAuxSends = minu(DefaultSends, static_cast<uint>(max_sends));
}
device->NumStereoSources = 1;
device->NumMonoSources = device->SourcesMax - device->NumStereoSources;

+ 56
- 58
modules/openal-soft/Alc/alu.cpp View File

@ -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_<CubicTag,CTag>;
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_<FastBSincTag,NEONTag>;
return Resample_<BSincTag,NEONTag>;
#endif
#ifdef HAVE_SSE
if((CPUCapFlags&CPU_CAP_SSE))
return Resample_<FastBSincTag,SSETag>;
return Resample_<BSincTag,SSETag>;
#endif
return Resample_<FastBSincTag,CTag>;
return Resample_<BSincTag,CTag>;
}
/* fall-through */
case Resampler::FastBSinc12:
case Resampler::FastBSinc24:
#ifdef HAVE_NEON
if((CPUCapFlags&CPU_CAP_NEON))
return Resample_<BSincTag,NEONTag>;
return Resample_<FastBSincTag,NEONTag>;
#endif
#ifdef HAVE_SSE
if((CPUCapFlags&CPU_CAP_SSE))
return Resample_<BSincTag,SSETag>;
return Resample_<FastBSincTag,SSETag>;
#endif
return Resample_<BSincTag,CTag>;
return Resample_<FastBSincTag,CTag>;
}
return Resample_<PointTag,CTag>;
@ -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<std::array<float,MaxAmbiChannels>,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<std::array<float,MaxAmbiChannels>,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<std::array<float,MaxAmbiChannels>,MaxAmbiChannels> &R)
const AmbiRotateMatrix &R)
{
const float ri1{ R[static_cast<uint>(i+2)][ 1+2]};
const float rim1{R[static_cast<uint>(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<std::array<float,MaxAmbiChannels>,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<std::array<float,MaxAmbiChannels>,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<float> : (p0 + p1);
};
auto W = [P](const int l, const int m, const int n, const size_t last_band,
const std::array<std::array<float,MaxAmbiChannels>,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<std::array<float,MaxAmbiChannels>,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<size_t>(msglen) >= sizeof(evt.u.disconnect.msg))
evt.u.disconnect.msg[sizeof(evt.u.disconnect.msg)-1] = 0;
if(msglen < 0 || static_cast<size_t>(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<AsyncEvent*>(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<AsyncEvent*>(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);
}

+ 20
- 54
modules/openal-soft/Alc/backends/base.cpp View File

@ -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<Channel>
{
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

+ 0
- 5
modules/openal-soft/Alc/backends/base.h View File

@ -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<BackendBase>;

+ 25
- 22
modules/openal-soft/Alc/backends/coreaudio.cpp View File

@ -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<uint>(uint64_t{mDevice->BufferSize} *
streamFormat.mSampleRate / mDevice->Frequency);
mDevice->BufferSize = static_cast<uint>(mDevice->BufferSize*streamFormat.mSampleRate/
mDevice->Frequency + 0.5);
mDevice->Frequency = static_cast<uint>(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<uint64_t>(std::ceil(mDevice->BufferSize*srateScale)),
static_cast<UInt32>(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);

+ 47
- 43
modules/openal-soft/Alc/backends/dsound.cpp View File

@ -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<WORD>(mDevice->channelsFromFmt());
OutputType.Format.wBitsPerSample = static_cast<WORD>(mDevice->bytesFromFmt() * 8);
OutputType.Format.nBlockAlign = static_cast<WORD>(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<WORD>(mDevice->channelsFromFmt());
OutputType.Format.wBitsPerSample = static_cast<WORD>(mDevice->bytesFromFmt() * 8);
OutputType.Format.nBlockAlign = static_cast<WORD>(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;
}

+ 24
- 66
modules/openal-soft/Alc/backends/oboe.cpp View File

@ -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<al::byte> 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<uint32_t>(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<int32_t>(mDevice->BufferSize))
->setSampleRate(static_cast<int32_t>(mDevice->Frequency));
->setSampleRate(static_cast<int32_t>(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<int32_t>(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<int32_t>(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<int32_t>(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<uint>(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<uint32_t>(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<uint>(availres.value()), mLastAvail);
const size_t frame_size{static_cast<uint32_t>(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<uint>(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<uint>(result.value()), mLastAvail);
const auto frame_size = static_cast<uint32_t>(mStream->getBytesPerFrame());
return static_cast<uint>(mSamples.size()/frame_size) + mLastAvail;
}
{ return static_cast<uint>(mRing->readSpace()); }
void OboeCapture::captureSamples(al::byte *buffer, uint samples)
{
const auto frame_size = static_cast<uint>(mStream->getBytesPerFrame());
if(const size_t storelen{mSamples.size()})
{
const auto instore = static_cast<uint>(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<int32_t>(samples), 0);
uint got{bool{result} ? static_cast<uint>(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

+ 33
- 18
modules/openal-soft/Alc/backends/opensl.cpp View File

@ -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");
}
}
}

+ 108
- 47
modules/openal-soft/Alc/backends/pipewire.cpp View File

@ -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<spa_data> 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<uint>(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<float*>(datas[i].data);
length = minu(length, data.maxsize/sizeof(float));
*chanptr_end = static_cast<float*>(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;

+ 2
- 0
modules/openal-soft/Alc/backends/pulseaudio.cpp View File

@ -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)};

+ 4
- 1
modules/openal-soft/Alc/backends/sdl2.cpp View File

@ -32,7 +32,10 @@
#include "core/device.h"
#include "core/logging.h"
#include <SDL2/SDL.h>
_Pragma("GCC diagnostic push")
_Pragma("GCC diagnostic ignored \"-Wold-style-cast\"")
#include "SDL.h"
_Pragma("GCC diagnostic pop")
namespace {

+ 66
- 17
modules/openal-soft/Alc/backends/wasapi.cpp View File

@ -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<IAudioClient>{static_cast<IAudioClient*>(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());

+ 2
- 0
modules/openal-soft/Alc/backends/wave.cpp View File

@ -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);

+ 2
- 8
modules/openal-soft/Alc/backends/winmm.cpp View File

@ -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)};

+ 107
- 135
modules/openal-soft/Alc/context.cpp View File

@ -34,8 +34,8 @@
#include <cstring>
#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<std::mutex> 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<std::mutex> 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<ContextException>(eax_.context.guidPrimaryFXSlotID);
call.set_value<ContextException>(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<ContextException>(eax_.context.flDistanceFactor);
call.set_value<ContextException>(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<ContextException>(eax_.context.flAirAbsorptionHF);
call.set_value<ContextException>(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<ContextException>(eax_.context.flHFReference);
call.set_value<ContextException>(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<ContextException>(eax_last_error);
call.set_value<ContextException>(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<ContextException>(eax_speaker_config_);
call.set_value<ContextException>(eax_speaker_config_);
}
void ALCcontext::eax_get_session(
const EaxEaxCall& eax_call)
void ALCcontext::eax_get_session(const EaxCall& call)
{
eax_call.set_value<ContextException>(eax_session_);
call.set_value<ContextException>(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<ContextException>(eax_.context.flMacroFXFactor);
call.set_value<ContextException>(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<ContextException>(static_cast<const EAX40CONTEXTPROPERTIES&>(eax_.context));
call.set_value<ContextException>(static_cast<const EAX40CONTEXTPROPERTIES&>(eax_.context));
break;
case 5:
eax_call.set_value<ContextException>(static_cast<const EAX50CONTEXTPROPERTIES&>(eax_.context));
call.set_value<ContextException>(static_cast<const EAX50CONTEXTPROPERTIES&>(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<std::mutex> 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<ContextException, EAX40CONTEXTPROPERTIES>();
call.get_value<ContextException, EAX40CONTEXTPROPERTIES>();
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<ContextException, EAX50CONTEXTPROPERTIES>();
call.get_value<ContextException, EAX50CONTEXTPROPERTIES>();
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<ContextException, const decltype(EAX50CONTEXTPROPERTIES::guidPrimaryFXSlotID)>();
call.get_value<ContextException, const decltype(EAX50CONTEXTPROPERTIES::guidPrimaryFXSlotID)>();
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<ContextException, const decltype(EAX50CONTEXTPROPERTIES::flDistanceFactor)>();
call.get_value<ContextException, const decltype(EAX50CONTEXTPROPERTIES::flDistanceFactor)>();
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<ContextException, const decltype(EAX50CONTEXTPROPERTIES::flAirAbsorptionHF)>();
call.get_value<ContextException, const decltype(EAX50CONTEXTPROPERTIES::flAirAbsorptionHF)>();
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<ContextException, const decltype(EAX50CONTEXTPROPERTIES::flHFReference)>();
call.get_value<ContextException, const decltype(EAX50CONTEXTPROPERTIES::flHFReference)>();
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<ContextException, const EAXSESSIONPROPERTIES>();
call.get_value<ContextException, const EAXSESSIONPROPERTIES>();
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<ContextException, const decltype(EAX50CONTEXTPROPERTIES::flMacroFXFactor)>();
call.get_value<ContextException, const decltype(EAX50CONTEXTPROPERTIES::flMacroFXFactor)>();
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{};
}

+ 29
- 62
modules/openal-soft/Alc/context.h View File

@ -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

+ 1
- 0
modules/openal-soft/Alc/device.cpp View File

@ -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;

+ 2
- 2
modules/openal-soft/Alc/device.h View File

@ -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<typename T>
al::optional<T> configValue(const char *block, const char *key) = delete;
inline al::optional<T> configValue(const char *block, const char *key) = delete;
DEF_NEWDEL(ALCdevice)
};

+ 18
- 11
modules/openal-soft/Alc/effects/reverb.cpp View File

@ -454,10 +454,8 @@ struct ReverbState final : public EffectState {
alignas(16) std::array<ReverbUpdateLine,NUM_LINES> mEarlySamples{};
alignas(16) std::array<ReverbUpdateLine,NUM_LINES> mLateSamples{};
using MixOutT = void (ReverbState::*)(const al::span<FloatBufferLine> samplesOut,
const size_t counter, const size_t offset, const size_t todo);
MixOutT mMixOut{&ReverbState::MixOutPlain};
bool mUpmixOutput{false};
std::array<float,MaxAmbiOrder+1> mOrderScales{};
std::array<std::array<BandSplitter,NUM_LINES>,2> mAmbiSplitter;
@ -535,6 +533,15 @@ struct ReverbState final : public EffectState {
}
}
void mixOut(const al::span<FloatBufferLine> 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<float> / 2.0f};
constexpr float mod_scale{al::numbers::pi_v<float> * 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<float>(idx&MOD_FRACMASK) / inv_scale)};
const float lfo{std::sin(static_cast<float>(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<float> / 2.0f};
constexpr float mod_scale{al::numbers::pi_v<float> * 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<float>(idx&MOD_FRACMASK) / inv_scale)};
const float lfo{std::sin(static_cast<float>(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
lateUnfaded(offset, todo);
/* Finally, mix early reflections and late reverb. */
(this->*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
earlyFaded(offset, todo, fadeCount, fadeStep);
lateFaded(offset, todo, fadeCount, fadeStep);
(this->*mMixOut)(samplesOut, samplesToDo-base, base, todo);
mixOut(samplesOut, samplesToDo-base, base, todo);
offset += todo;
base += todo;

+ 54
- 4
modules/openal-soft/Alc/panning.cpp View File

@ -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<DualBand, 0>;
@ -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<Channel>(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<DualBand, 6> 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
case DevFmtX51: layout = "surround51"; break;
case DevFmtX61: layout = "surround61"; break;
case DevFmtX71: layout = "surround71"; break;
case DevFmtX3D71: layout = "surround3d71"; break;
/* Mono, Stereo, and Ambisonics output don't use custom decoders. */
case DevFmtMono:
case DevFmtStereo:
@ -915,7 +965,7 @@ void aluInitRenderer(ALCdevice *device, int hrtf_id, al::optional
std::unique_ptr<DecoderConfig<DualBand,MAX_OUTPUT_CHANNELS>> 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{};

+ 73
- 56
modules/openal-soft/CMakeLists.txt View File

@ -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} $<$<COMPILE_LANGUAGE:CXX>:/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 )

+ 29
- 0
modules/openal-soft/ChangeLog View File

@ -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

+ 86
- 112
modules/openal-soft/al/auxeffectslot.cpp View File

@ -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<EaxFxSlotException>(
"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<EaxFxSlotException>(
"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<EaxFxSlotException>(
"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<EaxFxSlotException>(
"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<const EAX40FXSLOTPROPERTIES&>(fx_slot), eax_version);
eax_validate_fx_slot_all(call, static_cast<const EAX40FXSLOTPROPERTIES&>(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<const EAX40FXSLOTPROPERTIES&>(eax_fx_slot));
eax_set_fx_slot_all(call, static_cast<const EAX40FXSLOTPROPERTIES&>(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<EaxFxSlotException, EAX40FXSLOTPROPERTIES>(eax_eax_fx_slot_);
call.set_value<EaxFxSlotException, EAX40FXSLOTPROPERTIES>(eax_eax_fx_slot_);
break;
case 5:
eax_call.set_value<EaxFxSlotException, EAX50FXSLOTPROPERTIES>(eax_eax_fx_slot_);
call.set_value<EaxFxSlotException, EAX50FXSLOTPROPERTIES>(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<EaxFxSlotException>(eax_eax_fx_slot_.guidLoadEffect);
call.set_value<EaxFxSlotException>(eax_eax_fx_slot_.guidLoadEffect);
break;
case EAXFXSLOT_VOLUME:
eax_call.set_value<EaxFxSlotException>(eax_eax_fx_slot_.lVolume);
call.set_value<EaxFxSlotException>(eax_eax_fx_slot_.lVolume);
break;
case EAXFXSLOT_LOCK:
eax_call.set_value<EaxFxSlotException>(eax_eax_fx_slot_.lLock);
call.set_value<EaxFxSlotException>(eax_eax_fx_slot_.lLock);
break;
case EAXFXSLOT_FLAGS:
eax_call.set_value<EaxFxSlotException>(eax_eax_fx_slot_.ulFlags);
call.set_value<EaxFxSlotException>(eax_eax_fx_slot_.ulFlags);
break;
case EAXFXSLOT_OCCLUSION:
eax_call.set_value<EaxFxSlotException>(eax_eax_fx_slot_.lOcclusion);
call.set_value<EaxFxSlotException>(eax_eax_fx_slot_.lOcclusion);
break;
case EAXFXSLOT_OCCLUSIONLFRATIO:
eax_call.set_value<EaxFxSlotException>(eax_eax_fx_slot_.flOcclusionLFRatio);
call.set_value<EaxFxSlotException>(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<EaxFxSlotException, const decltype(EAX40FXSLOTPROPERTIES::guidLoadEffect)>();
call.get_value<EaxFxSlotException, const decltype(EAX40FXSLOTPROPERTIES::guidLoadEffect)>();
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<EaxFxSlotException, const decltype(EAX40FXSLOTPROPERTIES::lVolume)>();
call.get_value<EaxFxSlotException, const decltype(EAX40FXSLOTPROPERTIES::lVolume)>();
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<EaxFxSlotException, const decltype(EAX40FXSLOTPROPERTIES::lLock)>();
call.get_value<EaxFxSlotException, const decltype(EAX40FXSLOTPROPERTIES::lLock)>();
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<EaxFxSlotException, const decltype(EAX40FXSLOTPROPERTIES::ulFlags)>();
call.get_value<EaxFxSlotException, const decltype(EAX40FXSLOTPROPERTIES::ulFlags)>();
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<EaxFxSlotException, const decltype(EAX50FXSLOTPROPERTIES::lOcclusion)>();
call.get_value<EaxFxSlotException, const decltype(EAX50FXSLOTPROPERTIES::lOcclusion)>();
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<EaxFxSlotException, const decltype(EAX50FXSLOTPROPERTIES::flOcclusionLFRatio)>();
call.get_value<EaxFxSlotException, const decltype(EAX50FXSLOTPROPERTIES::flOcclusionLFRatio)>();
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<EaxFxSlotException, const EAX40FXSLOTPROPERTIES>();
call.get_value<EaxFxSlotException, const EAX40FXSLOTPROPERTIES>();
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<EaxFxSlotException, const EAX50FXSLOTPROPERTIES>();
call.get_value<EaxFxSlotException, const EAX50FXSLOTPROPERTIES>();
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_);
}

+ 33
- 70
modules/openal-soft/al/auxeffectslot.h View File

@ -18,10 +18,9 @@
#ifdef ALSOFT_EAX
#include <memory>
#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)`

+ 2
- 2
modules/openal-soft/al/buffer.cpp View File

@ -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

+ 1
- 1
modules/openal-soft/al/buffer.h View File

@ -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 */

modules/openal-soft/al/eax_api.cpp → modules/openal-soft/al/eax/api.cpp View File

@ -9,7 +9,7 @@
#include <algorithm>
#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<const EAX40CONTEXTPROPERTIES&>(lhs) == static_cast<const EAX40CONTEXTPROPERTIES&>(rhs) &&
lhs.flMacroFXFactor == rhs.flMacroFXFactor;
}
const GUID EAXCONTEXT_DEFAULTPRIMARYFXSLOTID = EAXPROPERTYID_EAX40_FXSlot0;
bool operator==(
const EAX40FXSLOTPROPERTIES& lhs,
const EAX40FXSLOTPROPERTIES& rhs) noexcept
{
return
lhs.guidLoadEffect == rhs.guidLoadEffect &&
lhs.lVolume == rhs.lVolume &&
lhs.lLock == rhs.lLock &&
lhs.ulFlags == rhs.ulFlags;
}
bool operator==(
const EAX50FXSLOTPROPERTIES& lhs,
const EAX50FXSLOTPROPERTIES& rhs) noexcept
{
return
static_cast<const EAX40FXSLOTPROPERTIES&>(lhs) == static_cast<const EAX40FXSLOTPROPERTIES&>(rhs) &&
lhs.lOcclusion == rhs.lOcclusion &&
lhs.flOcclusionLFRatio == rhs.flOcclusionLFRatio;
}
const EAX50ACTIVEFXSLOTS EAX40SOURCE_DEFAULTACTIVEFXSLOTID = EAX50ACTIVEFXSLOTS
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,
}};

modules/openal-soft/al/eax_api.h → modules/openal-soft/al/eax/api.h View File

@ -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<unsigned long>(EAX_ENVIRONMENT_GENERIC);
constexpr auto EAX1REVERB_MAXENVIRONMENT = static_cast<unsigned long>(EAX_ENVIRONMENT_PSYCHOTIC);
@ -957,28 +941,27 @@ constexpr auto EAXREVERB_DEFAULTFLAGS =
EAXREVERBFLAGS_DECAYHFLIMIT;
using EaxReverbPresets = std::array<EAXREVERBPROPERTIES, EAX1_ENVIRONMENT_COUNT>;
extern const EaxReverbPresets EAXREVERB_PRESETS;
using Eax1ReverbPresets = std::array<EAX_REVERBPROPERTIES, EAX1_ENVIRONMENT_COUNT>;
extern const Eax1ReverbPresets EAX1REVERB_PRESETS;
using Eax2ReverbPresets = std::array<EAX20LISTENERPROPERTIES, EAX2_ENVIRONMENT_COUNT>;
extern const Eax2ReverbPresets EAX2REVERB_PRESETS;
using EaxReverbPresets = std::array<EAXREVERBPROPERTIES, EAX1_ENVIRONMENT_COUNT>;
extern const EaxReverbPresets EAXREVERB_PRESETS;
// AGC Compressor Effect
extern const GUID EAX_AGCCOMPRESSOR_EFFECT;
enum EAXAGCCOMPRESSOR_PROPERTY :
unsigned int
{
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

+ 212
- 0
modules/openal-soft/al/eax/call.cpp View File

@ -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
};
}

+ 97
- 0
modules/openal-soft/al/eax/call.h View File

@ -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<typename TException, typename TValue>
TValue& get_value() const
{
if (property_size_ < static_cast<ALuint>(sizeof(TValue)))
{
fail_too_small();
}
return *static_cast<TValue*>(property_buffer_);
}
template<typename TValue>
al::span<TValue> get_values(size_t max_count) const
{
if (max_count == 0 || property_size_ < static_cast<ALuint>(sizeof(TValue)))
fail_too_small();
const auto count = minz(property_size_ / sizeof(TValue), max_count);
return al::span<TValue>{static_cast<TValue*>(property_buffer_), count};
}
template<typename TValue>
al::span<TValue> get_values() const
{
return get_values<TValue>(~size_t{});
}
template<typename TException, typename TValue>
void set_value(const TValue& value) const
{
get_value<TException, TValue>() = value;
}
private:
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

+ 173
- 0
modules/openal-soft/al/eax/effect.h View File

@ -0,0 +1,173 @@
#ifndef EAX_EFFECT_INCLUDED
#define EAX_EFFECT_INCLUDED
#include <cassert>
#include <memory>
#include "alnumeric.h"
#include "AL/al.h"
#include "core/effects/base.h"
#include "call.h"
struct EaxEffectErrorMessages
{
static constexpr auto unknown_property_id() noexcept { return "Unknown property id."; }
static constexpr auto unknown_version() noexcept { return "Unknown version."; }
}; // EaxEffectErrorMessages
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<typename TException, typename TProps>
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<typename TValidator, typename TProperty>
static void defer(const EaxCall& call, TProperty& property)
{
const auto& value = call.get_value<Exception, const TProperty>();
TValidator{}(value);
property = value;
}
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<EaxEffect>;
// Creates EAX4+ effect.
template<typename TEffect>
EaxEffectUPtr eax_create_eax4_effect(const EaxCall& call)
{
auto effect = std::make_unique<TEffect>(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

modules/openal-soft/al/eax_exception.cpp → modules/openal-soft/al/eax/exception.cpp View File

@ -1,9 +1,8 @@
#include "config.h"
#include "eax_exception.h"
#include "exception.h"
#include <cassert>
#include <string>

modules/openal-soft/al/eax_exception.h → modules/openal-soft/al/eax/exception.h View File


modules/openal-soft/al/eax_fx_slot_index.cpp → modules/openal-soft/al/eax/fx_slot_index.cpp View File

@ -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

modules/openal-soft/al/eax_fx_slot_index.h → modules/openal-soft/al/eax/fx_slot_index.h View File

@ -5,7 +5,7 @@
#include <cstddef>
#include "aloptional.h"
#include "eax_api.h"
#include "api.h"
using EaxFxSlotIndexValue = std::size_t;

modules/openal-soft/al/eax_fx_slots.cpp → modules/openal-soft/al/eax/fx_slots.cpp View File

@ -1,12 +1,11 @@
#include "config.h"
#include "eax_fx_slots.h"
#include "fx_slots.h"
#include <array>
#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;
}
}

modules/openal-soft/al/eax_fx_slots.h → modules/openal-soft/al/eax/fx_slots.h View File

@ -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

modules/openal-soft/al/eax_globals.cpp → modules/openal-soft/al/eax/globals.cpp View File

@ -1,6 +1,6 @@
#include "config.h"
#include "eax_globals.h"
#include "globals.h"
bool eax_g_is_enabled = true;

modules/openal-soft/al/eax_globals.h → modules/openal-soft/al/eax/globals.h View File


modules/openal-soft/al/eax_utils.cpp → modules/openal-soft/al/eax/utils.cpp View File

@ -1,6 +1,6 @@
#include "config.h"
#include "eax_utils.h"
#include "utils.h"
#include <cassert>
#include <exception>

modules/openal-soft/al/eax_utils.h → modules/openal-soft/al/eax/utils.h View File

@ -6,22 +6,14 @@
#include <string>
#include <type_traits>
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<typename TException, typename TValue>
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<typename T>
struct EaxIsBitFieldStruct {
private:
using yes = std::true_type;
using no = std::false_type;
template<
typename U
>
template<typename U>
static auto test(int) -> decltype(std::declval<typename U::EaxIsBitFieldStruct>(), yes{});
template<
typename
>
template<typename>
static no test(...);
public:
static constexpr auto value = std::is_same<decltype(test<T>(0)), yes>::value;
}; // EaxIsBitFieldStruct
};
template<
typename T,
typename TValue
>
inline bool eax_bit_fields_are_equal(
const T& lhs,
const T& rhs) noexcept
template<typename T, typename TValue>
inline bool eax_bit_fields_are_equal(const T& lhs, const T& rhs) noexcept
{
static_assert(sizeof(T) == sizeof(TValue), "Invalid type size.");
return reinterpret_cast<const TValue&>(lhs) == reinterpret_cast<const TValue&>(rhs);
}
} // namespace detail
template<
typename T,
std::enable_if_t<detail::EaxIsBitFieldStruct<T>::value, int> = 0
>
inline bool operator==(
const T& lhs,
const T& rhs) noexcept
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, void>::value, "Unsupported type.");
return detail::eax_bit_fields_are_equal<T, Value>(lhs, rhs);
}
@ -121,12 +85,9 @@ template<
typename T,
std::enable_if_t<detail::EaxIsBitFieldStruct<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

modules/openal-soft/al/eax_x_ram.h → modules/openal-soft/al/eax/x_ram.h View File


+ 0
- 324
modules/openal-soft/al/eax_eax_call.cpp View File

@ -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
};
}

+ 0
- 117
modules/openal-soft/al/eax_eax_call.h View File

@ -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<ALuint>(sizeof(TValue)))
{
throw TException{"Property buffer too small."};
}
return *static_cast<TValue*>(property_buffer_);
}
template<
typename TException,
typename TValue
>
al::span<TValue> get_values() const
{
if (property_size_ < static_cast<ALuint>(sizeof(TValue)))
{
throw TException{"Property buffer too small."};
}
const auto count = property_size_ / sizeof(TValue);
return al::span<TValue>{static_cast<TValue*>(property_buffer_), count};
}
template<
typename TException,
typename TValue
>
void set_value(
const TValue& value) const
{
get_value<TException, TValue>() = value;
}
private:
const bool is_get_;
int version_;
EaxFxSlotIndex fx_slot_index_;
EaxEaxCallPropertySetId property_set_id_;
ALuint property_id_;
const ALuint property_source_id_;
ALvoid*const property_buffer_;
const ALuint property_size_;
[[noreturn]]
static void fail(
const char* message);
static ALuint convert_eax_v2_0_listener_property_id(
ALuint property_id);
static ALuint convert_eax_v2_0_buffer_property_id(
ALuint property_id);
}; // EaxEaxCall
EaxEaxCall create_eax_call(
bool is_get,
const GUID* property_set_id,
ALuint property_id,
ALuint property_source_id,
ALvoid* property_buffer,
ALuint property_size);
#endif // !EAX_EAX_CALL_INCLUDED

+ 0
- 3
modules/openal-soft/al/eax_effect.cpp View File

@ -1,3 +0,0 @@
#include "config.h"
#include "eax_effect.h"

+ 0
- 44
modules/openal-soft/al/eax_effect.h View File

@ -1,44 +0,0 @@
#ifndef EAX_EFFECT_INCLUDED
#define EAX_EFFECT_INCLUDED
#include <memory>
#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<EaxEffect>;
EaxEffectUPtr eax_create_eax_null_effect();
EaxEffectUPtr eax_create_eax_chorus_effect();
EaxEffectUPtr eax_create_eax_distortion_effect();
EaxEffectUPtr eax_create_eax_echo_effect();
EaxEffectUPtr eax_create_eax_flanger_effect();
EaxEffectUPtr eax_create_eax_frequency_shifter_effect();
EaxEffectUPtr eax_create_eax_vocal_morpher_effect();
EaxEffectUPtr eax_create_eax_pitch_shifter_effect();
EaxEffectUPtr eax_create_eax_ring_modulator_effect();
EaxEffectUPtr eax_create_eax_auto_wah_effect();
EaxEffectUPtr eax_create_eax_compressor_effect();
EaxEffectUPtr eax_create_eax_equalizer_effect();
EaxEffectUPtr eax_create_eax_reverb_effect();
#endif // !EAX_EFFECT_INCLUDED

+ 0
- 3
modules/openal-soft/al/eax_x_ram.cpp View File

@ -1,3 +0,0 @@
#include "config.h"
#include "eax_x_ram.h"

+ 1
- 1
modules/openal-soft/al/effect.cpp View File

@ -54,7 +54,7 @@
#ifdef ALSOFT_EAX
#include <cassert>
#include "eax_exception.h"
#include "eax/exception.h"
#endif // ALSOFT_EAX
const EffectList gEffectList[16]{

+ 128
- 358
modules/openal-soft/al/effects/autowah.cpp View File

@ -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<EaxAutoWahEffectException, EAXAUTOWAHPROPERTIES> {
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<Exception>(
"Attack Time",
flAttackTime,
EAXAUTOWAH_MINATTACKTIME,
EAXAUTOWAH_MAXATTACKTIME);
}
}; // AttackTimeValidator
struct ReleaseTimeValidator {
void operator()(float flReleaseTime) const
{
eax_validate_range<Exception>(
"Release Time",
flReleaseTime,
EAXAUTOWAH_MINRELEASETIME,
EAXAUTOWAH_MAXRELEASETIME);
}
}; // ReleaseTimeValidator
struct ResonanceValidator {
void operator()(long lResonance) const
{
eax_validate_range<Exception>(
"Resonance",
lResonance,
EAXAUTOWAH_MINRESONANCE,
EAXAUTOWAH_MAXRESONANCE);
}
}; // ResonanceValidator
struct PeakLevelValidator {
void operator()(long lPeakLevel) const
{
eax_validate_range<Exception>(
"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<float>(eax_.lResonance)),
al_effect_props_.Autowah.Resonance = clamp(
level_mb_to_gain(static_cast<float>(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<float>(eax_.lPeakLevel)),
al_effect_props_.Autowah.PeakGain = clamp(
level_mb_to_gain(static_cast<float>(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<EaxAutoWahEffectException>(eax_);
break;
case EAXAUTOWAH_ATTACKTIME:
eax_call.set_value<EaxAutoWahEffectException>(eax_.flAttackTime);
break;
case EAXAUTOWAH_RELEASETIME:
eax_call.set_value<EaxAutoWahEffectException>(eax_.flReleaseTime);
break;
case EAXAUTOWAH_RESONANCE:
eax_call.set_value<EaxAutoWahEffectException>(eax_.lResonance);
break;
case EAXAUTOWAH_PEAKLEVEL:
eax_call.set_value<EaxAutoWahEffectException>(eax_.lPeakLevel);
break;
default:
throw EaxAutoWahEffectException{"Unsupported property id."};
case EAXAUTOWAH_NONE: break;
case EAXAUTOWAH_ALLPARAMETERS: call.set_value<Exception>(props); break;
case EAXAUTOWAH_ATTACKTIME: call.set_value<Exception>(props.flAttackTime); break;
case EAXAUTOWAH_RELEASETIME: call.set_value<Exception>(props.flReleaseTime); break;
case EAXAUTOWAH_RESONANCE: call.set_value<Exception>(props.lResonance); break;
case EAXAUTOWAH_PEAKLEVEL: call.set_value<Exception>(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<EaxAutoWahEffectException>(
"Attack Time",
flAttackTime,
EAXAUTOWAH_MINATTACKTIME,
EAXAUTOWAH_MAXATTACKTIME);
}
void EaxAutoWahEffect::validate_release_time(
float flReleaseTime)
{
eax_validate_range<EaxAutoWahEffectException>(
"Release Time",
flReleaseTime,
EAXAUTOWAH_MINRELEASETIME,
EAXAUTOWAH_MAXRELEASETIME);
}
void EaxAutoWahEffect::validate_resonance(
long lResonance)
{
eax_validate_range<EaxAutoWahEffectException>(
"Resonance",
lResonance,
EAXAUTOWAH_MINRESONANCE,
EAXAUTOWAH_MAXRESONANCE);
}
void EaxAutoWahEffect::validate_peak_level(
long lPeakLevel)
{
eax_validate_range<EaxAutoWahEffectException>(
"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<EaxAutoWahEffectException, const decltype(EAXAUTOWAHPROPERTIES::flAttackTime)>();
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<EaxAutoWahEffectException, const decltype(EAXAUTOWAHPROPERTIES::flReleaseTime)>();
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<EaxAutoWahEffectException, const decltype(EAXAUTOWAHPROPERTIES::lResonance)>();
validate_resonance(resonance);
defer_resonance(resonance);
}
void EaxAutoWahEffect::defer_peak_level(
const EaxEaxCall& eax_call)
{
const auto& peak_level =
eax_call.get_value<EaxAutoWahEffectException, const decltype(EAXAUTOWAHPROPERTIES::lPeakLevel)>();
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<EaxAutoWahEffectException, const EAXAUTOWAHPROPERTIES>();
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<AllValidator>(call, props); break;
case EAXAUTOWAH_ATTACKTIME: defer<AttackTimeValidator>(call, props.flAttackTime); break;
case EAXAUTOWAH_RELEASETIME: defer<ReleaseTimeValidator>(call, props.flReleaseTime); break;
case EAXAUTOWAH_RESONANCE: defer<ResonanceValidator>(call, props.lResonance); break;
case EAXAUTOWAH_PEAKLEVEL: defer<PeakLevelValidator>(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<EaxAutoWahEffect>(call);
}
#endif // ALSOFT_EAX

+ 390
- 1013
modules/openal-soft/al/effects/chorus.cpp
File diff suppressed because it is too large
View File


+ 64
- 170
modules/openal-soft/al/effects/compressor.cpp View File

@ -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<EaxCompressorEffectException, EAXAGCCOMPRESSORPROPERTIES>
{
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<Exception>(
"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<ALint>(eax_.ulOnOff),
static_cast<ALint>(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<EaxCompressorEffectException>(eax_);
break;
case EAXAGCCOMPRESSOR_ONOFF:
eax_call.set_value<EaxCompressorEffectException>(eax_.ulOnOff);
break;
default:
throw EaxCompressorEffectException{"Unsupported property id."};
case EAXAGCCOMPRESSOR_NONE: break;
case EAXAGCCOMPRESSOR_ALLPARAMETERS: call.set_value<Exception>(props); break;
case EAXAGCCOMPRESSOR_ONOFF: call.set_value<Exception>(props.ulOnOff); break;
default: fail_unknown_property_id();
}
}
void EaxCompressorEffect::validate_on_off(
unsigned long ulOnOff)
{
eax_validate_range<EaxCompressorEffectException>(
"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<EaxCompressorEffectException, const decltype(EAXAGCCOMPRESSORPROPERTIES::ulOnOff)>();
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<EaxCompressorEffectException, const EAXAGCCOMPRESSORPROPERTIES>();
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<AllValidator>(call, props); break;
case EAXAGCCOMPRESSOR_ONOFF: defer<OnOffValidator>(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<EaxCompressorEffect>();
return eax_create_eax4_effect<EaxCompressorEffect>(call);
}
#endif // ALSOFT_EAX

+ 149
- 365
modules/openal-soft/al/effects/distortion.cpp View File

@ -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<EaxDistortionEffectException, EAXDISTORTIONPROPERTIES>
{
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<Exception>(
"Edge",
flEdge,
EAXDISTORTION_MINEDGE,
EAXDISTORTION_MAXEDGE);
}
}; // EdgeValidator
struct GainValidator {
void operator()(long lGain) const
{
eax_validate_range<Exception>(
"Gain",
lGain,
EAXDISTORTION_MINGAIN,
EAXDISTORTION_MAXGAIN);
}
}; // GainValidator
struct LowPassCutOffValidator {
void operator()(float flLowPassCutOff) const
{
eax_validate_range<Exception>(
"Low-pass Cut-off",
flLowPassCutOff,
EAXDISTORTION_MINLOWPASSCUTOFF,
EAXDISTORTION_MAXLOWPASSCUTOFF);
}
}; // LowPassCutOffValidator
struct EqCenterValidator {
void operator()(float flEQCenter) const
{
eax_validate_range<Exception>(
"EQ Center",
flEQCenter,
EAXDISTORTION_MINEQCENTER,
EAXDISTORTION_MAXEQCENTER);
}
}; // EqCenterValidator
struct EqBandwidthValidator {
void operator()(float flEQBandwidth) const
{
eax_validate_range<Exception>(
"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<float>(eax_.lGain)),
al_effect_props_.Distortion.Gain = clamp(
level_mb_to_gain(static_cast<float>(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<EaxDistortionEffectException>(eax_);
break;
case EAXDISTORTION_EDGE:
eax_call.set_value<EaxDistortionEffectException>(eax_.flEdge);
break;
case EAXDISTORTION_GAIN:
eax_call.set_value<EaxDistortionEffectException>(eax_.lGain);
break;
case EAXDISTORTION_LOWPASSCUTOFF:
eax_call.set_value<EaxDistortionEffectException>(eax_.flLowPassCutOff);
break;
case EAXDISTORTION_EQCENTER:
eax_call.set_value<EaxDistortionEffectException>(eax_.flEQCenter);
break;
case EAXDISTORTION_EQBANDWIDTH:
eax_call.set_value<EaxDistortionEffectException>(eax_.flEQBandwidth);
break;
default:
throw EaxDistortionEffectException{"Unsupported property id."};
case EAXDISTORTION_NONE: break;
case EAXDISTORTION_ALLPARAMETERS: call.set_value<Exception>(props); break;
case EAXDISTORTION_EDGE: call.set_value<Exception>(props.flEdge); break;
case EAXDISTORTION_GAIN: call.set_value<Exception>(props.lGain); break;
case EAXDISTORTION_LOWPASSCUTOFF: call.set_value<Exception>(props.flLowPassCutOff); break;
case EAXDISTORTION_EQCENTER: call.set_value<Exception>(props.flEQCenter); break;
case EAXDISTORTION_EQBANDWIDTH: call.set_value<Exception>(props.flEQBandwidth); break;
default: fail_unknown_property_id();
}
}
void EaxDistortionEffect::validate_edge(
float flEdge)
{
eax_validate_range<EaxDistortionEffectException>(
"Edge",
flEdge,
EAXDISTORTION_MINEDGE,
EAXDISTORTION_MAXEDGE);
}
void EaxDistortionEffect::validate_gain(
long lGain)
{
eax_validate_range<EaxDistortionEffectException>(
"Gain",
lGain,
EAXDISTORTION_MINGAIN,
EAXDISTORTION_MAXGAIN);
}
void EaxDistortionEffect::validate_lowpass_cutoff(
float flLowPassCutOff)
{
eax_validate_range<EaxDistortionEffectException>(
"Low-pass Cut-off",
flLowPassCutOff,
EAXDISTORTION_MINLOWPASSCUTOFF,
EAXDISTORTION_MAXLOWPASSCUTOFF);
}
void EaxDistortionEffect::validate_eq_center(
float flEQCenter)
{
eax_validate_range<EaxDistortionEffectException>(
"EQ Center",
flEQCenter,
EAXDISTORTION_MINEQCENTER,
EAXDISTORTION_MAXEQCENTER);
}
void EaxDistortionEffect::validate_eq_bandwidth(
float flEQBandwidth)
{
eax_validate_range<EaxDistortionEffectException>(
"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<EaxDistortionEffectException, const decltype(EAXDISTORTIONPROPERTIES::flEdge)>();
validate_edge(edge);
defer_edge(edge);
}
void EaxDistortionEffect::defer_gain(
const EaxEaxCall& eax_call)
{
const auto& gain =
eax_call.get_value<EaxDistortionEffectException, const decltype(EAXDISTORTIONPROPERTIES::lGain)>();
validate_gain(gain);
defer_gain(gain);
}
void EaxDistortionEffect::defer_low_pass_cutoff(
const EaxEaxCall& eax_call)
{
const auto& lowpass_cutoff =
eax_call.get_value<EaxDistortionEffectException, const decltype(EAXDISTORTIONPROPERTIES::flLowPassCutOff)>();
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<EaxDistortionEffectException, const decltype(EAXDISTORTIONPROPERTIES::flEQCenter)>();
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<EaxDistortionEffectException, const decltype(EAXDISTORTIONPROPERTIES::flEQBandwidth)>();
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<EaxDistortionEffectException, const EAXDISTORTIONPROPERTIES>();
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<AllValidator>(call, props); break;
case EAXDISTORTION_EDGE: defer<EdgeValidator>(call, props.flEdge); break;
case EAXDISTORTION_GAIN: defer<GainValidator>(call, props.lGain); break;
case EAXDISTORTION_LOWPASSCUTOFF: defer<LowPassCutOffValidator>(call, props.flLowPassCutOff); break;
case EAXDISTORTION_EQCENTER: defer<EqCenterValidator>(call, props.flEQCenter); break;
case EAXDISTORTION_EQBANDWIDTH: defer<EqBandwidthValidator>(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<EaxDistortionEffect>();
return eax_create_eax4_effect<EaxDistortionEffect>(call);
}
#endif // ALSOFT_EAX

+ 149
- 366
modules/openal-soft/al/effects/echo.cpp View File

@ -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<EaxEchoEffectException, EAXECHOPROPERTIES>
{
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<Exception>(
"Delay",
flDelay,
EAXECHO_MINDELAY,
EAXECHO_MAXDELAY);
}
}; // DelayValidator
struct LrDelayValidator {
void operator()(float flLRDelay) const
{
eax_validate_range<Exception>(
"LR Delay",
flLRDelay,
EAXECHO_MINLRDELAY,
EAXECHO_MAXLRDELAY);
}
}; // LrDelayValidator
struct DampingValidator {
void operator()(float flDamping) const
{
eax_validate_range<Exception>(
"Damping",
flDamping,
EAXECHO_MINDAMPING,
EAXECHO_MAXDAMPING);
}
}; // DampingValidator
struct FeedbackValidator {
void operator()(float flFeedback) const
{
eax_validate_range<Exception>(
"Feedback",
flFeedback,
EAXECHO_MINFEEDBACK,
EAXECHO_MAXFEEDBACK);
}
}; // FeedbackValidator
struct SpreadValidator {
void operator()(float flSpread) const
{
eax_validate_range<Exception>(
"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<EaxEchoEffectException>(eax_);
break;
case EAXECHO_DELAY:
eax_call.set_value<EaxEchoEffectException>(eax_.flDelay);
break;
case EAXECHO_LRDELAY:
eax_call.set_value<EaxEchoEffectException>(eax_.flLRDelay);
break;
case EAXECHO_DAMPING:
eax_call.set_value<EaxEchoEffectException>(eax_.flDamping);
break;
case EAXECHO_FEEDBACK:
eax_call.set_value<EaxEchoEffectException>(eax_.flFeedback);
break;
case EAXECHO_SPREAD:
eax_call.set_value<EaxEchoEffectException>(eax_.flSpread);
break;
default:
throw EaxEchoEffectException{"Unsupported property id."};
case EAXECHO_NONE: break;
case EAXECHO_ALLPARAMETERS: call.set_value<Exception>(props); break;
case EAXECHO_DELAY: call.set_value<Exception>(props.flDelay); break;
case EAXECHO_LRDELAY: call.set_value<Exception>(props.flLRDelay); break;
case EAXECHO_DAMPING: call.set_value<Exception>(props.flDamping); break;
case EAXECHO_FEEDBACK: call.set_value<Exception>(props.flFeedback); break;
case EAXECHO_SPREAD: call.set_value<Exception>(props.flSpread); break;
default: fail_unknown_property_id();
}
}
void EaxEchoEffect::validate_delay(
float flDelay)
{
eax_validate_range<EaxEchoEffectException>(
"Delay",
flDelay,
EAXECHO_MINDELAY,
EAXECHO_MAXDELAY);
}
void EaxEchoEffect::validate_lr_delay(
float flLRDelay)
{
eax_validate_range<EaxEchoEffectException>(
"LR Delay",
flLRDelay,
EAXECHO_MINLRDELAY,
EAXECHO_MAXLRDELAY);
}
void EaxEchoEffect::validate_damping(
float flDamping)
{
eax_validate_range<EaxEchoEffectException>(
"Damping",
flDamping,
EAXECHO_MINDAMPING,
EAXECHO_MAXDAMPING);
}
void EaxEchoEffect::validate_feedback(
float flFeedback)
{
eax_validate_range<EaxEchoEffectException>(
"Feedback",
flFeedback,
EAXECHO_MINFEEDBACK,
EAXECHO_MAXFEEDBACK);
}
void EaxEchoEffect::validate_spread(
float flSpread)
{
eax_validate_range<EaxEchoEffectException>(
"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<EaxEchoEffectException, const decltype(EAXECHOPROPERTIES::flDelay)>();
validate_delay(delay);
defer_delay(delay);
}
void EaxEchoEffect::defer_lr_delay(
const EaxEaxCall& eax_call)
{
const auto& lr_delay =
eax_call.get_value<EaxEchoEffectException, const decltype(EAXECHOPROPERTIES::flLRDelay)>();
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<EaxEchoEffectException, const decltype(EAXECHOPROPERTIES::flDamping)>();
validate_damping(damping);
defer_damping(damping);
}
void EaxEchoEffect::defer_feedback(
const EaxEaxCall& eax_call)
{
const auto& feedback =
eax_call.get_value<EaxEchoEffectException, const decltype(EAXECHOPROPERTIES::flFeedback)>();
validate_feedback(feedback);
defer_feedback(feedback);
}
void EaxEchoEffect::defer_spread(
const EaxEaxCall& eax_call)
{
const auto& spread =
eax_call.get_value<EaxEchoEffectException, const decltype(EAXECHOPROPERTIES::flSpread)>();
validate_spread(spread);
defer_spread(spread);
}
void EaxEchoEffect::defer_all(
const EaxEaxCall& eax_call)
{
const auto& all =
eax_call.get_value<EaxEchoEffectException, const EAXECHOPROPERTIES>();
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<AllValidator>(call, props); break;
case EAXECHO_DELAY: defer<DelayValidator>(call, props.flDelay); break;
case EAXECHO_LRDELAY: defer<LrDelayValidator>(call, props.flLRDelay); break;
case EAXECHO_DAMPING: defer<DampingValidator>(call, props.flDamping); break;
case EAXECHO_FEEDBACK: defer<FeedbackValidator>(call, props.flFeedback); break;
case EAXECHO_SPREAD: defer<SpreadValidator>(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<EaxEchoEffect>();
return eax_create_eax4_effect<EaxEchoEffect>(call);
}
#endif // ALSOFT_EAX

+ 13
- 13
modules/openal-soft/al/effects/effects.cpp View File

@ -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.");

+ 3
- 2
modules/openal-soft/al/effects/effects.h View File

@ -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 */

+ 255
- 611
modules/openal-soft/al/effects/equalizer.cpp View File

@ -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<EaxEqualizerEffectException, EAXEQUALIZERPROPERTIES>
{
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<Exception>(
"Low Gain",
lLowGain,
EAXEQUALIZER_MINLOWGAIN,
EAXEQUALIZER_MAXLOWGAIN);
}
}; // LowGainValidator
struct LowCutOffValidator {
void operator()(float flLowCutOff) const
{
eax_validate_range<Exception>(
"Low Cutoff",
flLowCutOff,
EAXEQUALIZER_MINLOWCUTOFF,
EAXEQUALIZER_MAXLOWCUTOFF);
}
}; // LowCutOffValidator
struct Mid1GainValidator {
void operator()(long lMid1Gain) const
{
eax_validate_range<Exception>(
"Mid1 Gain",
lMid1Gain,
EAXEQUALIZER_MINMID1GAIN,
EAXEQUALIZER_MAXMID1GAIN);
}
}; // Mid1GainValidator
struct Mid1CenterValidator {
void operator()(float flMid1Center) const
{
eax_validate_range<Exception>(
"Mid1 Center",
flMid1Center,
EAXEQUALIZER_MINMID1CENTER,
EAXEQUALIZER_MAXMID1CENTER);
}
}; // Mid1CenterValidator
struct Mid1WidthValidator {
void operator()(float flMid1Width) const
{
eax_validate_range<Exception>(
"Mid1 Width",
flMid1Width,
EAXEQUALIZER_MINMID1WIDTH,
EAXEQUALIZER_MAXMID1WIDTH);
}
}; // Mid1WidthValidator
struct Mid2GainValidator {
void operator()(long lMid2Gain) const
{
eax_validate_range<Exception>(
"Mid2 Gain",
lMid2Gain,
EAXEQUALIZER_MINMID2GAIN,
EAXEQUALIZER_MAXMID2GAIN);
}
}; // Mid2GainValidator
struct Mid2CenterValidator {
void operator()(float flMid2Center) const
{
eax_validate_range<Exception>(
"Mid2 Center",
flMid2Center,
EAXEQUALIZER_MINMID2CENTER,
EAXEQUALIZER_MAXMID2CENTER);
}
}; // Mid2CenterValidator
struct Mid2WidthValidator {
void operator()(float flMid2Width) const
{
eax_validate_range<Exception>(
"Mid2 Width",
flMid2Width,
EAXEQUALIZER_MINMID2WIDTH,
EAXEQUALIZER_MAXMID2WIDTH);
}
}; // Mid2WidthValidator
struct HighGainValidator {
void operator()(long lHighGain) const
{
eax_validate_range<Exception>(
"High Gain",
lHighGain,
EAXEQUALIZER_MINHIGHGAIN,
EAXEQUALIZER_MAXHIGHGAIN);
}
}; // HighGainValidator
struct HighCutOffValidator {
void operator()(float flHighCutOff) const
{
eax_validate_range<Exception>(
"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<float>(eax_.lLowGain)),
al_effect_props_.Equalizer.LowGain = clamp(
level_mb_to_gain(static_cast<float>(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<float>(eax_.lMid1Gain)),
al_effect_props_.Equalizer.Mid1Gain = clamp(
level_mb_to_gain(static_cast<float>(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<float>(eax_.lMid2Gain)),
al_effect_props_.Equalizer.Mid2Gain = clamp(
level_mb_to_gain(static_cast<float>(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<float>(eax_.lHighGain)),
al_effect_props_.Equalizer.HighGain = clamp(
level_mb_to_gain(static_cast<float>(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<EaxEqualizerEffectException>(eax_);
break;
case EAXEQUALIZER_LOWGAIN:
eax_call.set_value<EaxEqualizerEffectException>(eax_.lLowGain);
break;
case EAXEQUALIZER_LOWCUTOFF:
eax_call.set_value<EaxEqualizerEffectException>(eax_.flLowCutOff);
break;
case EAXEQUALIZER_MID1GAIN:
eax_call.set_value<EaxEqualizerEffectException>(eax_.lMid1Gain);
break;
case EAXEQUALIZER_MID1CENTER:
eax_call.set_value<EaxEqualizerEffectException>(eax_.flMid1Center);
break;
case EAXEQUALIZER_MID1WIDTH:
eax_call.set_value<EaxEqualizerEffectException>(eax_.flMid1Width);
break;
case EAXEQUALIZER_MID2GAIN:
eax_call.set_value<EaxEqualizerEffectException>(eax_.lMid2Gain);
break;
case EAXEQUALIZER_MID2CENTER:
eax_call.set_value<EaxEqualizerEffectException>(eax_.flMid2Center);
break;
case EAXEQUALIZER_MID2WIDTH:
eax_call.set_value<EaxEqualizerEffectException>(eax_.flMid2Width);
break;
case EAXEQUALIZER_HIGHGAIN:
eax_call.set_value<EaxEqualizerEffectException>(eax_.lHighGain);
break;
case EAXEQUALIZER_HIGHCUTOFF:
eax_call.set_value<EaxEqualizerEffectException>(eax_.flHighCutOff);
break;
default:
throw EaxEqualizerEffectException{"Unsupported property id."};
case EAXEQUALIZER_NONE: break;
case EAXEQUALIZER_ALLPARAMETERS: call.set_value<Exception>(props); break;
case EAXEQUALIZER_LOWGAIN: call.set_value<Exception>(props.lLowGain); break;
case EAXEQUALIZER_LOWCUTOFF: call.set_value<Exception>(props.flLowCutOff); break;
case EAXEQUALIZER_MID1GAIN: call.set_value<Exception>(props.lMid1Gain); break;
case EAXEQUALIZER_MID1CENTER: call.set_value<Exception>(props.flMid1Center); break;
case EAXEQUALIZER_MID1WIDTH: call.set_value<Exception>(props.flMid1Width); break;
case EAXEQUALIZER_MID2GAIN: call.set_value<Exception>(props.lMid2Gain); break;
case EAXEQUALIZER_MID2CENTER: call.set_value<Exception>(props.flMid2Center); break;
case EAXEQUALIZER_MID2WIDTH: call.set_value<Exception>(props.flMid2Width); break;
case EAXEQUALIZER_HIGHGAIN: call.set_value<Exception>(props.lHighGain); break;
case EAXEQUALIZER_HIGHCUTOFF: call.set_value<Exception>(props.flHighCutOff); break;
default: fail_unknown_property_id();
}
}
void EaxEqualizerEffect::validate_low_gain(
long lLowGain)
{
eax_validate_range<EaxEqualizerEffectException>(
"Low Gain",
lLowGain,
EAXEQUALIZER_MINLOWGAIN,
EAXEQUALIZER_MAXLOWGAIN);
}
void EaxEqualizerEffect::validate_low_cutoff(
float flLowCutOff)
{
eax_validate_range<EaxEqualizerEffectException>(
"Low Cutoff",
flLowCutOff,
EAXEQUALIZER_MINLOWCUTOFF,
EAXEQUALIZER_MAXLOWCUTOFF);
}
void EaxEqualizerEffect::validate_mid1_gain(
long lMid1Gain)
{
eax_validate_range<EaxEqualizerEffectException>(
"Mid1 Gain",
lMid1Gain,
EAXEQUALIZER_MINMID1GAIN,
EAXEQUALIZER_MAXMID1GAIN);
}
void EaxEqualizerEffect::validate_mid1_center(
float flMid1Center)
{
eax_validate_range<EaxEqualizerEffectException>(
"Mid1 Center",
flMid1Center,
EAXEQUALIZER_MINMID1CENTER,
EAXEQUALIZER_MAXMID1CENTER);
}
void EaxEqualizerEffect::validate_mid1_width(
float flMid1Width)
{
eax_validate_range<EaxEqualizerEffectException>(
"Mid1 Width",
flMid1Width,
EAXEQUALIZER_MINMID1WIDTH,
EAXEQUALIZER_MAXMID1WIDTH);
}
void EaxEqualizerEffect::validate_mid2_gain(
long lMid2Gain)
{
eax_validate_range<EaxEqualizerEffectException>(
"Mid2 Gain",
lMid2Gain,
EAXEQUALIZER_MINMID2GAIN,
EAXEQUALIZER_MAXMID2GAIN);
}
void EaxEqualizerEffect::validate_mid2_center(
float flMid2Center)
{
eax_validate_range<EaxEqualizerEffectException>(
"Mid2 Center",
flMid2Center,
EAXEQUALIZER_MINMID2CENTER,
EAXEQUALIZER_MAXMID2CENTER);
}
void EaxEqualizerEffect::validate_mid2_width(
float flMid2Width)
{
eax_validate_range<EaxEqualizerEffectException>(
"Mid2 Width",
flMid2Width,
EAXEQUALIZER_MINMID2WIDTH,
EAXEQUALIZER_MAXMID2WIDTH);
}
void EaxEqualizerEffect::validate_high_gain(
long lHighGain)
{
eax_validate_range<EaxEqualizerEffectException>(
"High Gain",
lHighGain,
EAXEQUALIZER_MINHIGHGAIN,
EAXEQUALIZER_MAXHIGHGAIN);
}
void EaxEqualizerEffect::validate_high_cutoff(
float flHighCutOff)
{
eax_validate_range<EaxEqualizerEffectException>(
"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<EaxEqualizerEffectException, const decltype(EAXEQUALIZERPROPERTIES::lLowGain)>();
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<EaxEqualizerEffectException, const decltype(EAXEQUALIZERPROPERTIES::flLowCutOff)>();
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<EaxEqualizerEffectException, const decltype(EAXEQUALIZERPROPERTIES::lMid1Gain)>();
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<EaxEqualizerEffectException, const decltype(EAXEQUALIZERPROPERTIES::flMid1Center)>();
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<EaxEqualizerEffectException, const decltype(EAXEQUALIZERPROPERTIES::flMid1Width)>();
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<EaxEqualizerEffectException, const decltype(EAXEQUALIZERPROPERTIES::lMid2Gain)>();
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<EaxEqualizerEffectException, const decltype(EAXEQUALIZERPROPERTIES::flMid2Center)>();
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<EaxEqualizerEffectException, const decltype(EAXEQUALIZERPROPERTIES::flMid2Width)>();
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<EaxEqualizerEffectException, const decltype(EAXEQUALIZERPROPERTIES::lHighGain)>();
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<EaxEqualizerEffectException, const decltype(EAXEQUALIZERPROPERTIES::flHighCutOff)>();
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<EaxEqualizerEffectException, const EAXEQUALIZERPROPERTIES>();
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<AllValidator>(call, props); break;
case EAXEQUALIZER_LOWGAIN: defer<LowGainValidator>(call, props.lLowGain); break;
case EAXEQUALIZER_LOWCUTOFF: defer<LowCutOffValidator>(call, props.flLowCutOff); break;
case EAXEQUALIZER_MID1GAIN: defer<Mid1GainValidator>(call, props.lMid1Gain); break;
case EAXEQUALIZER_MID1CENTER: defer<Mid1CenterValidator>(call, props.flMid1Center); break;
case EAXEQUALIZER_MID1WIDTH: defer<Mid1WidthValidator>(call, props.flMid1Width); break;
case EAXEQUALIZER_MID2GAIN: defer<Mid2GainValidator>(call, props.lMid2Gain); break;
case EAXEQUALIZER_MID2CENTER: defer<Mid2CenterValidator>(call, props.flMid2Center); break;
case EAXEQUALIZER_MID2WIDTH: defer<Mid2WidthValidator>(call, props.flMid2Width); break;
case EAXEQUALIZER_HIGHGAIN: defer<HighGainValidator>(call, props.lHighGain); break;
case EAXEQUALIZER_HIGHCUTOFF: defer<HighCutOffValidator>(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<EaxEqualizerEffect>();
return eax_create_eax4_effect<EaxEqualizerEffect>(call);
}
#endif // ALSOFT_EAX

+ 100
- 263
modules/openal-soft/al/effects/fshifter.cpp View File

@ -12,11 +12,9 @@
#ifdef ALSOFT_EAX
#include <cassert>
#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<EaxFrequencyShifterEffectException, EAXFREQUENCYSHIFTERPROPERTIES> {
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<Exception>(
"Frequency",
flFrequency,
EAXFREQUENCYSHIFTER_MINFREQUENCY,
EAXFREQUENCYSHIFTER_MAXFREQUENCY);
}
}; // FrequencyValidator
struct LeftDirectionValidator {
void operator()(unsigned long ulLeftDirection) const
{
eax_validate_range<Exception>(
"Left Direction",
ulLeftDirection,
EAXFREQUENCYSHIFTER_MINLEFTDIRECTION,
EAXFREQUENCYSHIFTER_MAXLEFTDIRECTION);
}
}; // LeftDirectionValidator
struct RightDirectionValidator {
void operator()(unsigned long ulRightDirection) const
{
eax_validate_range<Exception>(
"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<ALint>(eax_.ulLeftDirection),
static_cast<ALint>(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<ALint>(eax_.ulRightDirection),
static_cast<ALint>(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<EaxFrequencyShifterEffectException>(eax_);
break;
case EAXFREQUENCYSHIFTER_FREQUENCY:
eax_call.set_value<EaxFrequencyShifterEffectException>(eax_.flFrequency);
break;
case EAXFREQUENCYSHIFTER_LEFTDIRECTION:
eax_call.set_value<EaxFrequencyShifterEffectException>(eax_.ulLeftDirection);
break;
case EAXFREQUENCYSHIFTER_RIGHTDIRECTION:
eax_call.set_value<EaxFrequencyShifterEffectException>(eax_.ulRightDirection);
break;
default:
throw EaxFrequencyShifterEffectException{"Unsupported property id."};
case EAXFREQUENCYSHIFTER_NONE: break;
case EAXFREQUENCYSHIFTER_ALLPARAMETERS: call.set_value<Exception>(props); break;
case EAXFREQUENCYSHIFTER_FREQUENCY: call.set_value<Exception>(props.flFrequency); break;
case EAXFREQUENCYSHIFTER_LEFTDIRECTION: call.set_value<Exception>(props.ulLeftDirection); break;
case EAXFREQUENCYSHIFTER_RIGHTDIRECTION: call.set_value<Exception>(props.ulRightDirection); break;
default: fail_unknown_property_id();
}
}
void EaxFrequencyShifterEffect::validate_frequency(
float flFrequency)
{
eax_validate_range<EaxFrequencyShifterEffectException>(
"Frequency",
flFrequency,
EAXFREQUENCYSHIFTER_MINFREQUENCY,
EAXFREQUENCYSHIFTER_MAXFREQUENCY);
}
void EaxFrequencyShifterEffect::validate_left_direction(
unsigned long ulLeftDirection)
{
eax_validate_range<EaxFrequencyShifterEffectException>(
"Left Direction",
ulLeftDirection,
EAXFREQUENCYSHIFTER_MINLEFTDIRECTION,
EAXFREQUENCYSHIFTER_MAXLEFTDIRECTION);
}
void EaxFrequencyShifterEffect::validate_right_direction(
unsigned long ulRightDirection)
{
eax_validate_range<EaxFrequencyShifterEffectException>(
"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<AllValidator>(call, props); break;
case EAXFREQUENCYSHIFTER_FREQUENCY: defer<FrequencyValidator>(call, props.flFrequency); break;
case EAXFREQUENCYSHIFTER_LEFTDIRECTION: defer<LeftDirectionValidator>(call, props.ulLeftDirection); break;
case EAXFREQUENCYSHIFTER_RIGHTDIRECTION: defer<RightDirectionValidator>(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<EaxFrequencyShifterEffect>();
return eax_create_eax4_effect<EaxFrequencyShifterEffect>(call);
}
#endif // ALSOFT_EAX

+ 103
- 266
modules/openal-soft/al/effects/modulator.cpp View File

@ -12,11 +12,9 @@
#ifdef ALSOFT_EAX
#include <cassert>
#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<EaxRingModulatorEffectException, EAXRINGMODULATORPROPERTIES>
{
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<EaxRingModulatorEffectException>(
"Frequency",
flFrequency,
EAXRINGMODULATOR_MINFREQUENCY,
EAXRINGMODULATOR_MAXFREQUENCY);
}
}; // FrequencyValidator
struct HighPassCutOffValidator {
void operator()(float flHighPassCutOff) const
{
eax_validate_range<EaxRingModulatorEffectException>(
"High-Pass Cutoff",
flHighPassCutOff,
EAXRINGMODULATOR_MINHIGHPASSCUTOFF,
EAXRINGMODULATOR_MAXHIGHPASSCUTOFF);
}
}; // HighPassCutOffValidator
struct WaveformValidator {
void operator()(unsigned long ulWaveform) const
{
eax_validate_range<EaxRingModulatorEffectException>(
"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<ALint>(eax_.ulWaveform),
static_cast<ALint>(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<EaxRingModulatorEffectException>(eax_);
break;
case EAXRINGMODULATOR_FREQUENCY:
eax_call.set_value<EaxRingModulatorEffectException>(eax_.flFrequency);
break;
case EAXRINGMODULATOR_HIGHPASSCUTOFF:
eax_call.set_value<EaxRingModulatorEffectException>(eax_.flHighPassCutOff);
break;
case EAXRINGMODULATOR_WAVEFORM:
eax_call.set_value<EaxRingModulatorEffectException>(eax_.ulWaveform);
break;
default:
throw EaxRingModulatorEffectException{"Unsupported property id."};
case EAXRINGMODULATOR_NONE: break;
case EAXRINGMODULATOR_ALLPARAMETERS: call.set_value<Exception>(props); break;
case EAXRINGMODULATOR_FREQUENCY: call.set_value<Exception>(props.flFrequency); break;
case EAXRINGMODULATOR_HIGHPASSCUTOFF: call.set_value<Exception>(props.flHighPassCutOff); break;
case EAXRINGMODULATOR_WAVEFORM: call.set_value<Exception>(props.ulWaveform); break;
default: fail_unknown_property_id();
}
}
void EaxRingModulatorEffect::validate_frequency(
float flFrequency)
{
eax_validate_range<EaxRingModulatorEffectException>(
"Frequency",
flFrequency,
EAXRINGMODULATOR_MINFREQUENCY,
EAXRINGMODULATOR_MAXFREQUENCY);
}
void EaxRingModulatorEffect::validate_high_pass_cutoff(
float flHighPassCutOff)
{
eax_validate_range<EaxRingModulatorEffectException>(
"High-Pass Cutoff",
flHighPassCutOff,
EAXRINGMODULATOR_MINHIGHPASSCUTOFF,
EAXRINGMODULATOR_MAXHIGHPASSCUTOFF);
}
void EaxRingModulatorEffect::validate_waveform(
unsigned long ulWaveform)
{
eax_validate_range<EaxRingModulatorEffectException>(
"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<EaxRingModulatorEffectException, const EAXRINGMODULATORPROPERTIES>();
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<AllValidator>(call, props); break;
case EAXRINGMODULATOR_FREQUENCY: defer<FrequencyValidator>(call, props.flFrequency); break;
case EAXRINGMODULATOR_HIGHPASSCUTOFF: defer<HighPassCutOffValidator>(call, props.flHighPassCutOff); break;
case EAXRINGMODULATOR_WAVEFORM: defer<WaveformValidator>(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<EaxRingModulatorEffect>();
return eax_create_eax4_effect<EaxRingModulatorEffect>(call);
}
#endif // ALSOFT_EAX

+ 14
- 24
modules/openal-soft/al/effects/null.cpp View File

@ -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;
}

+ 86
- 219
modules/openal-soft/al/effects/pshifter.cpp View File

@ -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<EaxPitchShifterEffectException, EAXPITCHSHIFTERPROPERTIES> {
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<Exception>(
"Coarse Tune",
lCoarseTune,
EAXPITCHSHIFTER_MINCOARSETUNE,
EAXPITCHSHIFTER_MAXCOARSETUNE);
}
}; // CoarseTuneValidator
struct FineTuneValidator {
void operator()(long lFineTune) const
{
eax_validate_range<Exception>(
"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<ALint>(eax_.lCoarseTune),
al_effect_props_.Pshifter.CoarseTune = clamp(
static_cast<ALint>(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<ALint>(eax_.lFineTune),
al_effect_props_.Pshifter.FineTune = clamp(
static_cast<ALint>(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<EaxPitchShifterEffectException>(eax_);
break;
case EAXPITCHSHIFTER_COARSETUNE:
eax_call.set_value<EaxPitchShifterEffectException>(eax_.lCoarseTune);
break;
case EAXPITCHSHIFTER_FINETUNE:
eax_call.set_value<EaxPitchShifterEffectException>(eax_.lFineTune);
break;
default:
throw EaxPitchShifterEffectException{"Unsupported property id."};
case EAXPITCHSHIFTER_NONE: break;
case EAXPITCHSHIFTER_ALLPARAMETERS: call.set_value<Exception>(props); break;
case EAXPITCHSHIFTER_COARSETUNE: call.set_value<Exception>(props.lCoarseTune); break;
case EAXPITCHSHIFTER_FINETUNE: call.set_value<Exception>(props.lFineTune); break;
default: fail_unknown_property_id();
}
}
void EaxPitchShifterEffect::validate_coarse_tune(
long lCoarseTune)
{
eax_validate_range<EaxPitchShifterEffectException>(
"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<EaxPitchShifterEffectException>(
"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<EaxPitchShifterEffectException, const decltype(EAXPITCHSHIFTERPROPERTIES::lCoarseTune)>();
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<EaxPitchShifterEffectException, const decltype(EAXPITCHSHIFTERPROPERTIES::lFineTune)>();
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<EaxPitchShifterEffectException, const EAXPITCHSHIFTERPROPERTIES>();
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<AllValidator>(call, props); break;
case EAXPITCHSHIFTER_COARSETUNE: defer<CoarseTuneValidator>(call, props.lCoarseTune); break;
case EAXPITCHSHIFTER_FINETUNE: defer<FineTuneValidator>(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<EaxPitchShifterEffect>();
return eax_create_eax4_effect<EaxPitchShifterEffect>(call);
}
#endif // ALSOFT_EAX

+ 1081
- 1629
modules/openal-soft/al/effects/reverb.cpp
File diff suppressed because it is too large
View File


+ 174
- 382
modules/openal-soft/al/effects/vmorpher.cpp View File

@ -12,11 +12,9 @@
#ifdef ALSOFT_EAX
#include <cassert>
#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<EaxVocalMorpherEffectException, EAXVOCALMORPHERPROPERTIES> {
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<Exception>(
"Phoneme A",
ulPhonemeA,
EAXVOCALMORPHER_MINPHONEMEA,
EAXVOCALMORPHER_MAXPHONEMEA);
}
}; // PhonemeAValidator
struct PhonemeACoarseTuningValidator {
void operator()(long lPhonemeACoarseTuning) const
{
eax_validate_range<Exception>(
"Phoneme A Coarse Tuning",
lPhonemeACoarseTuning,
EAXVOCALMORPHER_MINPHONEMEACOARSETUNING,
EAXVOCALMORPHER_MAXPHONEMEACOARSETUNING);
}
}; // PhonemeACoarseTuningValidator
struct PhonemeBValidator {
void operator()(unsigned long ulPhonemeB) const
{
eax_validate_range<Exception>(
"Phoneme B",
ulPhonemeB,
EAXVOCALMORPHER_MINPHONEMEB,
EAXVOCALMORPHER_MAXPHONEMEB);
}
}; // PhonemeBValidator
struct PhonemeBCoarseTuningValidator {
void operator()(long lPhonemeBCoarseTuning) const
{
eax_validate_range<Exception>(
"Phoneme B Coarse Tuning",
lPhonemeBCoarseTuning,
EAXVOCALMORPHER_MINPHONEMEBCOARSETUNING,
EAXVOCALMORPHER_MAXPHONEMEBCOARSETUNING);
}
}; // PhonemeBCoarseTuningValidator
struct WaveformValidator {
void operator()(unsigned long ulWaveform) const
{
eax_validate_range<Exception>(
"Waveform",
ulWaveform,
EAXVOCALMORPHER_MINWAVEFORM,
EAXVOCALMORPHER_MAXWAVEFORM);
}
}; // WaveformValidator
struct RateValidator {
void operator()(float flRate) const
{
eax_validate_range<Exception>(
"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<ALint>(eax_.ulPhonemeA),
static_cast<ALint>(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<ALint>(eax_.lPhonemeACoarseTuning),
static_cast<ALint>(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<ALint>(eax_.ulPhonemeB),
static_cast<ALint>(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<ALint>(eax_.lPhonemeBCoarseTuning),
al_effect_props_.Vmorpher.PhonemeBCoarseTuning = clamp(
static_cast<ALint>(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<ALint>(eax_.ulWaveform),
static_cast<ALint>(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<EaxVocalMorpherEffectException>(eax_);
call.set_value<Exception>(props);
break;
case EAXVOCALMORPHER_PHONEMEA:
eax_call.set_value<EaxVocalMorpherEffectException>(eax_.ulPhonemeA);
call.set_value<Exception>(props.ulPhonemeA);
break;
case EAXVOCALMORPHER_PHONEMEACOARSETUNING:
eax_call.set_value<EaxVocalMorpherEffectException>(eax_.lPhonemeACoarseTuning);
call.set_value<Exception>(props.lPhonemeACoarseTuning);
break;
case EAXVOCALMORPHER_PHONEMEB:
eax_call.set_value<EaxVocalMorpherEffectException>(eax_.ulPhonemeB);
call.set_value<Exception>(props.ulPhonemeB);
break;
case EAXVOCALMORPHER_PHONEMEBCOARSETUNING:
eax_call.set_value<EaxVocalMorpherEffectException>(eax_.lPhonemeBCoarseTuning);
call.set_value<Exception>(props.lPhonemeBCoarseTuning);
break;
case EAXVOCALMORPHER_WAVEFORM:
eax_call.set_value<EaxVocalMorpherEffectException>(eax_.ulWaveform);
call.set_value<Exception>(props.ulWaveform);
break;
case EAXVOCALMORPHER_RATE:
eax_call.set_value<EaxVocalMorpherEffectException>(eax_.flRate);
call.set_value<Exception>(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<EaxVocalMorpherEffectException>(
"Phoneme A",
ulPhonemeA,
EAXVOCALMORPHER_MINPHONEMEA,
EAXVOCALMORPHER_MAXPHONEMEA);
}
void EaxVocalMorpherEffect::validate_phoneme_a_coarse_tuning(
long lPhonemeACoarseTuning)
{
eax_validate_range<EaxVocalMorpherEffectException>(
"Phoneme A Coarse Tuning",
lPhonemeACoarseTuning,
EAXVOCALMORPHER_MINPHONEMEACOARSETUNING,
EAXVOCALMORPHER_MAXPHONEMEACOARSETUNING);
}
void EaxVocalMorpherEffect::validate_phoneme_b(
unsigned long ulPhonemeB)
{
eax_validate_range<EaxVocalMorpherEffectException>(
"Phoneme B",
ulPhonemeB,
EAXVOCALMORPHER_MINPHONEMEB,
EAXVOCALMORPHER_MAXPHONEMEB);
}
void EaxVocalMorpherEffect::validate_phoneme_b_coarse_tuning(
long lPhonemeBCoarseTuning)
{
eax_validate_range<EaxVocalMorpherEffectException>(
"Phoneme B Coarse Tuning",
lPhonemeBCoarseTuning,
EAXVOCALMORPHER_MINPHONEMEBCOARSETUNING,
EAXVOCALMORPHER_MAXPHONEMEBCOARSETUNING);
}
void EaxVocalMorpherEffect::validate_waveform(
unsigned long ulWaveform)
{
eax_validate_range<EaxVocalMorpherEffectException>(
"Waveform",
ulWaveform,
EAXVOCALMORPHER_MINWAVEFORM,
EAXVOCALMORPHER_MAXWAVEFORM);
}
void EaxVocalMorpherEffect::validate_rate(
float flRate)
{
eax_validate_range<EaxVocalMorpherEffectException>(
"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<EaxVocalMorpherEffectException,
const decltype(EAXVOCALMORPHERPROPERTIES::ulPhonemeA)>();
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<AllValidator>(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<PhonemeAValidator>(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<PhonemeACoarseTuningValidator>(call, props.lPhonemeACoarseTuning);
break;
validate_waveform(waveform);
defer_waveform(waveform);
}
case EAXVOCALMORPHER_PHONEMEB:
defer<PhonemeBValidator>(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<PhonemeBCoarseTuningValidator>(call, props.lPhonemeBCoarseTuning);
break;
validate_rate(rate);
defer_rate(rate);
}
case EAXVOCALMORPHER_WAVEFORM:
defer<WaveformValidator>(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<RateValidator>(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<EaxVocalMorpherEffect>();
return eax_create_eax4_effect<EaxVocalMorpherEffect>(call);
}
#endif // ALSOFT_EAX

+ 822
- 1946
modules/openal-soft/al/source.cpp
File diff suppressed because it is too large
View File


+ 787
- 545
modules/openal-soft/al/source.h
File diff suppressed because it is too large
View File


+ 3
- 2
modules/openal-soft/al/state.cpp View File

@ -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;

+ 11
- 7
modules/openal-soft/alsoftrc.sample View File

@ -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)
##

+ 1
- 1
modules/openal-soft/appveyor.yml View File

@ -1,4 +1,4 @@
version: 1.22.0.{build}
version: 1.22.2.{build}
environment:
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017

+ 7
- 3
modules/openal-soft/common/almalloc.h View File

@ -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)); \
} \

+ 2
- 2
modules/openal-soft/common/aloptional.h View File

@ -310,10 +310,10 @@ public:
template<typename U>
constexpr T value_or(U&& defval) const&
{ return bool{*this} ? **this : static_cast<T>(std::forward<U>(defval)); }
{ return bool(*this) ? **this : static_cast<T>(std::forward<U>(defval)); }
template<typename U>
constexpr T value_or(U&& defval) &&
{ return bool{*this} ? std::move(**this) : static_cast<T>(std::forward<U>(defval)); }
{ return bool(*this) ? std::move(**this) : static_cast<T>(std::forward<U>(defval)); }
template<typename ...Args>
constexpr T& emplace(Args&& ...args)

+ 1
- 0
modules/openal-soft/common/alstring.h View File

@ -2,6 +2,7 @@
#define AL_STRING_H
#include <cstddef>
#include <cstring>
namespace al {

+ 2
- 2
modules/openal-soft/common/polyphase_resampler.h View File

@ -4,6 +4,8 @@
#include <vector>
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);

+ 3
- 0
modules/openal-soft/config.h.in View File

@ -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@"

+ 3
- 4
modules/openal-soft/core/cpu_caps.cpp View File

@ -11,11 +11,10 @@
#endif
#endif
#ifdef HAVE_INTRIN_H
#include <intrin.h>
#endif
#ifdef HAVE_CPUID_H
#if defined(HAVE_CPUID_H)
#include <cpuid.h>
#elif defined(HAVE_INTRIN_H)
#include <intrin.h>
#endif
#include <array>

+ 2
- 0
modules/openal-soft/core/devformat.cpp View File

@ -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)";

+ 18
- 0
modules/openal-soft/core/devformat.h View File

@ -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

+ 25
- 12
modules/openal-soft/core/helpers.cpp View File

@ -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)

+ 6
- 6
modules/openal-soft/core/uhjfilter.cpp View File

@ -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<const float*const,3> 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<float*> samples, const size_t samplesToDo,
void UhjStereoDecoder::decode(const al::span<float*> samples, const size_t samplesToDo,
const size_t forwardSamples)
{
ASSUME(samplesToDo > 0);

+ 31
- 17
modules/openal-soft/core/uhjfilter.h View File

@ -4,10 +4,27 @@
#include <array>
#include "almalloc.h"
#include "alspan.h"
#include "bufferline.h"
#include "resampler_limits.h"
struct DecoderBase {
virtual ~DecoderBase() = default;
virtual void decode(const al::span<float*> 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<const float*const,3> 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<float,BufferLineSize+MaxResamplerEdge+sFilterDelay> mS{};
alignas(16) std::array<float,BufferLineSize+MaxResamplerEdge+sFilterDelay> mD{};
alignas(16) std::array<float,BufferLineSize+MaxResamplerEdge+sFilterDelay> mT{};
@ -47,14 +68,6 @@ struct UhjDecoder : public UhjFilterBase {
alignas(16) std::array<float,BufferLineSize+MaxResamplerEdge + sFilterDelay*2> 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<float*> 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<float*> samples, const size_t samplesToDo,
const size_t forwardSamples);
using DecoderFunc = void (UhjDecoder::*)(const al::span<float*> samples,
const size_t samplesToDo, const size_t forwardSamples);
void decode(const al::span<float*> samples, const size_t samplesToDo,
const size_t forwardSamples) override;
DEF_NEWDEL(UhjDecoder)
DEF_NEWDEL(UhjStereoDecoder)
};
#endif /* CORE_UHJFILTER_H */

+ 17
- 14
modules/openal-soft/core/voice.cpp View File

@ -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<UhjStereoDecoder>();
mDecoderPadding = UhjStereoDecoder::sFilterDelay;
}
else if(IsUHJ(mFmtChannels))
{
mDecoder = std::make_unique<UhjDecoder>();
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

+ 2
- 2
modules/openal-soft/core/voice.h View File

@ -219,8 +219,8 @@ struct Voice {
AmbiScaling mAmbiScaling;
uint mAmbiOrder;
std::unique_ptr<UhjDecoder> mDecoder;
UhjDecoder::DecoderFunc mDecoderFunc{};
std::unique_ptr<DecoderBase> mDecoder;
uint mDecoderPadding{};
/** Current target parameters used for mixing. */
uint mStep{0};

+ 4
- 11
modules/openal-soft/docs/3D7.1.txt View File

@ -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

+ 67
- 100
modules/openal-soft/examples/alffplay.cpp View File

@ -28,12 +28,12 @@
#include <mutex>
#include <ratio>
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<const T*>(in);
auto *dst = reinterpret_cast<T*>(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<uint64_t>(out, in, count, frame_size);
else if((frame_size&3) == 0)
sample_dup<uint32_t>(out, in, count, frame_size);
else if((frame_size&1) == 0)
sample_dup<uint16_t>(out, in, count, frame_size);
else
sample_dup<uint8_t>(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<unsigned int>(-mSamplesPos));
/* Add samples by copying the first sample */
if((mFrameSize&7) == 0)
sample_dup<uint64_t>(samples, mSamples, rem, mFrameSize);
else if((mFrameSize&3) == 0)
sample_dup<uint32_t>(samples, mSamples, rem, mFrameSize);
else if((mFrameSize&1) == 0)
sample_dup<uint16_t>(samples, mSamples, rem, mFrameSize);
else
sample_dup<uint8_t>(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<size_t>(rem, static_cast<ALuint>(-mSamplesPos));
if(rem == 0) break;
auto *splout{&mBufferData[woffset]};
if((mFrameSize&7) == 0)
sample_dup<uint64_t>(splout, mSamples, rem, mFrameSize);
else if((mFrameSize&3) == 0)
sample_dup<uint32_t>(splout, mSamples, rem, mFrameSize);
else if((mFrameSize&1) == 0)
sample_dup<uint16_t>(splout, mSamples, rem, mFrameSize);
else
sample_dup<uint8_t>(splout, mSamples, rem, mFrameSize);
const size_t rem{std::min<size_t>(nsamples, static_cast<ALuint>(-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<int>(rem);
mCurrentPts += nanoseconds{seconds{rem}} / mCodecCtx->sample_rate;
mSamplesPos += static_cast<int>(rem);
continue;
}
const size_t rem{std::min<size_t>(nsamples, static_cast<ALuint>(mSamplesLen-mSamplesPos))};
const size_t boffset{static_cast<ALuint>(mSamplesPos) * size_t{mFrameSize}};
const size_t nbytes{static_cast<ALuint>(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<size_t>(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<int>(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<ALuint>(buffer_len),
sync_skip)};
if(!got_audio)
{
if(mMovie.mQuit.load(std::memory_order_relaxed))
goto finish;
if(!readAudio(samples.get(), static_cast<ALuint>(buffer_len), sync_skip))
break;
}
const ALuint bufid{mBuffers[mBufferIdx]};
mBufferIdx = static_cast<ALuint>((mBufferIdx+1) % mBuffers.size());
@ -2046,9 +2015,7 @@ int main(int argc, char *argv[])
else
{
std::cout<< "Found AL_SOFT_UHJ" <<std::endl;
FormatStereo8 = AL_FORMAT_UHJ2CHN8_SOFT;
FormatStereo16 = AL_FORMAT_UHJ2CHN16_SOFT;
FormatStereo32F = AL_FORMAT_UHJ2CHN_FLOAT32_SOFT;
EnableUhj = true;
}
}
else if(strcmp(argv[fileidx], "-superstereo") == 0)

+ 13
- 8
modules/openal-soft/presets/3D7.1.ambdec View File

@ -5,6 +5,11 @@
/description 3D7-noCenter_1h1v_pinv_even_energy_rV_max_rE_2_band
# In OpenAL Soft, 3D7.1 is a distinct configuration that uses the standard 5.1
# channels (LF, RF, CE, LS, RS), plus two auxiliary channels (AUX0, AUX1) in
# place of the rear speakers. AUX0 corresponds to the LB speaker (upper back
# center), and AUX1 corresponds to the RB speaker (lower front center).
# Similar to the the ITU-5.1-nocenter configuration, the front-center is
# declared here so that an appropriate distance may be set (for proper delaying
# or attenuating of dialog and such which feed it directly). It otherwise does
@ -25,15 +30,15 @@
/opt/xover_ratio 0.000000
/speakers/{
# id dist azim elev conn
# id dist azim elev conn
#-----------------------------------------------------------------------
add_spkr FL 1.828800 51.000000 24.000000
add_spkr FR 1.828800 -51.000000 24.000000
add_spkr FC 1.828800 0.000000 0.000000
add_spkr BL 1.828800 180.000000 55.000000
add_spkr BR 1.828800 0.000000 -55.000000
add_spkr SL 1.828800 129.000000 -24.000000
add_spkr SR 1.828800 -129.000000 -24.000000
add_spkr LF 1.828800 51.000000 24.000000
add_spkr RF 1.828800 -51.000000 24.000000
add_spkr CE 1.828800 0.000000 0.000000
add_spkr AUX0 1.828800 180.000000 55.000000
add_spkr AUX1 1.828800 0.000000 -55.000000
add_spkr LS 1.828800 129.000000 -24.000000
add_spkr RS 1.828800 -129.000000 -24.000000
/}
/lfmatrix/{

+ 4
- 3
modules/openal-soft/presets/presets.txt View File

@ -37,6 +37,7 @@ output). A "proper" 7.1 decoder may be provided in the future, but due to the
nature of the speaker configuration will have trade-offs.
3D7.1.ambdec
Specifies a 3D7.1 speaker setup for 7.1 Surround output. Although it's for 7.1
output, the speakers for such a configuration need to be placed in different
positions for proper results. Please see docs/3D7.1.txt for more information.
Specifies a 3D7.1 speaker setup for 3D7.1 Surround output. Please see
docs/3D7.1.txt for information about speaker placement. Similar to 7.1, the
front-center speaker is not used for 3D sound, but will be used as appropriate
with AL_SOFT_direct_channels or ALC_EXT_DEDICATED.

+ 39
- 0
modules/openal-soft/router/al.cpp View File

@ -130,3 +130,42 @@ DECL_THUNK3(void, alGetBufferi, ALuint, ALenum, ALint*)
DECL_THUNK5(void, alGetBuffer3i, ALuint, ALenum, ALint*, ALint*, ALint*)
DECL_THUNK3(void, alGetBufferiv, ALuint, ALenum, ALint*)
DECL_THUNK5(void, alBufferData, ALuint, ALenum, const ALvoid*, ALsizei, ALsizei)
/* EFX 1.0. Required here to be exported from libOpenAL32.dll.a/OpenAL32.lib
* with the router enabled.
*/
DECL_THUNK2(void, alGenFilters, ALsizei, ALuint*)
DECL_THUNK2(void, alDeleteFilters, ALsizei, const ALuint*)
DECL_THUNK1(ALboolean, alIsFilter, ALuint)
DECL_THUNK3(void, alFilterf, ALuint, ALenum, ALfloat)
DECL_THUNK3(void, alFilterfv, ALuint, ALenum, const ALfloat*)
DECL_THUNK3(void, alFilteri, ALuint, ALenum, ALint)
DECL_THUNK3(void, alFilteriv, ALuint, ALenum, const ALint*)
DECL_THUNK3(void, alGetFilterf, ALuint, ALenum, ALfloat*)
DECL_THUNK3(void, alGetFilterfv, ALuint, ALenum, ALfloat*)
DECL_THUNK3(void, alGetFilteri, ALuint, ALenum, ALint*)
DECL_THUNK3(void, alGetFilteriv, ALuint, ALenum, ALint*)
DECL_THUNK2(void, alGenEffects, ALsizei, ALuint*)
DECL_THUNK2(void, alDeleteEffects, ALsizei, const ALuint*)
DECL_THUNK1(ALboolean, alIsEffect, ALuint)
DECL_THUNK3(void, alEffectf, ALuint, ALenum, ALfloat)
DECL_THUNK3(void, alEffectfv, ALuint, ALenum, const ALfloat*)
DECL_THUNK3(void, alEffecti, ALuint, ALenum, ALint)
DECL_THUNK3(void, alEffectiv, ALuint, ALenum, const ALint*)
DECL_THUNK3(void, alGetEffectf, ALuint, ALenum, ALfloat*)
DECL_THUNK3(void, alGetEffectfv, ALuint, ALenum, ALfloat*)
DECL_THUNK3(void, alGetEffecti, ALuint, ALenum, ALint*)
DECL_THUNK3(void, alGetEffectiv, ALuint, ALenum, ALint*)
DECL_THUNK2(void, alGenAuxiliaryEffectSlots, ALsizei, ALuint*)
DECL_THUNK2(void, alDeleteAuxiliaryEffectSlots, ALsizei, const ALuint*)
DECL_THUNK1(ALboolean, alIsAuxiliaryEffectSlot, ALuint)
DECL_THUNK3(void, alAuxiliaryEffectSlotf, ALuint, ALenum, ALfloat)
DECL_THUNK3(void, alAuxiliaryEffectSlotfv, ALuint, ALenum, const ALfloat*)
DECL_THUNK3(void, alAuxiliaryEffectSloti, ALuint, ALenum, ALint)
DECL_THUNK3(void, alAuxiliaryEffectSlotiv, ALuint, ALenum, const ALint*)
DECL_THUNK3(void, alGetAuxiliaryEffectSlotf, ALuint, ALenum, ALfloat*)
DECL_THUNK3(void, alGetAuxiliaryEffectSlotfv, ALuint, ALenum, ALfloat*)
DECL_THUNK3(void, alGetAuxiliaryEffectSloti, ALuint, ALenum, ALint*)
DECL_THUNK3(void, alGetAuxiliaryEffectSlotiv, ALuint, ALenum, ALint*)

+ 154
- 69
modules/openal-soft/router/alc.cpp View File

@ -118,6 +118,41 @@ static const std::array 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<decltype(iface.x)>(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;

+ 5
- 5
modules/openal-soft/router/router.cpp View File

@ -17,7 +17,7 @@
#include "version.h"
std::vector<DriverIface> DriverList;
std::vector<DriverIfacePtr> 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<void*>()){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<DriverIface>(name, module));
DriverIface &newdrv = *DriverList.back();
/* Load required functions. */
int err = 0;

+ 39
- 1
modules/openal-soft/router/router.h View File

@ -8,6 +8,7 @@
#include <stdio.h>
#include <atomic>
#include <memory>
#include <mutex>
#include <string>
#include <utility>
@ -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<typename T>
DriverIface(T&& name, HMODULE mod)
: Name(std::forward<T>(name)), Module(mod)
@ -134,8 +171,9 @@ struct DriverIface {
Module = nullptr;
}
};
using DriverIfacePtr = std::unique_ptr<DriverIface>;
extern std::vector<DriverIface> DriverList;
extern std::vector<DriverIfacePtr> DriverList;
extern thread_local DriverIface *ThreadCtxDriver;
extern std::atomic<DriverIface*> CurrentCtxDriver;

+ 17
- 0
modules/openal-soft/utils/alsoft-config/mainwindow.cpp View File

@ -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()};

+ 1
- 0
modules/openal-soft/utils/alsoft-config/mainwindow.h View File

@ -39,6 +39,7 @@ private slots:
void select51DecoderFile();
void select61DecoderFile();
void select71DecoderFile();
void select3D71DecoderFile();
void updateJackBufferSizeEdit(int size);
void updateJackBufferSizeSlider();

+ 92
- 39
modules/openal-soft/utils/alsoft-config/mainwindow.ui View File

@ -625,9 +625,7 @@ quantization with low-level whitenoise.
<string>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.</string>
surround sound speakers.</string>
</property>
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
@ -670,9 +668,9 @@ configuration file.
<property name="geometry">
<rect>
<x>-10</x>
<y>160</y>
<y>140</y>
<width>551</width>
<height>161</height>
<height>231</height>
</rect>
</property>
<property name="title">
@ -684,10 +682,10 @@ configuration file.
<widget class="QLineEdit" name="decoderQuadLineEdit">
<property name="geometry">
<rect>
<x>120</x>
<x>130</x>
<y>30</y>
<width>311</width>
<height>21</height>
<width>301</width>
<height>25</height>
</rect>
</property>
</widget>
@ -696,8 +694,8 @@ configuration file.
<rect>
<x>20</x>
<y>30</y>
<width>91</width>
<height>21</height>
<width>101</width>
<height>25</height>
</rect>
</property>
<property name="text">
@ -713,7 +711,7 @@ configuration file.
<x>440</x>
<y>30</y>
<width>91</width>
<height>21</height>
<height>25</height>
</rect>
</property>
<property name="text">
@ -723,10 +721,10 @@ configuration file.
<widget class="QLineEdit" name="decoder51LineEdit">
<property name="geometry">
<rect>
<x>120</x>
<y>60</y>
<width>311</width>
<height>21</height>
<x>130</x>
<y>70</y>
<width>301</width>
<height>25</height>
</rect>
</property>
</widget>
@ -734,9 +732,9 @@ configuration file.
<property name="geometry">
<rect>
<x>440</x>
<y>60</y>
<y>70</y>
<width>91</width>
<height>21</height>
<height>25</height>
</rect>
</property>
<property name="text">
@ -747,9 +745,9 @@ configuration file.
<property name="geometry">
<rect>
<x>20</x>
<y>60</y>
<width>91</width>
<height>21</height>
<y>70</y>
<width>101</width>
<height>25</height>
</rect>
</property>
<property name="text">
@ -763,9 +761,9 @@ configuration file.
<property name="geometry">
<rect>
<x>20</x>
<y>90</y>
<width>91</width>
<height>21</height>
<y>110</y>
<width>101</width>
<height>25</height>
</rect>
</property>
<property name="text">
@ -778,10 +776,10 @@ configuration file.
<widget class="QLineEdit" name="decoder61LineEdit">
<property name="geometry">
<rect>
<x>120</x>
<y>90</y>
<width>311</width>
<height>21</height>
<x>130</x>
<y>110</y>
<width>301</width>
<height>25</height>
</rect>
</property>
</widget>
@ -789,9 +787,9 @@ configuration file.
<property name="geometry">
<rect>
<x>440</x>
<y>90</y>
<y>110</y>
<width>91</width>
<height>21</height>
<height>25</height>
</rect>
</property>
<property name="text">
@ -802,9 +800,9 @@ configuration file.
<property name="geometry">
<rect>
<x>440</x>
<y>120</y>
<y>150</y>
<width>91</width>
<height>21</height>
<height>25</height>
</rect>
</property>
<property name="text">
@ -814,10 +812,10 @@ configuration file.
<widget class="QLineEdit" name="decoder71LineEdit">
<property name="geometry">
<rect>
<x>120</x>
<y>120</y>
<width>311</width>
<height>21</height>
<x>130</x>
<y>150</y>
<width>301</width>
<height>25</height>
</rect>
</property>
</widget>
@ -825,9 +823,9 @@ configuration file.
<property name="geometry">
<rect>
<x>20</x>
<y>120</y>
<width>91</width>
<height>21</height>
<y>150</y>
<width>101</width>
<height>25</height>
</rect>
</property>
<property name="text">
@ -837,6 +835,45 @@ configuration file.
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
<widget class="QLabel" name="label_33">
<property name="geometry">
<rect>
<x>20</x>
<y>190</y>
<width>101</width>
<height>25</height>
</rect>
</property>
<property name="text">
<string>3D7.1 Surround:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
<widget class="QLineEdit" name="decoder3D71LineEdit">
<property name="geometry">
<rect>
<x>130</x>
<y>190</y>
<width>301</width>
<height>25</height>
</rect>
</property>
</widget>
<widget class="QPushButton" name="decoder3D71Button">
<property name="geometry">
<rect>
<x>440</x>
<y>190</y>
<width>91</width>
<height>25</height>
</rect>
</property>
<property name="text">
<string>Browse...</string>
</property>
</widget>
</widget>
<widget class="QCheckBox" name="decoderNFEffectsCheckBox">
<property name="geometry">
@ -2110,7 +2147,7 @@ be useful for preventing those extensions from being used.
<property name="geometry">
<rect>
<x>10</x>
<y>100</y>
<y>60</y>
<width>511</width>
<height>241</height>
</rect>
@ -2516,6 +2553,22 @@ added by the ALC_EXT_DEDICATED extension.
</property>
</item>
</widget>
<widget class="QCheckBox" name="enableEaxCheck">
<property name="geometry">
<rect>
<x>30</x>
<y>320</y>
<width>231</width>
<height>21</height>
</rect>
</property>
<property name="toolTip">
<string>Enables legacy EAX API support.</string>
</property>
<property name="text">
<string>Enable EAX API support</string>
</property>
</widget>
</widget>
</widget>
<widget class="QPushButton" name="closeCancelButton">

+ 53
- 23
modules/openal-soft/utils/makemhr/loaddef.cpp View File

@ -37,8 +37,11 @@
#include <vector>
#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<double> upsampled, const uint rate,
const uint n, const double *hrir, const double f, const double onset)
{
std::vector<double> upsampled(10 * n);
{
PPhaseResampler rs;
rs.init(rate, 10 * rate);
rs.process(n, hrir, 10 * n, upsampled.data());
}
rs.process(n, hrir, static_cast<uint>(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<double> 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<double> hrir(hData->mIrPoints);
auto hrir = std::make_unique<double[]>(hData->mIrSize);
uint line, col, fi, ei, ai;
int count;
std::vector<double> onsetSamples(OnsetRateMultiple * hData->mIrPoints);
PPhaseResampler onsetResampler;
onsetResampler.init(hData->mIrRate, OnsetRateMultiple*hData->mIrRate);
al::optional<PPhaseResampler> resampler;
if(outRate && outRate != hData->mIrRate)
resampler.emplace().init(hData->mIrRate, outRate);
const double rateScale{outRate ? static_cast<double>(outRate) / hData->mIrRate : 1.0};
const uint irPoints{outRate
? std::min(static_cast<uint>(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;

+ 2
- 2
modules/openal-soft/utils/makemhr/loaddef.h View File

@ -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 */

+ 33
- 9
modules/openal-soft/utils/makemhr/loadsofa.cpp View File

@ -37,6 +37,8 @@
#include <thread>
#include <vector>
#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<double> &upsampled, const double *hrir)
al::span<double> upsampled, const double *hrir)
{
rs.process(n, hrir, static_cast<uint>(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<complex_d> &h,
double *hrir)
static void CalcHrirMagnitude(const uint points, const uint n, al::span<complex_d> 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
MagnitudeResponse(n, h.data(), hrir);
}
static bool LoadResponses(MYSOFA_HRTF *sofaHrtf, HrirDataT *hData)
static bool LoadResponses(MYSOFA_HRTF *sofaHrtf, HrirDataT *hData, const uint outRate)
{
std::atomic<uint> 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<double[]> restmp;
al::optional<PPhaseResampler> resampler;
if(outRate && outRate != hData->mIrRate)
{
resampler.emplace().init(hData->mIrRate, outRate);
restmp = std::make_unique<double[]>(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<double>(outRate) / hData->mIrRate};
hData->mIrRate = outRate;
hData->mIrPoints = std::min(static_cast<uint>(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;

+ 1
- 1
modules/openal-soft/utils/makemhr/loadsofa.h View File

@ -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 */

+ 3
- 3
modules/openal-soft/utils/makemhr/makemhr.cpp View File

@ -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;
}
}

Loading…
Cancel
Save