aboutsummaryrefslogtreecommitdiffstats
path: root/alc
diff options
context:
space:
mode:
Diffstat (limited to 'alc')
-rw-r--r--alc/alc.cpp557
-rw-r--r--alc/alconfig.cpp198
-rw-r--r--alc/alconfig.h19
-rw-r--r--alc/alu.cpp451
-rw-r--r--alc/backends/alsa.cpp121
-rw-r--r--alc/backends/base.cpp9
-rw-r--r--alc/backends/base.h23
-rw-r--r--alc/backends/coreaudio.cpp8
-rw-r--r--alc/backends/dsound.cpp16
-rw-r--r--alc/backends/jack.cpp47
-rw-r--r--alc/backends/loopback.cpp2
-rw-r--r--alc/backends/null.cpp3
-rw-r--r--alc/backends/oboe.cpp13
-rw-r--r--alc/backends/opensl.cpp77
-rw-r--r--alc/backends/oss.cpp28
-rw-r--r--alc/backends/pipewire.cpp132
-rw-r--r--alc/backends/portaudio.cpp74
-rw-r--r--alc/backends/pulseaudio.cpp75
-rw-r--r--alc/backends/sdl2.cpp27
-rw-r--r--alc/backends/sndio.cpp164
-rw-r--r--alc/backends/solaris.cpp20
-rw-r--r--alc/backends/wasapi.cpp62
-rw-r--r--alc/backends/wave.cpp117
-rw-r--r--alc/backends/winmm.cpp36
-rw-r--r--alc/context.cpp51
-rw-r--r--alc/context.h49
-rw-r--r--alc/device.cpp9
-rw-r--r--alc/device.h78
-rw-r--r--alc/effects/autowah.cpp86
-rw-r--r--alc/effects/base.h43
-rw-r--r--alc/effects/chorus.cpp117
-rw-r--r--alc/effects/compressor.cpp13
-rw-r--r--alc/effects/convolution.cpp160
-rw-r--r--alc/effects/dedicated.cpp94
-rw-r--r--alc/effects/distortion.cpp29
-rw-r--r--alc/effects/echo.cpp45
-rw-r--r--alc/effects/equalizer.cpp36
-rw-r--r--alc/effects/fshifter.cpp30
-rw-r--r--alc/effects/modulator.cpp24
-rw-r--r--alc/effects/null.cpp4
-rw-r--r--alc/effects/pshifter.cpp65
-rw-r--r--alc/effects/reverb.cpp368
-rw-r--r--alc/effects/vmorpher.cpp127
-rw-r--r--alc/export_list.h16
-rw-r--r--alc/inprogext.h32
-rw-r--r--alc/panning.cpp273
46 files changed, 1999 insertions, 2029 deletions
diff --git a/alc/alc.cpp b/alc/alc.cpp
index 6017e743..b629a3fc 100644
--- a/alc/alc.cpp
+++ b/alc/alc.cpp
@@ -50,7 +50,6 @@
#include <mutex>
#include <new>
#include <optional>
-#include <stddef.h>
#include <stdexcept>
#include <string>
#include <type_traits>
@@ -100,6 +99,7 @@
#include "device.h"
#include "effects/base.h"
#include "export_list.h"
+#include "flexarray.h"
#include "inprogext.h"
#include "intrusive_ptr.h"
#include "opthelpers.h"
@@ -174,7 +174,7 @@ BOOL APIENTRY DllMain(HINSTANCE module, DWORD reason, LPVOID /*reserved*/)
case DLL_PROCESS_ATTACH:
/* Pin the DLL so we won't get unloaded until the process terminates */
GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_PIN | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
- al::bit_cast<WCHAR*>(module), &module);
+ reinterpret_cast<WCHAR*>(module), &module);
break;
}
return TRUE;
@@ -196,66 +196,66 @@ using float2 = std::array<float,2>;
************************************************/
struct BackendInfo {
const char *name;
- BackendFactory& (*getFactory)(void);
+ BackendFactory& (*getFactory)();
};
-BackendInfo BackendList[] = {
+std::array BackendList{
#ifdef HAVE_PIPEWIRE
- { "pipewire", PipeWireBackendFactory::getFactory },
+ BackendInfo{"pipewire", PipeWireBackendFactory::getFactory},
#endif
#ifdef HAVE_PULSEAUDIO
- { "pulse", PulseBackendFactory::getFactory },
+ BackendInfo{"pulse", PulseBackendFactory::getFactory},
#endif
#ifdef HAVE_WASAPI
- { "wasapi", WasapiBackendFactory::getFactory },
+ BackendInfo{"wasapi", WasapiBackendFactory::getFactory},
#endif
#ifdef HAVE_COREAUDIO
- { "core", CoreAudioBackendFactory::getFactory },
+ BackendInfo{"core", CoreAudioBackendFactory::getFactory},
#endif
#ifdef HAVE_OBOE
- { "oboe", OboeBackendFactory::getFactory },
+ BackendInfo{"oboe", OboeBackendFactory::getFactory},
#endif
#ifdef HAVE_OPENSL
- { "opensl", OSLBackendFactory::getFactory },
+ BackendInfo{"opensl", OSLBackendFactory::getFactory},
#endif
#ifdef HAVE_ALSA
- { "alsa", AlsaBackendFactory::getFactory },
+ BackendInfo{"alsa", AlsaBackendFactory::getFactory},
#endif
#ifdef HAVE_SOLARIS
- { "solaris", SolarisBackendFactory::getFactory },
+ BackendInfo{"solaris", SolarisBackendFactory::getFactory},
#endif
#ifdef HAVE_SNDIO
- { "sndio", SndIOBackendFactory::getFactory },
+ BackendInfo{"sndio", SndIOBackendFactory::getFactory},
#endif
#ifdef HAVE_OSS
- { "oss", OSSBackendFactory::getFactory },
+ BackendInfo{"oss", OSSBackendFactory::getFactory},
#endif
#ifdef HAVE_JACK
- { "jack", JackBackendFactory::getFactory },
+ BackendInfo{"jack", JackBackendFactory::getFactory},
#endif
#ifdef HAVE_DSOUND
- { "dsound", DSoundBackendFactory::getFactory },
+ BackendInfo{"dsound", DSoundBackendFactory::getFactory},
#endif
#ifdef HAVE_WINMM
- { "winmm", WinMMBackendFactory::getFactory },
+ BackendInfo{"winmm", WinMMBackendFactory::getFactory},
#endif
#ifdef HAVE_PORTAUDIO
- { "port", PortBackendFactory::getFactory },
+ BackendInfo{"port", PortBackendFactory::getFactory},
#endif
#ifdef HAVE_SDL2
- { "sdl2", SDL2BackendFactory::getFactory },
+ BackendInfo{"sdl2", SDL2BackendFactory::getFactory},
#endif
- { "null", NullBackendFactory::getFactory },
+ BackendInfo{"null", NullBackendFactory::getFactory},
#ifdef HAVE_WAVE
- { "wave", WaveBackendFactory::getFactory },
+ BackendInfo{"wave", WaveBackendFactory::getFactory},
#endif
};
BackendFactory *PlaybackFactory{};
BackendFactory *CaptureFactory{};
-
+/* NOLINTBEGIN(*-avoid-c-arrays) */
constexpr ALCchar alcNoError[] = "No Error";
constexpr ALCchar alcErrInvalidDevice[] = "Invalid Device";
constexpr ALCchar alcErrInvalidContext[] = "Invalid Context";
@@ -270,6 +270,7 @@ constexpr ALCchar alcErrOutOfMemory[] = "Out of Memory";
/* Enumerated device names */
constexpr ALCchar alcDefaultName[] = "OpenAL Soft\0";
+/* NOLINTEND(*-avoid-c-arrays) */
std::string alcAllDevicesList;
std::string alcCaptureDeviceList;
@@ -298,6 +299,7 @@ constexpr uint DitherRNGSeed{22222u};
/************************************************
* ALC information
************************************************/
+/* NOLINTBEGIN(*-avoid-c-arrays) */
constexpr ALCchar alcNoDeviceExtList[] =
"ALC_ENUMERATE_ALL_EXT "
"ALC_ENUMERATION_EXT "
@@ -328,6 +330,7 @@ constexpr ALCchar alcExtensionList[] =
"ALC_SOFT_pause_device "
"ALC_SOFT_reopen_device "
"ALC_SOFT_system_events";
+/* NOLINTEND(*-avoid-c-arrays) */
constexpr int alcMajorVersion{1};
constexpr int alcMinorVersion{1};
@@ -347,7 +350,7 @@ std::vector<ALCcontext*> ContextList;
std::recursive_mutex ListLock;
-void alc_initconfig(void)
+void alc_initconfig()
{
if(auto loglevel = al::getenv("ALSOFT_LOGLEVEL"))
{
@@ -424,7 +427,7 @@ void alc_initconfig(void)
#ifdef HAVE_NEON
capfilter |= CPU_CAP_NEON;
#endif
- if(auto cpuopt = ConfigValueStr(nullptr, nullptr, "disable-cpu-exts"))
+ if(auto cpuopt = ConfigValueStr({}, {}, "disable-cpu-exts"))
{
const char *str{cpuopt->c_str()};
if(al::strcasecmp(str, "all") == 0)
@@ -477,9 +480,9 @@ void alc_initconfig(void)
CPUCapFlags = caps & capfilter;
}
- if(auto priopt = ConfigValueInt(nullptr, nullptr, "rt-prio"))
+ if(auto priopt = ConfigValueInt({}, {}, "rt-prio"))
RTPrioLevel = *priopt;
- if(auto limopt = ConfigValueBool(nullptr, nullptr, "rt-time-limit"))
+ if(auto limopt = ConfigValueBool({}, {}, "rt-time-limit"))
AllowRTTimeLimit = *limopt;
{
@@ -493,18 +496,18 @@ void alc_initconfig(void)
return true;
return false;
}
- return GetConfigValueBool(nullptr, "game_compat", optname, false);
+ return GetConfigValueBool({}, "game_compat", optname, false);
};
sBufferSubDataCompat = checkflag("__ALSOFT_ENABLE_SUB_DATA_EXT", "enable-sub-data-ext");
compatflags.set(CompatFlags::ReverseX, checkflag("__ALSOFT_REVERSE_X", "reverse-x"));
compatflags.set(CompatFlags::ReverseY, checkflag("__ALSOFT_REVERSE_Y", "reverse-y"));
compatflags.set(CompatFlags::ReverseZ, checkflag("__ALSOFT_REVERSE_Z", "reverse-z"));
- aluInit(compatflags, ConfigValueFloat(nullptr, "game_compat", "nfc-scale").value_or(1.0f));
+ aluInit(compatflags, ConfigValueFloat({}, "game_compat", "nfc-scale").value_or(1.0f));
}
- Voice::InitMixer(ConfigValueStr(nullptr, nullptr, "resampler"));
+ Voice::InitMixer(ConfigValueStr({}, {}, "resampler"));
- if(auto uhjfiltopt = ConfigValueStr(nullptr, "uhj", "decode-filter"))
+ if(auto uhjfiltopt = ConfigValueStr({}, "uhj", "decode-filter"))
{
if(al::strcasecmp(uhjfiltopt->c_str(), "fir256") == 0)
UhjDecodeQuality = UhjQualityType::FIR256;
@@ -515,7 +518,7 @@ void alc_initconfig(void)
else
WARN("Unsupported uhj/decode-filter: %s\n", uhjfiltopt->c_str());
}
- if(auto uhjfiltopt = ConfigValueStr(nullptr, "uhj", "encode-filter"))
+ if(auto uhjfiltopt = ConfigValueStr({}, "uhj", "encode-filter"))
{
if(al::strcasecmp(uhjfiltopt->c_str(), "fir256") == 0)
UhjEncodeQuality = UhjQualityType::FIR256;
@@ -541,17 +544,17 @@ void alc_initconfig(void)
TrapALError = al::strcasecmp(traperr->c_str(), "true") == 0
|| strtol(traperr->c_str(), nullptr, 0) == 1;
else
- TrapALError = !!GetConfigValueBool(nullptr, nullptr, "trap-al-error", false);
+ TrapALError = GetConfigValueBool({}, {}, "trap-al-error", false);
traperr = al::getenv("ALSOFT_TRAP_ALC_ERROR");
if(traperr)
TrapALCError = al::strcasecmp(traperr->c_str(), "true") == 0
|| strtol(traperr->c_str(), nullptr, 0) == 1;
else
- TrapALCError = !!GetConfigValueBool(nullptr, nullptr, "trap-alc-error", false);
+ TrapALCError = GetConfigValueBool({}, {}, "trap-alc-error", false);
}
- if(auto boostopt = ConfigValueFloat(nullptr, "reverb", "boost"))
+ if(auto boostopt = ConfigValueFloat({}, "reverb", "boost"))
{
const float valf{std::isfinite(*boostopt) ? clampf(*boostopt, -24.0f, 24.0f) : 0.0f};
ReverbBoost *= std::pow(10.0f, valf / 20.0f);
@@ -559,7 +562,8 @@ void alc_initconfig(void)
auto BackendListEnd = std::end(BackendList);
auto devopt = al::getenv("ALSOFT_DRIVERS");
- if(devopt || (devopt=ConfigValueStr(nullptr, nullptr, "drivers")))
+ if(!devopt) devopt = ConfigValueStr({}, {}, "drivers");
+ if(devopt)
{
auto backendlist_cur = std::begin(BackendList);
@@ -645,7 +649,7 @@ void alc_initconfig(void)
if(!CaptureFactory)
WARN("No capture backend available!\n");
- if(auto exclopt = ConfigValueStr(nullptr, nullptr, "excludefx"))
+ if(auto exclopt = ConfigValueStr({}, {}, "excludefx"))
{
const char *next{exclopt->c_str()};
do {
@@ -660,21 +664,19 @@ void alc_initconfig(void)
{
if(len == strlen(effectitem.name) &&
strncmp(effectitem.name, str, len) == 0)
- DisabledEffects[effectitem.type] = true;
+ DisabledEffects.set(effectitem.type);
}
} while(next++);
}
InitEffect(&ALCcontext::sDefaultEffect);
auto defrevopt = al::getenv("ALSOFT_DEFAULT_REVERB");
- if(defrevopt || (defrevopt=ConfigValueStr(nullptr, nullptr, "default-reverb")))
- LoadReverbPreset(defrevopt->c_str(), &ALCcontext::sDefaultEffect);
+ if(!defrevopt) defrevopt = ConfigValueStr({}, {}, "default-reverb");
+ if(defrevopt) LoadReverbPreset(defrevopt->c_str(), &ALCcontext::sDefaultEffect);
#ifdef ALSOFT_EAX
{
- static constexpr char eax_block_name[] = "eax";
-
- if(const auto eax_enable_opt = ConfigValueBool(nullptr, eax_block_name, "enable"))
+ if(const auto eax_enable_opt = ConfigValueBool({}, "eax", "enable"))
{
eax_g_is_enabled = *eax_enable_opt;
if(!eax_g_is_enabled)
@@ -683,15 +685,15 @@ void alc_initconfig(void)
else
eax_g_is_enabled = true;
- if((DisabledEffects[EAXREVERB_EFFECT] || DisabledEffects[CHORUS_EFFECT])
+ if((DisabledEffects.test(EAXREVERB_EFFECT) || DisabledEffects.test(CHORUS_EFFECT))
&& eax_g_is_enabled)
{
eax_g_is_enabled = false;
TRACE("EAX disabled because %s disabled.\n",
- (DisabledEffects[EAXREVERB_EFFECT] && DisabledEffects[CHORUS_EFFECT])
+ (DisabledEffects.test(EAXREVERB_EFFECT) && DisabledEffects.test(CHORUS_EFFECT))
? "EAXReverb and Chorus are" :
- DisabledEffects[EAXREVERB_EFFECT] ? "EAXReverb is" :
- DisabledEffects[CHORUS_EFFECT] ? "Chorus is" : "");
+ DisabledEffects.test(EAXREVERB_EFFECT) ? "EAXReverb is" :
+ DisabledEffects.test(CHORUS_EFFECT) ? "Chorus is" : "");
}
}
#endif // ALSOFT_EAX
@@ -736,44 +738,45 @@ void ProbeCaptureDeviceList()
struct DevFmtPair { DevFmtChannels chans; DevFmtType type; };
std::optional<DevFmtPair> DecomposeDevFormat(ALenum format)
{
- static const struct {
+ struct FormatType {
ALenum format;
DevFmtChannels channels;
DevFmtType type;
- } list[] = {
- { AL_FORMAT_MONO8, DevFmtMono, DevFmtUByte },
- { AL_FORMAT_MONO16, DevFmtMono, DevFmtShort },
- { AL_FORMAT_MONO_I32, DevFmtMono, DevFmtInt },
- { AL_FORMAT_MONO_FLOAT32, DevFmtMono, DevFmtFloat },
-
- { AL_FORMAT_STEREO8, DevFmtStereo, DevFmtUByte },
- { AL_FORMAT_STEREO16, DevFmtStereo, DevFmtShort },
- { AL_FORMAT_STEREO_I32, DevFmtStereo, DevFmtInt },
- { AL_FORMAT_STEREO_FLOAT32, DevFmtStereo, DevFmtFloat },
-
- { AL_FORMAT_QUAD8, DevFmtQuad, DevFmtUByte },
- { AL_FORMAT_QUAD16, DevFmtQuad, DevFmtShort },
- { AL_FORMAT_QUAD32, DevFmtQuad, DevFmtFloat },
- { AL_FORMAT_QUAD_I32, DevFmtQuad, DevFmtInt },
- { AL_FORMAT_QUAD_FLOAT32, DevFmtQuad, DevFmtFloat },
-
- { AL_FORMAT_51CHN8, DevFmtX51, DevFmtUByte },
- { AL_FORMAT_51CHN16, DevFmtX51, DevFmtShort },
- { AL_FORMAT_51CHN32, DevFmtX51, DevFmtFloat },
- { AL_FORMAT_51CHN_I32, DevFmtX51, DevFmtInt },
- { AL_FORMAT_51CHN_FLOAT32, DevFmtX51, DevFmtFloat },
-
- { AL_FORMAT_61CHN8, DevFmtX61, DevFmtUByte },
- { AL_FORMAT_61CHN16, DevFmtX61, DevFmtShort },
- { AL_FORMAT_61CHN32, DevFmtX61, DevFmtFloat },
- { AL_FORMAT_61CHN_I32, DevFmtX61, DevFmtInt },
- { AL_FORMAT_61CHN_FLOAT32, DevFmtX61, DevFmtFloat },
-
- { AL_FORMAT_71CHN8, DevFmtX71, DevFmtUByte },
- { AL_FORMAT_71CHN16, DevFmtX71, DevFmtShort },
- { AL_FORMAT_71CHN32, DevFmtX71, DevFmtFloat },
- { AL_FORMAT_71CHN_I32, DevFmtX71, DevFmtInt },
- { AL_FORMAT_71CHN_FLOAT32, DevFmtX71, DevFmtFloat },
+ };
+ static constexpr std::array list{
+ FormatType{AL_FORMAT_MONO8, DevFmtMono, DevFmtUByte},
+ FormatType{AL_FORMAT_MONO16, DevFmtMono, DevFmtShort},
+ FormatType{AL_FORMAT_MONO_I32, DevFmtMono, DevFmtInt},
+ FormatType{AL_FORMAT_MONO_FLOAT32, DevFmtMono, DevFmtFloat},
+
+ FormatType{AL_FORMAT_STEREO8, DevFmtStereo, DevFmtUByte},
+ FormatType{AL_FORMAT_STEREO16, DevFmtStereo, DevFmtShort},
+ FormatType{AL_FORMAT_STEREO_I32, DevFmtStereo, DevFmtInt},
+ FormatType{AL_FORMAT_STEREO_FLOAT32, DevFmtStereo, DevFmtFloat},
+
+ FormatType{AL_FORMAT_QUAD8, DevFmtQuad, DevFmtUByte},
+ FormatType{AL_FORMAT_QUAD16, DevFmtQuad, DevFmtShort},
+ FormatType{AL_FORMAT_QUAD32, DevFmtQuad, DevFmtFloat},
+ FormatType{AL_FORMAT_QUAD_I32, DevFmtQuad, DevFmtInt},
+ FormatType{AL_FORMAT_QUAD_FLOAT32, DevFmtQuad, DevFmtFloat},
+
+ FormatType{AL_FORMAT_51CHN8, DevFmtX51, DevFmtUByte},
+ FormatType{AL_FORMAT_51CHN16, DevFmtX51, DevFmtShort},
+ FormatType{AL_FORMAT_51CHN32, DevFmtX51, DevFmtFloat},
+ FormatType{AL_FORMAT_51CHN_I32, DevFmtX51, DevFmtInt},
+ FormatType{AL_FORMAT_51CHN_FLOAT32, DevFmtX51, DevFmtFloat},
+
+ FormatType{AL_FORMAT_61CHN8, DevFmtX61, DevFmtUByte},
+ FormatType{AL_FORMAT_61CHN16, DevFmtX61, DevFmtShort},
+ FormatType{AL_FORMAT_61CHN32, DevFmtX61, DevFmtFloat},
+ FormatType{AL_FORMAT_61CHN_I32, DevFmtX61, DevFmtInt},
+ FormatType{AL_FORMAT_61CHN_FLOAT32, DevFmtX61, DevFmtFloat},
+
+ FormatType{AL_FORMAT_71CHN8, DevFmtX71, DevFmtUByte},
+ FormatType{AL_FORMAT_71CHN16, DevFmtX71, DevFmtShort},
+ FormatType{AL_FORMAT_71CHN32, DevFmtX71, DevFmtFloat},
+ FormatType{AL_FORMAT_71CHN_I32, DevFmtX71, DevFmtInt},
+ FormatType{AL_FORMAT_71CHN_FLOAT32, DevFmtX71, DevFmtFloat},
};
for(const auto &item : list)
@@ -976,10 +979,14 @@ std::unique_ptr<Compressor> CreateDeviceLimiter(const ALCdevice *device, const f
*/
inline void UpdateClockBase(ALCdevice *device)
{
- IncrementRef(device->MixCount);
- device->ClockBase += nanoseconds{seconds{device->SamplesDone}} / device->Frequency;
- device->SamplesDone = 0;
- IncrementRef(device->MixCount);
+ const auto mixLock = device->getWriteMixLock();
+
+ auto samplesDone = device->mSamplesDone.load(std::memory_order_relaxed);
+ auto clockBase = device->mClockBase.load(std::memory_order_relaxed);
+
+ clockBase += nanoseconds{seconds{samplesDone}} / device->Frequency;
+ device->mClockBase.store(clockBase, std::memory_order_relaxed);
+ device->mSamplesDone.store(0, std::memory_order_relaxed);
}
/**
@@ -1004,8 +1011,8 @@ ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList)
std::optional<DevFmtType> opttype;
std::optional<DevAmbiLayout> optlayout;
std::optional<DevAmbiScaling> optscale;
- uint period_size{DEFAULT_UPDATE_SIZE};
- uint buffer_size{DEFAULT_UPDATE_SIZE * DEFAULT_NUM_UPDATES};
+ uint period_size{DefaultUpdateSize};
+ uint buffer_size{DefaultUpdateSize * DefaultNumUpdates};
int hrtf_id{-1};
uint aorder{0u};
@@ -1013,71 +1020,73 @@ ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList)
{
/* Get default settings from the user configuration */
- if(auto freqopt = device->configValue<uint>(nullptr, "frequency"))
+ if(auto freqopt = device->configValue<uint>({}, "frequency"))
{
- optsrate = clampu(*freqopt, MIN_OUTPUT_RATE, MAX_OUTPUT_RATE);
+ optsrate = clampu(*freqopt, MinOutputRate, MaxOutputRate);
- const double scale{static_cast<double>(*optsrate) / DEFAULT_OUTPUT_RATE};
- period_size = static_cast<uint>(period_size*scale + 0.5);
+ const double scale{static_cast<double>(*optsrate) / double{DefaultOutputRate}};
+ period_size = static_cast<uint>(std::lround(period_size * scale));
}
- if(auto persizeopt = device->configValue<uint>(nullptr, "period_size"))
+ if(auto persizeopt = device->configValue<uint>({}, "period_size"))
period_size = clampu(*persizeopt, 64, 8192);
- if(auto numperopt = device->configValue<uint>(nullptr, "periods"))
+ if(auto numperopt = device->configValue<uint>({}, "periods"))
buffer_size = clampu(*numperopt, 2, 16) * period_size;
else
- buffer_size = period_size * DEFAULT_NUM_UPDATES;
+ buffer_size = period_size * uint{DefaultNumUpdates};
- if(auto typeopt = device->configValue<std::string>(nullptr, "sample-type"))
+ if(auto typeopt = device->configValue<std::string>({}, "sample-type"))
{
- static constexpr struct TypeMap {
- const char name[8];
+ struct TypeMap {
+ const char name[8]; /* NOLINT(*-avoid-c-arrays) */
DevFmtType type;
- } typelist[] = {
- { "int8", DevFmtByte },
- { "uint8", DevFmtUByte },
- { "int16", DevFmtShort },
- { "uint16", DevFmtUShort },
- { "int32", DevFmtInt },
- { "uint32", DevFmtUInt },
- { "float32", DevFmtFloat },
+ };
+ static constexpr std::array typelist{
+ TypeMap{"int8", DevFmtByte },
+ TypeMap{"uint8", DevFmtUByte },
+ TypeMap{"int16", DevFmtShort },
+ TypeMap{"uint16", DevFmtUShort},
+ TypeMap{"int32", DevFmtInt },
+ TypeMap{"uint32", DevFmtUInt },
+ TypeMap{"float32", DevFmtFloat },
};
const ALCchar *fmt{typeopt->c_str()};
- auto iter = std::find_if(std::begin(typelist), std::end(typelist),
+ auto iter = std::find_if(typelist.begin(), typelist.end(),
[fmt](const TypeMap &entry) -> bool
{ return al::strcasecmp(entry.name, fmt) == 0; });
- if(iter == std::end(typelist))
+ if(iter == typelist.end())
ERR("Unsupported sample-type: %s\n", fmt);
else
opttype = iter->type;
}
- if(auto chanopt = device->configValue<std::string>(nullptr, "channels"))
+ if(auto chanopt = device->configValue<std::string>({}, "channels"))
{
- static constexpr struct ChannelMap {
- const char name[16];
+ struct ChannelMap {
+ const char name[16]; /* NOLINT(*-avoid-c-arrays) */
DevFmtChannels chans;
uint8_t order;
- } chanlist[] = {
- { "mono", DevFmtMono, 0 },
- { "stereo", DevFmtStereo, 0 },
- { "quad", DevFmtQuad, 0 },
- { "surround51", DevFmtX51, 0 },
- { "surround61", DevFmtX61, 0 },
- { "surround71", DevFmtX71, 0 },
- { "surround714", DevFmtX714, 0 },
- { "surround3d71", DevFmtX3D71, 0 },
- { "surround51rear", DevFmtX51, 0 },
- { "ambi1", DevFmtAmbi3D, 1 },
- { "ambi2", DevFmtAmbi3D, 2 },
- { "ambi3", DevFmtAmbi3D, 3 },
+ };
+ static constexpr std::array chanlist{
+ ChannelMap{"mono", DevFmtMono, 0},
+ ChannelMap{"stereo", DevFmtStereo, 0},
+ ChannelMap{"quad", DevFmtQuad, 0},
+ ChannelMap{"surround51", DevFmtX51, 0},
+ ChannelMap{"surround61", DevFmtX61, 0},
+ ChannelMap{"surround71", DevFmtX71, 0},
+ ChannelMap{"surround714", DevFmtX714, 0},
+ ChannelMap{"surround3d71", DevFmtX3D71, 0},
+ ChannelMap{"surround51rear", DevFmtX51, 0},
+ ChannelMap{"ambi1", DevFmtAmbi3D, 1},
+ ChannelMap{"ambi2", DevFmtAmbi3D, 2},
+ ChannelMap{"ambi3", DevFmtAmbi3D, 3},
};
const ALCchar *fmt{chanopt->c_str()};
- auto iter = std::find_if(std::begin(chanlist), std::end(chanlist),
+ auto iter = std::find_if(chanlist.begin(), chanlist.end(),
[fmt](const ChannelMap &entry) -> bool
{ return al::strcasecmp(entry.name, fmt) == 0; });
- if(iter == std::end(chanlist))
+ if(iter == chanlist.end())
ERR("Unsupported channels: %s\n", fmt);
else
{
@@ -1085,7 +1094,7 @@ ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList)
aorder = iter->order;
}
}
- if(auto ambiopt = device->configValue<std::string>(nullptr, "ambi-format"))
+ if(auto ambiopt = device->configValue<std::string>({}, "ambi-format"))
{
const ALCchar *fmt{ambiopt->c_str()};
if(al::strcasecmp(fmt, "fuma") == 0)
@@ -1112,7 +1121,7 @@ ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList)
ERR("Unsupported ambi-format: %s\n", fmt);
}
- if(auto hrtfopt = device->configValue<std::string>(nullptr, "hrtf"))
+ if(auto hrtfopt = device->configValue<std::string>({}, "hrtf"))
{
WARN("general/hrtf is deprecated, please use stereo-encoding instead\n");
@@ -1129,7 +1138,7 @@ ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList)
}
}
- if(auto encopt = device->configValue<std::string>(nullptr, "stereo-encoding"))
+ if(auto encopt = device->configValue<std::string>({}, "stereo-encoding"))
{
const char *mode{encopt->c_str()};
if(al::strcasecmp(mode, "basic") == 0 || al::strcasecmp(mode, "panpot") == 0)
@@ -1197,7 +1206,7 @@ ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList)
case ATTRIBUTE(ALC_MAX_AUXILIARY_SENDS)
numSends = static_cast<uint>(attrList[attrIdx + 1]);
if(numSends > INT_MAX) numSends = 0;
- else numSends = minu(numSends, MAX_SENDS);
+ else numSends = minu(numSends, MaxSendCount);
break;
case ATTRIBUTE(ALC_HRTF_SOFT)
@@ -1240,7 +1249,7 @@ ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList)
{
if(!optchans || !opttype)
return ALC_INVALID_VALUE;
- if(freqAttr < MIN_OUTPUT_RATE || freqAttr > MAX_OUTPUT_RATE)
+ if(freqAttr < int{MinOutputRate} || freqAttr > int{MaxOutputRate})
return ALC_INVALID_VALUE;
if(*optchans == DevFmtAmbi3D)
{
@@ -1317,12 +1326,12 @@ ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList)
if(freqAttr)
{
- uint oldrate = optsrate.value_or(DEFAULT_OUTPUT_RATE);
- freqAttr = clampi(freqAttr, MIN_OUTPUT_RATE, MAX_OUTPUT_RATE);
+ uint oldrate = optsrate.value_or(DefaultOutputRate);
+ freqAttr = clampi(freqAttr, MinOutputRate, MaxOutputRate);
const double scale{static_cast<double>(freqAttr) / oldrate};
- period_size = static_cast<uint>(period_size*scale + 0.5);
- buffer_size = static_cast<uint>(buffer_size*scale + 0.5);
+ period_size = static_cast<uint>(std::lround(period_size * scale));
+ buffer_size = static_cast<uint>(std::lround(buffer_size * scale));
optsrate = static_cast<uint>(freqAttr);
}
}
@@ -1330,16 +1339,19 @@ ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList)
/* If a context is already running on the device, stop playback so the
* device attributes can be updated.
*/
- if(device->Flags.test(DeviceRunning))
+ if(device->mDeviceState == DeviceState::Playing)
+ {
device->Backend->stop();
- device->Flags.reset(DeviceRunning);
+ device->mDeviceState = DeviceState::Unprepared;
+ }
UpdateClockBase(device);
}
- if(device->Flags.test(DeviceRunning))
+ if(device->mDeviceState == DeviceState::Playing)
return ALC_NO_ERROR;
+ device->mDeviceState = DeviceState::Unprepared;
device->AvgSpeakerDist = 0.0f;
device->mNFCtrlFilter = NfcFilter{};
device->mUhjEncoder = nullptr;
@@ -1393,7 +1405,7 @@ ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList)
device->mAmbiOrder = 0;
device->BufferSize = buffer_size;
device->UpdateSize = period_size;
- device->Frequency = optsrate.value_or(DEFAULT_OUTPUT_RATE);
+ device->Frequency = optsrate.value_or(DefaultOutputRate);
device->Flags.set(FrequencyRequest, optsrate.has_value())
.set(ChannelsRequest, optchans.has_value())
.set(SampleTypeRequest, opttype.has_value());
@@ -1462,7 +1474,7 @@ ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList)
if(device->Type != DeviceType::Loopback)
{
- if(auto modeopt = device->configValue<std::string>(nullptr, "stereo-mode"))
+ if(auto modeopt = device->configValue<std::string>({}, "stereo-mode"))
{
const char *mode{modeopt->c_str()};
if(al::strcasecmp(mode, "headphones") == 0)
@@ -1479,7 +1491,7 @@ ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList)
/* Calculate the max number of sources, and split them between the mono and
* stereo count given the requested number of stereo sources.
*/
- if(auto srcsopt = device->configValue<uint>(nullptr, "sources"))
+ if(auto srcsopt = device->configValue<uint>({}, "sources"))
{
if(*srcsopt <= 0) numMono = 256;
else numMono = maxu(*srcsopt, 16);
@@ -1495,8 +1507,8 @@ ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList)
device->NumMonoSources = numMono;
device->NumStereoSources = numStereo;
- if(auto sendsopt = device->configValue<int>(nullptr, "sends"))
- numSends = minu(numSends, static_cast<uint>(clampi(*sendsopt, 0, MAX_SENDS)));
+ if(auto sendsopt = device->configValue<int>({}, "sends"))
+ numSends = minu(numSends, static_cast<uint>(clampi(*sendsopt, 0, MaxSendCount)));
device->NumAuxSends = numSends;
TRACE("Max sources: %d (%d + %d), effect slots: %d, sends: %d\n",
@@ -1519,13 +1531,13 @@ ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList)
case DevFmtAmbi3D: break;
}
- nanoseconds::rep sample_delay{0};
+ size_t sample_delay{0};
if(auto *encoder{device->mUhjEncoder.get()})
sample_delay += encoder->getDelay();
- if(device->getConfigValueBool(nullptr, "dither", true))
+ if(device->getConfigValueBool({}, "dither", true))
{
- int depth{device->configValue<int>(nullptr, "dither-depth").value_or(0)};
+ int depth{device->configValue<int>({}, "dither-depth").value_or(0)};
if(depth <= 0)
{
switch(device->FmtType)
@@ -1558,7 +1570,7 @@ ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList)
device->DitherDepth);
if(!optlimit)
- optlimit = device->configValue<bool>(nullptr, "output-limiter");
+ optlimit = device->configValue<bool>({}, "output-limiter");
/* If the gain limiter is unset, use the limiter for integer-based output
* (where samples must be clamped), and don't for floating-point (which can
@@ -1612,6 +1624,7 @@ ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList)
}
/* Convert the sample delay from samples to nanosamples to nanoseconds. */
+ sample_delay = std::min<size_t>(sample_delay, std::numeric_limits<int>::max());
device->FixedLatency += nanoseconds{seconds{sample_delay}} / device->Frequency;
TRACE("Fixed device latency: %" PRId64 "ns\n", int64_t{device->FixedLatency.count()});
@@ -1624,9 +1637,10 @@ ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList)
std::unique_lock<std::mutex> slotlock{context->mEffectSlotLock};
/* Clear out unused effect slot clusters. */
- auto slot_cluster_not_in_use = [](ContextBase::EffectSlotCluster &cluster)
+ auto slot_cluster_not_in_use = [](ContextBase::EffectSlotCluster &clusterptr)
{
- for(size_t i{0};i < ContextBase::EffectSlotClusterSize;++i)
+ const auto cluster = al::span{*clusterptr};
+ for(size_t i{0};i < cluster.size();++i)
{
if(cluster[i].InUse)
return false;
@@ -1640,24 +1654,29 @@ ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList)
/* Free all wet buffers. Any in use will be reallocated with an updated
* configuration in aluInitEffectPanning.
*/
- for(auto&& slots : context->mEffectSlotClusters)
+ for(auto& clusterptr : context->mEffectSlotClusters)
{
- for(size_t i{0};i < ContextBase::EffectSlotClusterSize;++i)
+ const auto cluster = al::span{*clusterptr};
+ for(size_t i{0};i < cluster.size();++i)
{
- slots[i].mWetBuffer.clear();
- slots[i].mWetBuffer.shrink_to_fit();
- slots[i].Wet.Buffer = {};
+ cluster[i].mWetBuffer.clear();
+ cluster[i].mWetBuffer.shrink_to_fit();
+ cluster[i].Wet.Buffer = {};
}
}
if(ALeffectslot *slot{context->mDefaultSlot.get()})
{
- aluInitEffectPanning(slot->mSlot, context);
+ auto *slotbase = slot->mSlot;
+ aluInitEffectPanning(slotbase, context);
+
+ if(auto *props = slotbase->Update.exchange(nullptr, std::memory_order_relaxed))
+ AtomicReplaceHead(context->mFreeEffectSlotProps, props);
EffectState *state{slot->Effect.State.get()};
state->mOutTarget = device->Dry.Buffer;
state->deviceUpdate(device, slot->Buffer);
- slot->updateProps(context);
+ slot->mPropsDirty = true;
}
if(EffectSlotArray *curarray{context->mActiveAuxSlots.load(std::memory_order_relaxed)})
@@ -1667,18 +1686,25 @@ ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList)
uint64_t usemask{~sublist.FreeMask};
while(usemask)
{
- const int idx{al::countr_zero(usemask)};
- ALeffectslot *slot{sublist.EffectSlots + idx};
+ const auto idx = static_cast<uint>(al::countr_zero(usemask));
+ auto &slot = (*sublist.EffectSlots)[idx];
usemask &= ~(1_u64 << idx);
- aluInitEffectPanning(slot->mSlot, context);
+ auto *slotbase = slot.mSlot;
+ aluInitEffectPanning(slotbase, context);
- EffectState *state{slot->Effect.State.get()};
+ if(auto *props = slotbase->Update.exchange(nullptr, std::memory_order_relaxed))
+ AtomicReplaceHead(context->mFreeEffectSlotProps, props);
+
+ EffectState *state{slot.Effect.State.get()};
state->mOutTarget = device->Dry.Buffer;
- state->deviceUpdate(device, slot->Buffer);
- slot->updateProps(context);
+ state->deviceUpdate(device, slot.Buffer);
+ slot.mPropsDirty = true;
}
}
+ /* Clear all effect slot props to let them get allocated again. */
+ context->mEffectSlotPropClusters.clear();
+ context->mFreeEffectSlotProps.store(nullptr, std::memory_order_relaxed);
slotlock.unlock();
const uint num_sends{device->NumAuxSends};
@@ -1688,8 +1714,8 @@ ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList)
uint64_t usemask{~sublist.FreeMask};
while(usemask)
{
- const int idx{al::countr_zero(usemask)};
- ALsource *source{sublist.Sources + idx};
+ const auto idx = static_cast<uint>(al::countr_zero(usemask));
+ auto &source = (*sublist.Sources)[idx];
usemask &= ~(1_u64 << idx);
auto clear_send = [](ALsource::SendData &send) -> void
@@ -1699,19 +1725,18 @@ ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList)
send.Slot = nullptr;
send.Gain = 1.0f;
send.GainHF = 1.0f;
- send.HFReference = LOWPASSFREQREF;
+ send.HFReference = LowPassFreqRef;
send.GainLF = 1.0f;
- send.LFReference = HIGHPASSFREQREF;
+ send.LFReference = HighPassFreqRef;
};
- auto send_begin = source->Send.begin() + static_cast<ptrdiff_t>(num_sends);
- std::for_each(send_begin, source->Send.end(), clear_send);
+ auto send_begin = source.Send.begin() + static_cast<ptrdiff_t>(num_sends);
+ std::for_each(send_begin, source.Send.end(), clear_send);
- source->mPropsDirty = true;
+ source.mPropsDirty = true;
}
}
- auto voicelist = context->getVoicesSpan();
- for(Voice *voice : voicelist)
+ for(Voice *voice : context->getVoicesSpan())
{
/* Clear extraneous property set sends. */
std::fill(std::begin(voice->mProps.Send)+num_sends, std::end(voice->mProps.Send),
@@ -1743,16 +1768,18 @@ ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList)
context->mPropsDirty = false;
UpdateContextProps(context);
+ UpdateAllEffectSlotProps(context);
UpdateAllSourceProps(context);
}
mixer_mode.leave();
+ device->mDeviceState = DeviceState::Configured;
if(!device->Flags.test(DevicePaused))
{
try {
auto backend = device->Backend.get();
backend->start();
- device->Flags.set(DeviceRunning);
+ device->mDeviceState = DeviceState::Playing;
}
catch(al::backend_exception& e) {
ERR("%s\n", e.what());
@@ -1777,7 +1804,7 @@ bool ResetDeviceParams(ALCdevice *device, const int *attrList)
if(!device->Connected.load(std::memory_order_relaxed)) UNLIKELY
{
/* Make sure disconnection is finished before continuing on. */
- device->waitForMix();
+ std::ignore = device->waitForMix();
for(ContextBase *ctxbase : *device->mContexts.load(std::memory_order_acquire))
{
@@ -1850,7 +1877,7 @@ FORCE_ALIGN void ALC_APIENTRY alsoft_set_log_callback(LPALSOFTLOGCALLBACK callba
}
/** Returns a new reference to the currently active context for this thread. */
-ContextRef GetContextRef(void)
+ContextRef GetContextRef()
{
ALCcontext *context{ALCcontext::getThreadContext()};
if(context)
@@ -2030,7 +2057,7 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para
ProbeAllDevicesList();
/* Copy first entry as default. */
- alcDefaultAllDevicesSpecifier = alcAllDevicesList.c_str();
+ alcDefaultAllDevicesSpecifier = alcAllDevicesList.substr(0, alcAllDevicesList.find('\0'));
value = alcDefaultAllDevicesSpecifier.c_str();
break;
@@ -2039,7 +2066,8 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para
ProbeCaptureDeviceList();
/* Copy first entry as default. */
- alcCaptureDefaultDeviceSpecifier = alcCaptureDeviceList.c_str();
+ alcCaptureDefaultDeviceSpecifier = alcCaptureDeviceList.substr(0,
+ alcCaptureDeviceList.find('\0'));
value = alcCaptureDefaultDeviceSpecifier.c_str();
break;
@@ -2097,7 +2125,7 @@ static size_t GetIntegerv(ALCdevice *device, ALCenum param, const al::span<int>
values[0] = alcEFXMinorVersion;
return 1;
case ALC_MAX_AUXILIARY_SENDS:
- values[0] = MAX_SENDS;
+ values[0] = MaxSendCount;
return 1;
case ALC_ATTRIBUTES_SIZE:
@@ -2504,9 +2532,10 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname,
nanoseconds basecount;
do {
refcount = dev->waitForMix();
- basecount = dev->ClockBase;
- samplecount = dev->SamplesDone;
- } while(refcount != ReadRef(dev->MixCount));
+ basecount = dev->mClockBase.load(std::memory_order_relaxed);
+ samplecount = dev->mSamplesDone.load(std::memory_order_relaxed);
+ std::atomic_thread_fence(std::memory_order_acquire);
+ } while(refcount != dev->mMixCount.load(std::memory_order_relaxed));
basecount += nanoseconds{seconds{samplecount}} / dev->Frequency;
*values = basecount.count();
}
@@ -2540,23 +2569,25 @@ ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const A
{
DeviceRef dev{VerifyDevice(device)};
if(!extName)
+ {
alcSetError(dev.get(), ALC_INVALID_VALUE);
- else
+ return ALC_FALSE;
+ }
+
+ const std::string_view tofind{extName};
+ auto extlist = dev ? std::string_view{alcExtensionList} : std::string_view{alcNoDeviceExtList};
+ while(!extlist.empty())
{
- size_t len = strlen(extName);
- const char *ptr = (dev ? alcExtensionList : alcNoDeviceExtList);
- while(ptr && *ptr)
- {
- if(al::strncasecmp(ptr, extName, len) == 0 && (ptr[len] == '\0' || isspace(ptr[len])))
- return ALC_TRUE;
+ auto nextpos = extlist.find(' ');
+ auto tocheck = extlist.substr(0, nextpos);
+ if(tocheck.size() == tofind.size()
+ && al::strncasecmp(tofind.data(), tocheck.data(), tofind.size()) == 0)
+ return ALC_TRUE;
- if((ptr=strchr(ptr, ' ')) != nullptr)
- {
- do {
- ++ptr;
- } while(isspace(*ptr));
- }
- }
+ if(nextpos == std::string_view::npos)
+ break;
+
+ extlist.remove_prefix(nextpos+1);
}
return ALC_FALSE;
}
@@ -2678,7 +2709,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin
}
context->init();
- if(auto volopt = dev->configValue<float>(nullptr, "volume-adjust"))
+ if(auto volopt = dev->configValue<float>({}, "volume-adjust"))
{
const float valf{*volopt};
if(!std::isfinite(valf))
@@ -2700,8 +2731,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin
* old array.
*/
auto *oldarray = device->mContexts.load();
- const size_t newcount{oldarray->size()+1};
- std::unique_ptr<ContextArray> newarray{ContextArray::Create(newcount)};
+ auto newarray = ContextArray::Create(oldarray->size() + 1);
/* Copy the current/old context handles to the new array, appending the
* new context.
@@ -2712,12 +2742,8 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin
/* Store the new context array in the device. Wait for any current mix
* to finish before deleting the old array.
*/
- dev->mContexts.store(newarray.release());
- if(oldarray != &DeviceBase::sEmptyContextArray)
- {
- dev->waitForMix();
- delete oldarray;
- }
+ auto prevarray = dev->mContexts.exchange(std::move(newarray));
+ std::ignore = dev->waitForMix();
}
statelock.unlock();
@@ -2761,15 +2787,11 @@ ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context) noexcept
ALCdevice *Device{ctx->mALDevice.get()};
std::lock_guard<std::mutex> _{Device->StateLock};
- if(!ctx->deinit() && Device->Flags.test(DeviceRunning))
- {
- Device->Backend->stop();
- Device->Flags.reset(DeviceRunning);
- }
+ ctx->deinit();
}
-ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void) noexcept
+ALC_API auto ALC_APIENTRY alcGetCurrentContext() noexcept -> ALCcontext*
{
ALCcontext *Context{ALCcontext::getThreadContext()};
if(!Context) Context = ALCcontext::sGlobalContext.load();
@@ -2777,7 +2799,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void) noexcept
}
/** Returns the currently active thread-local context. */
-ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void) noexcept
+ALC_API auto ALC_APIENTRY alcGetThreadContext() noexcept -> ALCcontext*
{ return ALCcontext::getThreadContext(); }
ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context) noexcept
@@ -2802,7 +2824,7 @@ ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context) noexc
* the current context as its refcount is decremented.
*/
}
- ContextRef{ALCcontext::sGlobalContext.exchange(ctx.release())};
+ ctx = ContextRef{ALCcontext::sGlobalContext.exchange(ctx.release())};
ALCcontext::sGlobalContextLock.store(false, std::memory_order_release);
/* Take ownership of the thread-local context reference (if any), clearing
@@ -2887,17 +2909,23 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) noexcep
#ifdef ALSOFT_EAX
eax_g_is_enabled ? uint{EAX_MAX_FXSLOTS} :
#endif // ALSOFT_EAX
- DEFAULT_SENDS
+ uint{DefaultSendCount}
};
- DeviceRef device{new ALCdevice{DeviceType::Playback}};
+ DeviceRef device{new(std::nothrow) ALCdevice{DeviceType::Playback}};
+ if(!device)
+ {
+ WARN("Failed to create playback device handle\n");
+ alcSetError(nullptr, ALC_OUT_OF_MEMORY);
+ return nullptr;
+ }
/* Set output format */
device->FmtChans = DevFmtChannelsDefault;
device->FmtType = DevFmtTypeDefault;
- device->Frequency = DEFAULT_OUTPUT_RATE;
- device->UpdateSize = DEFAULT_UPDATE_SIZE;
- device->BufferSize = DEFAULT_UPDATE_SIZE * DEFAULT_NUM_UPDATES;
+ device->Frequency = DefaultOutputRate;
+ device->UpdateSize = DefaultUpdateSize;
+ device->BufferSize = DefaultUpdateSize * DefaultNumUpdates;
device->SourcesMax = 256;
device->NumStereoSources = 1;
@@ -2973,7 +3001,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) noexcept
auto ctxiter = std::lower_bound(ContextList.begin(), ContextList.end(), ctx);
if(ctxiter != ContextList.end() && *ctxiter == ctx)
{
- orphanctxs.emplace_back(ContextRef{*ctxiter});
+ orphanctxs.emplace_back(*ctxiter);
ContextList.erase(ctxiter);
}
}
@@ -2986,9 +3014,11 @@ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) noexcept
}
orphanctxs.clear();
- if(dev->Flags.test(DeviceRunning))
+ if(dev->mDeviceState == DeviceState::Playing)
+ {
dev->Backend->stop();
- dev->Flags.reset(DeviceRunning);
+ dev->mDeviceState = DeviceState::Configured;
+ }
return ALC_TRUE;
}
@@ -3023,7 +3053,13 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName,
else
TRACE("Opening default capture device\n");
- DeviceRef device{new ALCdevice{DeviceType::Capture}};
+ DeviceRef device{new(std::nothrow) ALCdevice{DeviceType::Capture}};
+ if(!device)
+ {
+ WARN("Failed to create capture device handle\n");
+ alcSetError(nullptr, ALC_OUT_OF_MEMORY);
+ return nullptr;
+ }
auto decompfmt = DecomposeDevFormat(format);
if(!decompfmt)
@@ -3070,6 +3106,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName,
auto iter = std::lower_bound(DeviceList.cbegin(), DeviceList.cend(), device.get());
DeviceList.emplace(iter, device.get());
}
+ device->mDeviceState = DeviceState::Configured;
TRACE("Created capture device %p, \"%s\"\n", voidp{device.get()}, device->DeviceName.c_str());
return device.release();
@@ -3095,9 +3132,11 @@ ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) noexcep
listlock.unlock();
std::lock_guard<std::mutex> _{dev->StateLock};
- if(dev->Flags.test(DeviceRunning))
+ if(dev->mDeviceState == DeviceState::Playing)
+ {
dev->Backend->stop();
- dev->Flags.reset(DeviceRunning);
+ dev->mDeviceState = DeviceState::Configured;
+ }
return ALC_TRUE;
}
@@ -3112,14 +3151,15 @@ ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device) noexcept
}
std::lock_guard<std::mutex> _{dev->StateLock};
- if(!dev->Connected.load(std::memory_order_acquire))
+ if(!dev->Connected.load(std::memory_order_acquire)
+ || dev->mDeviceState < DeviceState::Configured)
alcSetError(dev.get(), ALC_INVALID_DEVICE);
- else if(!dev->Flags.test(DeviceRunning))
+ else if(dev->mDeviceState != DeviceState::Playing)
{
try {
auto backend = dev->Backend.get();
backend->start();
- dev->Flags.set(DeviceRunning);
+ dev->mDeviceState = DeviceState::Playing;
}
catch(al::backend_exception& e) {
ERR("%s\n", e.what());
@@ -3137,9 +3177,11 @@ ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device) noexcept
else
{
std::lock_guard<std::mutex> _{dev->StateLock};
- if(dev->Flags.test(DeviceRunning))
+ if(dev->mDeviceState == DeviceState::Playing)
+ {
dev->Backend->stop();
- dev->Flags.reset(DeviceRunning);
+ dev->mDeviceState = DeviceState::Configured;
+ }
}
}
@@ -3194,10 +3236,16 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN
#ifdef ALSOFT_EAX
eax_g_is_enabled ? uint{EAX_MAX_FXSLOTS} :
#endif // ALSOFT_EAX
- DEFAULT_SENDS
+ uint{DefaultSendCount}
};
- DeviceRef device{new ALCdevice{DeviceType::Loopback}};
+ DeviceRef device{new(std::nothrow) ALCdevice{DeviceType::Loopback}};
+ if(!device)
+ {
+ WARN("Failed to create loopback device handle\n");
+ alcSetError(nullptr, ALC_OUT_OF_MEMORY);
+ return nullptr;
+ }
device->SourcesMax = 256;
device->AuxiliaryEffectSlotMax = 64;
@@ -3207,7 +3255,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN
device->BufferSize = 0;
device->UpdateSize = 0;
- device->Frequency = DEFAULT_OUTPUT_RATE;
+ device->Frequency = DefaultOutputRate;
device->FmtChans = DevFmtChannelsDefault;
device->FmtType = DevFmtTypeDefault;
@@ -3250,7 +3298,7 @@ ALC_API ALCboolean ALC_APIENTRY alcIsRenderFormatSupportedSOFT(ALCdevice *device
else
{
if(DevFmtTypeFromEnum(type).has_value() && DevFmtChannelsFromEnum(channels).has_value()
- && freq >= MIN_OUTPUT_RATE && freq <= MAX_OUTPUT_RATE)
+ && freq >= int{MinOutputRate} && freq <= int{MaxOutputRate})
return ALC_TRUE;
}
@@ -3291,9 +3339,11 @@ ALC_API void ALC_APIENTRY alcDevicePauseSOFT(ALCdevice *device) noexcept
else
{
std::lock_guard<std::mutex> _{dev->StateLock};
- if(dev->Flags.test(DeviceRunning))
+ if(dev->mDeviceState == DeviceState::Playing)
+ {
dev->Backend->stop();
- dev->Flags.reset(DeviceRunning);
+ dev->mDeviceState = DeviceState::Configured;
+ }
dev->Flags.set(DevicePaused);
}
}
@@ -3311,6 +3361,18 @@ ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device) noexcept
std::lock_guard<std::mutex> _{dev->StateLock};
if(!dev->Flags.test(DevicePaused))
return;
+ if(dev->mDeviceState < DeviceState::Configured)
+ {
+ WARN("Cannot resume unconfigured device\n");
+ alcSetError(dev.get(), ALC_INVALID_DEVICE);
+ return;
+ }
+ if(!dev->Connected.load())
+ {
+ WARN("Cannot resume a disconnected device\n");
+ alcSetError(dev.get(), ALC_INVALID_DEVICE);
+ return;
+ }
dev->Flags.reset(DevicePaused);
if(dev->mContexts.load()->empty())
return;
@@ -3318,7 +3380,7 @@ ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device) noexcept
try {
auto backend = dev->Backend.get();
backend->start();
- dev->Flags.set(DeviceRunning);
+ dev->mDeviceState = DeviceState::Playing;
}
catch(al::backend_exception& e) {
ERR("%s\n", e.what());
@@ -3327,8 +3389,8 @@ ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device) noexcept
return;
}
TRACE("Post-resume: %s, %s, %uhz, %u / %u buffer\n",
- DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType),
- device->Frequency, device->UpdateSize, device->BufferSize);
+ DevFmtChannelsString(dev->FmtChans), DevFmtTypeString(dev->FmtType),
+ dev->Frequency, dev->UpdateSize, dev->BufferSize);
}
@@ -3375,9 +3437,11 @@ ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCi
/* Force the backend to stop mixing first since we're resetting. Also reset
* the connected state so lost devices can attempt recover.
*/
- if(dev->Flags.test(DeviceRunning))
+ if(dev->mDeviceState == DeviceState::Playing)
+ {
dev->Backend->stop();
- dev->Flags.reset(DeviceRunning);
+ dev->mDeviceState = DeviceState::Configured;
+ }
return ResetDeviceParams(dev.get(), attribs) ? ALC_TRUE : ALC_FALSE;
}
@@ -3407,12 +3471,12 @@ FORCE_ALIGN ALCboolean ALC_APIENTRY alcReopenDeviceSOFT(ALCdevice *device,
}
std::lock_guard<std::mutex> _{dev->StateLock};
- /* Force the backend to stop mixing first since we're reopening. */
- if(dev->Flags.test(DeviceRunning))
+ /* Force the backend device to stop first since we're opening another one. */
+ const bool wasPlaying{dev->mDeviceState == DeviceState::Playing};
+ if(wasPlaying)
{
- auto backend = dev->Backend.get();
- backend->stop();
- dev->Flags.reset(DeviceRunning);
+ dev->Backend->stop();
+ dev->mDeviceState = DeviceState::Configured;
}
BackendPtr newbackend;
@@ -3434,16 +3498,12 @@ FORCE_ALIGN ALCboolean ALC_APIENTRY alcReopenDeviceSOFT(ALCdevice *device,
alcSetError(dev.get(), (e.errorCode() == al::backend_error::OutOfMemory)
? ALC_OUT_OF_MEMORY : ALC_INVALID_VALUE);
- /* If the device is connected, not paused, and has contexts, ensure it
- * continues playing.
- */
- if(dev->Connected.load(std::memory_order_relaxed) && !dev->Flags.test(DevicePaused)
- && !dev->mContexts.load(std::memory_order_relaxed)->empty())
+ if(dev->Connected.load(std::memory_order_relaxed) && wasPlaying)
{
try {
auto backend = dev->Backend.get();
backend->start();
- dev->Flags.set(DeviceRunning);
+ dev->mDeviceState = DeviceState::Playing;
}
catch(al::backend_exception &be) {
ERR("%s\n", be.what());
@@ -3454,6 +3514,7 @@ FORCE_ALIGN ALCboolean ALC_APIENTRY alcReopenDeviceSOFT(ALCdevice *device,
}
listlock.unlock();
dev->Backend = std::move(newbackend);
+ dev->mDeviceState = DeviceState::Unprepared;
TRACE("Reopened device %p, \"%s\"\n", voidp{dev.get()}, dev->DeviceName.c_str());
/* Always return true even if resetting fails. It shouldn't fail, but this
diff --git a/alc/alconfig.cpp b/alc/alconfig.cpp
index cfa178fb..d9e97e09 100644
--- a/alc/alconfig.cpp
+++ b/alc/alconfig.cpp
@@ -22,9 +22,6 @@
#include "alconfig.h"
-#include <cstdlib>
-#include <cctype>
-#include <cstring>
#ifdef _WIN32
#include <windows.h>
#include <shlobj.h>
@@ -34,16 +31,20 @@
#endif
#include <algorithm>
-#include <cstdio>
+#include <cctype>
+#include <cstdlib>
+#include <istream>
+#include <limits>
#include <string>
+#include <string_view>
#include <utility>
+#include <vector>
#include "alfstream.h"
#include "alstring.h"
#include "core/helpers.h"
#include "core/logging.h"
#include "strutils.h"
-#include "vector.h"
#if defined(ALSOFT_UWP)
#include <winrt/Windows.Media.Core.h> // !!This is important!!
@@ -79,57 +80,43 @@ bool readline(std::istream &f, std::string &output)
return std::getline(f, output) && !output.empty();
}
-std::string expdup(const char *str)
+std::string expdup(std::string_view str)
{
std::string output;
- std::string envval;
- while(*str != '\0')
+ while(!str.empty())
{
- const char *addstr;
- size_t addstrlen;
-
- if(str[0] != '$')
+ if(auto nextpos = str.find('$'))
{
- const char *next = std::strchr(str, '$');
- addstr = str;
- addstrlen = next ? static_cast<size_t>(next-str) : std::strlen(str);
+ output += str.substr(0, nextpos);
+ if(nextpos == std::string_view::npos)
+ break;
- str += addstrlen;
+ str.remove_prefix(nextpos);
}
- else
- {
- str++;
- if(*str == '$')
- {
- const char *next = std::strchr(str+1, '$');
- addstr = str;
- addstrlen = next ? static_cast<size_t>(next-str) : std::strlen(str);
- str += addstrlen;
- }
- else
- {
- const bool hasbraces{(*str == '{')};
+ str.remove_prefix(1);
+ if(str.front() == '$')
+ {
+ output += '$';
+ str.remove_prefix(1);
+ continue;
+ }
- if(hasbraces) str++;
- const char *envstart = str;
- while(std::isalnum(*str) || *str == '_')
- ++str;
- if(hasbraces && *str != '}')
- continue;
- const std::string envname{envstart, str};
- if(hasbraces) str++;
+ const bool hasbraces{str.front() == '{'};
+ if(hasbraces) str.remove_prefix(1);
- envval = al::getenv(envname.c_str()).value_or(std::string{});
- addstr = envval.data();
- addstrlen = envval.length();
- }
- }
- if(addstrlen == 0)
+ size_t envend{0};
+ while(std::isalnum(str[envend]) || str[envend] == '_')
+ ++envend;
+ if(hasbraces && str[envend] != '}')
continue;
+ const std::string envname{str.substr(0, envend)};
+ if(hasbraces) ++envend;
+ str.remove_prefix(envend);
- output.append(addstr, addstrlen);
+ if(auto envval = al::getenv(envname.c_str()))
+ output += *envval;
}
return output;
@@ -147,42 +134,42 @@ void LoadConfigFromFile(std::istream &f)
if(buffer[0] == '[')
{
- auto line = const_cast<char*>(buffer.data());
- char *section = line+1;
- char *endsection;
-
- endsection = std::strchr(section, ']');
- if(!endsection || section == endsection)
+ auto endpos = buffer.find(']', 1);
+ if(endpos == 1 || endpos == std::string::npos)
{
- ERR(" config parse error: bad line \"%s\"\n", line);
+ ERR(" config parse error: bad line \"%s\"\n", buffer.c_str());
continue;
}
- if(endsection[1] != 0)
+ if(buffer[endpos+1] != '\0')
{
- char *end = endsection+1;
- while(std::isspace(*end))
- ++end;
- if(*end != 0 && *end != '#')
+ size_t last{endpos+1};
+ while(last < buffer.size() && std::isspace(buffer[last]))
+ ++last;
+
+ if(last < buffer.size() && buffer[last] != '#')
{
- ERR(" config parse error: bad line \"%s\"\n", line);
+ ERR(" config parse error: bad line \"%s\"\n", buffer.c_str());
continue;
}
}
- *endsection = 0;
+
+ auto section = std::string_view{buffer}.substr(1, endpos-1);
+ auto generalName = std::string_view{"general"};
curSection.clear();
- if(al::strcasecmp(section, "general") != 0)
+ if(section.size() != generalName.size()
+ || al::strncasecmp(section.data(), generalName.data(), section.size()) != 0)
{
do {
- char *nextp = std::strchr(section, '%');
- if(!nextp)
+ auto nextp = section.find('%');
+ if(nextp == std::string_view::npos)
{
curSection += section;
break;
}
- curSection.append(section, nextp);
- section = nextp;
+ curSection += section.substr(0, nextp);
+ section.remove_prefix(nextp);
if(((section[1] >= '0' && section[1] <= '9') ||
(section[1] >= 'a' && section[1] <= 'f') ||
@@ -205,19 +192,19 @@ void LoadConfigFromFile(std::istream &f)
else if(section[2] >= 'A' && section[2] <= 'F')
b |= (section[2]-'A'+0x0a);
curSection += static_cast<char>(b);
- section += 3;
+ section.remove_prefix(3);
}
else if(section[1] == '%')
{
curSection += '%';
- section += 2;
+ section.remove_prefix(2);
}
else
{
curSection += '%';
- section += 1;
+ section.remove_prefix(1);
}
- } while(*section != 0);
+ } while(!section.empty());
}
continue;
@@ -235,16 +222,17 @@ void LoadConfigFromFile(std::istream &f)
ERR(" config parse error: malformed option line: \"%s\"\n", buffer.c_str());
continue;
}
- auto keyend = sep++;
- while(keyend > 0 && std::isspace(buffer[keyend-1]))
- --keyend;
- if(!keyend)
+ auto keypart = std::string_view{buffer}.substr(0, sep++);
+ while(!keypart.empty() && std::isspace(keypart.back()))
+ keypart.remove_suffix(1);
+ if(keypart.empty())
{
ERR(" config parse error: malformed option line: \"%s\"\n", buffer.c_str());
continue;
}
- while(sep < buffer.size() && std::isspace(buffer[sep]))
- sep++;
+ auto valpart = std::string_view{buffer}.substr(sep);
+ while(!valpart.empty() && std::isspace(valpart.front()))
+ valpart.remove_prefix(1);
std::string fullKey;
if(!curSection.empty())
@@ -252,20 +240,25 @@ void LoadConfigFromFile(std::istream &f)
fullKey += curSection;
fullKey += '/';
}
- fullKey += buffer.substr(0u, keyend);
+ fullKey += keypart;
- std::string value{(sep < buffer.size()) ? buffer.substr(sep) : std::string{}};
- if(value.size() > 1)
+ if(valpart.size() > std::numeric_limits<int>::max())
+ {
+ ERR(" config parse error: value too long in line \"%s\"\n", buffer.c_str());
+ continue;
+ }
+ if(valpart.size() > 1)
{
- if((value.front() == '"' && value.back() == '"')
- || (value.front() == '\'' && value.back() == '\''))
+ if((valpart.front() == '"' && valpart.back() == '"')
+ || (valpart.front() == '\'' && valpart.back() == '\''))
{
- value.pop_back();
- value.erase(value.begin());
+ valpart.remove_prefix(1);
+ valpart.remove_suffix(1);
}
}
- TRACE(" setting '%s' = '%s'\n", fullKey.c_str(), value.c_str());
+ TRACE(" setting '%s' = '%.*s'\n", fullKey.c_str(), static_cast<int>(valpart.size()),
+ valpart.data());
/* Check if we already have this option set */
auto find_key = [&fullKey](const ConfigEntry &entry) -> bool
@@ -273,27 +266,30 @@ void LoadConfigFromFile(std::istream &f)
auto ent = std::find_if(ConfOpts.begin(), ConfOpts.end(), find_key);
if(ent != ConfOpts.end())
{
- if(!value.empty())
- ent->value = expdup(value.c_str());
+ if(!valpart.empty())
+ ent->value = expdup(valpart);
else
ConfOpts.erase(ent);
}
- else if(!value.empty())
- ConfOpts.emplace_back(ConfigEntry{std::move(fullKey), expdup(value.c_str())});
+ else if(!valpart.empty())
+ ConfOpts.emplace_back(ConfigEntry{std::move(fullKey), expdup(valpart)});
}
ConfOpts.shrink_to_fit();
}
-const char *GetConfigValue(const char *devName, const char *blockName, const char *keyName)
+const char *GetConfigValue(const std::string_view devName, const std::string_view blockName,
+ const std::string_view keyName)
{
- if(!keyName)
+ if(keyName.empty())
return nullptr;
+ auto generalName = std::string_view{"general"};
std::string key;
- if(blockName && al::strcasecmp(blockName, "general") != 0)
+ if(!blockName.empty() && (blockName.size() != generalName.size() ||
+ al::strncasecmp(blockName.data(), generalName.data(), blockName.size()) != 0))
{
key = blockName;
- if(devName)
+ if(!devName.empty())
{
key += '/';
key += devName;
@@ -303,7 +299,7 @@ const char *GetConfigValue(const char *devName, const char *blockName, const cha
}
else
{
- if(devName)
+ if(!devName.empty())
{
key = devName;
key += '/';
@@ -322,9 +318,9 @@ const char *GetConfigValue(const char *devName, const char *blockName, const cha
return nullptr;
}
- if(!devName)
+ if(devName.empty())
return nullptr;
- return GetConfigValue(nullptr, blockName, keyName);
+ return GetConfigValue({}, blockName, keyName);
}
} // namespace
@@ -496,35 +492,40 @@ void ReadALConfig()
}
#endif
-std::optional<std::string> ConfigValueStr(const char *devName, const char *blockName, const char *keyName)
+std::optional<std::string> ConfigValueStr(const std::string_view devName,
+ const std::string_view blockName, const std::string_view keyName)
{
if(const char *val{GetConfigValue(devName, blockName, keyName)})
return val;
return std::nullopt;
}
-std::optional<int> ConfigValueInt(const char *devName, const char *blockName, const char *keyName)
+std::optional<int> ConfigValueInt(const std::string_view devName, const std::string_view blockName,
+ const std::string_view keyName)
{
if(const char *val{GetConfigValue(devName, blockName, keyName)})
return static_cast<int>(std::strtol(val, nullptr, 0));
return std::nullopt;
}
-std::optional<unsigned int> ConfigValueUInt(const char *devName, const char *blockName, const char *keyName)
+std::optional<unsigned int> ConfigValueUInt(const std::string_view devName,
+ const std::string_view blockName, const std::string_view keyName)
{
if(const char *val{GetConfigValue(devName, blockName, keyName)})
return static_cast<unsigned int>(std::strtoul(val, nullptr, 0));
return std::nullopt;
}
-std::optional<float> ConfigValueFloat(const char *devName, const char *blockName, const char *keyName)
+std::optional<float> ConfigValueFloat(const std::string_view devName,
+ const std::string_view blockName, const std::string_view keyName)
{
if(const char *val{GetConfigValue(devName, blockName, keyName)})
return std::strtof(val, nullptr);
return std::nullopt;
}
-std::optional<bool> ConfigValueBool(const char *devName, const char *blockName, const char *keyName)
+std::optional<bool> ConfigValueBool(const std::string_view devName,
+ const std::string_view blockName, const std::string_view keyName)
{
if(const char *val{GetConfigValue(devName, blockName, keyName)})
return al::strcasecmp(val, "on") == 0 || al::strcasecmp(val, "yes") == 0
@@ -532,7 +533,8 @@ std::optional<bool> ConfigValueBool(const char *devName, const char *blockName,
return std::nullopt;
}
-bool GetConfigValueBool(const char *devName, const char *blockName, const char *keyName, bool def)
+bool GetConfigValueBool(const std::string_view devName, const std::string_view blockName,
+ const std::string_view keyName, bool def)
{
if(const char *val{GetConfigValue(devName, blockName, keyName)})
return (al::strcasecmp(val, "on") == 0 || al::strcasecmp(val, "yes") == 0
diff --git a/alc/alconfig.h b/alc/alconfig.h
index 1eb44405..e7daac28 100644
--- a/alc/alconfig.h
+++ b/alc/alconfig.h
@@ -3,16 +3,23 @@
#include <optional>
#include <string>
+#include <string_view>
void ReadALConfig();
-bool GetConfigValueBool(const char *devName, const char *blockName, const char *keyName, bool def);
+bool GetConfigValueBool(const std::string_view devName, const std::string_view blockName,
+ const std::string_view keyName, bool def);
-std::optional<std::string> ConfigValueStr(const char *devName, const char *blockName, const char *keyName);
-std::optional<int> ConfigValueInt(const char *devName, const char *blockName, const char *keyName);
-std::optional<unsigned int> ConfigValueUInt(const char *devName, const char *blockName, const char *keyName);
-std::optional<float> ConfigValueFloat(const char *devName, const char *blockName, const char *keyName);
-std::optional<bool> ConfigValueBool(const char *devName, const char *blockName, const char *keyName);
+std::optional<std::string> ConfigValueStr(const std::string_view devName,
+ const std::string_view blockName, const std::string_view keyName);
+std::optional<int> ConfigValueInt(const std::string_view devName, const std::string_view blockName,
+ const std::string_view keyName);
+std::optional<unsigned int> ConfigValueUInt(const std::string_view devName,
+ const std::string_view blockName, const std::string_view keyName);
+std::optional<float> ConfigValueFloat(const std::string_view devName,
+ const std::string_view blockName, const std::string_view keyName);
+std::optional<bool> ConfigValueBool(const std::string_view devName,
+ const std::string_view blockName, const std::string_view keyName);
#endif /* ALCONFIG_H */
diff --git a/alc/alu.cpp b/alc/alu.cpp
index e0858b18..b50eaa41 100644
--- a/alc/alu.cpp
+++ b/alc/alu.cpp
@@ -29,6 +29,7 @@
#include <chrono>
#include <climits>
#include <cstdarg>
+#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <functional>
@@ -37,7 +38,6 @@
#include <memory>
#include <new>
#include <optional>
-#include <stdint.h>
#include <utility>
#include "almalloc.h"
@@ -141,7 +141,7 @@ using HrtfDirectMixerFunc = void(*)(const FloatBufferSpan LeftOut, const FloatBu
HrtfDirectMixerFunc MixDirectHrtf{MixDirectHrtf_<CTag>};
-inline HrtfDirectMixerFunc SelectHrtfMixer(void)
+inline HrtfDirectMixerFunc SelectHrtfMixer()
{
#ifdef HAVE_NEON
if((CPUCapFlags&CPU_CAP_NEON))
@@ -261,15 +261,15 @@ ResamplerFunc PrepareResampler(Resampler resampler, uint increment, InterpState
case Resampler::Linear:
break;
case Resampler::Cubic:
- state->cubic.filter = gCubicSpline.Tab.data();
+ state->emplace<CubicState>().filter = gCubicSpline.Tab.data();
break;
case Resampler::FastBSinc12:
case Resampler::BSinc12:
- BsincPrepare(increment, &state->bsinc, &gBSinc12);
+ BsincPrepare(increment, &state->emplace<BsincState>(), &gBSinc12);
break;
case Resampler::FastBSinc24:
case Resampler::BSinc24:
- BsincPrepare(increment, &state->bsinc, &gBSinc24);
+ BsincPrepare(increment, &state->emplace<BsincState>(), &gBSinc24);
break;
}
return SelectResampler(resampler, increment);
@@ -282,7 +282,7 @@ void DeviceBase::ProcessHrtf(const size_t SamplesToDo)
const size_t lidx{RealOut.ChannelIndex[FrontLeft]};
const size_t ridx{RealOut.ChannelIndex[FrontRight]};
- MixDirectHrtf(RealOut.Buffer[lidx], RealOut.Buffer[ridx], Dry.Buffer, HrtfAccumData,
+ MixDirectHrtf(RealOut.Buffer[lidx], RealOut.Buffer[ridx], Dry.Buffer, HrtfAccumData.data(),
mHrtfState->mTemp.data(), mHrtfState->mChannels.data(), mHrtfState->mIrSize, SamplesToDo);
}
@@ -323,8 +323,7 @@ void DeviceBase::ProcessBs2b(const size_t SamplesToDo)
const size_t ridx{RealOut.ChannelIndex[FrontRight]};
/* Now apply the BS2B binaural/crossfeed filter. */
- bs2b_cross_feed(Bs2b.get(), RealOut.Buffer[lidx].data(), RealOut.Buffer[ridx].data(),
- SamplesToDo);
+ Bs2b->cross_feed(RealOut.Buffer[lidx].data(), RealOut.Buffer[ridx].data(), SamplesToDo);
}
@@ -451,14 +450,14 @@ bool CalcEffectSlotParams(EffectSlot *slot, EffectSlot **sorted_slots, ContextBa
slot->Target = props->Target;
slot->EffectType = props->Type;
slot->mEffectProps = props->Props;
- if(props->Type == EffectSlotType::Reverb || props->Type == EffectSlotType::EAXReverb)
+ if(auto *reverbprops = std::get_if<ReverbProps>(&props->Props))
{
- slot->RoomRolloff = props->Props.Reverb.RoomRolloffFactor;
- slot->DecayTime = props->Props.Reverb.DecayTime;
- slot->DecayLFRatio = props->Props.Reverb.DecayLFRatio;
- slot->DecayHFRatio = props->Props.Reverb.DecayHFRatio;
- slot->DecayHFLimit = props->Props.Reverb.DecayHFLimit;
- slot->AirAbsorptionGainHF = props->Props.Reverb.AirAbsorptionGainHF;
+ slot->RoomRolloff = reverbprops->RoomRolloffFactor;
+ slot->DecayTime = reverbprops->DecayTime;
+ slot->DecayLFRatio = reverbprops->DecayLFRatio;
+ slot->DecayHFRatio = reverbprops->DecayHFRatio;
+ slot->DecayHFLimit = reverbprops->DecayHFLimit;
+ slot->AirAbsorptionGainHF = reverbprops->AirAbsorptionGainHF;
}
else
{
@@ -499,7 +498,7 @@ bool CalcEffectSlotParams(EffectSlot *slot, EffectSlot **sorted_slots, ContextBa
}
}
- AtomicReplaceHead(context->mFreeEffectslotProps, props);
+ AtomicReplaceHead(context->mFreeEffectSlotProps, props);
EffectTarget output;
if(EffectSlot *target{slot->Target})
@@ -679,16 +678,16 @@ void AmbiRotator(AmbiRotateMatrix &matrix, const int order)
auto P = [](const int i, const int l, const int a, const int n, const size_t last_band,
const AmbiRotateMatrix &R)
{
- const float ri1{ R[ 1+2][static_cast<size_t>(i+2)]};
- const float rim1{R[-1+2][static_cast<size_t>(i+2)]};
- const float ri0{ R[ 0+2][static_cast<size_t>(i+2)]};
+ const float ri1{ R[ 1+2][static_cast<size_t>(i+2_z)]};
+ const float rim1{R[-1+2][static_cast<size_t>(i+2_z)]};
+ const float ri0{ R[ 0+2][static_cast<size_t>(i+2_z)]};
const size_t y{last_band + static_cast<size_t>(a+l-1)};
if(n == -l)
- return ri1*R[last_band][y] + rim1*R[last_band + static_cast<size_t>(l-1)*2][y];
+ return ri1*R[last_band][y] + rim1*R[last_band + static_cast<size_t>(l-1_z)*2][y];
if(n == l)
- return ri1*R[last_band + static_cast<size_t>(l-1)*2][y] - rim1*R[last_band][y];
- return ri0*R[last_band + static_cast<size_t>(n+l-1)][y];
+ return ri1*R[last_band + static_cast<size_t>(l-1_z)*2][y] - rim1*R[last_band][y];
+ return ri0*R[last_band + static_cast<size_t>(l-1_z+n)][y];
};
auto U = [P](const int l, const int m, const int n, const size_t last_band,
@@ -776,48 +775,54 @@ struct GainTriplet { float Base, HF, LF; };
void CalcPanningAndFilters(Voice *voice, const float xpos, const float ypos, const float zpos,
const float Distance, const float Spread, const GainTriplet &DryGain,
- const al::span<const GainTriplet,MAX_SENDS> WetGain, EffectSlot *(&SendSlots)[MAX_SENDS],
- const VoiceProps *props, const ContextParams &Context, DeviceBase *Device)
+ const al::span<const GainTriplet,MaxSendCount> WetGain,
+ const al::span<EffectSlot*,MaxSendCount> SendSlots, const VoiceProps *props,
+ const ContextParams &Context, DeviceBase *Device)
{
- static constexpr ChanPosMap MonoMap[1]{
- { FrontCenter, std::array{0.0f, 0.0f, -1.0f} }
- }, RearMap[2]{
- { BackLeft, std::array{-sin30, 0.0f, cos30} },
- { BackRight, std::array{ sin30, 0.0f, cos30} },
- }, QuadMap[4]{
- { FrontLeft, std::array{-sin45, 0.0f, -cos45} },
- { FrontRight, std::array{ sin45, 0.0f, -cos45} },
- { BackLeft, std::array{-sin45, 0.0f, cos45} },
- { BackRight, std::array{ sin45, 0.0f, cos45} },
- }, X51Map[6]{
- { FrontLeft, std::array{-sin30, 0.0f, -cos30} },
- { FrontRight, std::array{ sin30, 0.0f, -cos30} },
- { FrontCenter, std::array{ 0.0f, 0.0f, -1.0f} },
- { LFE, {} },
- { SideLeft, std::array{-sin110, 0.0f, -cos110} },
- { SideRight, std::array{ sin110, 0.0f, -cos110} },
- }, X61Map[7]{
- { FrontLeft, std::array{-sin30, 0.0f, -cos30} },
- { FrontRight, std::array{ sin30, 0.0f, -cos30} },
- { FrontCenter, std::array{ 0.0f, 0.0f, -1.0f} },
- { LFE, {} },
- { BackCenter, std::array{ 0.0f, 0.0f, 1.0f} },
- { SideLeft, std::array{-1.0f, 0.0f, 0.0f} },
- { SideRight, std::array{ 1.0f, 0.0f, 0.0f} },
- }, X71Map[8]{
- { FrontLeft, std::array{-sin30, 0.0f, -cos30} },
- { FrontRight, std::array{ sin30, 0.0f, -cos30} },
- { FrontCenter, std::array{ 0.0f, 0.0f, -1.0f} },
- { LFE, {} },
- { BackLeft, std::array{-sin30, 0.0f, cos30} },
- { BackRight, std::array{ sin30, 0.0f, cos30} },
- { SideLeft, std::array{ -1.0f, 0.0f, 0.0f} },
- { SideRight, std::array{ 1.0f, 0.0f, 0.0f} },
+ static constexpr std::array MonoMap{
+ ChanPosMap{FrontCenter, std::array{0.0f, 0.0f, -1.0f}}
+ };
+ static constexpr std::array RearMap{
+ ChanPosMap{BackLeft, std::array{-sin30, 0.0f, cos30}},
+ ChanPosMap{BackRight, std::array{ sin30, 0.0f, cos30}},
+ };
+ static constexpr std::array QuadMap{
+ ChanPosMap{FrontLeft, std::array{-sin45, 0.0f, -cos45}},
+ ChanPosMap{FrontRight, std::array{ sin45, 0.0f, -cos45}},
+ ChanPosMap{BackLeft, std::array{-sin45, 0.0f, cos45}},
+ ChanPosMap{BackRight, std::array{ sin45, 0.0f, cos45}},
+ };
+ static constexpr std::array X51Map{
+ ChanPosMap{FrontLeft, std::array{-sin30, 0.0f, -cos30}},
+ ChanPosMap{FrontRight, std::array{ sin30, 0.0f, -cos30}},
+ ChanPosMap{FrontCenter, std::array{ 0.0f, 0.0f, -1.0f}},
+ ChanPosMap{LFE, {}},
+ ChanPosMap{SideLeft, std::array{-sin110, 0.0f, -cos110}},
+ ChanPosMap{SideRight, std::array{ sin110, 0.0f, -cos110}},
+ };
+ static constexpr std::array X61Map{
+ ChanPosMap{FrontLeft, std::array{-sin30, 0.0f, -cos30}},
+ ChanPosMap{FrontRight, std::array{ sin30, 0.0f, -cos30}},
+ ChanPosMap{FrontCenter, std::array{ 0.0f, 0.0f, -1.0f}},
+ ChanPosMap{LFE, {}},
+ ChanPosMap{BackCenter, std::array{ 0.0f, 0.0f, 1.0f}},
+ ChanPosMap{SideLeft, std::array{-1.0f, 0.0f, 0.0f}},
+ ChanPosMap{SideRight, std::array{ 1.0f, 0.0f, 0.0f}},
+ };
+ static constexpr std::array X71Map{
+ ChanPosMap{FrontLeft, std::array{-sin30, 0.0f, -cos30}},
+ ChanPosMap{FrontRight, std::array{ sin30, 0.0f, -cos30}},
+ ChanPosMap{FrontCenter, std::array{ 0.0f, 0.0f, -1.0f}},
+ ChanPosMap{LFE, {}},
+ ChanPosMap{BackLeft, std::array{-sin30, 0.0f, cos30}},
+ ChanPosMap{BackRight, std::array{ sin30, 0.0f, cos30}},
+ ChanPosMap{SideLeft, std::array{ -1.0f, 0.0f, 0.0f}},
+ ChanPosMap{SideRight, std::array{ 1.0f, 0.0f, 0.0f}},
};
- ChanPosMap StereoMap[2]{
- { FrontLeft, std::array{-sin30, 0.0f, -cos30} },
- { FrontRight, std::array{ sin30, 0.0f, -cos30} },
+ std::array StereoMap{
+ ChanPosMap{FrontLeft, std::array{-sin30, 0.0f, -cos30}},
+ ChanPosMap{FrontRight, std::array{ sin30, 0.0f, -cos30}},
};
const auto Frequency = static_cast<float>(Device->Frequency);
@@ -834,45 +839,45 @@ void CalcPanningAndFilters(Voice *voice, const float xpos, const float ypos, con
[](SendParams &params) -> void { params.Gains.Target.fill(0.0f); });
}
- DirectMode DirectChannels{props->DirectChannels};
- const ChanPosMap *chans{nullptr};
- switch(voice->mFmtChannels)
+ const auto getChans = [props,&StereoMap](FmtChannels chanfmt) noexcept
+ -> std::pair<DirectMode,al::span<const ChanPosMap>>
{
- case FmtMono:
- chans = MonoMap;
- /* Mono buffers are never played direct. */
- DirectChannels = DirectMode::Off;
- break;
-
- case FmtStereo:
- if(DirectChannels == DirectMode::Off)
+ switch(chanfmt)
{
- for(size_t i{0};i < 2;++i)
+ case FmtMono:
+ /* Mono buffers are never played direct. */
+ return {DirectMode::Off, al::span{MonoMap}};
+
+ case FmtStereo:
+ if(props->DirectChannels == DirectMode::Off)
{
- /* StereoPan is counter-clockwise in radians. */
- const float a{props->StereoPan[i]};
- StereoMap[i].pos[0] = -std::sin(a);
- StereoMap[i].pos[2] = -std::cos(a);
+ for(size_t i{0};i < 2;++i)
+ {
+ /* StereoPan is counter-clockwise in radians. */
+ const float a{props->StereoPan[i]};
+ StereoMap[i].pos[0] = -std::sin(a);
+ StereoMap[i].pos[2] = -std::cos(a);
+ }
}
+ return {props->DirectChannels, al::span{StereoMap}};
+
+ case FmtRear: return {props->DirectChannels, al::span{RearMap}};
+ case FmtQuad: return {props->DirectChannels, al::span{QuadMap}};
+ case FmtX51: return {props->DirectChannels, al::span{X51Map}};
+ case FmtX61: return {props->DirectChannels, al::span{X61Map}};
+ case FmtX71: return {props->DirectChannels, al::span{X71Map}};
+
+ case FmtBFormat2D:
+ case FmtBFormat3D:
+ case FmtUHJ2:
+ case FmtUHJ3:
+ case FmtUHJ4:
+ case FmtSuperStereo:
+ return {DirectMode::Off, {}};
}
- chans = StereoMap;
- break;
-
- case FmtRear: chans = RearMap; break;
- case FmtQuad: chans = QuadMap; break;
- case FmtX51: chans = X51Map; break;
- case FmtX61: chans = X61Map; break;
- case FmtX71: chans = X71Map; break;
-
- case FmtBFormat2D:
- case FmtBFormat3D:
- case FmtUHJ2:
- case FmtUHJ3:
- case FmtUHJ4:
- case FmtSuperStereo:
- DirectChannels = DirectMode::Off;
- break;
- }
+ return {props->DirectChannels, {}};
+ };
+ const auto [DirectChannels,chans] = getChans(voice->mFmtChannels);
voice->mFlags.reset(VoiceHasHrtf).reset(VoiceHasNfc);
if(auto *decoder{voice->mDecoder.get()})
@@ -1065,8 +1070,8 @@ void CalcPanningAndFilters(Voice *voice, const float xpos, const float ypos, con
voice->mChans[c].mDryParams.Gains.Target[idx] = DryGain.Base;
else if(DirectChannels == DirectMode::RemixMismatch)
{
- auto match_channel = [chans,c](const InputRemixMap &map) noexcept -> bool
- { return chans[c].channel == map.channel; };
+ auto match_channel = [channel=chans[c].channel](const InputRemixMap &map) noexcept
+ { return channel == map.channel; };
auto remap = std::find_if(Device->RealOut.RemixMap.cbegin(),
Device->RealOut.RemixMap.cend(), match_channel);
if(remap != Device->RealOut.RemixMap.cend())
@@ -1176,7 +1181,7 @@ void CalcPanningAndFilters(Voice *voice, const float xpos, const float ypos, con
* where it can be 0 or full (non-mono sources are always full
* spread here).
*/
- const float spread{Spread * (voice->mFmtChannels == FmtMono)};
+ const float spread{Spread * float(voice->mFmtChannels == FmtMono)};
/* Local sources on HRTF play with each channel panned to its
* relative location around the listener, providing "virtual
@@ -1324,7 +1329,7 @@ void CalcPanningAndFilters(Voice *voice, const float xpos, const float ypos, con
* where it can be 0 or full (non-mono sources are always full
* spread here).
*/
- const float spread{Spread * (voice->mFmtChannels == FmtMono)};
+ const float spread{Spread * float(voice->mFmtChannels == FmtMono)};
for(size_t c{0};c < num_channels;c++)
{
/* Special-case LFE */
@@ -1396,7 +1401,7 @@ void CalcPanningAndFilters(Voice *voice, const float xpos, const float ypos, con
void CalcNonAttnSourceParams(Voice *voice, const VoiceProps *props, const ContextBase *context)
{
DeviceBase *Device{context->mDevice};
- EffectSlot *SendSlots[MAX_SENDS];
+ std::array<EffectSlot*,MaxSendCount> SendSlots;
voice->mDirect.Buffer = Device->Dry.Buffer;
for(uint i{0};i < Device->NumAuxSends;i++)
@@ -1426,7 +1431,8 @@ void CalcNonAttnSourceParams(Voice *voice, const VoiceProps *props, const Contex
context->mParams.Gain, GainMixMax);
DryGain.HF = props->Direct.GainHF;
DryGain.LF = props->Direct.GainLF;
- GainTriplet WetGain[MAX_SENDS];
+
+ std::array<GainTriplet,MaxSendCount> WetGain;
for(uint i{0};i < Device->NumAuxSends;i++)
{
WetGain[i].Base = minf(clampf(props->Gain, props->MinGain, props->MaxGain) *
@@ -1446,20 +1452,30 @@ void CalcAttnSourceParams(Voice *voice, const VoiceProps *props, const ContextBa
/* Set mixing buffers and get send parameters. */
voice->mDirect.Buffer = Device->Dry.Buffer;
- EffectSlot *SendSlots[MAX_SENDS];
- uint UseDryAttnForRoom{0};
+ std::array<EffectSlot*,MaxSendCount> SendSlots{};
+ std::array<float,MaxSendCount> RoomRolloff{};
+ std::bitset<MaxSendCount> UseDryAttnForRoom{0};
for(uint i{0};i < NumSends;i++)
{
SendSlots[i] = props->Send[i].Slot;
if(!SendSlots[i] || SendSlots[i]->EffectType == EffectSlotType::None)
SendSlots[i] = nullptr;
- else if(!SendSlots[i]->AuxSendAuto)
+ else if(SendSlots[i]->AuxSendAuto)
{
- /* If the slot's auxiliary send auto is off, the data sent to the
- * effect slot is the same as the dry path, sans filter effects.
+ /* NOTE: Contrary to the EFX docs, the effect's room rolloff factor
+ * applies to the selected distance model along with the source's
+ * room rolloff factor, not necessarily the inverse distance model.
+ *
+ * Generic Software also applies these rolloff factors regardless
+ * of any setting. It doesn't seem to use the effect slot's send
+ * auto for anything, though as far as I understand, it's supposed
+ * to control whether the send gets the same gain/gainhf as the
+ * direct path (excluding the filter).
*/
- UseDryAttnForRoom |= 1u<<i;
+ RoomRolloff[i] = props->RoomRolloffFactor + SendSlots[i]->RoomRolloff;
}
+ else
+ UseDryAttnForRoom.set(i);
if(!SendSlots[i])
voice->mSend[i].Buffer = {};
@@ -1491,62 +1507,77 @@ void CalcAttnSourceParams(Voice *voice, const VoiceProps *props, const ContextBa
/* Calculate distance attenuation */
float ClampedDist{Distance};
float DryGainBase{props->Gain};
- float WetGainBase{props->Gain};
+ std::array<float,MaxSendCount> WetGainBase{};
+ WetGainBase.fill(props->Gain);
+ float DryAttnBase{1.0f};
switch(context->mParams.SourceDistanceModel ? props->mDistanceModel
: context->mParams.mDistanceModel)
{
- case DistanceModel::InverseClamped:
- if(props->MaxDistance < props->RefDistance) break;
- ClampedDist = clampf(ClampedDist, props->RefDistance, props->MaxDistance);
- /*fall-through*/
- case DistanceModel::Inverse:
- if(props->RefDistance > 0.0f)
+ case DistanceModel::InverseClamped:
+ if(props->MaxDistance < props->RefDistance) break;
+ ClampedDist = clampf(ClampedDist, props->RefDistance, props->MaxDistance);
+ /*fall-through*/
+ case DistanceModel::Inverse:
+ if(props->RefDistance > 0.0f)
+ {
+ float dist{lerpf(props->RefDistance, ClampedDist, props->RolloffFactor)};
+ if(dist > 0.0f)
{
- float dist{lerpf(props->RefDistance, ClampedDist, props->RolloffFactor)};
- if(dist > 0.0f) DryGainBase *= props->RefDistance / dist;
-
- dist = lerpf(props->RefDistance, ClampedDist, props->RoomRolloffFactor);
- if(dist > 0.0f) WetGainBase *= props->RefDistance / dist;
+ DryAttnBase = props->RefDistance / dist;
+ DryGainBase *= DryAttnBase;
}
- break;
-
- case DistanceModel::LinearClamped:
- if(props->MaxDistance < props->RefDistance) break;
- ClampedDist = clampf(ClampedDist, props->RefDistance, props->MaxDistance);
- /*fall-through*/
- case DistanceModel::Linear:
- if(props->MaxDistance != props->RefDistance)
- {
- float attn{(ClampedDist-props->RefDistance) /
- (props->MaxDistance-props->RefDistance) * props->RolloffFactor};
- DryGainBase *= maxf(1.0f - attn, 0.0f);
- attn = (ClampedDist-props->RefDistance) /
- (props->MaxDistance-props->RefDistance) * props->RoomRolloffFactor;
- WetGainBase *= maxf(1.0f - attn, 0.0f);
+ for(size_t i{0};i < NumSends;++i)
+ {
+ dist = lerpf(props->RefDistance, ClampedDist, RoomRolloff[i]);
+ if(dist > 0.0f) WetGainBase[i] *= props->RefDistance / dist;
}
- break;
-
- case DistanceModel::ExponentClamped:
- if(props->MaxDistance < props->RefDistance) break;
- ClampedDist = clampf(ClampedDist, props->RefDistance, props->MaxDistance);
- /*fall-through*/
- case DistanceModel::Exponent:
- if(ClampedDist > 0.0f && props->RefDistance > 0.0f)
+ }
+ break;
+
+ case DistanceModel::LinearClamped:
+ if(props->MaxDistance < props->RefDistance) break;
+ ClampedDist = clampf(ClampedDist, props->RefDistance, props->MaxDistance);
+ /*fall-through*/
+ case DistanceModel::Linear:
+ if(props->MaxDistance != props->RefDistance)
+ {
+ float attn{(ClampedDist-props->RefDistance) /
+ (props->MaxDistance-props->RefDistance) * props->RolloffFactor};
+ DryAttnBase = maxf(1.0f - attn, 0.0f);
+ DryGainBase *= DryAttnBase;
+
+ for(size_t i{0};i < NumSends;++i)
{
- const float dist_ratio{ClampedDist/props->RefDistance};
- DryGainBase *= std::pow(dist_ratio, -props->RolloffFactor);
- WetGainBase *= std::pow(dist_ratio, -props->RoomRolloffFactor);
+ attn = (ClampedDist-props->RefDistance) /
+ (props->MaxDistance-props->RefDistance) * RoomRolloff[i];
+ WetGainBase[i] *= maxf(1.0f - attn, 0.0f);
}
- break;
+ }
+ break;
+
+ case DistanceModel::ExponentClamped:
+ if(props->MaxDistance < props->RefDistance) break;
+ ClampedDist = clampf(ClampedDist, props->RefDistance, props->MaxDistance);
+ /*fall-through*/
+ case DistanceModel::Exponent:
+ if(ClampedDist > 0.0f && props->RefDistance > 0.0f)
+ {
+ const float dist_ratio{ClampedDist/props->RefDistance};
+ DryAttnBase = std::pow(dist_ratio, -props->RolloffFactor);
+ DryGainBase *= DryAttnBase;
+ for(size_t i{0};i < NumSends;++i)
+ WetGainBase[i] *= std::pow(dist_ratio, -RoomRolloff[i]);
+ }
+ break;
- case DistanceModel::Disable:
- break;
+ case DistanceModel::Disable:
+ break;
}
/* Calculate directional soundcones */
- float ConeHF{1.0f}, WetConeHF{1.0f};
+ float ConeHF{1.0f}, WetCone{1.0f}, WetConeHF{1.0f};
if(directional && props->InnerAngle < 360.0f)
{
static constexpr float Rad2Deg{static_cast<float>(180.0 / al::numbers::pi)};
@@ -1556,39 +1587,43 @@ void CalcAttnSourceParams(Voice *voice, const VoiceProps *props, const ContextBa
if(Angle >= props->OuterAngle)
{
ConeGain = props->OuterGain;
- ConeHF = lerpf(1.0f, props->OuterGainHF, props->DryGainHFAuto);
+ if(props->DryGainHFAuto)
+ ConeHF = props->OuterGainHF;
}
else if(Angle >= props->InnerAngle)
{
const float scale{(Angle-props->InnerAngle) / (props->OuterAngle-props->InnerAngle)};
ConeGain = lerpf(1.0f, props->OuterGain, scale);
- ConeHF = lerpf(1.0f, props->OuterGainHF, scale * props->DryGainHFAuto);
+ if(props->DryGainHFAuto)
+ ConeHF = lerpf(1.0f, props->OuterGainHF, scale);
}
DryGainBase *= ConeGain;
- WetGainBase *= lerpf(1.0f, ConeGain, props->WetGainAuto);
-
- WetConeHF = lerpf(1.0f, ConeHF, props->WetGainHFAuto);
+ if(props->WetGainAuto)
+ WetCone = ConeGain;
+ if(props->WetGainHFAuto)
+ WetConeHF = ConeHF;
}
/* Apply gain and frequency filters */
- DryGainBase = clampf(DryGainBase, props->MinGain, props->MaxGain) * context->mParams.Gain;
- WetGainBase = clampf(WetGainBase, props->MinGain, props->MaxGain) * context->mParams.Gain;
-
GainTriplet DryGain{};
+ DryGainBase = clampf(DryGainBase, props->MinGain, props->MaxGain) * context->mParams.Gain;
DryGain.Base = minf(DryGainBase * props->Direct.Gain, GainMixMax);
DryGain.HF = ConeHF * props->Direct.GainHF;
DryGain.LF = props->Direct.GainLF;
- GainTriplet WetGain[MAX_SENDS]{};
+
+ std::array<GainTriplet,MaxSendCount> WetGain{};
for(uint i{0};i < NumSends;i++)
{
+ WetGainBase[i] = clampf(WetGainBase[i]*WetCone, props->MinGain, props->MaxGain) *
+ context->mParams.Gain;
/* If this effect slot's Auxiliary Send Auto is off, then use the dry
* path distance and cone attenuation, otherwise use the wet (room)
* path distance and cone attenuation. The send filter is used instead
* of the direct filter, regardless.
*/
- const bool use_room{!(UseDryAttnForRoom&(1u<<i))};
- const float gain{use_room ? WetGainBase : DryGainBase};
+ const bool use_room{!UseDryAttnForRoom.test(i)};
+ const float gain{use_room ? WetGainBase[i] : DryGainBase};
WetGain[i].Base = minf(gain * props->Send[i].Gain, GainMixMax);
WetGain[i].HF = (use_room ? WetConeHF : ConeHF) * props->Send[i].GainHF;
WetGain[i].LF = props->Send[i].GainLF;
@@ -1611,25 +1646,15 @@ void CalcAttnSourceParams(Voice *voice, const VoiceProps *props, const ContextBa
if(!SendSlots[i] || !(SendSlots[i]->DecayTime > 0.0f))
continue;
- auto calc_attenuation = [](float distance, float refdist, float rolloff) noexcept
- {
- const float dist{lerpf(refdist, distance, rolloff)};
- if(dist > refdist) return refdist / dist;
- return 1.0f;
- };
-
- /* The reverb effect's room rolloff factor always applies to an
- * inverse distance rolloff model.
- */
- WetGain[i].Base *= calc_attenuation(Distance, props->RefDistance,
- SendSlots[i]->RoomRolloff);
-
if(distance_meters > std::numeric_limits<float>::epsilon())
WetGain[i].HF *= std::pow(SendSlots[i]->AirAbsorptionGainHF, distance_meters);
/* If this effect slot's Auxiliary Send Auto is off, don't apply
- * the automatic initial reverb decay (should the reverb's room
- * rolloff still apply?).
+ * the automatic initial reverb decay.
+ *
+ * NOTE: Generic Software applies the initial decay regardless of
+ * this setting. It doesn't seem to use it for anything, only the
+ * source's send filter gain auto flag affects this.
*/
if(!SendSlots[i]->AuxSendAuto)
continue;
@@ -1640,7 +1665,7 @@ void CalcAttnSourceParams(Voice *voice, const VoiceProps *props, const ContextBa
*/
DecayDistance.Base = SendSlots[i]->DecayTime * SpeedOfSoundMetersPerSec;
DecayDistance.LF = DecayDistance.Base * SendSlots[i]->DecayLFRatio;
- DecayDistance.HF = DecayDistance.Base * SendSlots[i]->DecayHFRatio;
+ DecayDistance.HF = SendSlots[i]->DecayHFRatio;
if(SendSlots[i]->DecayHFLimit)
{
const float airAbsorption{SendSlots[i]->AirAbsorptionGainHF};
@@ -1656,14 +1681,18 @@ void CalcAttnSourceParams(Voice *voice, const VoiceProps *props, const ContextBa
DecayDistance.HF = minf(absorb_dist, DecayDistance.HF);
}
}
-
- const float baseAttn = calc_attenuation(Distance, props->RefDistance,
- props->RolloffFactor);
+ DecayDistance.HF *= DecayDistance.Base;
/* Apply a decay-time transformation to the wet path, based on the
* source distance. The initial decay of the reverb effect is
* calculated and applied to the wet path.
+ *
+ * FIXME: This is very likely not correct. It more likely should
+ * work by calculating a rolloff dynamically based on the reverb
+ * parameters (and source distance?) and add it to the room rolloff
+ * with the reverb and source rolloff parameters.
*/
+ const float baseAttn{DryAttnBase};
const float fact{distance_base / DecayDistance.Base};
const float gain{std::pow(ReverbDecayGain, fact)*(1.0f-baseAttn) + baseAttn};
WetGain[i].Base *= gain;
@@ -1743,7 +1772,7 @@ void CalcSourceParams(Voice *voice, ContextBase *context, bool force)
if(props)
{
- voice->mProps = *props;
+ voice->mProps = static_cast<VoiceProps&>(*props);
AtomicReplaceHead(context->mFreeVoiceProps, props);
}
@@ -1883,7 +1912,7 @@ void ProcessVoiceChanges(ContextBase *ctx)
ctx->mCurrentVoiceChange.store(cur, std::memory_order_release);
}
-void ProcessParamUpdates(ContextBase *ctx, const EffectSlotArray &slots,
+void ProcessParamUpdates(ContextBase *ctx, const al::span<EffectSlot*> slots,
const al::span<Voice*> voices)
{
ProcessVoiceChanges(ctx);
@@ -1892,7 +1921,7 @@ void ProcessParamUpdates(ContextBase *ctx, const EffectSlotArray &slots,
if(!ctx->mHoldUpdates.load(std::memory_order_acquire)) LIKELY
{
bool force{CalcContextParams(ctx)};
- auto sorted_slots = const_cast<EffectSlot**>(slots.data() + slots.size());
+ auto sorted_slots = al::to_address(slots.end());
for(EffectSlot *slot : slots)
force |= CalcEffectSlotParams(slot, sorted_slots, ctx);
@@ -1910,12 +1939,13 @@ void ProcessContexts(DeviceBase *device, const uint SamplesToDo)
{
ASSUME(SamplesToDo > 0);
- const nanoseconds curtime{device->ClockBase +
- nanoseconds{seconds{device->SamplesDone}}/device->Frequency};
+ const nanoseconds curtime{device->mClockBase.load(std::memory_order_relaxed) +
+ nanoseconds{seconds{device->mSamplesDone.load(std::memory_order_relaxed)}}/
+ device->Frequency};
for(ContextBase *ctx : *device->mContexts.load(std::memory_order_acquire))
{
- const EffectSlotArray &auxslots = *ctx->mActiveAuxSlots.load(std::memory_order_acquire);
+ auto auxslots = al::span{*ctx->mActiveAuxSlots.load(std::memory_order_acquire)};
const al::span<Voice*> voices{ctx->getVoicesSpanAcquired()};
/* Process pending property updates for objects on the context. */
@@ -1937,16 +1967,12 @@ void ProcessContexts(DeviceBase *device, const uint SamplesToDo)
}
/* Process effects. */
- if(const size_t num_slots{auxslots.size()})
+ if(!auxslots.empty())
{
- auto slots = auxslots.data();
- auto slots_end = slots + num_slots;
-
/* Sort the slots into extra storage, so that effect slots come
* before their effect slot target (or their targets' target).
*/
- const al::span<EffectSlot*> sorted_slots{const_cast<EffectSlot**>(slots_end),
- num_slots};
+ const al::span sorted_slots{al::to_address(auxslots.end()), auxslots.size()};
/* Skip sorting if it has already been done. */
if(!sorted_slots[0])
{
@@ -1954,7 +1980,7 @@ void ProcessContexts(DeviceBase *device, const uint SamplesToDo)
* sorted list so that all slots without a target slot go to
* the end.
*/
- std::copy(slots, slots_end, sorted_slots.begin());
+ std::copy(auxslots.begin(), auxslots.end(), sorted_slots.begin());
auto split_point = std::partition(sorted_slots.begin(), sorted_slots.end(),
[](const EffectSlot *slot) noexcept -> bool
{ return slot->Target != nullptr; });
@@ -2041,11 +2067,12 @@ void ApplyDistanceComp(const al::span<FloatBufferLine> Samples, const size_t Sam
void ApplyDither(const al::span<FloatBufferLine> Samples, uint *dither_seed,
const float quant_scale, const size_t SamplesToDo)
{
+ static constexpr double invRNGRange{1.0 / std::numeric_limits<uint>::max()};
ASSUME(SamplesToDo > 0);
/* Dithering. Generate whitenoise (uniform distribution of random values
* between -1 and +1) and add it to the sample values, after scaling up to
- * the desired quantization depth amd before rounding.
+ * the desired quantization depth and before rounding.
*/
const float invscale{1.0f / quant_scale};
uint seed{*dither_seed};
@@ -2054,7 +2081,7 @@ void ApplyDither(const al::span<FloatBufferLine> Samples, uint *dither_seed,
float val{sample * quant_scale};
uint rng0{dither_rng(&seed)};
uint rng1{dither_rng(&seed)};
- val += static_cast<float>(rng0*(1.0/UINT_MAX) - rng1*(1.0/UINT_MAX));
+ val += static_cast<float>(rng0*invRNGRange - rng1*invRNGRange);
return fast_roundf(val) * invscale;
};
for(FloatBufferLine &inout : Samples)
@@ -2134,22 +2161,22 @@ uint DeviceBase::renderSamples(const uint numSamples)
for(FloatBufferLine &buffer : MixBuffer)
buffer.fill(0.0f);
- /* Increment the mix count at the start (lsb should now be 1). */
- IncrementRef(MixCount);
-
- /* Process and mix each context's sources and effects. */
- ProcessContexts(this, samplesToDo);
+ {
+ const auto mixLock = getWriteMixLock();
- /* Increment the clock time. Every second's worth of samples is converted
- * and added to clock base so that large sample counts don't overflow
- * during conversion. This also guarantees a stable conversion.
- */
- SamplesDone += samplesToDo;
- ClockBase += std::chrono::seconds{SamplesDone / Frequency};
- SamplesDone %= Frequency;
+ /* Process and mix each context's sources and effects. */
+ ProcessContexts(this, samplesToDo);
- /* Increment the mix count at the end (lsb should now be 0). */
- IncrementRef(MixCount);
+ /* Every second's worth of samples is converted and added to clock base
+ * so that large sample counts don't overflow during conversion. This
+ * also guarantees a stable conversion.
+ */
+ auto samplesDone = mSamplesDone.load(std::memory_order_relaxed) + samplesToDo;
+ auto clockBase = mClockBase.load(std::memory_order_relaxed) +
+ std::chrono::seconds{samplesDone/Frequency};
+ mSamplesDone.store(samplesDone%Frequency, std::memory_order_relaxed);
+ mClockBase.store(clockBase, std::memory_order_relaxed);
+ }
/* Apply any needed post-process for finalizing the Dry mix to the RealOut
* (Ambisonic decode, UHJ encode, etc).
@@ -2225,7 +2252,8 @@ void DeviceBase::renderSamples(void *outBuffer, const uint numSamples, const siz
void DeviceBase::handleDisconnect(const char *msg, ...)
{
- IncrementRef(MixCount);
+ const auto mixLock = getWriteMixLock();
+
if(Connected.exchange(false, std::memory_order_acq_rel))
{
AsyncEvent evt{std::in_place_type<AsyncDisconnectEvent>};
@@ -2233,10 +2261,10 @@ void DeviceBase::handleDisconnect(const char *msg, ...)
va_list args;
va_start(args, msg);
- int msglen{vsnprintf(disconnect.msg, sizeof(disconnect.msg), msg, args)};
+ int msglen{vsnprintf(disconnect.msg.data(), disconnect.msg.size(), msg, args)};
va_end(args);
- if(msglen < 0 || static_cast<size_t>(msglen) >= sizeof(disconnect.msg))
+ if(msglen < 0 || static_cast<size_t>(msglen) >= disconnect.msg.size())
disconnect.msg[sizeof(disconnect.msg)-1] = 0;
for(ContextBase *ctx : *mContexts.load())
@@ -2267,5 +2295,4 @@ void DeviceBase::handleDisconnect(const char *msg, ...)
std::for_each(voicelist.begin(), voicelist.end(), stop_voice);
}
}
- IncrementRef(MixCount);
}
diff --git a/alc/backends/alsa.cpp b/alc/backends/alsa.cpp
index 0d9ff30d..4bda5b02 100644
--- a/alc/backends/alsa.cpp
+++ b/alc/backends/alsa.cpp
@@ -53,6 +53,7 @@
namespace {
+/* NOLINTNEXTLINE(*-avoid-c-arrays) */
constexpr char alsaDevice[] = "ALSA Default";
@@ -252,10 +253,11 @@ std::vector<DevMap> PlaybackDevices;
std::vector<DevMap> CaptureDevices;
-const char *prefix_name(snd_pcm_stream_t stream)
+const std::string_view prefix_name(snd_pcm_stream_t stream)
{
- assert(stream == SND_PCM_STREAM_PLAYBACK || stream == SND_PCM_STREAM_CAPTURE);
- return (stream==SND_PCM_STREAM_PLAYBACK) ? "device-prefix" : "capture-prefix";
+ if(stream == SND_PCM_STREAM_PLAYBACK)
+ return "device-prefix";
+ return "capture-prefix";
}
std::vector<DevMap> probe_devices(snd_pcm_stream_t stream)
@@ -267,11 +269,11 @@ std::vector<DevMap> probe_devices(snd_pcm_stream_t stream)
snd_pcm_info_t *pcminfo;
snd_pcm_info_malloc(&pcminfo);
- auto defname = ConfigValueStr(nullptr, "alsa",
+ auto defname = ConfigValueStr({}, "alsa",
(stream == SND_PCM_STREAM_PLAYBACK) ? "device" : "capture");
devlist.emplace_back(alsaDevice, defname ? defname->c_str() : "default");
- if(auto customdevs = ConfigValueStr(nullptr, "alsa",
+ if(auto customdevs = ConfigValueStr({}, "alsa",
(stream == SND_PCM_STREAM_PLAYBACK) ? "custom-devices" : "custom-captures"))
{
size_t nextpos{customdevs->find_first_not_of(';')};
@@ -299,8 +301,8 @@ std::vector<DevMap> probe_devices(snd_pcm_stream_t stream)
}
}
- const std::string main_prefix{
- ConfigValueStr(nullptr, "alsa", prefix_name(stream)).value_or("plughw:")};
+ const std::string main_prefix{ConfigValueStr({}, "alsa", prefix_name(stream))
+ .value_or("plughw:")};
int card{-1};
int err{snd_card_next(&card)};
@@ -309,12 +311,14 @@ std::vector<DevMap> probe_devices(snd_pcm_stream_t stream)
std::string name{"hw:" + std::to_string(card)};
snd_ctl_t *handle;
- if((err=snd_ctl_open(&handle, name.c_str(), 0)) < 0)
+ err = snd_ctl_open(&handle, name.c_str(), 0);
+ if(err < 0)
{
ERR("control open (hw:%d): %s\n", card, snd_strerror(err));
continue;
}
- if((err=snd_ctl_card_info(handle, info)) < 0)
+ err = snd_ctl_card_info(handle, info);
+ if(err < 0)
{
ERR("control hardware info (hw:%d): %s\n", card, snd_strerror(err));
snd_ctl_close(handle);
@@ -326,8 +330,7 @@ std::vector<DevMap> probe_devices(snd_pcm_stream_t stream)
name = prefix_name(stream);
name += '-';
name += cardid;
- const std::string card_prefix{
- ConfigValueStr(nullptr, "alsa", name.c_str()).value_or(main_prefix)};
+ const std::string card_prefix{ConfigValueStr({}, "alsa", name).value_or(main_prefix)};
int dev{-1};
while(true)
@@ -339,7 +342,8 @@ std::vector<DevMap> probe_devices(snd_pcm_stream_t stream)
snd_pcm_info_set_device(pcminfo, static_cast<uint>(dev));
snd_pcm_info_set_subdevice(pcminfo, 0);
snd_pcm_info_set_stream(pcminfo, stream);
- if((err=snd_ctl_pcm_info(handle, pcminfo)) < 0)
+ err = snd_ctl_pcm_info(handle, pcminfo);
+ if(err < 0)
{
if(err != -ENOENT)
ERR("control digital audio info (hw:%d): %s\n", card, snd_strerror(err));
@@ -352,8 +356,7 @@ std::vector<DevMap> probe_devices(snd_pcm_stream_t stream)
name += cardid;
name += '-';
name += std::to_string(dev);
- const std::string device_prefix{
- ConfigValueStr(nullptr, "alsa", name.c_str()).value_or(card_prefix)};
+ const std::string device_prefix{ConfigValueStr({},"alsa", name).value_or(card_prefix)};
/* "CardName, PcmName (CARD=cardid,DEV=dev)" */
name = cardname;
@@ -405,13 +408,14 @@ int verify_state(snd_pcm_t *handle)
break;
case SND_PCM_STATE_XRUN:
- if((err=snd_pcm_recover(handle, -EPIPE, 1)) < 0)
- return err;
+ err=snd_pcm_recover(handle, -EPIPE, 1);
+ if(err < 0) return err;
break;
case SND_PCM_STATE_SUSPENDED:
- if((err=snd_pcm_recover(handle, -ESTRPIPE, 1)) < 0)
- return err;
+ err = snd_pcm_recover(handle, -ESTRPIPE, 1);
+ if(err < 0) return err;
break;
+
case SND_PCM_STATE_DISCONNECTED:
return -ENODEV;
}
@@ -443,8 +447,6 @@ struct AlsaPlayback final : public BackendBase {
std::atomic<bool> mKillNow{true};
std::thread mThread;
-
- DEF_NEWDEL(AlsaPlayback)
};
AlsaPlayback::~AlsaPlayback()
@@ -644,7 +646,7 @@ void AlsaPlayback::open(std::string_view name)
else
{
name = alsaDevice;
- if(auto driveropt = ConfigValueStr(nullptr, "alsa", "device"))
+ if(auto driveropt = ConfigValueStr({}, "alsa", "device"))
driver = std::move(driveropt).value();
}
TRACE("Opening device \"%s\"\n", driver.c_str());
@@ -692,7 +694,7 @@ bool AlsaPlayback::reset()
break;
}
- bool allowmmap{!!GetConfigValueBool(mDevice->DeviceName.c_str(), "alsa", "mmap", true)};
+ bool allowmmap{GetConfigValueBool(mDevice->DeviceName, "alsa", "mmap", true)};
uint periodLen{static_cast<uint>(mDevice->UpdateSize * 1000000_u64 / mDevice->Frequency)};
uint bufferLen{static_cast<uint>(mDevice->BufferSize * 1000000_u64 / mDevice->Frequency)};
uint rate{mDevice->Frequency};
@@ -700,7 +702,8 @@ bool AlsaPlayback::reset()
int err{};
HwParamsPtr hp{CreateHwParams()};
#define CHECK(x) do { \
- if((err=(x)) < 0) \
+ err = (x); \
+ if(err < 0) \
throw al::backend_exception{al::backend_error::DeviceError, #x " failed: %s", \
snd_strerror(err)}; \
} while(0)
@@ -715,17 +718,18 @@ bool AlsaPlayback::reset()
/* test and set format (implicitly sets sample bits) */
if(snd_pcm_hw_params_test_format(mPcmHandle, hp.get(), format) < 0)
{
- static const struct {
+ struct FormatMap {
snd_pcm_format_t format;
DevFmtType fmttype;
- } formatlist[] = {
- { SND_PCM_FORMAT_FLOAT, DevFmtFloat },
- { SND_PCM_FORMAT_S32, DevFmtInt },
- { SND_PCM_FORMAT_U32, DevFmtUInt },
- { SND_PCM_FORMAT_S16, DevFmtShort },
- { SND_PCM_FORMAT_U16, DevFmtUShort },
- { SND_PCM_FORMAT_S8, DevFmtByte },
- { SND_PCM_FORMAT_U8, DevFmtUByte },
+ };
+ static constexpr std::array formatlist{
+ FormatMap{SND_PCM_FORMAT_FLOAT, DevFmtFloat },
+ FormatMap{SND_PCM_FORMAT_S32, DevFmtInt },
+ FormatMap{SND_PCM_FORMAT_U32, DevFmtUInt },
+ FormatMap{SND_PCM_FORMAT_S16, DevFmtShort },
+ FormatMap{SND_PCM_FORMAT_U16, DevFmtUShort},
+ FormatMap{SND_PCM_FORMAT_S8, DevFmtByte },
+ FormatMap{SND_PCM_FORMAT_U8, DevFmtUByte },
};
for(const auto &fmt : formatlist)
@@ -750,7 +754,7 @@ bool AlsaPlayback::reset()
else mDevice->FmtChans = DevFmtStereo;
}
/* set rate (implicitly constrains period/buffer parameters) */
- if(!GetConfigValueBool(mDevice->DeviceName.c_str(), "alsa", "allow-resampler", false)
+ if(!GetConfigValueBool(mDevice->DeviceName, "alsa", "allow-resampler", false)
|| !mDevice->Flags.test(FrequencyRequest))
{
if(snd_pcm_hw_params_set_rate_resample(mPcmHandle, hp.get(), 0) < 0)
@@ -760,11 +764,11 @@ bool AlsaPlayback::reset()
WARN("Failed to enable ALSA resampler\n");
CHECK(snd_pcm_hw_params_set_rate_near(mPcmHandle, hp.get(), &rate, nullptr));
/* set period time (implicitly constrains period/buffer parameters) */
- if((err=snd_pcm_hw_params_set_period_time_near(mPcmHandle, hp.get(), &periodLen, nullptr)) < 0)
- ERR("snd_pcm_hw_params_set_period_time_near failed: %s\n", snd_strerror(err));
+ err = snd_pcm_hw_params_set_period_time_near(mPcmHandle, hp.get(), &periodLen, nullptr);
+ if(err < 0) ERR("snd_pcm_hw_params_set_period_time_near failed: %s\n", snd_strerror(err));
/* set buffer time (implicitly sets buffer size/bytes/time and period size/bytes) */
- if((err=snd_pcm_hw_params_set_buffer_time_near(mPcmHandle, hp.get(), &bufferLen, nullptr)) < 0)
- ERR("snd_pcm_hw_params_set_buffer_time_near failed: %s\n", snd_strerror(err));
+ err = snd_pcm_hw_params_set_buffer_time_near(mPcmHandle, hp.get(), &bufferLen, nullptr);
+ if(err < 0) ERR("snd_pcm_hw_params_set_buffer_time_near failed: %s\n", snd_strerror(err));
/* install and prepare hardware configuration */
CHECK(snd_pcm_hw_params(mPcmHandle, hp.get()));
@@ -802,7 +806,8 @@ void AlsaPlayback::start()
snd_pcm_access_t access{};
HwParamsPtr hp{CreateHwParams()};
#define CHECK(x) do { \
- if((err=(x)) < 0) \
+ err = (x); \
+ if(err < 0) \
throw al::backend_exception{al::backend_error::DeviceError, #x " failed: %s", \
snd_strerror(err)}; \
} while(0)
@@ -852,7 +857,7 @@ ClockLatency AlsaPlayback::getClockLatency()
ClockLatency ret;
std::lock_guard<std::mutex> _{mMutex};
- ret.ClockTime = GetDeviceClockTime(mDevice);
+ ret.ClockTime = mDevice->getClockTime();
snd_pcm_sframes_t delay{};
int err{snd_pcm_delay(mPcmHandle, &delay)};
if(err < 0)
@@ -886,8 +891,6 @@ struct AlsaCapture final : public BackendBase {
RingBufferPtr mRing{nullptr};
snd_pcm_sframes_t mLastAvail{0};
-
- DEF_NEWDEL(AlsaCapture)
};
AlsaCapture::~AlsaCapture()
@@ -916,7 +919,7 @@ void AlsaCapture::open(std::string_view name)
else
{
name = alsaDevice;
- if(auto driveropt = ConfigValueStr(nullptr, "alsa", "capture"))
+ if(auto driveropt = ConfigValueStr({}, "alsa", "capture"))
driver = std::move(driveropt).value();
}
@@ -961,7 +964,8 @@ void AlsaCapture::open(std::string_view name)
bool needring{false};
HwParamsPtr hp{CreateHwParams()};
#define CHECK(x) do { \
- if((err=(x)) < 0) \
+ err = (x); \
+ if(err < 0) \
throw al::backend_exception{al::backend_error::DeviceError, #x " failed: %s", \
snd_strerror(err)}; \
} while(0)
@@ -1039,7 +1043,7 @@ void AlsaCapture::captureSamples(std::byte *buffer, uint samples)
{
if(mRing)
{
- mRing->read(buffer, samples);
+ std::ignore = mRing->read(buffer, samples);
return;
}
@@ -1068,7 +1072,8 @@ void AlsaCapture::captureSamples(std::byte *buffer, uint samples)
if(amt == -EAGAIN)
continue;
- if((amt=snd_pcm_recover(mPcmHandle, static_cast<int>(amt), 1)) >= 0)
+ amt = snd_pcm_recover(mPcmHandle, static_cast<int>(amt), 1);
+ if(amt >= 0)
{
amt = snd_pcm_start(mPcmHandle);
if(amt >= 0)
@@ -1105,7 +1110,8 @@ uint AlsaCapture::availableSamples()
{
ERR("avail update failed: %s\n", snd_strerror(static_cast<int>(avail)));
- if((avail=snd_pcm_recover(mPcmHandle, static_cast<int>(avail), 1)) >= 0)
+ avail = snd_pcm_recover(mPcmHandle, static_cast<int>(avail), 1);
+ if(avail >= 0)
{
if(mDoCapture)
avail = snd_pcm_start(mPcmHandle);
@@ -1141,7 +1147,8 @@ uint AlsaCapture::availableSamples()
if(amt == -EAGAIN)
continue;
- if((amt=snd_pcm_recover(mPcmHandle, static_cast<int>(amt), 1)) >= 0)
+ amt = snd_pcm_recover(mPcmHandle, static_cast<int>(amt), 1);
+ if(amt >= 0)
{
if(mDoCapture)
amt = snd_pcm_start(mPcmHandle);
@@ -1170,7 +1177,7 @@ ClockLatency AlsaCapture::getClockLatency()
{
ClockLatency ret;
- ret.ClockTime = GetDeviceClockTime(mDevice);
+ ret.ClockTime = mDevice->getClockTime();
snd_pcm_sframes_t delay{};
int err{snd_pcm_delay(mPcmHandle, &delay)};
if(err < 0)
@@ -1189,13 +1196,9 @@ ClockLatency AlsaCapture::getClockLatency()
bool AlsaBackendFactory::init()
{
- bool error{false};
-
#ifdef HAVE_DYNLOAD
if(!alsa_handle)
{
- std::string missing_funcs;
-
alsa_handle = LoadLib("libasound.so.2");
if(!alsa_handle)
{
@@ -1203,27 +1206,25 @@ bool AlsaBackendFactory::init()
return false;
}
- error = false;
+ std::string missing_funcs;
#define LOAD_FUNC(f) do { \
- p##f = al::bit_cast<decltype(p##f)>(GetSymbol(alsa_handle, #f)); \
- if(p##f == nullptr) { \
- error = true; \
- missing_funcs += "\n" #f; \
- } \
+ p##f = reinterpret_cast<decltype(p##f)>(GetSymbol(alsa_handle, #f)); \
+ if(p##f == nullptr) missing_funcs += "\n" #f; \
} while(0)
ALSA_FUNCS(LOAD_FUNC);
#undef LOAD_FUNC
- if(error)
+ if(!missing_funcs.empty())
{
WARN("Missing expected functions:%s\n", missing_funcs.c_str());
CloseLib(alsa_handle);
alsa_handle = nullptr;
+ return false;
}
}
#endif
- return !error;
+ return true;
}
bool AlsaBackendFactory::querySupport(BackendType type)
diff --git a/alc/backends/base.cpp b/alc/backends/base.cpp
index ab3ad028..b287b6d9 100644
--- a/alc/backends/base.cpp
+++ b/alc/backends/base.cpp
@@ -45,21 +45,20 @@ uint BackendBase::availableSamples()
ClockLatency BackendBase::getClockLatency()
{
- ClockLatency ret;
+ ClockLatency ret{};
uint refcount;
do {
refcount = mDevice->waitForMix();
- ret.ClockTime = GetDeviceClockTime(mDevice);
+ ret.ClockTime = mDevice->getClockTime();
std::atomic_thread_fence(std::memory_order_acquire);
- } while(refcount != ReadRef(mDevice->MixCount));
+ } while(refcount != mDevice->mMixCount.load(std::memory_order_relaxed));
/* NOTE: The device will generally have about all but one periods filled at
* any given time during playback. Without a more accurate measurement from
* the output, this is an okay approximation.
*/
- ret.Latency = std::max(std::chrono::seconds{mDevice->BufferSize-mDevice->UpdateSize},
- std::chrono::seconds::zero());
+ ret.Latency = std::chrono::seconds{mDevice->BufferSize - mDevice->UpdateSize};
ret.Latency /= mDevice->Frequency;
return ret;
diff --git a/alc/backends/base.h b/alc/backends/base.h
index eea0d238..6726cd9a 100644
--- a/alc/backends/base.h
+++ b/alc/backends/base.h
@@ -52,18 +52,6 @@ enum class BackendType {
};
-/* Helper to get the current clock time from the device's ClockBase, and
- * SamplesDone converted from the sample rate.
- */
-inline std::chrono::nanoseconds GetDeviceClockTime(DeviceBase *device)
-{
- using std::chrono::seconds;
- using std::chrono::nanoseconds;
-
- auto ns = nanoseconds{seconds{device->SamplesDone}} / device->Frequency;
- return device->ClockBase + ns;
-}
-
/* Helper to get the device latency from the backend, including any fixed
* latency from post-processing.
*/
@@ -76,6 +64,8 @@ inline ClockLatency GetClockLatency(DeviceBase *device, BackendBase *backend)
struct BackendFactory {
+ virtual ~BackendFactory() = default;
+
virtual bool init() = 0;
virtual bool querySupport(BackendType type) = 0;
@@ -86,9 +76,6 @@ struct BackendFactory {
virtual std::string probe(BackendType type) = 0;
virtual BackendPtr createBackend(DeviceBase *device, BackendType type) = 0;
-
-protected:
- virtual ~BackendFactory() = default;
};
namespace al {
@@ -103,15 +90,15 @@ class backend_exception final : public base_exception {
backend_error mErrorCode;
public:
-#ifdef __USE_MINGW_ANSI_STDIO
- [[gnu::format(gnu_printf, 3, 4)]]
+#ifdef __MINGW32__
+ [[gnu::format(__MINGW_PRINTF_FORMAT, 3, 4)]]
#else
[[gnu::format(printf, 3, 4)]]
#endif
backend_exception(backend_error code, const char *msg, ...);
~backend_exception() override;
- backend_error errorCode() const noexcept { return mErrorCode; }
+ [[nodiscard]] auto errorCode() const noexcept -> backend_error { return mErrorCode; }
};
} // namespace al
diff --git a/alc/backends/coreaudio.cpp b/alc/backends/coreaudio.cpp
index 16b0781e..86c4b89b 100644
--- a/alc/backends/coreaudio.cpp
+++ b/alc/backends/coreaudio.cpp
@@ -337,8 +337,6 @@ struct CoreAudioPlayback final : public BackendBase {
uint mFrameSize{0u};
AudioStreamBasicDescription mFormat{}; // This is the OpenAL format as a CoreAudio ASBD
-
- DEF_NEWDEL(CoreAudioPlayback)
};
CoreAudioPlayback::~CoreAudioPlayback()
@@ -623,8 +621,6 @@ struct CoreAudioCapture final : public BackendBase {
std::vector<char> mCaptureData;
RingBufferPtr mRing{nullptr};
-
- DEF_NEWDEL(CoreAudioCapture)
};
CoreAudioCapture::~CoreAudioCapture()
@@ -657,7 +653,7 @@ OSStatus CoreAudioCapture::RecordProc(AudioUnitRenderActionFlags *ioActionFlags,
return err;
}
- mRing->write(mCaptureData.data(), inNumberFrames);
+ std::ignore = mRing->write(mCaptureData.data(), inNumberFrames);
return noErr;
}
@@ -924,7 +920,7 @@ void CoreAudioCapture::captureSamples(std::byte *buffer, uint samples)
{
if(!mConverter)
{
- mRing->read(buffer, samples);
+ std::ignore = mRing->read(buffer, samples);
return;
}
diff --git a/alc/backends/dsound.cpp b/alc/backends/dsound.cpp
index 58aa69b2..e51c7ab5 100644
--- a/alc/backends/dsound.cpp
+++ b/alc/backends/dsound.cpp
@@ -35,11 +35,11 @@
#include <algorithm>
#include <atomic>
#include <cassert>
+#include <cstdio>
+#include <cstdlib>
#include <functional>
#include <memory.h>
#include <mutex>
-#include <stdlib.h>
-#include <stdio.h>
#include <string>
#include <thread>
#include <vector>
@@ -191,8 +191,6 @@ struct DSoundPlayback final : public BackendBase {
std::atomic<bool> mKillNow{true};
std::thread mThread;
-
- DEF_NEWDEL(DSoundPlayback)
};
DSoundPlayback::~DSoundPlayback()
@@ -560,8 +558,6 @@ struct DSoundCapture final : public BackendBase {
DWORD mCursor{0u};
RingBufferPtr mRing;
-
- DEF_NEWDEL(DSoundCapture)
};
DSoundCapture::~DSoundCapture()
@@ -717,7 +713,7 @@ void DSoundCapture::stop()
}
void DSoundCapture::captureSamples(std::byte *buffer, uint samples)
-{ mRing->read(buffer, samples); }
+{ std::ignore = mRing->read(buffer, samples); }
uint DSoundCapture::availableSamples()
{
@@ -740,9 +736,9 @@ uint DSoundCapture::availableSamples()
}
if(SUCCEEDED(hr))
{
- mRing->write(ReadPtr1, ReadCnt1/FrameSize);
+ std::ignore = mRing->write(ReadPtr1, ReadCnt1/FrameSize);
if(ReadPtr2 != nullptr && ReadCnt2 > 0)
- mRing->write(ReadPtr2, ReadCnt2/FrameSize);
+ std::ignore = mRing->write(ReadPtr2, ReadCnt2/FrameSize);
hr = mDSCbuffer->Unlock(ReadPtr1, ReadCnt1, ReadPtr2, ReadCnt2);
mCursor = ReadCursor;
}
@@ -778,7 +774,7 @@ bool DSoundBackendFactory::init()
}
#define LOAD_FUNC(f) do { \
- p##f = al::bit_cast<decltype(p##f)>(GetSymbol(ds_handle, #f)); \
+ p##f = reinterpret_cast<decltype(p##f)>(GetSymbol(ds_handle, #f)); \
if(!p##f) \
{ \
CloseLib(ds_handle); \
diff --git a/alc/backends/jack.cpp b/alc/backends/jack.cpp
index a0a5c440..529bb9fe 100644
--- a/alc/backends/jack.cpp
+++ b/alc/backends/jack.cpp
@@ -102,19 +102,16 @@ decltype(jack_error_callback) * pjack_error_callback;
#endif
+/* NOLINTNEXTLINE(*-avoid-c-arrays) */
constexpr char JackDefaultAudioType[] = JACK_DEFAULT_AUDIO_TYPE;
jack_options_t ClientOptions = JackNullOption;
bool jack_load()
{
- bool error{false};
-
#ifdef HAVE_DYNLOAD
if(!jack_handle)
{
- std::string missing_funcs;
-
#ifdef _WIN32
#define JACKLIB "libjack.dll"
#else
@@ -127,38 +124,36 @@ bool jack_load()
return false;
}
- error = false;
+ std::string missing_funcs;
#define LOAD_FUNC(f) do { \
- p##f = al::bit_cast<decltype(p##f)>(GetSymbol(jack_handle, #f)); \
- if(p##f == nullptr) { \
- error = true; \
- missing_funcs += "\n" #f; \
- } \
+ p##f = reinterpret_cast<decltype(p##f)>(GetSymbol(jack_handle, #f)); \
+ if(p##f == nullptr) missing_funcs += "\n" #f; \
} while(0)
JACK_FUNCS(LOAD_FUNC);
#undef LOAD_FUNC
/* Optional symbols. These don't exist in all versions of JACK. */
-#define LOAD_SYM(f) p##f = al::bit_cast<decltype(p##f)>(GetSymbol(jack_handle, #f))
+#define LOAD_SYM(f) p##f = reinterpret_cast<decltype(p##f)>(GetSymbol(jack_handle, #f))
LOAD_SYM(jack_error_callback);
#undef LOAD_SYM
- if(error)
+ if(!missing_funcs.empty())
{
WARN("Missing expected functions:%s\n", missing_funcs.c_str());
CloseLib(jack_handle);
jack_handle = nullptr;
+ return false;
}
}
#endif
- return !error;
+ return true;
}
struct JackDeleter {
void operator()(void *ptr) { jack_free(ptr); }
};
-using JackPortsPtr = std::unique_ptr<const char*[],JackDeleter>;
+using JackPortsPtr = std::unique_ptr<const char*[],JackDeleter>; /* NOLINT(*-avoid-c-arrays) */
struct DeviceEntry {
std::string mName;
@@ -209,7 +204,7 @@ void EnumerateDevices(jack_client_t *client, std::vector<DeviceEntry> &list)
}
}
- if(auto listopt = ConfigValueStr(nullptr, "jack", "custom-devices"))
+ if(auto listopt = ConfigValueStr({}, "jack", "custom-devices"))
{
for(size_t strpos{0};strpos < listopt->size();)
{
@@ -307,7 +302,7 @@ struct JackPlayback final : public BackendBase {
std::string mPortPattern;
jack_client_t *mClient{nullptr};
- std::array<jack_port_t*,MAX_OUTPUT_CHANNELS> mPort{};
+ std::array<jack_port_t*,MaxOutputChannels> mPort{};
std::mutex mMutex;
@@ -318,8 +313,6 @@ struct JackPlayback final : public BackendBase {
std::atomic<bool> mKillNow{true};
std::thread mThread;
-
- DEF_NEWDEL(JackPlayback)
};
JackPlayback::~JackPlayback()
@@ -339,7 +332,7 @@ JackPlayback::~JackPlayback()
int JackPlayback::processRt(jack_nframes_t numframes) noexcept
{
- std::array<jack_default_audio_sample_t*,MAX_OUTPUT_CHANNELS> out;
+ std::array<jack_default_audio_sample_t*,MaxOutputChannels> out;
size_t numchans{0};
for(auto port : mPort)
{
@@ -363,7 +356,7 @@ int JackPlayback::processRt(jack_nframes_t numframes) noexcept
int JackPlayback::process(jack_nframes_t numframes) noexcept
{
- std::array<jack_default_audio_sample_t*,MAX_OUTPUT_CHANNELS> out;
+ std::array<jack_default_audio_sample_t*,MaxOutputChannels> out;
size_t numchans{0};
for(auto port : mPort)
{
@@ -378,7 +371,7 @@ int JackPlayback::process(jack_nframes_t numframes) noexcept
jack_nframes_t todo{minu(numframes, static_cast<uint>(data.first.len))};
auto write_first = [&data,numchans,todo](float *outbuf) -> float*
{
- const float *RESTRICT in = reinterpret_cast<float*>(data.first.buf);
+ const auto *RESTRICT in = reinterpret_cast<const float*>(data.first.buf);
auto deinterlace_input = [&in,numchans]() noexcept -> float
{
float ret{*in};
@@ -397,7 +390,7 @@ int JackPlayback::process(jack_nframes_t numframes) noexcept
{
auto write_second = [&data,numchans,todo](float *outbuf) -> float*
{
- const float *RESTRICT in = reinterpret_cast<float*>(data.second.buf);
+ const auto *RESTRICT in = reinterpret_cast<const float*>(data.second.buf);
auto deinterlace_input = [&in,numchans]() noexcept -> float
{
float ret{*in};
@@ -510,7 +503,7 @@ bool JackPlayback::reset()
std::for_each(mPort.begin(), mPort.end(), unregister_port);
mPort.fill(nullptr);
- mRTMixing = GetConfigValueBool(mDevice->DeviceName.c_str(), "jack", "rt-mix", true);
+ mRTMixing = GetConfigValueBool(mDevice->DeviceName, "jack", "rt-mix", true);
jack_set_process_callback(mClient,
mRTMixing ? &JackPlayback::processRtC : &JackPlayback::processC, this);
@@ -528,7 +521,7 @@ bool JackPlayback::reset()
}
else
{
- const char *devname{mDevice->DeviceName.c_str()};
+ const std::string_view devname{mDevice->DeviceName};
uint bufsize{ConfigValueUInt(devname, "jack", "buffer-size").value_or(mDevice->UpdateSize)};
bufsize = maxu(NextPowerOf2(bufsize), mDevice->UpdateSize);
mDevice->BufferSize = bufsize + mDevice->UpdateSize;
@@ -578,7 +571,7 @@ void JackPlayback::start()
if(jack_activate(mClient))
throw al::backend_exception{al::backend_error::DeviceError, "Failed to activate client"};
- const char *devname{mDevice->DeviceName.c_str()};
+ const std::string_view devname{mDevice->DeviceName};
if(ConfigValueBool(devname, "jack", "connect-ports").value_or(true))
{
JackPortsPtr pnames{jack_get_ports(mClient, mPortPattern.c_str(), JackDefaultAudioType,
@@ -657,7 +650,7 @@ ClockLatency JackPlayback::getClockLatency()
ClockLatency ret;
std::lock_guard<std::mutex> _{mMutex};
- ret.ClockTime = GetDeviceClockTime(mDevice);
+ ret.ClockTime = mDevice->getClockTime();
ret.Latency = std::chrono::seconds{mRing ? mRing->readSpace() : mDevice->UpdateSize};
ret.Latency /= mDevice->Frequency;
@@ -677,7 +670,7 @@ bool JackBackendFactory::init()
if(!jack_load())
return false;
- if(!GetConfigValueBool(nullptr, "jack", "spawn-server", false))
+ if(!GetConfigValueBool({}, "jack", "spawn-server", false))
ClientOptions = static_cast<jack_options_t>(ClientOptions | JackNoStartServer);
const PathNamePair &binname = GetProcBinary();
diff --git a/alc/backends/loopback.cpp b/alc/backends/loopback.cpp
index 2972fc01..e42e35b0 100644
--- a/alc/backends/loopback.cpp
+++ b/alc/backends/loopback.cpp
@@ -34,8 +34,6 @@ struct LoopbackBackend final : public BackendBase {
bool reset() override;
void start() override;
void stop() override;
-
- DEF_NEWDEL(LoopbackBackend)
};
diff --git a/alc/backends/null.cpp b/alc/backends/null.cpp
index 3c68e4ce..f28eaa47 100644
--- a/alc/backends/null.cpp
+++ b/alc/backends/null.cpp
@@ -42,6 +42,7 @@ using std::chrono::seconds;
using std::chrono::milliseconds;
using std::chrono::nanoseconds;
+/* NOLINTNEXTLINE(*-avoid-c-arrays) */
constexpr char nullDevice[] = "No Output";
@@ -57,8 +58,6 @@ struct NullBackend final : public BackendBase {
std::atomic<bool> mKillNow{true};
std::thread mThread;
-
- DEF_NEWDEL(NullBackend)
};
int NullBackend::mixerProc()
diff --git a/alc/backends/oboe.cpp b/alc/backends/oboe.cpp
index b7bab19a..d55a7066 100644
--- a/alc/backends/oboe.cpp
+++ b/alc/backends/oboe.cpp
@@ -4,8 +4,8 @@
#include "oboe.h"
#include <cassert>
+#include <cstdint>
#include <cstring>
-#include <stdint.h>
#include "alnumeric.h"
#include "core/device.h"
@@ -17,6 +17,7 @@
namespace {
+/* NOLINTNEXTLINE(*-avoid-c-arrays) */
constexpr char device_name[] = "Oboe Default";
@@ -48,11 +49,10 @@ oboe::DataCallbackResult OboePlayback::onAudioReady(oboe::AudioStream *oboeStrea
return oboe::DataCallbackResult::Continue;
}
-void OboePlayback::onErrorAfterClose(oboe::AudioStream* audioStream, oboe::Result error)
+void OboePlayback::onErrorAfterClose(oboe::AudioStream*, oboe::Result error)
{
- if (error == oboe::Result::ErrorDisconnected) {
+ if(error == oboe::Result::ErrorDisconnected)
mDevice->handleDisconnect("Oboe AudioStream was disconnected: %s", oboe::convertToText(error));
- }
TRACE("Error was %s", oboe::convertToText(error));
}
@@ -81,6 +81,7 @@ bool OboePlayback::reset()
oboe::AudioStreamBuilder builder;
builder.setDirection(oboe::Direction::Output);
builder.setPerformanceMode(oboe::PerformanceMode::LowLatency);
+ builder.setUsage(oboe::Usage::Game);
/* Don't let Oboe convert. We should be able to handle anything it gives
* back.
*/
@@ -230,7 +231,7 @@ struct OboeCapture final : public BackendBase, public oboe::AudioStreamCallback
oboe::DataCallbackResult OboeCapture::onAudioReady(oboe::AudioStream*, void *audioData,
int32_t numFrames)
{
- mRing->write(audioData, static_cast<uint32_t>(numFrames));
+ std::ignore = mRing->write(audioData, static_cast<uint32_t>(numFrames));
return oboe::DataCallbackResult::Continue;
}
@@ -330,7 +331,7 @@ uint OboeCapture::availableSamples()
{ return static_cast<uint>(mRing->readSpace()); }
void OboeCapture::captureSamples(std::byte *buffer, uint samples)
-{ mRing->read(buffer, samples); }
+{ std::ignore = mRing->read(buffer, samples); }
} // namespace
diff --git a/alc/backends/opensl.cpp b/alc/backends/opensl.cpp
index 61e3c9a7..6b2de909 100644
--- a/alc/backends/opensl.cpp
+++ b/alc/backends/opensl.cpp
@@ -23,10 +23,10 @@
#include "opensl.h"
-#include <stdlib.h>
#include <jni.h>
#include <array>
+#include <cstdlib>
#include <cstring>
#include <mutex>
#include <new>
@@ -56,6 +56,7 @@ namespace {
#define VCALL0(obj, func) ((*(obj))->func((obj) EXTRACT_VCALL_ARGS
+/* NOLINTNEXTLINE(*-avoid-c-arrays) */
constexpr char opensl_device[] = "OpenSL";
@@ -189,8 +190,6 @@ struct OpenSLPlayback final : public BackendBase {
std::atomic<bool> mKillNow{true};
std::thread mThread;
-
- DEF_NEWDEL(OpenSLPlayback)
};
OpenSLPlayback::~OpenSLPlayback()
@@ -375,74 +374,6 @@ bool OpenSLPlayback::reset()
mRing = nullptr;
-#if 0
- if(!mDevice->Flags.get<FrequencyRequest>())
- {
- /* FIXME: Disabled until I figure out how to get the Context needed for
- * the getSystemService call.
- */
- JNIEnv *env = Android_GetJNIEnv();
- jobject jctx = Android_GetContext();
-
- /* Get necessary stuff for using java.lang.Integer,
- * android.content.Context, and android.media.AudioManager.
- */
- jclass int_cls = JCALL(env,FindClass)("java/lang/Integer");
- jmethodID int_parseint = JCALL(env,GetStaticMethodID)(int_cls,
- "parseInt", "(Ljava/lang/String;)I"
- );
- TRACE("Integer: %p, parseInt: %p\n", int_cls, int_parseint);
-
- jclass ctx_cls = JCALL(env,FindClass)("android/content/Context");
- jfieldID ctx_audsvc = JCALL(env,GetStaticFieldID)(ctx_cls,
- "AUDIO_SERVICE", "Ljava/lang/String;"
- );
- jmethodID ctx_getSysSvc = JCALL(env,GetMethodID)(ctx_cls,
- "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;"
- );
- TRACE("Context: %p, AUDIO_SERVICE: %p, getSystemService: %p\n",
- ctx_cls, ctx_audsvc, ctx_getSysSvc);
-
- jclass audmgr_cls = JCALL(env,FindClass)("android/media/AudioManager");
- jfieldID audmgr_prop_out_srate = JCALL(env,GetStaticFieldID)(audmgr_cls,
- "PROPERTY_OUTPUT_SAMPLE_RATE", "Ljava/lang/String;"
- );
- jmethodID audmgr_getproperty = JCALL(env,GetMethodID)(audmgr_cls,
- "getProperty", "(Ljava/lang/String;)Ljava/lang/String;"
- );
- TRACE("AudioManager: %p, PROPERTY_OUTPUT_SAMPLE_RATE: %p, getProperty: %p\n",
- audmgr_cls, audmgr_prop_out_srate, audmgr_getproperty);
-
- const char *strchars;
- jstring strobj;
-
- /* Now make the calls. */
- //AudioManager audMgr = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
- strobj = JCALL(env,GetStaticObjectField)(ctx_cls, ctx_audsvc);
- jobject audMgr = JCALL(env,CallObjectMethod)(jctx, ctx_getSysSvc, strobj);
- strchars = JCALL(env,GetStringUTFChars)(strobj, nullptr);
- TRACE("Context.getSystemService(%s) = %p\n", strchars, audMgr);
- JCALL(env,ReleaseStringUTFChars)(strobj, strchars);
-
- //String srateStr = audMgr.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
- strobj = JCALL(env,GetStaticObjectField)(audmgr_cls, audmgr_prop_out_srate);
- jstring srateStr = JCALL(env,CallObjectMethod)(audMgr, audmgr_getproperty, strobj);
- strchars = JCALL(env,GetStringUTFChars)(strobj, nullptr);
- TRACE("audMgr.getProperty(%s) = %p\n", strchars, srateStr);
- JCALL(env,ReleaseStringUTFChars)(strobj, strchars);
-
- //int sampleRate = Integer.parseInt(srateStr);
- sampleRate = JCALL(env,CallStaticIntMethod)(int_cls, int_parseint, srateStr);
-
- strchars = JCALL(env,GetStringUTFChars)(srateStr, nullptr);
- TRACE("Got system sample rate %uhz (%s)\n", sampleRate, strchars);
- JCALL(env,ReleaseStringUTFChars)(srateStr, strchars);
-
- if(!sampleRate) sampleRate = device->Frequency;
- else sampleRate = maxu(sampleRate, MIN_OUTPUT_RATE);
- }
-#endif
-
mDevice->FmtChans = DevFmtStereo;
mDevice->FmtType = DevFmtShort;
@@ -631,7 +562,7 @@ ClockLatency OpenSLPlayback::getClockLatency()
ClockLatency ret;
std::lock_guard<std::mutex> _{mMutex};
- ret.ClockTime = GetDeviceClockTime(mDevice);
+ ret.ClockTime = mDevice->getClockTime();
ret.Latency = std::chrono::seconds{mRing->readSpace() * mDevice->UpdateSize};
ret.Latency /= mDevice->Frequency;
@@ -662,8 +593,6 @@ struct OpenSLCapture final : public BackendBase {
uint mSplOffset{0u};
uint mFrameSize{0};
-
- DEF_NEWDEL(OpenSLCapture)
};
OpenSLCapture::~OpenSLCapture()
diff --git a/alc/backends/oss.cpp b/alc/backends/oss.cpp
index 87d3ba35..d541b534 100644
--- a/alc/backends/oss.cpp
+++ b/alc/backends/oss.cpp
@@ -79,7 +79,9 @@
namespace {
+/* NOLINTNEXTLINE(*-avoid-c-arrays) */
constexpr char DefaultName[] = "OSS Default";
+
std::string DefaultPlayback{"/dev/dsp"};
std::string DefaultCapture{"/dev/dsp"};
@@ -238,8 +240,6 @@ struct OSSPlayback final : public BackendBase {
std::atomic<bool> mKillNow{true};
std::thread mThread;
-
- DEF_NEWDEL(OSSPlayback)
};
OSSPlayback::~OSSPlayback()
@@ -367,11 +367,9 @@ bool OSSPlayback::reset()
uint numFragmentsLogSize{(periods << 16) | log2FragmentSize};
audio_buf_info info{};
- const char *err;
-#define CHECKERR(func) if((func) < 0) { \
- err = #func; \
- goto err; \
-}
+#define CHECKERR(func) if((func) < 0) \
+ throw al::backend_exception{al::backend_error::DeviceError, "%s failed: %s\n", #func, strerror(errno)};
+
/* Don't fail if SETFRAGMENT fails. We can handle just about anything
* that's reported back via GETOSPACE */
ioctl(mFd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize);
@@ -379,12 +377,6 @@ bool OSSPlayback::reset()
CHECKERR(ioctl(mFd, SNDCTL_DSP_CHANNELS, &numChannels));
CHECKERR(ioctl(mFd, SNDCTL_DSP_SPEED, &ossSpeed));
CHECKERR(ioctl(mFd, SNDCTL_DSP_GETOSPACE, &info));
- if(0)
- {
- err:
- ERR("%s failed: %s\n", err, strerror(errno));
- return false;
- }
#undef CHECKERR
if(mDevice->channelsFromFmt() != numChannels)
@@ -409,7 +401,7 @@ bool OSSPlayback::reset()
setDefaultChannelOrder();
- mMixData.resize(mDevice->UpdateSize * mDevice->frameSizeFromFmt());
+ mMixData.resize(size_t{mDevice->UpdateSize} * mDevice->frameSizeFromFmt());
return true;
}
@@ -455,8 +447,6 @@ struct OSScapture final : public BackendBase {
std::atomic<bool> mKillNow{true};
std::thread mThread;
-
- DEF_NEWDEL(OSScapture)
};
OSScapture::~OSScapture()
@@ -617,7 +607,7 @@ void OSScapture::stop()
}
void OSScapture::captureSamples(std::byte *buffer, uint samples)
-{ mRing->read(buffer, samples); }
+{ std::ignore = mRing->read(buffer, samples); }
uint OSScapture::availableSamples()
{ return static_cast<uint>(mRing->readSpace()); }
@@ -633,9 +623,9 @@ BackendFactory &OSSBackendFactory::getFactory()
bool OSSBackendFactory::init()
{
- if(auto devopt = ConfigValueStr(nullptr, "oss", "device"))
+ if(auto devopt = ConfigValueStr({}, "oss", "device"))
DefaultPlayback = std::move(*devopt);
- if(auto capopt = ConfigValueStr(nullptr, "oss", "capture"))
+ if(auto capopt = ConfigValueStr({}, "oss", "capture"))
DefaultCapture = std::move(*capopt);
return true;
diff --git a/alc/backends/pipewire.cpp b/alc/backends/pipewire.cpp
index 6a001d7a..55bcf6f4 100644
--- a/alc/backends/pipewire.cpp
+++ b/alc/backends/pipewire.cpp
@@ -28,12 +28,12 @@
#include <cstring>
#include <cerrno>
#include <chrono>
+#include <cstdint>
#include <ctime>
#include <list>
#include <memory>
#include <mutex>
#include <optional>
-#include <stdint.h>
#include <thread>
#include <type_traits>
#include <utility>
@@ -76,6 +76,10 @@ _Pragma("GCC diagnostic ignored \"-Weverything\"")
#include "spa/pod/builder.h"
#include "spa/utils/json.h"
+/* NOLINTBEGIN : All kinds of unsafe C stuff here from PipeWire headers
+ * (function-like macros, C style casts in macros, etc), which we can't do
+ * anything about except wrap into inline functions.
+ */
namespace {
/* Wrap some nasty macros here too... */
template<typename ...Args>
@@ -117,6 +121,7 @@ constexpr auto make_pod_builder(void *data, uint32_t size) noexcept
constexpr auto PwIdAny = PW_ID_ANY;
} // namespace
+/* NOLINTEND */
_Pragma("GCC diagnostic pop")
namespace {
@@ -169,8 +174,10 @@ using std::chrono::milliseconds;
using std::chrono::nanoseconds;
using uint = unsigned int;
+/* NOLINTBEGIN(*-avoid-c-arrays) */
constexpr char pwireDevice[] = "PipeWire Output";
constexpr char pwireInput[] = "PipeWire Input";
+/* NOLINTEND(*-avoid-c-arrays) */
bool check_version(const char *version)
@@ -238,7 +245,7 @@ bool pwire_load()
if(pwire_handle)
return true;
- static constexpr char pwire_library[] = "libpipewire-0.3.so.0";
+ const char *pwire_library{"libpipewire-0.3.so.0"};
std::string missing_funcs;
pwire_handle = LoadLib(pwire_library);
@@ -249,7 +256,7 @@ bool pwire_load()
}
#define LOAD_FUNC(f) do { \
- p##f = al::bit_cast<decltype(p##f)>(GetSymbol(pwire_handle, #f)); \
+ p##f = reinterpret_cast<decltype(p##f)>(GetSymbol(pwire_handle, #f)); \
if(p##f == nullptr) missing_funcs += "\n" #f; \
} while(0);
PWIRE_FUNCS(LOAD_FUNC)
@@ -367,11 +374,11 @@ To as(From) noexcept = delete;
* - pw_metadata
*/
template<>
-pw_proxy* as(pw_registry *reg) noexcept { return al::bit_cast<pw_proxy*>(reg); }
+pw_proxy* as(pw_registry *reg) noexcept { return reinterpret_cast<pw_proxy*>(reg); }
template<>
-pw_proxy* as(pw_node *node) noexcept { return al::bit_cast<pw_proxy*>(node); }
+pw_proxy* as(pw_node *node) noexcept { return reinterpret_cast<pw_proxy*>(node); }
template<>
-pw_proxy* as(pw_metadata *mdata) noexcept { return al::bit_cast<pw_proxy*>(mdata); }
+pw_proxy* as(pw_metadata *mdata) noexcept { return reinterpret_cast<pw_proxy*>(mdata); }
struct PwContextDeleter {
@@ -434,9 +441,11 @@ public:
explicit operator bool() const noexcept { return mLoop != nullptr; }
+ [[nodiscard]]
auto start() const { return pw_thread_loop_start(mLoop); }
auto stop() const { return pw_thread_loop_stop(mLoop); }
+ [[nodiscard]]
auto getLoop() const { return pw_thread_loop_get_loop(mLoop); }
auto lock() const { return pw_thread_loop_lock(mLoop); }
@@ -501,8 +510,8 @@ struct NodeProxy {
/* Track changes to the enumerable and current formats (indicates the
* default and active format, which is what we're interested in).
*/
- uint32_t fmtids[]{SPA_PARAM_EnumFormat, SPA_PARAM_Format};
- ppw_node_subscribe_params(mNode.get(), std::data(fmtids), std::size(fmtids));
+ std::array<uint32_t,2> fmtids{{SPA_PARAM_EnumFormat, SPA_PARAM_Format}};
+ ppw_node_subscribe_params(mNode.get(), fmtids.data(), fmtids.size());
}
~NodeProxy()
{ spa_hook_remove(&mListener); }
@@ -765,25 +774,32 @@ void DeviceNode::Remove(uint32_t id)
}
-const spa_audio_channel MonoMap[]{
+constexpr std::array MonoMap{
SPA_AUDIO_CHANNEL_MONO
-}, StereoMap[] {
+};
+constexpr std::array StereoMap{
SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR
-}, QuadMap[]{
+};
+constexpr std::array QuadMap{
SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, SPA_AUDIO_CHANNEL_RL, SPA_AUDIO_CHANNEL_RR
-}, X51Map[]{
+};
+constexpr std::array X51Map{
SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_LFE,
SPA_AUDIO_CHANNEL_SL, SPA_AUDIO_CHANNEL_SR
-}, X51RearMap[]{
+};
+constexpr std::array X51RearMap{
SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_LFE,
SPA_AUDIO_CHANNEL_RL, SPA_AUDIO_CHANNEL_RR
-}, X61Map[]{
+};
+constexpr std::array X61Map{
SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_LFE,
SPA_AUDIO_CHANNEL_RC, SPA_AUDIO_CHANNEL_SL, SPA_AUDIO_CHANNEL_SR
-}, X71Map[]{
+};
+constexpr std::array X71Map{
SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_LFE,
SPA_AUDIO_CHANNEL_RL, SPA_AUDIO_CHANNEL_RR, SPA_AUDIO_CHANNEL_SL, SPA_AUDIO_CHANNEL_SR
-}, X714Map[]{
+};
+constexpr std::array X714Map{
SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_LFE,
SPA_AUDIO_CHANNEL_RL, SPA_AUDIO_CHANNEL_RR, SPA_AUDIO_CHANNEL_SL, SPA_AUDIO_CHANNEL_SR,
SPA_AUDIO_CHANNEL_TFL, SPA_AUDIO_CHANNEL_TFR, SPA_AUDIO_CHANNEL_TRL, SPA_AUDIO_CHANNEL_TRR
@@ -793,10 +809,10 @@ const spa_audio_channel MonoMap[]{
* Checks if every channel in 'map1' exists in 'map0' (that is, map0 is equal
* to or a superset of map1).
*/
-template<size_t N>
-bool MatchChannelMap(const al::span<const uint32_t> map0, const spa_audio_channel (&map1)[N])
+bool MatchChannelMap(const al::span<const uint32_t> map0,
+ const al::span<const spa_audio_channel> map1)
{
- if(map0.size() < N)
+ if(map0.size() < map1.size())
return false;
for(const spa_audio_channel chid : map1)
{
@@ -831,7 +847,7 @@ void DeviceNode::parseSampleRate(const spa_pod *value, bool force_update) noexce
/* [0] is the default, [1] is the min, and [2] is the max. */
TRACE(" sample rate: %d (range: %d -> %d)\n", srates[0], srates[1], srates[2]);
if(!mSampleRate || force_update)
- mSampleRate = static_cast<uint>(clampi(srates[0], MIN_OUTPUT_RATE, MAX_OUTPUT_RATE));
+ mSampleRate = static_cast<uint>(clampi(srates[0], MinOutputRate, MaxOutputRate));
return;
}
@@ -857,7 +873,7 @@ void DeviceNode::parseSampleRate(const spa_pod *value, bool force_update) noexce
*/
for(const auto &rate : srates)
{
- if(rate >= MIN_OUTPUT_RATE && rate <= MAX_OUTPUT_RATE)
+ if(rate >= int{MinOutputRate} && rate <= int{MaxOutputRate})
{
if(!mSampleRate || force_update)
mSampleRate = static_cast<uint>(rate);
@@ -878,7 +894,7 @@ void DeviceNode::parseSampleRate(const spa_pod *value, bool force_update) noexce
TRACE(" sample rate: %d\n", srates[0]);
if(!mSampleRate || force_update)
- mSampleRate = static_cast<uint>(clampi(srates[0], MIN_OUTPUT_RATE, MAX_OUTPUT_RATE));
+ mSampleRate = static_cast<uint>(clampi(srates[0], MinOutputRate, MaxOutputRate));
return;
}
@@ -956,6 +972,7 @@ void DeviceNode::parseChannelCount(const spa_pod *value, bool force_update) noex
}
+/* NOLINTBEGIN(*-avoid-c-arrays) */
constexpr char MonitorPrefix[]{"Monitor of "};
constexpr auto MonitorPrefixLen = std::size(MonitorPrefix) - 1;
constexpr char AudioSinkClass[]{"Audio/Sink"};
@@ -963,6 +980,7 @@ constexpr char AudioSourceClass[]{"Audio/Source"};
constexpr char AudioSourceVirtualClass[]{"Audio/Source/Virtual"};
constexpr char AudioDuplexClass[]{"Audio/Duplex"};
constexpr char StreamClass[]{"Stream/"};
+/* NOLINTEND(*-avoid-c-arrays) */
void NodeProxy::infoCallback(const pw_node_info *info) noexcept
{
@@ -1070,8 +1088,11 @@ void NodeProxy::paramCallback(int, uint32_t id, uint32_t, uint32_t, const spa_po
if(const spa_pod_prop *prop{spa_pod_find_prop(param, nullptr, SPA_FORMAT_AUDIO_position)})
node->parsePositions(&prop->value, force_update);
- else if((prop=spa_pod_find_prop(param, nullptr, SPA_FORMAT_AUDIO_channels)) != nullptr)
- node->parseChannelCount(&prop->value, force_update);
+ else
+ {
+ prop = spa_pod_find_prop(param, nullptr, SPA_FORMAT_AUDIO_channels);
+ if(prop) node->parseChannelCount(&prop->value, force_update);
+ }
}
}
@@ -1103,8 +1124,8 @@ int MetadataProxy::propertyCallback(uint32_t id, const char *key, const char *ty
return 0;
}
- spa_json it[2]{};
- spa_json_init(&it[0], value, strlen(value));
+ std::array<spa_json,2> it{};
+ spa_json_init(it.data(), value, strlen(value));
if(spa_json_enter_object(&it[0], &it[1]) <= 0)
return 0;
@@ -1407,8 +1428,7 @@ class PipeWirePlayback final : public BackendBase {
PwStreamPtr mStream;
spa_hook mStreamListener{};
spa_io_rate_match *mRateMatch{};
- std::unique_ptr<float*[]> mChannelPtrs;
- uint mNumChannels{};
+ std::vector<float*> mChannelPtrs;
static constexpr pw_stream_events CreateEvents()
{
@@ -1425,13 +1445,11 @@ class PipeWirePlayback final : public BackendBase {
public:
PipeWirePlayback(DeviceBase *device) noexcept : BackendBase{device} { }
- ~PipeWirePlayback()
+ ~PipeWirePlayback() final
{
/* Stop the mainloop so the stream can be properly destroyed. */
if(mLoop) mLoop.stop();
}
-
- DEF_NEWDEL(PipeWirePlayback)
};
@@ -1455,7 +1473,7 @@ void PipeWirePlayback::outputCallback() noexcept
if(!pw_buf) UNLIKELY return;
const al::span<spa_data> datas{pw_buf->buffer->datas,
- minu(mNumChannels, pw_buf->buffer->n_datas)};
+ minz(mChannelPtrs.size(), 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.
@@ -1475,7 +1493,7 @@ void PipeWirePlayback::outputCallback() noexcept
* buffer length in any one channel is smaller than we wanted (shouldn't
* be, but just in case).
*/
- float **chanptr_end{mChannelPtrs.get()};
+ auto chanptr_end = mChannelPtrs.begin();
for(const auto &data : datas)
{
length = minu(length, data.maxsize/sizeof(float));
@@ -1487,7 +1505,7 @@ void PipeWirePlayback::outputCallback() noexcept
data.chunk->size = length * sizeof(float);
}
- mDevice->renderSamples({mChannelPtrs.get(), chanptr_end}, length);
+ mDevice->renderSamples(mChannelPtrs, length);
pw_buf->size = length;
pw_stream_queue_buffer(mStream.get(), pw_buf);
@@ -1590,7 +1608,7 @@ bool PipeWirePlayback::reset()
}
mStreamListener = {};
mRateMatch = nullptr;
- mTimeBase = GetDeviceClockTime(mDevice);
+ mTimeBase = mDevice->getClockTime();
/* If connecting to a specific device, update various device parameters to
* match its format.
@@ -1611,11 +1629,12 @@ bool PipeWirePlayback::reset()
{
/* Scale the update size if the sample rate changes. */
const double scale{static_cast<double>(match->mSampleRate) / mDevice->Frequency};
- const double numbufs{static_cast<double>(mDevice->BufferSize)/mDevice->UpdateSize};
+ const double updatesize{std::round(mDevice->UpdateSize * scale)};
+ const double buffersize{std::round(mDevice->BufferSize * scale)};
+
mDevice->Frequency = match->mSampleRate;
- mDevice->UpdateSize = static_cast<uint>(clampd(mDevice->UpdateSize*scale + 0.5,
- 64.0, 8192.0));
- mDevice->BufferSize = static_cast<uint>(numbufs*mDevice->UpdateSize + 0.5);
+ mDevice->UpdateSize = static_cast<uint>(clampd(updatesize, 64.0, 8192.0));
+ mDevice->BufferSize = static_cast<uint>(maxd(buffersize, 128.0));
}
if(!mDevice->Flags.test(ChannelsRequest) && match->mChannels != InvalidChannelConfig)
mDevice->FmtChans = match->mChannels;
@@ -1673,7 +1692,7 @@ bool PipeWirePlayback::reset()
pw_stream_flags flags{PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_INACTIVE
| PW_STREAM_FLAG_MAP_BUFFERS};
- if(GetConfigValueBool(mDevice->DeviceName.c_str(), "pipewire", "rt-mix", true))
+ if(GetConfigValueBool(mDevice->DeviceName, "pipewire", "rt-mix", false))
flags |= PW_STREAM_FLAG_RT_PROCESS;
if(int res{pw_stream_connect(mStream.get(), PW_DIRECTION_OUTPUT, PwIdAny, flags, &params, 1)})
throw al::backend_exception{al::backend_error::DeviceError,
@@ -1698,8 +1717,7 @@ bool PipeWirePlayback::reset()
*/
plock.unlock();
- mNumChannels = mDevice->channelsFromFmt();
- mChannelPtrs = std::make_unique<float*[]>(mNumChannels);
+ mChannelPtrs.resize(mDevice->channelsFromFmt());
setDefaultWFXChannelOrder();
@@ -1757,7 +1775,7 @@ void PipeWirePlayback::start()
mDevice->UpdateSize = updatesize;
mDevice->BufferSize = static_cast<uint>(ptime.buffered + delay +
- totalbuffers*updatesize);
+ uint64_t{totalbuffers}*updatesize);
break;
}
#else
@@ -1791,8 +1809,7 @@ void PipeWirePlayback::stop()
{
MainloopUniqueLock plock{mLoop};
if(int res{pw_stream_set_active(mStream.get(), false)})
- throw al::backend_exception{al::backend_error::DeviceError,
- "Failed to stop PipeWire stream (res: %d)", res};
+ ERR("Failed to stop PipeWire stream (res: %d)\n", res);
/* Wait for the stream to stop playing. */
plock.wait([stream=mStream.get()]()
@@ -1824,10 +1841,10 @@ ClockLatency PipeWirePlayback::getClockLatency()
uint refcount;
do {
refcount = mDevice->waitForMix();
- mixtime = GetDeviceClockTime(mDevice);
+ mixtime = mDevice->getClockTime();
clock_gettime(CLOCK_MONOTONIC, &tspec);
std::atomic_thread_fence(std::memory_order_acquire);
- } while(refcount != ReadRef(mDevice->MixCount));
+ } while(refcount != mDevice->mMixCount.load(std::memory_order_relaxed));
/* Convert the monotonic clock, stream ticks, and stream delay to
* nanoseconds.
@@ -1916,9 +1933,7 @@ class PipeWireCapture final : public BackendBase {
public:
PipeWireCapture(DeviceBase *device) noexcept : BackendBase{device} { }
- ~PipeWireCapture() { if(mLoop) mLoop.stop(); }
-
- DEF_NEWDEL(PipeWireCapture)
+ ~PipeWireCapture() final { if(mLoop) mLoop.stop(); }
};
@@ -1934,7 +1949,8 @@ void PipeWireCapture::inputCallback() noexcept
const uint offset{minu(bufdata->chunk->offset, bufdata->maxsize)};
const uint size{minu(bufdata->chunk->size, bufdata->maxsize - offset)};
- mRing->write(static_cast<char*>(bufdata->data) + offset, size / mRing->getElemSize());
+ std::ignore = mRing->write(static_cast<char*>(bufdata->data) + offset,
+ size / mRing->getElemSize());
pw_stream_queue_buffer(mStream.get(), pw_buf);
}
@@ -2057,7 +2073,8 @@ void PipeWireCapture::open(std::string_view name)
static constexpr uint32_t pod_buffer_size{1024};
PodDynamicBuilder b(pod_buffer_size);
- const spa_pod *params[]{spa_format_audio_raw_build(b.get(), SPA_PARAM_EnumFormat, &info)};
+ std::array params{static_cast<const spa_pod*>(spa_format_audio_raw_build(b.get(),
+ SPA_PARAM_EnumFormat, &info))};
if(!params[0])
throw al::backend_exception{al::backend_error::DeviceError,
"Failed to set PipeWire audio format parameters"};
@@ -2099,7 +2116,7 @@ void PipeWireCapture::open(std::string_view name)
constexpr pw_stream_flags Flags{PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_INACTIVE
| PW_STREAM_FLAG_MAP_BUFFERS | PW_STREAM_FLAG_RT_PROCESS};
- if(int res{pw_stream_connect(mStream.get(), PW_DIRECTION_INPUT, PwIdAny, Flags, params, 1)})
+ if(int res{pw_stream_connect(mStream.get(), PW_DIRECTION_INPUT, PwIdAny, Flags, params.data(), 1)})
throw al::backend_exception{al::backend_error::DeviceError,
"Error connecting PipeWire stream (res: %d)", res};
@@ -2145,8 +2162,7 @@ void PipeWireCapture::stop()
{
MainloopUniqueLock plock{mLoop};
if(int res{pw_stream_set_active(mStream.get(), false)})
- throw al::backend_exception{al::backend_error::DeviceError,
- "Failed to stop PipeWire stream (res: %d)", res};
+ ERR("Failed to stop PipeWire stream (res: %d)\n", res);
plock.wait([stream=mStream.get()]()
{ return pw_stream_get_state(stream, nullptr) != PW_STREAM_STATE_STREAMING; });
@@ -2156,7 +2172,7 @@ uint PipeWireCapture::availableSamples()
{ return static_cast<uint>(mRing->readSpace()); }
void PipeWireCapture::captureSamples(std::byte *buffer, uint samples)
-{ mRing->read(buffer, samples); }
+{ std::ignore = mRing->read(buffer, samples); }
} // namespace
@@ -2175,11 +2191,11 @@ bool PipeWireBackendFactory::init()
}
TRACE("Found PipeWire version \"%s\" (%s or newer)\n", version, pw_get_headers_version());
- pw_init(0, nullptr);
+ pw_init(nullptr, nullptr);
if(!gEventHandler.init())
return false;
- if(!GetConfigValueBool(nullptr, "pipewire", "assume-audio", false)
+ if(!GetConfigValueBool({}, "pipewire", "assume-audio", false)
&& !gEventHandler.waitForAudio())
{
gEventHandler.kill();
diff --git a/alc/backends/portaudio.cpp b/alc/backends/portaudio.cpp
index 979a54d6..7c61e134 100644
--- a/alc/backends/portaudio.cpp
+++ b/alc/backends/portaudio.cpp
@@ -39,7 +39,8 @@
namespace {
-constexpr char pa_device[] = "PortAudio Default";
+/* NOLINTNEXTLINE(*-avoid-c-arrays) */
+constexpr char pa_device[]{"PortAudio Default"};
#ifdef HAVE_DYNLOAD
@@ -78,13 +79,6 @@ struct PortPlayback final : public BackendBase {
int writeCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo *timeInfo, const PaStreamCallbackFlags statusFlags) noexcept;
- static int writeCallbackC(const void *inputBuffer, void *outputBuffer,
- unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo,
- const PaStreamCallbackFlags statusFlags, void *userData) noexcept
- {
- return static_cast<PortPlayback*>(userData)->writeCallback(inputBuffer, outputBuffer,
- framesPerBuffer, timeInfo, statusFlags);
- }
void open(std::string_view name) override;
bool reset() override;
@@ -94,8 +88,6 @@ struct PortPlayback final : public BackendBase {
PaStream *mStream{nullptr};
PaStreamParameters mParams{};
uint mUpdateSize{0u};
-
- DEF_NEWDEL(PortPlayback)
};
PortPlayback::~PortPlayback()
@@ -125,7 +117,7 @@ void PortPlayback::open(std::string_view name)
static_cast<int>(name.length()), name.data()};
PaStreamParameters params{};
- auto devidopt = ConfigValueInt(nullptr, "port", "device");
+ auto devidopt = ConfigValueInt({}, "port", "device");
if(devidopt && *devidopt >= 0) params.device = *devidopt;
else params.device = Pa_GetDefaultOutputDevice();
params.suggestedLatency = mDevice->BufferSize / static_cast<double>(mDevice->Frequency);
@@ -156,19 +148,21 @@ void PortPlayback::open(std::string_view name)
break;
}
-retry_open:
+ static constexpr auto writeCallback = [](const void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo,
+ const PaStreamCallbackFlags statusFlags, void *userData) noexcept
+ {
+ return static_cast<PortPlayback*>(userData)->writeCallback(inputBuffer, outputBuffer,
+ framesPerBuffer, timeInfo, statusFlags);
+ };
PaStream *stream{};
- PaError err{Pa_OpenStream(&stream, nullptr, &params, mDevice->Frequency, mDevice->UpdateSize,
- paNoFlag, &PortPlayback::writeCallbackC, this)};
- if(err != paNoError)
+ while(PaError err{Pa_OpenStream(&stream, nullptr, &params, mDevice->Frequency,
+ mDevice->UpdateSize, paNoFlag, writeCallback, this)})
{
- if(params.sampleFormat == paFloat32)
- {
- params.sampleFormat = paInt16;
- goto retry_open;
- }
- throw al::backend_exception{al::backend_error::NoDevice, "Failed to open stream: %s",
- Pa_GetErrorText(err)};
+ if(params.sampleFormat != paFloat32)
+ throw al::backend_exception{al::backend_error::NoDevice, "Failed to open stream: %s",
+ Pa_GetErrorText(err)};
+ params.sampleFormat = paInt16;
}
Pa_CloseStream(mStream);
@@ -237,13 +231,6 @@ struct PortCapture final : public BackendBase {
int readCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo *timeInfo, const PaStreamCallbackFlags statusFlags) noexcept;
- static int readCallbackC(const void *inputBuffer, void *outputBuffer,
- unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo,
- const PaStreamCallbackFlags statusFlags, void *userData) noexcept
- {
- return static_cast<PortCapture*>(userData)->readCallback(inputBuffer, outputBuffer,
- framesPerBuffer, timeInfo, statusFlags);
- }
void open(std::string_view name) override;
void start() override;
@@ -252,11 +239,9 @@ struct PortCapture final : public BackendBase {
uint availableSamples() override;
PaStream *mStream{nullptr};
- PaStreamParameters mParams;
+ PaStreamParameters mParams{};
RingBufferPtr mRing{nullptr};
-
- DEF_NEWDEL(PortCapture)
};
PortCapture::~PortCapture()
@@ -271,7 +256,7 @@ PortCapture::~PortCapture()
int PortCapture::readCallback(const void *inputBuffer, void*, unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo*, const PaStreamCallbackFlags) noexcept
{
- mRing->write(inputBuffer, framesPerBuffer);
+ std::ignore = mRing->write(inputBuffer, framesPerBuffer);
return 0;
}
@@ -290,7 +275,7 @@ void PortCapture::open(std::string_view name)
mRing = RingBuffer::Create(samples, frame_size, false);
- auto devidopt = ConfigValueInt(nullptr, "port", "capture");
+ auto devidopt = ConfigValueInt({}, "port", "capture");
if(devidopt && *devidopt >= 0) mParams.device = *devidopt;
else mParams.device = Pa_GetDefaultOutputDevice();
mParams.suggestedLatency = 0.0f;
@@ -320,8 +305,15 @@ void PortCapture::open(std::string_view name)
}
mParams.channelCount = static_cast<int>(mDevice->channelsFromFmt());
+ static constexpr auto readCallback = [](const void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo,
+ const PaStreamCallbackFlags statusFlags, void *userData) noexcept
+ {
+ return static_cast<PortCapture*>(userData)->readCallback(inputBuffer, outputBuffer,
+ framesPerBuffer, timeInfo, statusFlags);
+ };
PaError err{Pa_OpenStream(&mStream, &mParams, nullptr, mDevice->Frequency,
- paFramesPerBufferUnspecified, paNoFlag, &PortCapture::readCallbackC, this)};
+ paFramesPerBufferUnspecified, paNoFlag, readCallback, this)};
if(err != paNoError)
throw al::backend_exception{al::backend_error::NoDevice, "Failed to open stream: %s",
Pa_GetErrorText(err)};
@@ -350,15 +342,13 @@ uint PortCapture::availableSamples()
{ return static_cast<uint>(mRing->readSpace()); }
void PortCapture::captureSamples(std::byte *buffer, uint samples)
-{ mRing->read(buffer, samples); }
+{ std::ignore = mRing->read(buffer, samples); }
} // namespace
bool PortBackendFactory::init()
{
- PaError err;
-
#ifdef HAVE_DYNLOAD
if(!pa_handle)
{
@@ -377,7 +367,7 @@ bool PortBackendFactory::init()
return false;
#define LOAD_FUNC(f) do { \
- p##f = al::bit_cast<decltype(p##f)>(GetSymbol(pa_handle, #f)); \
+ p##f = reinterpret_cast<decltype(p##f)>(GetSymbol(pa_handle, #f)); \
if(p##f == nullptr) \
{ \
CloseLib(pa_handle); \
@@ -397,7 +387,8 @@ bool PortBackendFactory::init()
LOAD_FUNC(Pa_GetStreamInfo);
#undef LOAD_FUNC
- if((err=Pa_Initialize()) != paNoError)
+ const PaError err{Pa_Initialize()};
+ if(err != paNoError)
{
ERR("Pa_Initialize() returned an error: %s\n", Pa_GetErrorText(err));
CloseLib(pa_handle);
@@ -406,7 +397,8 @@ bool PortBackendFactory::init()
}
}
#else
- if((err=Pa_Initialize()) != paNoError)
+ const PaError err{Pa_Initialize()};
+ if(err != paNoError)
{
ERR("Pa_Initialize() returned an error: %s\n", Pa_GetErrorText(err));
return false;
diff --git a/alc/backends/pulseaudio.cpp b/alc/backends/pulseaudio.cpp
index bebc182d..e976fc27 100644
--- a/alc/backends/pulseaudio.cpp
+++ b/alc/backends/pulseaudio.cpp
@@ -28,12 +28,12 @@
#include <atomic>
#include <bitset>
#include <chrono>
+#include <cstdint>
+#include <cstdlib>
#include <cstring>
#include <limits>
#include <mutex>
#include <optional>
-#include <stdint.h>
-#include <stdlib.h>
#include <string>
#include <sys/types.h>
#include <utility>
@@ -320,11 +320,12 @@ public:
explicit operator bool() const noexcept { return mLoop != nullptr; }
+ [[nodiscard]]
auto start() const { return pa_threaded_mainloop_start(mLoop); }
auto stop() const { return pa_threaded_mainloop_stop(mLoop); }
- auto getApi() const { return pa_threaded_mainloop_get_api(mLoop); }
- auto getContext() const noexcept { return mContext; }
+ [[nodiscard]] auto getApi() const { return pa_threaded_mainloop_get_api(mLoop); }
+ [[nodiscard]] auto getContext() const noexcept { return mContext; }
auto lock() const { return pa_threaded_mainloop_lock(mLoop); }
auto unlock() const { return pa_threaded_mainloop_unlock(mLoop); }
@@ -509,8 +510,8 @@ void MainloopUniqueLock::connectContext()
pa_context_set_state_callback(mutex()->mContext, [](pa_context *ctx, void *pdata) noexcept
{ return static_cast<MainloopUniqueLock*>(pdata)->contextStateCallback(ctx); }, this);
- int err;
- if((err=pa_context_connect(mutex()->mContext, nullptr, pulse_ctx_flags, nullptr)) >= 0)
+ int err{pa_context_connect(mutex()->mContext, nullptr, pulse_ctx_flags, nullptr)};
+ if(err >= 0)
{
pa_context_state_t state;
while((state=pa_context_get_state(mutex()->mContext)) != PA_CONTEXT_READY)
@@ -657,14 +658,12 @@ struct PulsePlayback final : public BackendBase {
std::optional<std::string> mDeviceName{std::nullopt};
bool mIs51Rear{false};
- pa_buffer_attr mAttr;
- pa_sample_spec mSpec;
+ pa_buffer_attr mAttr{};
+ pa_sample_spec mSpec{};
pa_stream *mStream{nullptr};
uint mFrameSize{0u};
-
- DEF_NEWDEL(PulsePlayback)
};
PulsePlayback::~PulsePlayback()
@@ -753,9 +752,9 @@ void PulsePlayback::sinkInfoCallback(pa_context*, const pa_sink_info *info, int
else
{
mIs51Rear = false;
- char chanmap_str[PA_CHANNEL_MAP_SNPRINT_MAX]{};
- pa_channel_map_snprint(chanmap_str, sizeof(chanmap_str), &info->channel_map);
- WARN("Failed to find format for channel map:\n %s\n", chanmap_str);
+ std::array<char,PA_CHANNEL_MAP_SNPRINT_MAX> chanmap_str{};
+ pa_channel_map_snprint(chanmap_str.data(), chanmap_str.size(), &info->channel_map);
+ WARN("Failed to find format for channel map:\n %s\n", chanmap_str.data());
}
if(info->active_port)
@@ -784,7 +783,9 @@ void PulsePlayback::streamMovedCallback(pa_stream *stream) noexcept
void PulsePlayback::open(std::string_view name)
{
mMainloop = PulseMainloop::Create();
- mMainloop.start();
+ if(mMainloop.start() != 0)
+ throw al::backend_exception{al::backend_error::DeviceError,
+ "Failed to start device mainloop"};
const char *pulse_name{nullptr};
const char *dev_name{nullptr};
@@ -807,7 +808,7 @@ void PulsePlayback::open(std::string_view name)
pa_stream_flags_t flags{PA_STREAM_START_CORKED | PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE |
PA_STREAM_FIX_CHANNELS};
- if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", true))
+ if(!GetConfigValueBool({}, "pulse", "allow-moves", true))
flags |= PA_STREAM_DONT_MOVE;
pa_sample_spec spec{};
@@ -866,9 +867,9 @@ bool PulsePlayback::reset()
pa_stream_flags_t flags{PA_STREAM_START_CORKED | PA_STREAM_INTERPOLATE_TIMING |
PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_EARLY_REQUESTS};
- if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", true))
+ if(!GetConfigValueBool({}, "pulse", "allow-moves", true))
flags |= PA_STREAM_DONT_MOVE;
- if(GetConfigValueBool(mDevice->DeviceName.c_str(), "pulse", "adjust-latency", false))
+ if(GetConfigValueBool(mDevice->DeviceName, "pulse", "adjust-latency", false))
{
/* ADJUST_LATENCY can't be specified with EARLY_REQUESTS, for some
* reason. So if the user wants to adjust the overall device latency,
@@ -877,7 +878,7 @@ bool PulsePlayback::reset()
flags &= ~PA_STREAM_EARLY_REQUESTS;
flags |= PA_STREAM_ADJUST_LATENCY;
}
- if(GetConfigValueBool(mDevice->DeviceName.c_str(), "pulse", "fix-rate", false)
+ if(GetConfigValueBool(mDevice->DeviceName, "pulse", "fix-rate", false)
|| !mDevice->Flags.test(FrequencyRequest))
flags |= PA_STREAM_FIX_RATE;
@@ -967,8 +968,9 @@ bool PulsePlayback::reset()
const auto scale = static_cast<double>(mSpec.rate) / mDevice->Frequency;
const auto perlen = static_cast<uint>(clampd(scale*mDevice->UpdateSize + 0.5, 64.0,
8192.0));
- const auto buflen = static_cast<uint>(clampd(scale*mDevice->BufferSize + 0.5, perlen*2,
- std::numeric_limits<int>::max()/mFrameSize));
+ const auto bufmax = uint{std::numeric_limits<int>::max() / mFrameSize};
+ const auto buflen = static_cast<uint>(clampd(scale*mDevice->BufferSize + 0.5, perlen*2.0,
+ bufmax));
mAttr.maxlength = ~0u;
mAttr.tlength = buflen * mFrameSize;
@@ -1034,7 +1036,7 @@ ClockLatency PulsePlayback::getClockLatency()
{
MainloopUniqueLock plock{mMainloop};
- ret.ClockTime = GetDeviceClockTime(mDevice);
+ ret.ClockTime = mDevice->getClockTime();
err = pa_stream_get_latency(mStream, &latency, &neg);
}
@@ -1087,8 +1089,6 @@ struct PulseCapture final : public BackendBase {
pa_sample_spec mSpec{};
pa_stream *mStream{nullptr};
-
- DEF_NEWDEL(PulseCapture)
};
PulseCapture::~PulseCapture()
@@ -1127,7 +1127,9 @@ void PulseCapture::open(std::string_view name)
if(!mMainloop)
{
mMainloop = PulseMainloop::Create();
- mMainloop.start();
+ if(mMainloop.start() != 0)
+ throw al::backend_exception{al::backend_error::DeviceError,
+ "Failed to start device mainloop"};
}
const char *pulse_name{nullptr};
@@ -1214,7 +1216,7 @@ void PulseCapture::open(std::string_view name)
mAttr.fragsize = minu(samples, 50*mDevice->Frequency/1000) * frame_size;
pa_stream_flags_t flags{PA_STREAM_START_CORKED | PA_STREAM_ADJUST_LATENCY};
- if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", true))
+ if(!GetConfigValueBool({}, "pulse", "allow-moves", true))
flags |= PA_STREAM_DONT_MOVE;
TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)");
@@ -1362,7 +1364,7 @@ ClockLatency PulseCapture::getClockLatency()
{
MainloopUniqueLock plock{mMainloop};
- ret.ClockTime = GetDeviceClockTime(mDevice);
+ ret.ClockTime = mDevice->getClockTime();
err = pa_stream_get_latency(mStream, &latency, &neg);
}
@@ -1387,9 +1389,6 @@ bool PulseBackendFactory::init()
#ifdef HAVE_DYNLOAD
if(!pulse_handle)
{
- bool ret{true};
- std::string missing_funcs;
-
#ifdef _WIN32
#define PALIB "libpulse-0.dll"
#elif defined(__APPLE__) && defined(__MACH__)
@@ -1404,17 +1403,15 @@ bool PulseBackendFactory::init()
return false;
}
+ std::string missing_funcs;
#define LOAD_FUNC(x) do { \
- p##x = al::bit_cast<decltype(p##x)>(GetSymbol(pulse_handle, #x)); \
- if(!(p##x)) { \
- ret = false; \
- missing_funcs += "\n" #x; \
- } \
+ p##x = reinterpret_cast<decltype(p##x)>(GetSymbol(pulse_handle, #x)); \
+ if(!(p##x)) missing_funcs += "\n" #x; \
} while(0)
PULSE_FUNCS(LOAD_FUNC)
#undef LOAD_FUNC
- if(!ret)
+ if(!missing_funcs.empty())
{
WARN("Missing expected functions:%s\n", missing_funcs.c_str());
CloseLib(pulse_handle);
@@ -1425,14 +1422,18 @@ bool PulseBackendFactory::init()
#endif /* HAVE_DYNLOAD */
pulse_ctx_flags = PA_CONTEXT_NOFLAGS;
- if(!GetConfigValueBool(nullptr, "pulse", "spawn-server", false))
+ if(!GetConfigValueBool({}, "pulse", "spawn-server", false))
pulse_ctx_flags |= PA_CONTEXT_NOAUTOSPAWN;
try {
if(!gGlobalMainloop)
{
gGlobalMainloop = PulseMainloop::Create();
- gGlobalMainloop.start();
+ if(gGlobalMainloop.start() != 0)
+ {
+ gGlobalMainloop = nullptr;
+ return false;
+ }
}
MainloopUniqueLock plock{gGlobalMainloop};
diff --git a/alc/backends/sdl2.cpp b/alc/backends/sdl2.cpp
index f5ed4316..b69f17fd 100644
--- a/alc/backends/sdl2.cpp
+++ b/alc/backends/sdl2.cpp
@@ -26,6 +26,7 @@
#include <cstdlib>
#include <cstring>
#include <string>
+#include <string_view>
#include "almalloc.h"
#include "alnumeric.h"
@@ -46,7 +47,9 @@ namespace {
#define DEVNAME_PREFIX ""
#endif
-constexpr char defaultDeviceName[] = DEVNAME_PREFIX "Default Device";
+constexpr auto getDevicePrefix() noexcept -> std::string_view { return DEVNAME_PREFIX; }
+constexpr auto getDefaultDeviceName() noexcept -> std::string_view
+{ return DEVNAME_PREFIX "Default Device"; }
struct Sdl2Backend final : public BackendBase {
Sdl2Backend(DeviceBase *device) noexcept : BackendBase{device} { }
@@ -66,8 +69,6 @@ struct Sdl2Backend final : public BackendBase {
DevFmtChannels mFmtChans{};
DevFmtType mFmtType{};
uint mUpdateSize{0u};
-
- DEF_NEWDEL(Sdl2Backend)
};
Sdl2Backend::~Sdl2Backend()
@@ -108,6 +109,7 @@ void Sdl2Backend::open(std::string_view name)
/* Passing nullptr to SDL_OpenAudioDevice opens a default, which isn't
* necessarily the first in the list.
*/
+ const auto defaultDeviceName = getDefaultDeviceName();
SDL_AudioDeviceID devid;
if(name.empty() || name == defaultDeviceName)
{
@@ -116,13 +118,13 @@ void Sdl2Backend::open(std::string_view name)
}
else
{
- const size_t prefix_len = strlen(DEVNAME_PREFIX);
- if(name.length() >= prefix_len && strncmp(name.data(), DEVNAME_PREFIX, prefix_len) == 0)
+ const auto namePrefix = getDevicePrefix();
+ if(name.size() >= namePrefix.size() && name.substr(0, namePrefix.size()) == namePrefix)
{
/* Copy the string_view to a string to ensure it's null terminated
* for this call.
*/
- const std::string devname{name.substr(prefix_len)};
+ const std::string devname{name.substr(namePrefix.size())};
devid = SDL_OpenAudioDevice(devname.c_str(), SDL_FALSE, &want, &have,
SDL_AUDIO_ALLOW_ANY_CHANGE);
}
@@ -217,13 +219,16 @@ std::string SDL2BackendFactory::probe(BackendType type)
int num_devices{SDL_GetNumAudioDevices(SDL_FALSE)};
/* Includes null char. */
- outnames.append(defaultDeviceName, sizeof(defaultDeviceName));
+ outnames += getDefaultDeviceName();
+ outnames += '\0';
for(int i{0};i < num_devices;++i)
{
- std::string name{DEVNAME_PREFIX};
- name += SDL_GetAudioDeviceName(i, SDL_FALSE);
- if(!name.empty())
- outnames.append(name.c_str(), name.length()+1);
+ outnames += getDevicePrefix();
+ if(const char *name = SDL_GetAudioDeviceName(i, SDL_FALSE))
+ outnames += name;
+ else
+ outnames += "Unknown Device Name #"+std::to_string(i);
+ outnames += '\0';
}
return outnames;
}
diff --git a/alc/backends/sndio.cpp b/alc/backends/sndio.cpp
index d54c337b..ce3de366 100644
--- a/alc/backends/sndio.cpp
+++ b/alc/backends/sndio.cpp
@@ -23,11 +23,11 @@
#include "sndio.h"
#include <cinttypes>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
#include <functional>
#include <poll.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
#include <thread>
#include <vector>
@@ -43,10 +43,11 @@
namespace {
-static const char sndio_device[] = "SndIO Default";
+/* NOLINTNEXTLINE(*-avoid-c-arrays) */
+constexpr char sndio_device[] = "SndIO Default";
struct SioPar : public sio_par {
- SioPar() { sio_initpar(this); }
+ SioPar() : sio_par{} { sio_initpar(this); }
void clear() { sio_initpar(this); }
};
@@ -69,8 +70,6 @@ struct SndioPlayback final : public BackendBase {
std::atomic<bool> mKillNow{true};
std::thread mThread;
-
- DEF_NEWDEL(SndioPlayback)
};
SndioPlayback::~SndioPlayback()
@@ -136,72 +135,75 @@ bool SndioPlayback::reset()
SioPar par;
auto tryfmt = mDevice->FmtType;
-retry_params:
- switch(tryfmt)
+ while(true)
{
- case DevFmtByte:
- par.bits = 8;
- par.sig = 1;
- break;
- case DevFmtUByte:
- par.bits = 8;
- par.sig = 0;
- break;
- case DevFmtShort:
- par.bits = 16;
- par.sig = 1;
- break;
- case DevFmtUShort:
- par.bits = 16;
- par.sig = 0;
- break;
- case DevFmtFloat:
- case DevFmtInt:
- par.bits = 32;
- par.sig = 1;
- break;
- case DevFmtUInt:
- par.bits = 32;
- par.sig = 0;
- break;
- }
- par.bps = SIO_BPS(par.bits);
- par.le = SIO_LE_NATIVE;
- par.msb = 1;
-
- par.rate = mDevice->Frequency;
- par.pchan = mDevice->channelsFromFmt();
-
- par.round = mDevice->UpdateSize;
- par.appbufsz = mDevice->BufferSize - mDevice->UpdateSize;
- if(!par.appbufsz) par.appbufsz = mDevice->UpdateSize;
+ switch(tryfmt)
+ {
+ case DevFmtByte:
+ par.bits = 8;
+ par.sig = 1;
+ break;
+ case DevFmtUByte:
+ par.bits = 8;
+ par.sig = 0;
+ break;
+ case DevFmtShort:
+ par.bits = 16;
+ par.sig = 1;
+ break;
+ case DevFmtUShort:
+ par.bits = 16;
+ par.sig = 0;
+ break;
+ case DevFmtFloat:
+ case DevFmtInt:
+ par.bits = 32;
+ par.sig = 1;
+ break;
+ case DevFmtUInt:
+ par.bits = 32;
+ par.sig = 0;
+ break;
+ }
+ par.bps = SIO_BPS(par.bits);
+ par.le = SIO_LE_NATIVE;
+ par.msb = 1;
+
+ par.rate = mDevice->Frequency;
+ par.pchan = mDevice->channelsFromFmt();
+
+ par.round = mDevice->UpdateSize;
+ par.appbufsz = mDevice->BufferSize - mDevice->UpdateSize;
+ if(!par.appbufsz) par.appbufsz = mDevice->UpdateSize;
+
+ try {
+ if(!sio_setpar(mSndHandle, &par))
+ throw al::backend_exception{al::backend_error::DeviceError,
+ "Failed to set device parameters"};
+
+ par.clear();
+ if(!sio_getpar(mSndHandle, &par))
+ throw al::backend_exception{al::backend_error::DeviceError,
+ "Failed to get device parameters"};
+
+ if(par.bps > 1 && par.le != SIO_LE_NATIVE)
+ throw al::backend_exception{al::backend_error::DeviceError,
+ "%s-endian samples not supported", par.le ? "Little" : "Big"};
+ if(par.bits < par.bps*8 && !par.msb)
+ throw al::backend_exception{al::backend_error::DeviceError,
+ "MSB-padded samples not supported (%u of %u bits)", par.bits, par.bps*8};
+ if(par.pchan < 1)
+ throw al::backend_exception{al::backend_error::DeviceError,
+ "No playback channels on device"};
- try {
- if(!sio_setpar(mSndHandle, &par))
- throw al::backend_exception{al::backend_error::DeviceError,
- "Failed to set device parameters"};
-
- par.clear();
- if(!sio_getpar(mSndHandle, &par))
- throw al::backend_exception{al::backend_error::DeviceError,
- "Failed to get device parameters"};
-
- if(par.bps > 1 && par.le != SIO_LE_NATIVE)
- throw al::backend_exception{al::backend_error::DeviceError,
- "%s-endian samples not supported", par.le ? "Little" : "Big"};
- if(par.bits < par.bps*8 && !par.msb)
- throw al::backend_exception{al::backend_error::DeviceError,
- "MSB-padded samples not supported (%u of %u bits)", par.bits, par.bps*8};
- if(par.pchan < 1)
- throw al::backend_exception{al::backend_error::DeviceError,
- "No playback channels on device"};
- }
- catch(al::backend_exception &e) {
- if(tryfmt == DevFmtShort)
- throw;
- par.clear();
- tryfmt = DevFmtShort;
- goto retry_params;
+ break;
+ }
+ catch(al::backend_exception &e) {
+ if(tryfmt == DevFmtShort)
+ throw;
+ par.clear();
+ tryfmt = DevFmtShort;
+ }
}
if(par.bps == 1)
@@ -229,7 +231,7 @@ retry_params:
mDevice->UpdateSize = par.round;
mDevice->BufferSize = par.bufsz + par.round;
- mBuffer.resize(mDevice->UpdateSize * par.pchan*par.bps);
+ mBuffer.resize(size_t{mDevice->UpdateSize} * par.pchan*par.bps);
if(par.sig == 1)
std::fill(mBuffer.begin(), mBuffer.end(), std::byte{});
else if(par.bits == 8)
@@ -292,8 +294,6 @@ struct SndioCapture final : public BackendBase {
std::atomic<bool> mKillNow{true};
std::thread mThread;
-
- DEF_NEWDEL(SndioCapture)
};
SndioCapture::~SndioCapture()
@@ -317,19 +317,19 @@ int SndioCapture::recordProc()
return 1;
}
- auto fds = std::make_unique<pollfd[]>(static_cast<uint>(nfds_pre));
+ auto fds = std::vector<pollfd>(static_cast<uint>(nfds_pre));
while(!mKillNow.load(std::memory_order_acquire)
&& mDevice->Connected.load(std::memory_order_acquire))
{
/* Wait until there's some samples to read. */
- const int nfds{sio_pollfd(mSndHandle, fds.get(), POLLIN)};
+ const int nfds{sio_pollfd(mSndHandle, fds.data(), POLLIN)};
if(nfds <= 0)
{
mDevice->handleDisconnect("Failed to get polling fds: %d", nfds);
break;
}
- int pollres{::poll(fds.get(), static_cast<uint>(nfds), 2000)};
+ int pollres{::poll(fds.data(), fds.size(), 2000)};
if(pollres < 0)
{
if(errno == EINTR) continue;
@@ -339,7 +339,7 @@ int SndioCapture::recordProc()
if(pollres == 0)
continue;
- const int revents{sio_revents(mSndHandle, fds.get())};
+ const int revents{sio_revents(mSndHandle, fds.data())};
if((revents&POLLHUP))
{
mDevice->handleDisconnect("Got POLLHUP from poll events");
@@ -373,8 +373,8 @@ int SndioCapture::recordProc()
if(buffer.empty())
{
/* Got samples to read, but no place to store it. Drop it. */
- static char junk[4096];
- sio_read(mSndHandle, junk, sizeof(junk) - (sizeof(junk)%frameSize));
+ static std::array<char,4096> junk;
+ sio_read(mSndHandle, junk.data(), junk.size() - (junk.size()%frameSize));
}
}
@@ -461,7 +461,7 @@ void SndioCapture::open(std::string_view name)
DevFmtTypeString(mDevice->FmtType), DevFmtChannelsString(mDevice->FmtChans),
mDevice->Frequency, par.sig?'s':'u', par.bps*8, par.rchan, par.rate};
- mRing = RingBuffer::Create(mDevice->BufferSize, par.bps*par.rchan, false);
+ mRing = RingBuffer::Create(mDevice->BufferSize, size_t{par.bps}*par.rchan, false);
mDevice->BufferSize = static_cast<uint>(mRing->writeSpace());
mDevice->UpdateSize = par.round;
@@ -497,7 +497,7 @@ void SndioCapture::stop()
}
void SndioCapture::captureSamples(std::byte *buffer, uint samples)
-{ mRing->read(buffer, samples); }
+{ std::ignore = mRing->read(buffer, samples); }
uint SndioCapture::availableSamples()
{ return static_cast<uint>(mRing->readSpace()); }
diff --git a/alc/backends/solaris.cpp b/alc/backends/solaris.cpp
index 38f9db19..c7387284 100644
--- a/alc/backends/solaris.cpp
+++ b/alc/backends/solaris.cpp
@@ -51,6 +51,7 @@
namespace {
+/* NOLINTNEXTLINE(*-avoid-c-arrays) */
constexpr char solaris_device[] = "Solaris Default";
std::string solaris_driver{"/dev/audio"};
@@ -74,8 +75,6 @@ struct SolarisBackend final : public BackendBase {
std::atomic<bool> mKillNow{true};
std::thread mThread;
-
- DEF_NEWDEL(SolarisBackend)
};
SolarisBackend::~SolarisBackend()
@@ -91,7 +90,7 @@ int SolarisBackend::mixerProc()
althrd_setname(MIXER_THREAD_NAME);
const size_t frame_step{mDevice->channelsFromFmt()};
- const uint frame_size{mDevice->frameSizeFromFmt()};
+ const size_t frame_size{mDevice->frameSizeFromFmt()};
while(!mKillNow.load(std::memory_order_acquire)
&& mDevice->Connected.load(std::memory_order_acquire))
@@ -115,12 +114,12 @@ int SolarisBackend::mixerProc()
continue;
}
- std::byte *write_ptr{mBuffer.data()};
- size_t to_write{mBuffer.size()};
- mDevice->renderSamples(write_ptr, static_cast<uint>(to_write/frame_size), frame_step);
- while(to_write > 0 && !mKillNow.load(std::memory_order_acquire))
+ al::span<std::byte> buffer{mBuffer};
+ mDevice->renderSamples(buffer.data(), static_cast<uint>(buffer.size()/frame_size),
+ frame_step);
+ while(!buffer.empty() && !mKillNow.load(std::memory_order_acquire))
{
- ssize_t wrote{write(mFd, write_ptr, to_write)};
+ ssize_t wrote{write(mFd, buffer.data(), buffer.size())};
if(wrote < 0)
{
if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
@@ -130,8 +129,7 @@ int SolarisBackend::mixerProc()
break;
}
- to_write -= static_cast<size_t>(wrote);
- write_ptr += wrote;
+ buffer = buffer.subspan(static_cast<size_t>(wrote));
}
}
@@ -267,7 +265,7 @@ BackendFactory &SolarisBackendFactory::getFactory()
bool SolarisBackendFactory::init()
{
- if(auto devopt = ConfigValueStr(nullptr, "solaris", "device"))
+ if(auto devopt = ConfigValueStr({}, "solaris", "device"))
solaris_driver = std::move(*devopt);
return true;
}
diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp
index 3ee98457..4fcae59c 100644
--- a/alc/backends/wasapi.cpp
+++ b/alc/backends/wasapi.cpp
@@ -25,8 +25,8 @@
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
-#include <stdlib.h>
-#include <stdio.h>
+#include <cstdio>
+#include <cstdlib>
#include <memory.h>
#include <wtypes.h>
@@ -171,7 +171,7 @@ constexpr AudioObjectType ChannelMask_X714{AudioObjectType_FrontLeft | AudioObje
| AudioObjectType_TopFrontLeft | AudioObjectType_TopFrontRight | AudioObjectType_TopBackLeft
| AudioObjectType_TopBackRight};
-
+/* NOLINTNEXTLINE(*-avoid-c-arrays) */
constexpr char DevNameHead[] = "OpenAL Soft on ";
constexpr size_t DevNameHeadLen{std::size(DevNameHead) - 1};
@@ -201,16 +201,16 @@ constexpr uint RefTime2Samples(const ReferenceTime &val, T srate) noexcept
class GuidPrinter {
- char mMsg[64];
+ std::array<char,64> mMsg;
public:
GuidPrinter(const GUID &guid)
{
- std::snprintf(mMsg, std::size(mMsg), "{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
+ std::snprintf(mMsg.data(), mMsg.size(), "{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
DWORD{guid.Data1}, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1], guid.Data4[2],
guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
}
- const char *c_str() const { return mMsg; }
+ [[nodiscard]] auto c_str() const -> const char* { return mMsg.data(); }
};
struct PropVariant {
@@ -270,13 +270,13 @@ private:
struct DeviceListLock : public std::unique_lock<DeviceList> {
using std::unique_lock<DeviceList>::unique_lock;
- auto& getPlaybackList() const noexcept { return mutex()->mPlayback; }
- auto& getCaptureList() const noexcept { return mutex()->mCapture; }
+ [[nodiscard]] auto& getPlaybackList() const noexcept { return mutex()->mPlayback; }
+ [[nodiscard]] auto& getCaptureList() const noexcept { return mutex()->mCapture; }
void setPlaybackDefaultId(std::wstring_view devid) const { mutex()->mPlaybackDefaultId = devid; }
- std::wstring_view getPlaybackDefaultId() const noexcept { return mutex()->mPlaybackDefaultId; }
+ [[nodiscard]] auto getPlaybackDefaultId() const noexcept -> std::wstring_view { return mutex()->mPlaybackDefaultId; }
void setCaptureDefaultId(std::wstring_view devid) const { mutex()->mCaptureDefaultId = devid; }
- std::wstring_view getCaptureDefaultId() const noexcept { return mutex()->mCaptureDefaultId; }
+ [[nodiscard]] auto getCaptureDefaultId() const noexcept -> std::wstring_view { return mutex()->mCaptureDefaultId; }
};
DeviceList gDeviceList;
@@ -302,8 +302,10 @@ using DeviceHandle = ComPtr<IMMDevice>;
using NameGUIDPair = std::pair<std::string,std::string>;
static NameGUIDPair GetDeviceNameAndGuid(const DeviceHandle &device)
{
+ /* NOLINTBEGIN(*-avoid-c-arrays) */
static constexpr char UnknownName[]{"Unknown Device Name"};
static constexpr char UnknownGuid[]{"Unknown Device GUID"};
+ /* NOLINTEND(*-avoid-c-arrays) */
#if !defined(ALSOFT_UWP)
std::string name, guid;
@@ -384,9 +386,9 @@ struct DeviceHelper final : public IActivateAudioInterfaceCompletionHandler
struct DeviceHelper final : private IMMNotificationClient
#endif
{
+#if defined(ALSOFT_UWP)
DeviceHelper()
{
-#if defined(ALSOFT_UWP)
/* TODO: UWP also needs to watch for device added/removed events and
* dynamically add/remove devices from the lists.
*/
@@ -411,8 +413,10 @@ struct DeviceHelper final : private IMMNotificationClient
msg);
}
});
-#endif
}
+#else
+ DeviceHelper() = default;
+#endif
~DeviceHelper()
{
#if defined(ALSOFT_UWP)
@@ -1071,7 +1075,7 @@ struct WasapiPlayback final : public BackendBase, WasapiProxy {
HANDLE mNotifyEvent{nullptr};
UINT32 mOrigBufferSize{}, mOrigUpdateSize{};
- std::unique_ptr<char[]> mResampleBuffer{};
+ std::vector<char> mResampleBuffer{};
uint mBufferFilled{0};
SampleConverterPtr mResampler;
@@ -1082,8 +1086,6 @@ struct WasapiPlayback final : public BackendBase, WasapiProxy {
std::atomic<bool> mKillNow{true};
std::thread mThread;
-
- DEF_NEWDEL(WasapiPlayback)
};
WasapiPlayback::~WasapiPlayback()
@@ -1151,9 +1153,9 @@ FORCE_ALIGN int WasapiPlayback::mixerProc()
{
if(mBufferFilled == 0)
{
- mDevice->renderSamples(mResampleBuffer.get(), mDevice->UpdateSize,
+ mDevice->renderSamples(mResampleBuffer.data(), mDevice->UpdateSize,
mFormat.Format.nChannels);
- resbufferptr = mResampleBuffer.get();
+ resbufferptr = mResampleBuffer.data();
mBufferFilled = mDevice->UpdateSize;
}
@@ -1249,7 +1251,7 @@ FORCE_ALIGN int WasapiPlayback::mixerSpatialProc()
tmpbuffers.resize(buffers.size());
resbuffers.resize(buffers.size());
for(size_t i{0};i < tmpbuffers.size();++i)
- resbuffers[i] = reinterpret_cast<float*>(mResampleBuffer.get()) +
+ resbuffers[i] = reinterpret_cast<float*>(mResampleBuffer.data()) +
mDevice->UpdateSize*i;
}
}
@@ -1496,7 +1498,7 @@ void WasapiPlayback::prepareFormat(WAVEFORMATEXTENSIBLE &OutputType)
void WasapiPlayback::finalizeFormat(WAVEFORMATEXTENSIBLE &OutputType)
{
- if(!GetConfigValueBool(mDevice->DeviceName.c_str(), "wasapi", "allow-resampler", true))
+ if(!GetConfigValueBool(mDevice->DeviceName, "wasapi", "allow-resampler", true))
mDevice->Frequency = OutputType.Format.nSamplesPerSec;
else
mDevice->Frequency = minu(mDevice->Frequency, OutputType.Format.nSamplesPerSec);
@@ -1610,7 +1612,7 @@ bool WasapiPlayback::reset()
HRESULT WasapiPlayback::resetProxy()
{
- if(GetConfigValueBool(mDevice->DeviceName.c_str(), "wasapi", "spatial-api", false))
+ if(GetConfigValueBool(mDevice->DeviceName, "wasapi", "spatial-api", false))
{
auto &audio = mAudio.emplace<SpatialDevice>();
HRESULT hr{sDeviceHelper->activateAudioClient(mMMDev, __uuidof(ISpatialAudioClient),
@@ -1775,7 +1777,7 @@ HRESULT WasapiPlayback::resetProxy()
mDevice->Flags.reset(DirectEar).set(Virtualization);
if(streamParams.StaticObjectTypeMask == ChannelMask_Stereo)
mDevice->FmtChans = DevFmtStereo;
- if(!GetConfigValueBool(mDevice->DeviceName.c_str(), "wasapi", "allow-resampler", true))
+ if(!GetConfigValueBool(mDevice->DeviceName, "wasapi", "allow-resampler", true))
mDevice->Frequency = OutputType.Format.nSamplesPerSec;
else
mDevice->Frequency = minu(mDevice->Frequency, OutputType.Format.nSamplesPerSec);
@@ -1819,7 +1821,8 @@ HRESULT WasapiPlayback::resetProxy()
mDevice->BufferSize = mDevice->UpdateSize*2;
mResampler = nullptr;
- mResampleBuffer = nullptr;
+ mResampleBuffer.clear();
+ mResampleBuffer.shrink_to_fit();
mBufferFilled = 0;
if(mDevice->Frequency != mFormat.Format.nSamplesPerSec)
{
@@ -1828,7 +1831,7 @@ HRESULT WasapiPlayback::resetProxy()
mResampler = SampleConverter::Create(mDevice->FmtType, mDevice->FmtType,
channelCount, mDevice->Frequency, mFormat.Format.nSamplesPerSec,
Resampler::FastBSinc24);
- mResampleBuffer = std::make_unique<char[]>(size_t{mDevice->UpdateSize} * channelCount *
+ mResampleBuffer.resize(size_t{mDevice->UpdateSize} * channelCount *
mFormat.Format.wBitsPerSample / 8);
TRACE("Created converter for %s/%s format, dst: %luhz (%u), src: %uhz (%u)\n",
@@ -1950,15 +1953,16 @@ no_spatial:
mDevice->BufferSize/2);
mResampler = nullptr;
- mResampleBuffer = nullptr;
+ mResampleBuffer.clear();
+ mResampleBuffer.shrink_to_fit();
mBufferFilled = 0;
if(mDevice->Frequency != mFormat.Format.nSamplesPerSec)
{
mResampler = SampleConverter::Create(mDevice->FmtType, mDevice->FmtType,
mFormat.Format.nChannels, mDevice->Frequency, mFormat.Format.nSamplesPerSec,
Resampler::FastBSinc24);
- mResampleBuffer = std::make_unique<char[]>(size_t{mDevice->UpdateSize} *
- mFormat.Format.nChannels * mFormat.Format.wBitsPerSample / 8);
+ mResampleBuffer.resize(size_t{mDevice->UpdateSize} * mFormat.Format.nChannels *
+ mFormat.Format.wBitsPerSample / 8);
TRACE("Created converter for %s/%s format, dst: %luhz (%u), src: %uhz (%u)\n",
DevFmtChannelsString(mDevice->FmtChans), DevFmtTypeString(mDevice->FmtType),
@@ -2072,7 +2076,7 @@ ClockLatency WasapiPlayback::getClockLatency()
ClockLatency ret;
std::lock_guard<std::mutex> _{mMutex};
- ret.ClockTime = GetDeviceClockTime(mDevice);
+ ret.ClockTime = mDevice->getClockTime();
ret.Latency = seconds{mPadding.load(std::memory_order_relaxed)};
ret.Latency /= mFormat.Format.nSamplesPerSec;
if(mResampler)
@@ -2117,8 +2121,6 @@ struct WasapiCapture final : public BackendBase, WasapiProxy {
std::atomic<bool> mKillNow{true};
std::thread mThread;
-
- DEF_NEWDEL(WasapiCapture)
};
WasapiCapture::~WasapiCapture()
@@ -2651,7 +2653,7 @@ void WasapiCapture::stopProxy()
void WasapiCapture::captureSamples(std::byte *buffer, uint samples)
-{ mRing->read(buffer, samples); }
+{ std::ignore = mRing->read(buffer, samples); }
uint WasapiCapture::availableSamples()
{ return static_cast<uint>(mRing->readSpace()); }
diff --git a/alc/backends/wave.cpp b/alc/backends/wave.cpp
index 794d5cb8..985bb539 100644
--- a/alc/backends/wave.cpp
+++ b/alc/backends/wave.cpp
@@ -55,38 +55,44 @@ using std::chrono::nanoseconds;
using ubyte = unsigned char;
using ushort = unsigned short;
+struct FileDeleter {
+ void operator()(gsl::owner<FILE*> f) { fclose(f); }
+};
+using FilePtr = std::unique_ptr<FILE,FileDeleter>;
+
+/* NOLINTNEXTLINE(*-avoid-c-arrays) */
constexpr char waveDevice[] = "Wave File Writer";
-constexpr ubyte SUBTYPE_PCM[]{
+constexpr std::array<ubyte,16> SUBTYPE_PCM{{
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa,
0x00, 0x38, 0x9b, 0x71
-};
-constexpr ubyte SUBTYPE_FLOAT[]{
+}};
+constexpr std::array<ubyte,16> SUBTYPE_FLOAT{{
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa,
0x00, 0x38, 0x9b, 0x71
-};
+}};
-constexpr ubyte SUBTYPE_BFORMAT_PCM[]{
+constexpr std::array<ubyte,16> SUBTYPE_BFORMAT_PCM{{
0x01, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1,
0xca, 0x00, 0x00, 0x00
-};
+}};
-constexpr ubyte SUBTYPE_BFORMAT_FLOAT[]{
+constexpr std::array<ubyte,16> SUBTYPE_BFORMAT_FLOAT{{
0x03, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1,
0xca, 0x00, 0x00, 0x00
-};
+}};
void fwrite16le(ushort val, FILE *f)
{
- ubyte data[2]{ static_cast<ubyte>(val&0xff), static_cast<ubyte>((val>>8)&0xff) };
- fwrite(data, 1, 2, f);
+ std::array data{static_cast<ubyte>(val&0xff), static_cast<ubyte>((val>>8)&0xff)};
+ fwrite(data.data(), 1, data.size(), f);
}
void fwrite32le(uint val, FILE *f)
{
- ubyte data[4]{ static_cast<ubyte>(val&0xff), static_cast<ubyte>((val>>8)&0xff),
- static_cast<ubyte>((val>>16)&0xff), static_cast<ubyte>((val>>24)&0xff) };
- fwrite(data, 1, 4, f);
+ std::array data{static_cast<ubyte>(val&0xff), static_cast<ubyte>((val>>8)&0xff),
+ static_cast<ubyte>((val>>16)&0xff), static_cast<ubyte>((val>>24)&0xff)};
+ fwrite(data.data(), 1, data.size(), f);
}
@@ -101,23 +107,16 @@ struct WaveBackend final : public BackendBase {
void start() override;
void stop() override;
- FILE *mFile{nullptr};
+ FilePtr mFile{nullptr};
long mDataStart{-1};
std::vector<std::byte> mBuffer;
std::atomic<bool> mKillNow{true};
std::thread mThread;
-
- DEF_NEWDEL(WaveBackend)
};
-WaveBackend::~WaveBackend()
-{
- if(mFile)
- fclose(mFile);
- mFile = nullptr;
-}
+WaveBackend::~WaveBackend() = default;
int WaveBackend::mixerProc()
{
@@ -169,8 +168,8 @@ int WaveBackend::mixerProc()
}
}
- const size_t fs{fwrite(mBuffer.data(), frameSize, mDevice->UpdateSize, mFile)};
- if(fs < mDevice->UpdateSize || ferror(mFile))
+ const size_t fs{fwrite(mBuffer.data(), frameSize, mDevice->UpdateSize, mFile.get())};
+ if(fs < mDevice->UpdateSize || ferror(mFile.get()))
{
ERR("Error writing to file\n");
mDevice->handleDisconnect("Failed to write playback samples");
@@ -196,7 +195,7 @@ int WaveBackend::mixerProc()
void WaveBackend::open(std::string_view name)
{
- auto fname = ConfigValueStr(nullptr, "wave", "file");
+ auto fname = ConfigValueStr({}, "wave", "file");
if(!fname) throw al::backend_exception{al::backend_error::NoDevice,
"No wave output filename"};
@@ -212,10 +211,10 @@ void WaveBackend::open(std::string_view name)
#ifdef _WIN32
{
std::wstring wname{utf8_to_wstr(fname.value())};
- mFile = _wfopen(wname.c_str(), L"wb");
+ mFile = FilePtr{_wfopen(wname.c_str(), L"wb")};
}
#else
- mFile = fopen(fname->c_str(), "wb");
+ mFile = FilePtr{fopen(fname->c_str(), "wb")};
#endif
if(!mFile)
throw al::backend_exception{al::backend_error::DeviceError, "Could not open file '%s': %s",
@@ -228,12 +227,11 @@ bool WaveBackend::reset()
{
uint channels{0}, bytes{0}, chanmask{0};
bool isbformat{false};
- size_t val;
- fseek(mFile, 0, SEEK_SET);
- clearerr(mFile);
+ fseek(mFile.get(), 0, SEEK_SET);
+ clearerr(mFile.get());
- if(GetConfigValueBool(nullptr, "wave", "bformat", false))
+ if(GetConfigValueBool({}, "wave", "bformat", false))
{
mDevice->FmtChans = DevFmtAmbi3D;
mDevice->mAmbiOrder = 1;
@@ -282,49 +280,48 @@ bool WaveBackend::reset()
bytes = mDevice->bytesFromFmt();
channels = mDevice->channelsFromFmt();
- rewind(mFile);
+ rewind(mFile.get());
- fputs("RIFF", mFile);
- fwrite32le(0xFFFFFFFF, mFile); // 'RIFF' header len; filled in at close
+ fputs("RIFF", mFile.get());
+ fwrite32le(0xFFFFFFFF, mFile.get()); // 'RIFF' header len; filled in at close
- fputs("WAVE", mFile);
+ fputs("WAVE", mFile.get());
- fputs("fmt ", mFile);
- fwrite32le(40, mFile); // 'fmt ' header len; 40 bytes for EXTENSIBLE
+ fputs("fmt ", mFile.get());
+ fwrite32le(40, mFile.get()); // 'fmt ' header len; 40 bytes for EXTENSIBLE
// 16-bit val, format type id (extensible: 0xFFFE)
- fwrite16le(0xFFFE, mFile);
+ fwrite16le(0xFFFE, mFile.get());
// 16-bit val, channel count
- fwrite16le(static_cast<ushort>(channels), mFile);
+ fwrite16le(static_cast<ushort>(channels), mFile.get());
// 32-bit val, frequency
- fwrite32le(mDevice->Frequency, mFile);
+ fwrite32le(mDevice->Frequency, mFile.get());
// 32-bit val, bytes per second
- fwrite32le(mDevice->Frequency * channels * bytes, mFile);
+ fwrite32le(mDevice->Frequency * channels * bytes, mFile.get());
// 16-bit val, frame size
- fwrite16le(static_cast<ushort>(channels * bytes), mFile);
+ fwrite16le(static_cast<ushort>(channels * bytes), mFile.get());
// 16-bit val, bits per sample
- fwrite16le(static_cast<ushort>(bytes * 8), mFile);
+ fwrite16le(static_cast<ushort>(bytes * 8), mFile.get());
// 16-bit val, extra byte count
- fwrite16le(22, mFile);
+ fwrite16le(22, mFile.get());
// 16-bit val, valid bits per sample
- fwrite16le(static_cast<ushort>(bytes * 8), mFile);
+ fwrite16le(static_cast<ushort>(bytes * 8), mFile.get());
// 32-bit val, channel mask
- fwrite32le(chanmask, mFile);
+ fwrite32le(chanmask, mFile.get());
// 16 byte GUID, sub-type format
- val = fwrite((mDevice->FmtType == DevFmtFloat) ?
- (isbformat ? SUBTYPE_BFORMAT_FLOAT : SUBTYPE_FLOAT) :
- (isbformat ? SUBTYPE_BFORMAT_PCM : SUBTYPE_PCM), 1, 16, mFile);
- (void)val;
+ std::ignore = fwrite((mDevice->FmtType == DevFmtFloat) ?
+ (isbformat ? SUBTYPE_BFORMAT_FLOAT.data() : SUBTYPE_FLOAT.data()) :
+ (isbformat ? SUBTYPE_BFORMAT_PCM.data() : SUBTYPE_PCM.data()), 1, 16, mFile.get());
- fputs("data", mFile);
- fwrite32le(0xFFFFFFFF, mFile); // 'data' header len; filled in at close
+ fputs("data", mFile.get());
+ fwrite32le(0xFFFFFFFF, mFile.get()); // 'data' header len; filled in at close
- if(ferror(mFile))
+ if(ferror(mFile.get()))
{
ERR("Error writing header: %s\n", strerror(errno));
return false;
}
- mDataStart = ftell(mFile);
+ mDataStart = ftell(mFile.get());
setDefaultWFXChannelOrder();
@@ -336,7 +333,7 @@ bool WaveBackend::reset()
void WaveBackend::start()
{
- if(mDataStart > 0 && fseek(mFile, 0, SEEK_END) != 0)
+ if(mDataStart > 0 && fseek(mFile.get(), 0, SEEK_END) != 0)
WARN("Failed to seek on output file\n");
try {
mKillNow.store(false, std::memory_order_release);
@@ -356,14 +353,14 @@ void WaveBackend::stop()
if(mDataStart > 0)
{
- long size{ftell(mFile)};
+ long size{ftell(mFile.get())};
if(size > 0)
{
long dataLen{size - mDataStart};
- if(fseek(mFile, 4, SEEK_SET) == 0)
- fwrite32le(static_cast<uint>(size-8), mFile); // 'WAVE' header len
- if(fseek(mFile, mDataStart-4, SEEK_SET) == 0)
- fwrite32le(static_cast<uint>(dataLen), mFile); // 'data' header len
+ if(fseek(mFile.get(), 4, SEEK_SET) == 0)
+ fwrite32le(static_cast<uint>(size-8), mFile.get()); // 'WAVE' header len
+ if(fseek(mFile.get(), mDataStart-4, SEEK_SET) == 0)
+ fwrite32le(static_cast<uint>(dataLen), mFile.get()); // 'data' header len
}
}
}
diff --git a/alc/backends/winmm.cpp b/alc/backends/winmm.cpp
index f0fb0a1c..e593defb 100644
--- a/alc/backends/winmm.cpp
+++ b/alc/backends/winmm.cpp
@@ -22,8 +22,8 @@
#include "winmm.h"
-#include <stdlib.h>
-#include <stdio.h>
+#include <cstdlib>
+#include <cstdio>
#include <memory.h>
#include <windows.h>
@@ -46,6 +46,7 @@
#include "core/logging.h"
#include "ringbuffer.h"
#include "strutils.h"
+#include "vector.h"
#ifndef WAVE_FORMAT_IEEE_FLOAT
#define WAVE_FORMAT_IEEE_FLOAT 0x0003
@@ -62,7 +63,7 @@ std::vector<std::string> CaptureDevices;
bool checkName(const std::vector<std::string> &list, const std::string &name)
{ return std::find(list.cbegin(), list.cend(), name) != list.cend(); }
-void ProbePlaybackDevices(void)
+void ProbePlaybackDevices()
{
PlaybackDevices.clear();
@@ -93,7 +94,7 @@ void ProbePlaybackDevices(void)
}
}
-void ProbeCaptureDevices(void)
+void ProbeCaptureDevices()
{
CaptureDevices.clear();
@@ -144,6 +145,7 @@ struct WinMMPlayback final : public BackendBase {
al::semaphore mSem;
uint mIdx{0u};
std::array<WAVEHDR,4> mWaveBuffer{};
+ al::vector<char,16> mBuffer;
HWAVEOUT mOutHdl{nullptr};
@@ -151,8 +153,6 @@ struct WinMMPlayback final : public BackendBase {
std::atomic<bool> mKillNow{true};
std::thread mThread;
-
- DEF_NEWDEL(WinMMPlayback)
};
WinMMPlayback::~WinMMPlayback()
@@ -160,9 +160,6 @@ WinMMPlayback::~WinMMPlayback()
if(mOutHdl)
waveOutClose(mOutHdl);
mOutHdl = nullptr;
-
- al_free(mWaveBuffer[0].lpData);
- std::fill(mWaveBuffer.begin(), mWaveBuffer.end(), WAVEHDR{});
}
/* WinMMPlayback::waveOutProc
@@ -313,11 +310,11 @@ bool WinMMPlayback::reset()
}
setDefaultWFXChannelOrder();
- uint BufferSize{mDevice->UpdateSize * mFormat.nChannels * mDevice->bytesFromFmt()};
+ const uint BufferSize{mDevice->UpdateSize * mFormat.nChannels * mDevice->bytesFromFmt()};
- al_free(mWaveBuffer[0].lpData);
+ decltype(mBuffer)(BufferSize*mWaveBuffer.size()).swap(mBuffer);
mWaveBuffer[0] = WAVEHDR{};
- mWaveBuffer[0].lpData = static_cast<char*>(al_calloc(16, BufferSize * mWaveBuffer.size()));
+ mWaveBuffer[0].lpData = mBuffer.data();
mWaveBuffer[0].dwBufferLength = BufferSize;
for(size_t i{1};i < mWaveBuffer.size();i++)
{
@@ -380,6 +377,7 @@ struct WinMMCapture final : public BackendBase {
al::semaphore mSem;
uint mIdx{0};
std::array<WAVEHDR,4> mWaveBuffer{};
+ al::vector<char,16> mBuffer;
HWAVEIN mInHdl{nullptr};
@@ -389,8 +387,6 @@ struct WinMMCapture final : public BackendBase {
std::atomic<bool> mKillNow{true};
std::thread mThread;
-
- DEF_NEWDEL(WinMMCapture)
};
WinMMCapture::~WinMMCapture()
@@ -399,9 +395,6 @@ WinMMCapture::~WinMMCapture()
if(mInHdl)
waveInClose(mInHdl);
mInHdl = nullptr;
-
- al_free(mWaveBuffer[0].lpData);
- std::fill(mWaveBuffer.begin(), mWaveBuffer.end(), WAVEHDR{});
}
/* WinMMCapture::waveInProc
@@ -435,7 +428,8 @@ int WinMMCapture::captureProc()
WAVEHDR &waveHdr = mWaveBuffer[widx];
widx = (widx+1) % mWaveBuffer.size();
- mRing->write(waveHdr.lpData, waveHdr.dwBytesRecorded / mFormat.nBlockAlign);
+ std::ignore = mRing->write(waveHdr.lpData,
+ waveHdr.dwBytesRecorded / mFormat.nBlockAlign);
mReadable.fetch_sub(1, std::memory_order_acq_rel);
waveInAddBuffer(mInHdl, &waveHdr, sizeof(WAVEHDR));
} while(--todo);
@@ -519,9 +513,9 @@ void WinMMCapture::open(std::string_view name)
mRing = RingBuffer::Create(CapturedDataSize, mFormat.nBlockAlign, false);
- al_free(mWaveBuffer[0].lpData);
+ decltype(mBuffer)(BufferSize*mWaveBuffer.size()).swap(mBuffer);
mWaveBuffer[0] = WAVEHDR{};
- mWaveBuffer[0].lpData = static_cast<char*>(al_calloc(16, BufferSize * mWaveBuffer.size()));
+ mWaveBuffer[0].lpData = mBuffer.data();
mWaveBuffer[0].dwBufferLength = BufferSize;
for(size_t i{1};i < mWaveBuffer.size();++i)
{
@@ -573,7 +567,7 @@ void WinMMCapture::stop()
}
void WinMMCapture::captureSamples(std::byte *buffer, uint samples)
-{ mRing->read(buffer, samples); }
+{ std::ignore = mRing->read(buffer, samples); }
uint WinMMCapture::availableSamples()
{ return static_cast<uint>(mRing->readSpace()); }
diff --git a/alc/context.cpp b/alc/context.cpp
index ffc2743e..67f08aee 100644
--- a/alc/context.cpp
+++ b/alc/context.cpp
@@ -5,11 +5,11 @@
#include <algorithm>
#include <array>
+#include <cstddef>
#include <cstring>
#include <functional>
#include <limits>
#include <numeric>
-#include <stddef.h>
#include <stdexcept>
#include <string_view>
#include <utility>
@@ -24,6 +24,7 @@
#include "al/listener.h"
#include "albit.h"
#include "alc/alu.h"
+#include "alc/backends/base.h"
#include "alspan.h"
#include "core/async_event.h"
#include "core/device.h"
@@ -32,6 +33,7 @@
#include "core/voice.h"
#include "core/voice_change.h"
#include "device.h"
+#include "flexarray.h"
#include "ringbuffer.h"
#include "vecmat.h"
@@ -163,9 +165,13 @@ void ALCcontext::init()
else
{
auxslots = EffectSlot::CreatePtrArray(1);
- (*auxslots)[0] = mDefaultSlot->mSlot;
- mDefaultSlot->mState = SlotState::Playing;
+ if(auxslots)
+ {
+ (*auxslots)[0] = mDefaultSlot->mSlot;
+ mDefaultSlot->mState = SlotState::Playing;
+ }
}
+ if(!auxslots) throw std::bad_alloc{};
mActiveAuxSlots.store(auxslots, std::memory_order_relaxed);
allocVoiceChanges();
@@ -231,7 +237,7 @@ void ALCcontext::init()
mActiveVoiceCount.store(64, std::memory_order_relaxed);
}
-bool ALCcontext::deinit()
+void ALCcontext::deinit()
{
if(sLocalContext == this)
{
@@ -251,18 +257,14 @@ bool ALCcontext::deinit()
dec_ref();
}
- bool ret{};
+ bool stopPlayback{};
/* First make sure this context exists in the device's list. */
auto *oldarray = mDevice->mContexts.load(std::memory_order_acquire);
if(auto toremove = static_cast<size_t>(std::count(oldarray->begin(), oldarray->end(), this)))
{
using ContextArray = al::FlexArray<ContextBase*>;
- auto alloc_ctx_array = [](const size_t count) -> ContextArray*
- {
- if(count == 0) return &DeviceBase::sEmptyContextArray;
- return ContextArray::Create(count).release();
- };
- auto *newarray = alloc_ctx_array(oldarray->size() - toremove);
+ const size_t newsize{oldarray->size() - toremove};
+ auto newarray = ContextArray::Create(newsize);
/* Copy the current/old context handles to the new array, excluding the
* given context.
@@ -273,21 +275,21 @@ bool ALCcontext::deinit()
/* Store the new context array in the device. Wait for any current mix
* to finish before deleting the old array.
*/
- mDevice->mContexts.store(newarray);
- if(oldarray != &DeviceBase::sEmptyContextArray)
- {
- mDevice->waitForMix();
- delete oldarray;
- }
+ auto prevarray = mDevice->mContexts.exchange(std::move(newarray));
+ std::ignore = mDevice->waitForMix();
- ret = !newarray->empty();
+ stopPlayback = (newsize == 0);
}
else
- ret = !oldarray->empty();
+ stopPlayback = oldarray->empty();
StopEventThrd(this);
- return ret;
+ if(stopPlayback && mALDevice->mDeviceState == DeviceState::Playing)
+ {
+ mALDevice->Backend->stop();
+ mALDevice->mDeviceState = DeviceState::Configured;
+ }
}
void ALCcontext::applyAllUpdates()
@@ -328,10 +330,10 @@ void ForEachSource(ALCcontext *context, F func)
uint64_t usemask{~sublist.FreeMask};
while(usemask)
{
- const int idx{al::countr_zero(usemask)};
+ const auto idx = static_cast<uint>(al::countr_zero(usemask));
usemask &= ~(1_u64 << idx);
- func(sublist.Sources[idx]);
+ func((*sublist.Sources)[idx]);
}
}
}
@@ -576,7 +578,7 @@ void ALCcontext::eax_update_speaker_configuration()
void ALCcontext::eax_set_last_error_defaults() noexcept
{
- mEaxLastError = EAX_OK;
+ mEaxLastError = EAXCONTEXT_DEFAULTLASTERROR;
}
void ALCcontext::eax_session_set_defaults() noexcept
@@ -665,6 +667,7 @@ void ALCcontext::eax_get_misc(const EaxCall& call)
break;
case EAXCONTEXT_LASTERROR:
call.set_value<ContextException>(mEaxLastError);
+ mEaxLastError = EAX_OK;
break;
case EAXCONTEXT_SPEAKERCONFIG:
call.set_value<ContextException>(mEaxSpeakerConfig);
@@ -1035,6 +1038,7 @@ try
}
catch(...)
{
+ context->eaxSetLastError();
eax_log_exception(__func__);
return AL_INVALID_OPERATION;
}
@@ -1062,6 +1066,7 @@ try
}
catch(...)
{
+ context->eaxSetLastError();
eax_log_exception(__func__);
return AL_INVALID_OPERATION;
}
diff --git a/alc/context.h b/alc/context.h
index 201c8873..e27d10d3 100644
--- a/alc/context.h
+++ b/alc/context.h
@@ -1,6 +1,7 @@
#ifndef ALC_CONTEXT_H
#define ALC_CONTEXT_H
+#include <array>
#include <atomic>
#include <deque>
#include <memory>
@@ -36,6 +37,8 @@ struct ALeffect;
struct ALeffectslot;
struct ALsource;
struct DebugGroup;
+struct EffectSlotSubList;
+struct SourceSubList;
enum class DebugSource : uint8_t;
enum class DebugType : uint8_t;
@@ -68,37 +71,6 @@ struct DebugLogEntry {
};
-struct SourceSubList {
- uint64_t FreeMask{~0_u64};
- ALsource *Sources{nullptr}; /* 64 */
-
- SourceSubList() noexcept = default;
- SourceSubList(const SourceSubList&) = delete;
- SourceSubList(SourceSubList&& rhs) noexcept : FreeMask{rhs.FreeMask}, Sources{rhs.Sources}
- { rhs.FreeMask = ~0_u64; rhs.Sources = nullptr; }
- ~SourceSubList();
-
- SourceSubList& operator=(const SourceSubList&) = delete;
- SourceSubList& operator=(SourceSubList&& rhs) noexcept
- { std::swap(FreeMask, rhs.FreeMask); std::swap(Sources, rhs.Sources); return *this; }
-};
-
-struct EffectSlotSubList {
- uint64_t FreeMask{~0_u64};
- ALeffectslot *EffectSlots{nullptr}; /* 64 */
-
- EffectSlotSubList() noexcept = default;
- EffectSlotSubList(const EffectSlotSubList&) = delete;
- EffectSlotSubList(EffectSlotSubList&& rhs) noexcept
- : FreeMask{rhs.FreeMask}, EffectSlots{rhs.EffectSlots}
- { rhs.FreeMask = ~0_u64; rhs.EffectSlots = nullptr; }
- ~EffectSlotSubList();
-
- EffectSlotSubList& operator=(const EffectSlotSubList&) = delete;
- EffectSlotSubList& operator=(EffectSlotSubList&& rhs) noexcept
- { std::swap(FreeMask, rhs.FreeMask); std::swap(EffectSlots, rhs.EffectSlots); return *this; }
-};
-
struct ALCcontext : public al::intrusive_ref<ALCcontext>, ContextBase {
const al::intrusive_ptr<ALCdevice> mALDevice;
@@ -158,10 +130,10 @@ struct ALCcontext : public al::intrusive_ref<ALCcontext>, ContextBase {
void init();
/**
* Removes the context from its device and removes it from being current on
- * the running thread or globally. Returns true if other contexts still
- * exist on the device.
+ * the running thread or globally. Stops device playback if this was the
+ * last context on its device.
*/
- bool deinit();
+ void deinit();
/**
* Defers/suspends updates for the given context's listener and sources.
@@ -186,8 +158,8 @@ struct ALCcontext : public al::intrusive_ref<ALCcontext>, ContextBase {
*/
void applyAllUpdates();
-#ifdef __USE_MINGW_ANSI_STDIO
- [[gnu::format(gnu_printf, 3, 4)]]
+#ifdef __MINGW32__
+ [[gnu::format(__MINGW_PRINTF_FORMAT, 3, 4)]]
#else
[[gnu::format(printf, 3, 4)]]
#endif
@@ -230,10 +202,7 @@ public:
/* Default effect that applies to sources that don't have an effect on send 0. */
static ALeffect sDefaultEffect;
- DEF_NEWDEL(ALCcontext)
-
#ifdef ALSOFT_EAX
-public:
bool hasEax() const noexcept { return mEaxIsInitialized; }
bool eaxIsCapable() const noexcept;
@@ -560,7 +529,7 @@ private:
using ContextRef = al::intrusive_ptr<ALCcontext>;
-ContextRef GetContextRef(void);
+ContextRef GetContextRef();
void UpdateContextProps(ALCcontext *context);
diff --git a/alc/device.cpp b/alc/device.cpp
index 27aa6f36..fc145579 100644
--- a/alc/device.cpp
+++ b/alc/device.cpp
@@ -3,9 +3,12 @@
#include "device.h"
+#include <cstddef>
#include <numeric>
-#include <stddef.h>
+#include "al/buffer.h"
+#include "al/effect.h"
+#include "al/filter.h"
#include "albit.h"
#include "alconfig.h"
#include "backends/base.h"
@@ -55,8 +58,8 @@ ALCdevice::~ALCdevice()
void ALCdevice::enumerateHrtfs()
{
- mHrtfList = EnumerateHrtf(configValue<std::string>(nullptr, "hrtf-paths"));
- if(auto defhrtfopt = configValue<std::string>(nullptr, "default-hrtf"))
+ mHrtfList = EnumerateHrtf(configValue<std::string>({}, "hrtf-paths"));
+ if(auto defhrtfopt = configValue<std::string>({}, "default-hrtf"))
{
auto iter = std::find(mHrtfList.begin(), mHrtfList.end(), *defhrtfopt);
if(iter == mHrtfList.end())
diff --git a/alc/device.h b/alc/device.h
index 66f37a7e..dd9335dc 100644
--- a/alc/device.h
+++ b/alc/device.h
@@ -1,6 +1,7 @@
#ifndef ALC_DEVICE_H
#define ALC_DEVICE_H
+#include <array>
#include <atomic>
#include <memory>
#include <mutex>
@@ -29,56 +30,13 @@ struct ALbuffer;
struct ALeffect;
struct ALfilter;
struct BackendBase;
+struct BufferSubList;
+struct EffectSubList;
+struct FilterSubList;
using uint = unsigned int;
-struct BufferSubList {
- uint64_t FreeMask{~0_u64};
- ALbuffer *Buffers{nullptr}; /* 64 */
-
- BufferSubList() noexcept = default;
- BufferSubList(const BufferSubList&) = delete;
- BufferSubList(BufferSubList&& rhs) noexcept : FreeMask{rhs.FreeMask}, Buffers{rhs.Buffers}
- { rhs.FreeMask = ~0_u64; rhs.Buffers = nullptr; }
- ~BufferSubList();
-
- BufferSubList& operator=(const BufferSubList&) = delete;
- BufferSubList& operator=(BufferSubList&& rhs) noexcept
- { std::swap(FreeMask, rhs.FreeMask); std::swap(Buffers, rhs.Buffers); return *this; }
-};
-
-struct EffectSubList {
- uint64_t FreeMask{~0_u64};
- ALeffect *Effects{nullptr}; /* 64 */
-
- EffectSubList() noexcept = default;
- EffectSubList(const EffectSubList&) = delete;
- EffectSubList(EffectSubList&& rhs) noexcept : FreeMask{rhs.FreeMask}, Effects{rhs.Effects}
- { rhs.FreeMask = ~0_u64; rhs.Effects = nullptr; }
- ~EffectSubList();
-
- EffectSubList& operator=(const EffectSubList&) = delete;
- EffectSubList& operator=(EffectSubList&& rhs) noexcept
- { std::swap(FreeMask, rhs.FreeMask); std::swap(Effects, rhs.Effects); return *this; }
-};
-
-struct FilterSubList {
- uint64_t FreeMask{~0_u64};
- ALfilter *Filters{nullptr}; /* 64 */
-
- FilterSubList() noexcept = default;
- FilterSubList(const FilterSubList&) = delete;
- FilterSubList(FilterSubList&& rhs) noexcept : FreeMask{rhs.FreeMask}, Filters{rhs.Filters}
- { rhs.FreeMask = ~0_u64; rhs.Filters = nullptr; }
- ~FilterSubList();
-
- FilterSubList& operator=(const FilterSubList&) = delete;
- FilterSubList& operator=(FilterSubList&& rhs) noexcept
- { std::swap(FreeMask, rhs.FreeMask); std::swap(Filters, rhs.Filters); return *this; }
-};
-
-
struct ALCdevice : public al::intrusive_ref<ALCdevice>, DeviceBase {
/* This lock protects the device state (format, update size, etc) from
* being from being changed in multiple threads, or being accessed while
@@ -143,30 +101,28 @@ struct ALCdevice : public al::intrusive_ref<ALCdevice>, DeviceBase {
void enumerateHrtfs();
- bool getConfigValueBool(const char *block, const char *key, bool def)
- { return GetConfigValueBool(DeviceName.c_str(), block, key, def); }
+ bool getConfigValueBool(const std::string_view block, const std::string_view key, bool def)
+ { return GetConfigValueBool(DeviceName, block, key, def); }
template<typename T>
- inline std::optional<T> configValue(const char *block, const char *key) = delete;
-
- DEF_NEWDEL(ALCdevice)
+ inline std::optional<T> configValue(const std::string_view block, const std::string_view key) = delete;
};
template<>
-inline std::optional<std::string> ALCdevice::configValue(const char *block, const char *key)
-{ return ConfigValueStr(DeviceName.c_str(), block, key); }
+inline std::optional<std::string> ALCdevice::configValue(const std::string_view block, const std::string_view key)
+{ return ConfigValueStr(DeviceName, block, key); }
template<>
-inline std::optional<int> ALCdevice::configValue(const char *block, const char *key)
-{ return ConfigValueInt(DeviceName.c_str(), block, key); }
+inline std::optional<int> ALCdevice::configValue(const std::string_view block, const std::string_view key)
+{ return ConfigValueInt(DeviceName, block, key); }
template<>
-inline std::optional<uint> ALCdevice::configValue(const char *block, const char *key)
-{ return ConfigValueUInt(DeviceName.c_str(), block, key); }
+inline std::optional<uint> ALCdevice::configValue(const std::string_view block, const std::string_view key)
+{ return ConfigValueUInt(DeviceName, block, key); }
template<>
-inline std::optional<float> ALCdevice::configValue(const char *block, const char *key)
-{ return ConfigValueFloat(DeviceName.c_str(), block, key); }
+inline std::optional<float> ALCdevice::configValue(const std::string_view block, const std::string_view key)
+{ return ConfigValueFloat(DeviceName, block, key); }
template<>
-inline std::optional<bool> ALCdevice::configValue(const char *block, const char *key)
-{ return ConfigValueBool(DeviceName.c_str(), block, key); }
+inline std::optional<bool> ALCdevice::configValue(const std::string_view block, const std::string_view key)
+{ return ConfigValueBool(DeviceName, block, key); }
/** Stores the latest ALC device error. */
void alcSetError(ALCdevice *device, ALCenum errorCode);
diff --git a/alc/effects/autowah.cpp b/alc/effects/autowah.cpp
index 4f874ef2..424230e8 100644
--- a/alc/effects/autowah.cpp
+++ b/alc/effects/autowah.cpp
@@ -50,35 +50,37 @@ constexpr float QFactor{5.0f};
struct AutowahState final : public EffectState {
/* Effect parameters */
- float mAttackRate;
- float mReleaseRate;
- float mResonanceGain;
- float mPeakGain;
- float mFreqMinNorm;
- float mBandwidthNorm;
- float mEnvDelay;
+ float mAttackRate{};
+ float mReleaseRate{};
+ float mResonanceGain{};
+ float mPeakGain{};
+ float mFreqMinNorm{};
+ float mBandwidthNorm{};
+ float mEnvDelay{};
/* Filter components derived from the envelope. */
- struct {
- float cos_w0;
- float alpha;
- } mEnv[BufferLineSize];
+ struct FilterParam {
+ float cos_w0{};
+ float alpha{};
+ };
+ std::array<FilterParam,BufferLineSize> mEnv;
- struct {
+ struct ChannelData {
uint mTargetChannel{InvalidChannelIndex};
/* Effect filters' history. */
struct {
- float z1, z2;
+ float z1{}, z2{};
} mFilter;
/* Effect gains for each output channel */
- float mCurrentGain;
- float mTargetGain;
- } mChans[MaxAmbiChannels];
+ float mCurrentGain{};
+ float mTargetGain{};
+ };
+ std::array<ChannelData,MaxAmbiChannels> mChans;
/* Effects buffers */
- alignas(16) float mBufferOut[BufferLineSize];
+ alignas(16) FloatBufferLine mBufferOut{};
void deviceUpdate(const DeviceBase *device, const BufferStorage *buffer) override;
@@ -86,8 +88,6 @@ struct AutowahState final : public EffectState {
const EffectTarget target) override;
void process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn,
const al::span<FloatBufferLine> samplesOut) override;
-
- DEF_NEWDEL(AutowahState)
};
void AutowahState::deviceUpdate(const DeviceBase*, const BufferStorage*)
@@ -118,18 +118,19 @@ void AutowahState::deviceUpdate(const DeviceBase*, const BufferStorage*)
}
void AutowahState::update(const ContextBase *context, const EffectSlot *slot,
- const EffectProps *props, const EffectTarget target)
+ const EffectProps *props_, const EffectTarget target)
{
+ auto &props = std::get<AutowahProps>(*props_);
const DeviceBase *device{context->mDevice};
const auto frequency = static_cast<float>(device->Frequency);
- const float ReleaseTime{clampf(props->Autowah.ReleaseTime, 0.001f, 1.0f)};
+ const float ReleaseTime{clampf(props.ReleaseTime, 0.001f, 1.0f)};
- mAttackRate = std::exp(-1.0f / (props->Autowah.AttackTime*frequency));
+ mAttackRate = std::exp(-1.0f / (props.AttackTime*frequency));
mReleaseRate = std::exp(-1.0f / (ReleaseTime*frequency));
/* 0-20dB Resonance Peak gain */
- mResonanceGain = std::sqrt(std::log10(props->Autowah.Resonance)*10.0f / 3.0f);
- mPeakGain = 1.0f - std::log10(props->Autowah.PeakGain / GainScale);
+ mResonanceGain = std::sqrt(std::log10(props.Resonance)*10.0f / 3.0f);
+ mPeakGain = 1.0f - std::log10(props.PeakGain / GainScale);
mFreqMinNorm = MinFreq / frequency;
mBandwidthNorm = (MaxFreq-MinFreq) / frequency;
@@ -155,17 +156,16 @@ void AutowahState::process(const size_t samplesToDo,
float env_delay{mEnvDelay};
for(size_t i{0u};i < samplesToDo;i++)
{
- float w0, sample, a;
-
/* Envelope follower described on the book: Audio Effects, Theory,
* Implementation and Application.
*/
- sample = peak_gain * std::fabs(samplesIn[0][i]);
- a = (sample > env_delay) ? attack_rate : release_rate;
+ const float sample{peak_gain * std::fabs(samplesIn[0][i])};
+ const float a{(sample > env_delay) ? attack_rate : release_rate};
env_delay = lerpf(sample, env_delay, a);
/* Calculate the cos and alpha components for this sample's filter. */
- w0 = minf((bandwidth*env_delay + freq_min), 0.46f) * (al::numbers::pi_v<float>*2.0f);
+ const float w0{minf((bandwidth*env_delay + freq_min), 0.46f) *
+ (al::numbers::pi_v<float>*2.0f)};
mEnv[i].cos_w0 = std::cos(w0);
mEnv[i].alpha = std::sin(w0)/(2.0f * QFactor);
}
@@ -194,18 +194,18 @@ void AutowahState::process(const size_t samplesToDo,
{
const float alpha{mEnv[i].alpha};
const float cos_w0{mEnv[i].cos_w0};
- float input, output;
- float a[3], b[3];
-
- b[0] = 1.0f + alpha*res_gain;
- b[1] = -2.0f * cos_w0;
- b[2] = 1.0f - alpha*res_gain;
- a[0] = 1.0f + alpha/res_gain;
- a[1] = -2.0f * cos_w0;
- a[2] = 1.0f - alpha/res_gain;
-
- input = insamples[i];
- output = input*(b[0]/a[0]) + z1;
+
+ const std::array b{
+ 1.0f + alpha*res_gain,
+ -2.0f * cos_w0,
+ 1.0f - alpha*res_gain};
+ const std::array a{
+ 1.0f + alpha/res_gain,
+ -2.0f * cos_w0,
+ 1.0f - alpha/res_gain};
+
+ const float input{insamples[i]};
+ const float output{input*(b[0]/a[0]) + z1};
z1 = input*(b[1]/a[0]) - output*(a[1]/a[0]) + z2;
z2 = input*(b[2]/a[0]) - output*(a[2]/a[0]);
mBufferOut[i] = output;
@@ -214,8 +214,8 @@ void AutowahState::process(const size_t samplesToDo,
chandata->mFilter.z2 = z2;
/* Now, mix the processed sound data to the output. */
- MixSamples({mBufferOut, samplesToDo}, samplesOut[outidx].data(), chandata->mCurrentGain,
- chandata->mTargetGain, samplesToDo);
+ MixSamples({mBufferOut.data(), samplesToDo}, samplesOut[outidx].data(),
+ chandata->mCurrentGain, chandata->mTargetGain, samplesToDo);
++chandata;
}
}
diff --git a/alc/effects/base.h b/alc/effects/base.h
index 95695857..9bbbfc71 100644
--- a/alc/effects/base.h
+++ b/alc/effects/base.h
@@ -4,23 +4,30 @@
#include "core/effects/base.h"
-EffectStateFactory *NullStateFactory_getFactory(void);
-EffectStateFactory *ReverbStateFactory_getFactory(void);
-EffectStateFactory *StdReverbStateFactory_getFactory(void);
-EffectStateFactory *AutowahStateFactory_getFactory(void);
-EffectStateFactory *ChorusStateFactory_getFactory(void);
-EffectStateFactory *CompressorStateFactory_getFactory(void);
-EffectStateFactory *DistortionStateFactory_getFactory(void);
-EffectStateFactory *EchoStateFactory_getFactory(void);
-EffectStateFactory *EqualizerStateFactory_getFactory(void);
-EffectStateFactory *FlangerStateFactory_getFactory(void);
-EffectStateFactory *FshifterStateFactory_getFactory(void);
-EffectStateFactory *ModulatorStateFactory_getFactory(void);
-EffectStateFactory *PshifterStateFactory_getFactory(void);
-EffectStateFactory* VmorpherStateFactory_getFactory(void);
-
-EffectStateFactory *DedicatedStateFactory_getFactory(void);
-
-EffectStateFactory *ConvolutionStateFactory_getFactory(void);
+/* This is a user config option for modifying the overall output of the reverb
+ * effect.
+ */
+inline float ReverbBoost{1.0f};
+
+
+EffectStateFactory *NullStateFactory_getFactory();
+EffectStateFactory *ReverbStateFactory_getFactory();
+EffectStateFactory *StdReverbStateFactory_getFactory();
+EffectStateFactory *AutowahStateFactory_getFactory();
+EffectStateFactory *ChorusStateFactory_getFactory();
+EffectStateFactory *CompressorStateFactory_getFactory();
+EffectStateFactory *DistortionStateFactory_getFactory();
+EffectStateFactory *EchoStateFactory_getFactory();
+EffectStateFactory *EqualizerStateFactory_getFactory();
+EffectStateFactory *FlangerStateFactory_getFactory();
+EffectStateFactory *FshifterStateFactory_getFactory();
+EffectStateFactory *ModulatorStateFactory_getFactory();
+EffectStateFactory *PshifterStateFactory_getFactory();
+EffectStateFactory* VmorpherStateFactory_getFactory();
+
+EffectStateFactory *DedicatedDialogStateFactory_getFactory();
+EffectStateFactory *DedicatedLfeStateFactory_getFactory();
+
+EffectStateFactory *ConvolutionStateFactory_getFactory();
#endif /* EFFECTS_BASE_H */
diff --git a/alc/effects/chorus.cpp b/alc/effects/chorus.cpp
index 9cbc922f..bc6ddaf0 100644
--- a/alc/effects/chorus.cpp
+++ b/alc/effects/chorus.cpp
@@ -48,7 +48,14 @@ namespace {
using uint = unsigned int;
-struct ChorusState final : public EffectState {
+constexpr auto inv_sqrt2 = static_cast<float>(1.0 / al::numbers::sqrt2);
+constexpr auto lcoeffs_pw = CalcDirectionCoeffs(std::array{-1.0f, 0.0f, 0.0f});
+constexpr auto rcoeffs_pw = CalcDirectionCoeffs(std::array{ 1.0f, 0.0f, 0.0f});
+constexpr auto lcoeffs_nrml = CalcDirectionCoeffs(std::array{-inv_sqrt2, 0.0f, inv_sqrt2});
+constexpr auto rcoeffs_nrml = CalcDirectionCoeffs(std::array{ inv_sqrt2, 0.0f, inv_sqrt2});
+
+
+struct ChorusState : public EffectState {
std::vector<float> mDelayBuffer;
uint mOffset{0};
@@ -58,16 +65,17 @@ struct ChorusState final : public EffectState {
uint mLfoDisp{0};
/* Calculated delays to apply to the left and right outputs. */
- uint mModDelays[2][BufferLineSize];
+ std::array<std::array<uint,BufferLineSize>,2> mModDelays{};
/* Temp storage for the modulated left and right outputs. */
- alignas(16) float mBuffer[2][BufferLineSize];
+ alignas(16) std::array<FloatBufferLine,2> mBuffer{};
/* Gains for left and right outputs. */
- struct {
- float Current[MaxAmbiChannels]{};
- float Target[MaxAmbiChannels]{};
- } mGains[2];
+ struct OutGains {
+ std::array<float,MaxAmbiChannels> Current{};
+ std::array<float,MaxAmbiChannels> Target{};
+ };
+ std::array<OutGains,2> mGains;
/* effect parameters */
ChorusWaveform mWaveform{};
@@ -78,65 +86,81 @@ struct ChorusState final : public EffectState {
void calcTriangleDelays(const size_t todo);
void calcSinusoidDelays(const size_t todo);
- void deviceUpdate(const DeviceBase *device, const BufferStorage *buffer) override;
- void update(const ContextBase *context, const EffectSlot *slot, const EffectProps *props,
- const EffectTarget target) override;
+ void deviceUpdate(const DeviceBase *device, const float MaxDelay);
+ void update(const ContextBase *context, const EffectSlot *slot, const ChorusWaveform waveform,
+ const float delay, const float depth, const float feedback, const float rate,
+ int phase, const EffectTarget target);
+
+ void deviceUpdate(const DeviceBase *device, const BufferStorage*) override
+ { deviceUpdate(device, ChorusMaxDelay); }
+ void update(const ContextBase *context, const EffectSlot *slot, const EffectProps *props_,
+ const EffectTarget target) override
+ {
+ auto &props = std::get<ChorusProps>(*props_);
+ update(context, slot, props.Waveform, props.Delay, props.Depth, props.Feedback, props.Rate,
+ props.Phase, target);
+ }
void process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn,
- const al::span<FloatBufferLine> samplesOut) override;
+ const al::span<FloatBufferLine> samplesOut) final;
+};
- DEF_NEWDEL(ChorusState)
+struct FlangerState final : public ChorusState {
+ void deviceUpdate(const DeviceBase *device, const BufferStorage*) final
+ { ChorusState::deviceUpdate(device, FlangerMaxDelay); }
+ void update(const ContextBase *context, const EffectSlot *slot, const EffectProps *props_,
+ const EffectTarget target) final
+ {
+ auto &props = std::get<FlangerProps>(*props_);
+ ChorusState::update(context, slot, props.Waveform, props.Delay, props.Depth,
+ props.Feedback, props.Rate, props.Phase, target);
+ }
};
-void ChorusState::deviceUpdate(const DeviceBase *Device, const BufferStorage*)
-{
- constexpr float max_delay{maxf(ChorusMaxDelay, FlangerMaxDelay)};
+void ChorusState::deviceUpdate(const DeviceBase *Device, const float MaxDelay)
+{
const auto frequency = static_cast<float>(Device->Frequency);
- const size_t maxlen{NextPowerOf2(float2uint(max_delay*2.0f*frequency) + 1u)};
+ const size_t maxlen{NextPowerOf2(float2uint(MaxDelay*2.0f*frequency) + 1u)};
if(maxlen != mDelayBuffer.size())
decltype(mDelayBuffer)(maxlen).swap(mDelayBuffer);
std::fill(mDelayBuffer.begin(), mDelayBuffer.end(), 0.0f);
for(auto &e : mGains)
{
- std::fill(std::begin(e.Current), std::end(e.Current), 0.0f);
- std::fill(std::begin(e.Target), std::end(e.Target), 0.0f);
+ e.Current.fill(0.0f);
+ e.Target.fill(0.0f);
}
}
-void ChorusState::update(const ContextBase *Context, const EffectSlot *Slot,
- const EffectProps *props, const EffectTarget target)
+void ChorusState::update(const ContextBase *context, const EffectSlot *slot,
+ const ChorusWaveform waveform, const float delay, const float depth, const float feedback,
+ const float rate, int phase, const EffectTarget target)
{
- constexpr int mindelay{(MaxResamplerPadding>>1) << MixerFracBits};
+ static constexpr int mindelay{(MaxResamplerPadding>>1) << MixerFracBits};
/* The LFO depth is scaled to be relative to the sample delay. Clamp the
* delay and depth to allow enough padding for resampling.
*/
- const DeviceBase *device{Context->mDevice};
+ const DeviceBase *device{context->mDevice};
const auto frequency = static_cast<float>(device->Frequency);
- mWaveform = props->Chorus.Waveform;
+ mWaveform = waveform;
- mDelay = maxi(float2int(props->Chorus.Delay*frequency*MixerFracOne + 0.5f), mindelay);
- mDepth = minf(props->Chorus.Depth * static_cast<float>(mDelay),
+ mDelay = maxi(float2int(delay*frequency*MixerFracOne + 0.5f), mindelay);
+ mDepth = minf(depth * static_cast<float>(mDelay),
static_cast<float>(mDelay - mindelay));
- mFeedback = props->Chorus.Feedback;
+ mFeedback = feedback;
/* Gains for left and right sides */
- static constexpr auto inv_sqrt2 = static_cast<float>(1.0 / al::numbers::sqrt2);
- static constexpr auto lcoeffs_pw = CalcDirectionCoeffs(std::array{-1.0f, 0.0f, 0.0f});
- static constexpr auto rcoeffs_pw = CalcDirectionCoeffs(std::array{ 1.0f, 0.0f, 0.0f});
- static constexpr auto lcoeffs_nrml = CalcDirectionCoeffs(std::array{-inv_sqrt2, 0.0f, inv_sqrt2});
- static constexpr auto rcoeffs_nrml = CalcDirectionCoeffs(std::array{ inv_sqrt2, 0.0f, inv_sqrt2});
- auto &lcoeffs = (device->mRenderMode != RenderMode::Pairwise) ? lcoeffs_nrml : lcoeffs_pw;
- auto &rcoeffs = (device->mRenderMode != RenderMode::Pairwise) ? rcoeffs_nrml : rcoeffs_pw;
+ const bool ispairwise{device->mRenderMode == RenderMode::Pairwise};
+ const auto lcoeffs = (!ispairwise) ? al::span{lcoeffs_nrml} : al::span{lcoeffs_pw};
+ const auto rcoeffs = (!ispairwise) ? al::span{rcoeffs_nrml} : al::span{rcoeffs_pw};
mOutTarget = target.Main->Buffer;
- ComputePanGains(target.Main, lcoeffs, Slot->Gain, mGains[0].Target);
- ComputePanGains(target.Main, rcoeffs, Slot->Gain, mGains[1].Target);
+ ComputePanGains(target.Main, lcoeffs, slot->Gain, mGains[0].Target);
+ ComputePanGains(target.Main, rcoeffs, slot->Gain, mGains[1].Target);
- float rate{props->Chorus.Rate};
if(!(rate > 0.0f))
{
mLfoOffset = 0;
@@ -149,7 +173,7 @@ void ChorusState::update(const ContextBase *Context, const EffectSlot *Slot,
/* Calculate LFO coefficient (number of samples per cycle). Limit the
* max range to avoid overflow when calculating the displacement.
*/
- uint lfo_range{float2uint(minf(frequency/rate + 0.5f, float{INT_MAX/360 - 180}))};
+ const uint lfo_range{float2uint(minf(frequency/rate + 0.5f, float{INT_MAX/360 - 180}))};
mLfoOffset = mLfoOffset * lfo_range / mLfoRange;
mLfoRange = lfo_range;
@@ -164,7 +188,6 @@ void ChorusState::update(const ContextBase *Context, const EffectSlot *Slot,
}
/* Calculate lfo phase displacement */
- int phase{props->Chorus.Phase};
if(phase < 0) phase = 360 + phase;
mLfoDisp = (mLfoRange*static_cast<uint>(phase) + 180) / 360;
}
@@ -266,10 +289,10 @@ void ChorusState::process(const size_t samplesToDo, const al::span<const FloatBu
else /*if(mWaveform == ChorusWaveform::Triangle)*/
calcTriangleDelays(samplesToDo);
- const uint *RESTRICT ldelays{mModDelays[0]};
- const uint *RESTRICT rdelays{mModDelays[1]};
- float *RESTRICT lbuffer{al::assume_aligned<16>(mBuffer[0])};
- float *RESTRICT rbuffer{al::assume_aligned<16>(mBuffer[1])};
+ const uint *RESTRICT ldelays{mModDelays[0].data()};
+ const uint *RESTRICT rdelays{mModDelays[1].data()};
+ float *RESTRICT lbuffer{al::assume_aligned<16>(mBuffer[0].data())};
+ float *RESTRICT rbuffer{al::assume_aligned<16>(mBuffer[1].data())};
for(size_t i{0u};i < samplesToDo;++i)
{
// Feed the buffer's input first (necessary for delays < 1).
@@ -292,10 +315,10 @@ void ChorusState::process(const size_t samplesToDo, const al::span<const FloatBu
++offset;
}
- MixSamples({lbuffer, samplesToDo}, samplesOut, mGains[0].Current, mGains[0].Target,
- samplesToDo, 0);
- MixSamples({rbuffer, samplesToDo}, samplesOut, mGains[1].Current, mGains[1].Target,
- samplesToDo, 0);
+ MixSamples({lbuffer, samplesToDo}, samplesOut, mGains[0].Current.data(),
+ mGains[0].Target.data(), samplesToDo, 0);
+ MixSamples({rbuffer, samplesToDo}, samplesOut, mGains[1].Current.data(),
+ mGains[1].Target.data(), samplesToDo, 0);
mOffset = offset;
}
@@ -312,7 +335,7 @@ struct ChorusStateFactory final : public EffectStateFactory {
*/
struct FlangerStateFactory final : public EffectStateFactory {
al::intrusive_ptr<EffectState> create() override
- { return al::intrusive_ptr<EffectState>{new ChorusState{}}; }
+ { return al::intrusive_ptr<EffectState>{new FlangerState{}}; }
};
} // namespace
diff --git a/alc/effects/compressor.cpp b/alc/effects/compressor.cpp
index 0a7ed67a..717b6dd2 100644
--- a/alc/effects/compressor.cpp
+++ b/alc/effects/compressor.cpp
@@ -64,10 +64,11 @@ namespace {
struct CompressorState final : public EffectState {
/* Effect gains for each channel */
- struct {
+ struct TargetGain {
uint mTarget{InvalidChannelIndex};
float mGain{1.0f};
- } mChans[MaxAmbiChannels];
+ };
+ std::array<TargetGain,MaxAmbiChannels> mChans;
/* Effect parameters */
bool mEnabled{true};
@@ -81,8 +82,6 @@ struct CompressorState final : public EffectState {
const EffectTarget target) override;
void process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn,
const al::span<FloatBufferLine> samplesOut) override;
-
- DEF_NEWDEL(CompressorState)
};
void CompressorState::deviceUpdate(const DeviceBase *device, const BufferStorage*)
@@ -103,7 +102,7 @@ void CompressorState::deviceUpdate(const DeviceBase *device, const BufferStorage
void CompressorState::update(const ContextBase*, const EffectSlot *slot,
const EffectProps *props, const EffectTarget target)
{
- mEnabled = props->Compressor.OnOff;
+ mEnabled = std::get<CompressorProps>(*props).OnOff;
mOutTarget = target.Main->Buffer;
auto set_channel = [this](size_t idx, uint outchan, float outgain)
@@ -119,8 +118,8 @@ void CompressorState::process(const size_t samplesToDo,
{
for(size_t base{0u};base < samplesToDo;)
{
- float gains[256];
- const size_t td{minz(256, samplesToDo-base)};
+ std::array<float,256> gains;
+ const size_t td{minz(gains.size(), samplesToDo-base)};
/* Generate the per-sample gains from the signal envelope. */
float env{mEnvFollower};
diff --git a/alc/effects/convolution.cpp b/alc/effects/convolution.cpp
index 517e6b08..3f3e157c 100644
--- a/alc/effects/convolution.cpp
+++ b/alc/effects/convolution.cpp
@@ -5,11 +5,12 @@
#include <array>
#include <complex>
#include <cstddef>
+#include <cstdint>
#include <functional>
#include <iterator>
#include <memory>
-#include <stdint.h>
#include <utility>
+#include <vector>
#ifdef HAVE_SSE_INTRINSICS
#include <xmmintrin.h>
@@ -190,12 +191,6 @@ void apply_fir(al::span<float> dst, const float *RESTRICT src, const float *REST
}
-struct PFFFTSetupDeleter {
- void operator()(PFFFT_Setup *ptr) { pffft_destroy_setup(ptr); }
-};
-using PFFFTSetupPtr = std::unique_ptr<PFFFT_Setup,PFFFTSetupDeleter>;
-
-
struct ConvolutionState final : public EffectState {
FmtChannels mChannels{};
AmbiLayout mAmbiLayout{};
@@ -207,7 +202,7 @@ struct ConvolutionState final : public EffectState {
al::vector<std::array<float,ConvolveUpdateSamples>,16> mFilter;
al::vector<std::array<float,ConvolveUpdateSamples*2>,16> mOutput;
- PFFFTSetupPtr mFft{};
+ PFFFTSetup mFft{};
alignas(16) std::array<float,ConvolveUpdateSize> mFftBuffer{};
alignas(16) std::array<float,ConvolveUpdateSize> mFftWorkBuffer{};
@@ -218,8 +213,8 @@ struct ConvolutionState final : public EffectState {
alignas(16) FloatBufferLine mBuffer{};
float mHfScale{}, mLfScale{};
BandSplitter mFilter{};
- float Current[MAX_OUTPUT_CHANNELS]{};
- float Target[MAX_OUTPUT_CHANNELS]{};
+ std::array<float,MaxOutputChannels> Current{};
+ std::array<float,MaxOutputChannels> Target{};
};
std::vector<ChannelData> mChans;
al::vector<float,16> mComplexData;
@@ -238,16 +233,14 @@ struct ConvolutionState final : public EffectState {
const EffectTarget target) override;
void process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn,
const al::span<FloatBufferLine> samplesOut) override;
-
- DEF_NEWDEL(ConvolutionState)
};
void ConvolutionState::NormalMix(const al::span<FloatBufferLine> samplesOut,
const size_t samplesToDo)
{
for(auto &chan : mChans)
- MixSamples({chan.mBuffer.data(), samplesToDo}, samplesOut, chan.Current, chan.Target,
- samplesToDo, 0);
+ MixSamples({chan.mBuffer.data(), samplesToDo}, samplesOut, chan.Current.data(),
+ chan.Target.data(), samplesToDo, 0);
}
void ConvolutionState::UpsampleMix(const al::span<FloatBufferLine> samplesOut,
@@ -257,7 +250,7 @@ void ConvolutionState::UpsampleMix(const al::span<FloatBufferLine> samplesOut,
{
const al::span<float> src{chan.mBuffer.data(), samplesToDo};
chan.mFilter.processScale(src, chan.mHfScale, chan.mLfScale);
- MixSamples(src, samplesOut, chan.Current, chan.Target, samplesToDo, 0);
+ MixSamples(src, samplesOut, chan.Current.data(), chan.Target.data(), samplesToDo, 0);
}
}
@@ -270,7 +263,7 @@ void ConvolutionState::deviceUpdate(const DeviceBase *device, const BufferStorag
static constexpr uint MaxConvolveAmbiOrder{1u};
if(!mFft)
- mFft = PFFFTSetupPtr{pffft_new_setup(ConvolveUpdateSize, PFFFT_REAL)};
+ mFft = PFFFTSetup{ConvolveUpdateSize, PFFFT_REAL};
mFifoPos = 0;
mInput.fill(0.0f);
@@ -331,10 +324,10 @@ void ConvolutionState::deviceUpdate(const DeviceBase *device, const BufferStorag
/* Load the samples from the buffer. */
const size_t srclinelength{RoundUp(buffer->mSampleLen+DecoderPadding, 16)};
- auto srcsamples = std::make_unique<float[]>(srclinelength * numChannels);
- std::fill_n(srcsamples.get(), srclinelength * numChannels, 0.0f);
+ auto srcsamples = std::vector<float>(srclinelength * numChannels);
+ std::fill(srcsamples.begin(), srcsamples.end(), 0.0f);
for(size_t c{0};c < numChannels && c < realChannels;++c)
- LoadSamples(srcsamples.get() + srclinelength*c, buffer->mData.data() + bytesPerSample*c,
+ LoadSamples(srcsamples.data() + srclinelength*c, buffer->mData.data() + bytesPerSample*c,
realChannels, buffer->mType, buffer->mSampleLen);
if(IsUHJ(mChannels))
@@ -342,12 +335,11 @@ void ConvolutionState::deviceUpdate(const DeviceBase *device, const BufferStorag
auto decoder = std::make_unique<UhjDecoderType>();
std::array<float*,4> samples{};
for(size_t c{0};c < numChannels;++c)
- samples[c] = srcsamples.get() + srclinelength*c;
+ samples[c] = srcsamples.data() + srclinelength*c;
decoder->decode({samples.data(), numChannels}, buffer->mSampleLen, buffer->mSampleLen);
}
- auto ressamples = std::make_unique<double[]>(buffer->mSampleLen +
- (resampler ? resampledCount : 0));
+ auto ressamples = std::vector<double>(buffer->mSampleLen + (resampler ? resampledCount : 0));
auto ffttmp = al::vector<float,16>(ConvolveUpdateSize);
auto fftbuffer = std::vector<std::complex<double>>(ConvolveUpdateSize);
@@ -357,19 +349,20 @@ void ConvolutionState::deviceUpdate(const DeviceBase *device, const BufferStorag
/* Resample to match the device. */
if(resampler)
{
- std::copy_n(srcsamples.get() + srclinelength*c, buffer->mSampleLen,
- ressamples.get() + resampledCount);
- resampler.process(buffer->mSampleLen, ressamples.get()+resampledCount,
- resampledCount, ressamples.get());
+ std::copy_n(srcsamples.data() + srclinelength*c, buffer->mSampleLen,
+ ressamples.data() + resampledCount);
+ resampler.process(buffer->mSampleLen, ressamples.data()+resampledCount,
+ resampledCount, ressamples.data());
}
else
- std::copy_n(srcsamples.get() + srclinelength*c, buffer->mSampleLen, ressamples.get());
+ std::copy_n(srcsamples.data() + srclinelength*c, buffer->mSampleLen,
+ ressamples.data());
/* Store the first segment's samples in reverse in the time-domain, to
* apply as a FIR filter.
*/
const size_t first_size{minz(resampledCount, ConvolveUpdateSamples)};
- std::transform(ressamples.get(), ressamples.get()+first_size, mFilter[c].rbegin(),
+ std::transform(ressamples.data(), ressamples.data()+first_size, mFilter[c].rbegin(),
[](const double d) noexcept -> float { return static_cast<float>(d); });
size_t done{first_size};
@@ -400,7 +393,7 @@ void ConvolutionState::deviceUpdate(const DeviceBase *device, const BufferStorag
/* Reorder backward to make it suitable for pffft_zconvolve and the
* subsequent pffft_transform(..., PFFFT_BACKWARD).
*/
- pffft_zreorder(mFft.get(), ffttmp.data(), al::to_address(filteriter), PFFFT_BACKWARD);
+ mFft.zreorder(ffttmp.data(), al::to_address(filteriter), PFFFT_BACKWARD);
filteriter += ConvolveUpdateSize;
}
}
@@ -408,54 +401,61 @@ void ConvolutionState::deviceUpdate(const DeviceBase *device, const BufferStorag
void ConvolutionState::update(const ContextBase *context, const EffectSlot *slot,
- const EffectProps *props, const EffectTarget target)
+ const EffectProps *props_, const EffectTarget target)
{
/* TODO: LFE is not mixed to output. This will require each buffer channel
* to have its own output target since the main mixing buffer won't have an
* LFE channel (due to being B-Format).
*/
- static constexpr ChanPosMap MonoMap[1]{
- { FrontCenter, std::array{0.0f, 0.0f, -1.0f} }
- }, StereoMap[2]{
- { FrontLeft, std::array{-sin30, 0.0f, -cos30} },
- { FrontRight, std::array{ sin30, 0.0f, -cos30} },
- }, RearMap[2]{
- { BackLeft, std::array{-sin30, 0.0f, cos30} },
- { BackRight, std::array{ sin30, 0.0f, cos30} },
- }, QuadMap[4]{
- { FrontLeft, std::array{-sin45, 0.0f, -cos45} },
- { FrontRight, std::array{ sin45, 0.0f, -cos45} },
- { BackLeft, std::array{-sin45, 0.0f, cos45} },
- { BackRight, std::array{ sin45, 0.0f, cos45} },
- }, X51Map[6]{
- { FrontLeft, std::array{-sin30, 0.0f, -cos30} },
- { FrontRight, std::array{ sin30, 0.0f, -cos30} },
- { FrontCenter, std::array{ 0.0f, 0.0f, -1.0f} },
- { LFE, {} },
- { SideLeft, std::array{-sin110, 0.0f, -cos110} },
- { SideRight, std::array{ sin110, 0.0f, -cos110} },
- }, X61Map[7]{
- { FrontLeft, std::array{-sin30, 0.0f, -cos30} },
- { FrontRight, std::array{ sin30, 0.0f, -cos30} },
- { FrontCenter, std::array{ 0.0f, 0.0f, -1.0f} },
- { LFE, {} },
- { BackCenter, std::array{ 0.0f, 0.0f, 1.0f} },
- { SideLeft, std::array{-1.0f, 0.0f, 0.0f} },
- { SideRight, std::array{ 1.0f, 0.0f, 0.0f} },
- }, X71Map[8]{
- { FrontLeft, std::array{-sin30, 0.0f, -cos30} },
- { FrontRight, std::array{ sin30, 0.0f, -cos30} },
- { FrontCenter, std::array{ 0.0f, 0.0f, -1.0f} },
- { LFE, {} },
- { BackLeft, std::array{-sin30, 0.0f, cos30} },
- { BackRight, std::array{ sin30, 0.0f, cos30} },
- { SideLeft, std::array{ -1.0f, 0.0f, 0.0f} },
- { SideRight, std::array{ 1.0f, 0.0f, 0.0f} },
+ static constexpr std::array MonoMap{
+ ChanPosMap{FrontCenter, std::array{0.0f, 0.0f, -1.0f}}
+ };
+ static constexpr std::array StereoMap{
+ ChanPosMap{FrontLeft, std::array{-sin30, 0.0f, -cos30}},
+ ChanPosMap{FrontRight, std::array{ sin30, 0.0f, -cos30}},
+ };
+ static constexpr std::array RearMap{
+ ChanPosMap{BackLeft, std::array{-sin30, 0.0f, cos30}},
+ ChanPosMap{BackRight, std::array{ sin30, 0.0f, cos30}},
+ };
+ static constexpr std::array QuadMap{
+ ChanPosMap{FrontLeft, std::array{-sin45, 0.0f, -cos45}},
+ ChanPosMap{FrontRight, std::array{ sin45, 0.0f, -cos45}},
+ ChanPosMap{BackLeft, std::array{-sin45, 0.0f, cos45}},
+ ChanPosMap{BackRight, std::array{ sin45, 0.0f, cos45}},
+ };
+ static constexpr std::array X51Map{
+ ChanPosMap{FrontLeft, std::array{-sin30, 0.0f, -cos30}},
+ ChanPosMap{FrontRight, std::array{ sin30, 0.0f, -cos30}},
+ ChanPosMap{FrontCenter, std::array{ 0.0f, 0.0f, -1.0f}},
+ ChanPosMap{LFE, {}},
+ ChanPosMap{SideLeft, std::array{-sin110, 0.0f, -cos110}},
+ ChanPosMap{SideRight, std::array{ sin110, 0.0f, -cos110}},
+ };
+ static constexpr std::array X61Map{
+ ChanPosMap{FrontLeft, std::array{-sin30, 0.0f, -cos30}},
+ ChanPosMap{FrontRight, std::array{ sin30, 0.0f, -cos30}},
+ ChanPosMap{FrontCenter, std::array{ 0.0f, 0.0f, -1.0f}},
+ ChanPosMap{LFE, {}},
+ ChanPosMap{BackCenter, std::array{ 0.0f, 0.0f, 1.0f} },
+ ChanPosMap{SideLeft, std::array{-1.0f, 0.0f, 0.0f} },
+ ChanPosMap{SideRight, std::array{ 1.0f, 0.0f, 0.0f} },
+ };
+ static constexpr std::array X71Map{
+ ChanPosMap{FrontLeft, std::array{-sin30, 0.0f, -cos30}},
+ ChanPosMap{FrontRight, std::array{ sin30, 0.0f, -cos30}},
+ ChanPosMap{FrontCenter, std::array{ 0.0f, 0.0f, -1.0f}},
+ ChanPosMap{LFE, {}},
+ ChanPosMap{BackLeft, std::array{-sin30, 0.0f, cos30}},
+ ChanPosMap{BackRight, std::array{ sin30, 0.0f, cos30}},
+ ChanPosMap{SideLeft, std::array{ -1.0f, 0.0f, 0.0f}},
+ ChanPosMap{SideRight, std::array{ 1.0f, 0.0f, 0.0f}},
};
if(mNumConvolveSegs < 1) UNLIKELY
return;
+ auto &props = std::get<ConvolutionProps>(*props_);
mMix = &ConvolutionState::NormalMix;
for(auto &chan : mChans)
@@ -489,21 +489,19 @@ void ConvolutionState::update(const ContextBase *context, const EffectSlot *slot
}
mOutTarget = target.Main->Buffer;
- alu::Vector N{props->Convolution.OrientAt[0], props->Convolution.OrientAt[1],
- props->Convolution.OrientAt[2], 0.0f};
+ alu::Vector N{props.OrientAt[0], props.OrientAt[1], props.OrientAt[2], 0.0f};
N.normalize();
- alu::Vector V{props->Convolution.OrientUp[0], props->Convolution.OrientUp[1],
- props->Convolution.OrientUp[2], 0.0f};
+ alu::Vector V{props.OrientUp[0], props.OrientUp[1], props.OrientUp[2], 0.0f};
V.normalize();
/* Build and normalize right-vector */
alu::Vector U{N.cross_product(V)};
U.normalize();
- const float mixmatrix[4][4]{
- {1.0f, 0.0f, 0.0f, 0.0f},
- {0.0f, U[0], -U[1], U[2]},
- {0.0f, -V[0], V[1], -V[2]},
- {0.0f, -N[0], N[1], -N[2]},
+ const std::array mixmatrix{
+ std::array{1.0f, 0.0f, 0.0f, 0.0f},
+ std::array{0.0f, U[0], -U[1], U[2]},
+ std::array{0.0f, -V[0], V[1], -V[2]},
+ std::array{0.0f, -N[0], N[1], -N[2]},
};
const auto scales = GetAmbiScales(mAmbiScaling);
@@ -642,7 +640,7 @@ void ConvolutionState::process(const size_t samplesToDo,
/* Calculate the frequency-domain response and add the relevant
* frequency bins to the FFT history.
*/
- pffft_transform(mFft.get(), mInput.data(), mComplexData.data() + curseg*ConvolveUpdateSize,
+ mFft.transform(mInput.data(), mComplexData.data() + curseg*ConvolveUpdateSize,
mFftWorkBuffer.data(), PFFFT_FORWARD);
const float *filter{mComplexData.data() + mNumConvolveSegs*ConvolveUpdateSize};
@@ -655,14 +653,14 @@ void ConvolutionState::process(const size_t samplesToDo,
const float *input{&mComplexData[curseg*ConvolveUpdateSize]};
for(size_t s{curseg};s < mNumConvolveSegs;++s)
{
- pffft_zconvolve_accumulate(mFft.get(), input, filter, mFftBuffer.data());
+ mFft.zconvolve_accumulate(input, filter, mFftBuffer.data());
input += ConvolveUpdateSize;
filter += ConvolveUpdateSize;
}
input = mComplexData.data();
for(size_t s{0};s < curseg;++s)
{
- pffft_zconvolve_accumulate(mFft.get(), input, filter, mFftBuffer.data());
+ mFft.zconvolve_accumulate(input, filter, mFftBuffer.data());
input += ConvolveUpdateSize;
filter += ConvolveUpdateSize;
}
@@ -672,8 +670,8 @@ void ConvolutionState::process(const size_t samplesToDo,
* second-half samples (and this output's second half is
* subsequently saved for next time).
*/
- pffft_transform(mFft.get(), mFftBuffer.data(), mFftBuffer.data(),
- mFftWorkBuffer.data(), PFFFT_BACKWARD);
+ mFft.transform(mFftBuffer.data(), mFftBuffer.data(), mFftWorkBuffer.data(),
+ PFFFT_BACKWARD);
/* The filter was attenuated, so the response is already scaled. */
for(size_t i{0};i < ConvolveUpdateSamples;++i)
diff --git a/alc/effects/dedicated.cpp b/alc/effects/dedicated.cpp
index a9131bfa..23ac4d1a 100644
--- a/alc/effects/dedicated.cpp
+++ b/alc/effects/dedicated.cpp
@@ -42,82 +42,100 @@ namespace {
using uint = unsigned int;
-struct DedicatedState final : public EffectState {
+struct DedicatedState : public EffectState {
/* The "dedicated" effect can output to the real output, so should have
* gains for all possible output channels and not just the main ambisonic
* buffer.
*/
- float mCurrentGains[MAX_OUTPUT_CHANNELS];
- float mTargetGains[MAX_OUTPUT_CHANNELS];
+ std::array<float,MaxOutputChannels> mCurrentGains{};
+ std::array<float,MaxOutputChannels> mTargetGains{};
- void deviceUpdate(const DeviceBase *device, const BufferStorage *buffer) override;
+ void deviceUpdate(const DeviceBase *device, const BufferStorage *buffer) final;
void update(const ContextBase *context, const EffectSlot *slot, const EffectProps *props,
const EffectTarget target) override;
void process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn,
- const al::span<FloatBufferLine> samplesOut) override;
+ const al::span<FloatBufferLine> samplesOut) final;
+};
- DEF_NEWDEL(DedicatedState)
+struct DedicatedLfeState final : public DedicatedState {
+ void update(const ContextBase *context, const EffectSlot *slot, const EffectProps *props,
+ const EffectTarget target) final;
};
void DedicatedState::deviceUpdate(const DeviceBase*, const BufferStorage*)
{
- std::fill(std::begin(mCurrentGains), std::end(mCurrentGains), 0.0f);
+ std::fill(mCurrentGains.begin(), mCurrentGains.end(), 0.0f);
}
void DedicatedState::update(const ContextBase*, const EffectSlot *slot,
const EffectProps *props, const EffectTarget target)
{
- std::fill(std::begin(mTargetGains), std::end(mTargetGains), 0.0f);
+ std::fill(mTargetGains.begin(), mTargetGains.end(), 0.0f);
- const float Gain{slot->Gain * props->Dedicated.Gain};
+ const float Gain{slot->Gain * std::get<DedicatedDialogProps>(*props).Gain};
- if(slot->EffectType == EffectSlotType::DedicatedLFE)
+ /* Dialog goes to the front-center speaker if it exists, otherwise it plays
+ * from the front-center location.
+ */
+ const size_t idx{target.RealOut ? target.RealOut->ChannelIndex[FrontCenter]
+ : InvalidChannelIndex};
+ if(idx != InvalidChannelIndex)
{
- const size_t idx{target.RealOut ? target.RealOut->ChannelIndex[LFE] : InvalidChannelIndex};
- if(idx != InvalidChannelIndex)
- {
- mOutTarget = target.RealOut->Buffer;
- mTargetGains[idx] = Gain;
- }
+ mOutTarget = target.RealOut->Buffer;
+ mTargetGains[idx] = Gain;
}
- else if(slot->EffectType == EffectSlotType::DedicatedDialog)
+ else
{
- /* Dialog goes to the front-center speaker if it exists, otherwise it
- * plays from the front-center location. */
- const size_t idx{target.RealOut ? target.RealOut->ChannelIndex[FrontCenter]
- : InvalidChannelIndex};
- if(idx != InvalidChannelIndex)
- {
- mOutTarget = target.RealOut->Buffer;
- mTargetGains[idx] = Gain;
- }
- else
- {
- static constexpr auto coeffs = CalcDirectionCoeffs(std::array{0.0f, 0.0f, -1.0f});
-
- mOutTarget = target.Main->Buffer;
- ComputePanGains(target.Main, coeffs, Gain, mTargetGains);
- }
+ static constexpr auto coeffs = CalcDirectionCoeffs(std::array{0.0f, 0.0f, -1.0f});
+
+ mOutTarget = target.Main->Buffer;
+ ComputePanGains(target.Main, coeffs, Gain, mTargetGains);
+ }
+}
+
+void DedicatedLfeState::update(const ContextBase*, const EffectSlot *slot,
+ const EffectProps *props, const EffectTarget target)
+{
+ std::fill(mTargetGains.begin(), mTargetGains.end(), 0.0f);
+
+ const float Gain{slot->Gain * std::get<DedicatedLfeProps>(*props).Gain};
+
+ const size_t idx{target.RealOut ? target.RealOut->ChannelIndex[LFE] : InvalidChannelIndex};
+ if(idx != InvalidChannelIndex)
+ {
+ mOutTarget = target.RealOut->Buffer;
+ mTargetGains[idx] = Gain;
}
}
void DedicatedState::process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn, const al::span<FloatBufferLine> samplesOut)
{
- MixSamples({samplesIn[0].data(), samplesToDo}, samplesOut, mCurrentGains, mTargetGains,
- samplesToDo, 0);
+ MixSamples({samplesIn[0].data(), samplesToDo}, samplesOut, mCurrentGains.data(),
+ mTargetGains.data(), samplesToDo, 0);
}
-struct DedicatedStateFactory final : public EffectStateFactory {
+struct DedicatedDialogStateFactory final : public EffectStateFactory {
al::intrusive_ptr<EffectState> create() override
{ return al::intrusive_ptr<EffectState>{new DedicatedState{}}; }
};
+struct DedicatedLfeStateFactory final : public EffectStateFactory {
+ al::intrusive_ptr<EffectState> create() override
+ { return al::intrusive_ptr<EffectState>{new DedicatedLfeState{}}; }
+};
+
} // namespace
-EffectStateFactory *DedicatedStateFactory_getFactory()
+EffectStateFactory *DedicatedDialogStateFactory_getFactory()
+{
+ static DedicatedDialogStateFactory DedicatedFactory{};
+ return &DedicatedFactory;
+}
+
+EffectStateFactory *DedicatedLfeStateFactory_getFactory()
{
- static DedicatedStateFactory DedicatedFactory{};
+ static DedicatedLfeStateFactory DedicatedFactory{};
return &DedicatedFactory;
}
diff --git a/alc/effects/distortion.cpp b/alc/effects/distortion.cpp
index 3d77ff35..d0946971 100644
--- a/alc/effects/distortion.cpp
+++ b/alc/effects/distortion.cpp
@@ -45,7 +45,7 @@ namespace {
struct DistortionState final : public EffectState {
/* Effect gains for each channel */
- float mGain[MaxAmbiChannels]{};
+ std::array<float,MaxAmbiChannels> mGain{};
/* Effect parameters */
BiquadFilter mLowpass;
@@ -53,7 +53,7 @@ struct DistortionState final : public EffectState {
float mAttenuation{};
float mEdgeCoeff{};
- alignas(16) float mBuffer[2][BufferLineSize]{};
+ alignas(16) std::array<FloatBufferLine,2> mBuffer{};
void deviceUpdate(const DeviceBase *device, const BufferStorage *buffer) override;
@@ -61,8 +61,6 @@ struct DistortionState final : public EffectState {
const EffectTarget target) override;
void process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn,
const al::span<FloatBufferLine> samplesOut) override;
-
- DEF_NEWDEL(DistortionState)
};
void DistortionState::deviceUpdate(const DeviceBase*, const BufferStorage*)
@@ -72,16 +70,17 @@ void DistortionState::deviceUpdate(const DeviceBase*, const BufferStorage*)
}
void DistortionState::update(const ContextBase *context, const EffectSlot *slot,
- const EffectProps *props, const EffectTarget target)
+ const EffectProps *props_, const EffectTarget target)
{
+ auto &props = std::get<DistortionProps>(*props_);
const DeviceBase *device{context->mDevice};
/* Store waveshaper edge settings. */
- const float edge{minf(std::sin(al::numbers::pi_v<float>*0.5f * props->Distortion.Edge),
+ const float edge{minf(std::sin(al::numbers::pi_v<float>*0.5f * props.Edge),
0.99f)};
mEdgeCoeff = 2.0f * edge / (1.0f-edge);
- float cutoff{props->Distortion.LowpassCutoff};
+ float cutoff{props.LowpassCutoff};
/* Bandwidth value is constant in octaves. */
float bandwidth{(cutoff / 2.0f) / (cutoff * 0.67f)};
/* Divide normalized frequency by the amount of oversampling done during
@@ -90,15 +89,15 @@ void DistortionState::update(const ContextBase *context, const EffectSlot *slot,
auto frequency = static_cast<float>(device->Frequency);
mLowpass.setParamsFromBandwidth(BiquadType::LowPass, cutoff/frequency/4.0f, 1.0f, bandwidth);
- cutoff = props->Distortion.EQCenter;
+ cutoff = props.EQCenter;
/* Convert bandwidth in Hz to octaves. */
- bandwidth = props->Distortion.EQBandwidth / (cutoff * 0.67f);
+ bandwidth = props.EQBandwidth / (cutoff * 0.67f);
mBandpass.setParamsFromBandwidth(BiquadType::BandPass, cutoff/frequency/4.0f, 1.0f, bandwidth);
static constexpr auto coeffs = CalcDirectionCoeffs(std::array{0.0f, 0.0f, -1.0f});
mOutTarget = target.Main->Buffer;
- ComputePanGains(target.Main, coeffs, slot->Gain*props->Distortion.Gain, mGain);
+ ComputePanGains(target.Main, coeffs, slot->Gain*props.Gain, mGain);
}
void DistortionState::process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn, const al::span<FloatBufferLine> samplesOut)
@@ -124,7 +123,7 @@ void DistortionState::process(const size_t samplesToDo, const al::span<const Flo
* (which is fortunately first step of distortion). So combine three
* operations into the one.
*/
- mLowpass.process({mBuffer[0], todo}, mBuffer[1]);
+ mLowpass.process({mBuffer[0].data(), todo}, mBuffer[1].data());
/* Second step, do distortion using waveshaper function to emulate
* signal processing during tube overdriving. Three steps of
@@ -138,15 +137,15 @@ void DistortionState::process(const size_t samplesToDo, const al::span<const Flo
smp = (1.0f + fc) * smp/(1.0f + fc*std::abs(smp));
return smp;
};
- std::transform(std::begin(mBuffer[1]), std::begin(mBuffer[1])+todo, std::begin(mBuffer[0]),
+ std::transform(mBuffer[1].begin(), mBuffer[1].begin()+todo, mBuffer[0].begin(),
proc_sample);
/* Third step, do bandpass filtering of distorted signal. */
- mBandpass.process({mBuffer[0], todo}, mBuffer[1]);
+ mBandpass.process({mBuffer[0].data(), todo}, mBuffer[1].data());
todo >>= 2;
- const float *outgains{mGain};
- for(FloatBufferLine &output : samplesOut)
+ const float *outgains{mGain.data()};
+ for(FloatBufferLine &RESTRICT output : samplesOut)
{
/* Fourth step, final, do attenuation and perform decimation,
* storing only one sample out of four.
diff --git a/alc/effects/echo.cpp b/alc/effects/echo.cpp
index 714649c9..a5bfa6a5 100644
--- a/alc/effects/echo.cpp
+++ b/alc/effects/echo.cpp
@@ -53,29 +53,26 @@ struct EchoState final : public EffectState {
// The echo is two tap. The delay is the number of samples from before the
// current offset
- struct {
- size_t delay{0u};
- } mTap[2];
+ std::array<size_t,2> mDelayTap{};
size_t mOffset{0u};
/* The panning gains for the two taps */
- struct {
- float Current[MaxAmbiChannels]{};
- float Target[MaxAmbiChannels]{};
- } mGains[2];
+ struct OutGains {
+ std::array<float,MaxAmbiChannels> Current{};
+ std::array<float,MaxAmbiChannels> Target{};
+ };
+ std::array<OutGains,2> mGains;
BiquadFilter mFilter;
float mFeedGain{0.0f};
- alignas(16) float mTempBuffer[2][BufferLineSize];
+ alignas(16) std::array<FloatBufferLine,2> mTempBuffer{};
void deviceUpdate(const DeviceBase *device, const BufferStorage *buffer) override;
void update(const ContextBase *context, const EffectSlot *slot, const EffectProps *props,
const EffectTarget target) override;
void process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn,
const al::span<FloatBufferLine> samplesOut) override;
-
- DEF_NEWDEL(EchoState)
};
void EchoState::deviceUpdate(const DeviceBase *Device, const BufferStorage*)
@@ -92,27 +89,28 @@ void EchoState::deviceUpdate(const DeviceBase *Device, const BufferStorage*)
std::fill(mSampleBuffer.begin(), mSampleBuffer.end(), 0.0f);
for(auto &e : mGains)
{
- std::fill(std::begin(e.Current), std::end(e.Current), 0.0f);
- std::fill(std::begin(e.Target), std::end(e.Target), 0.0f);
+ std::fill(e.Current.begin(), e.Current.end(), 0.0f);
+ std::fill(e.Target.begin(), e.Target.end(), 0.0f);
}
}
void EchoState::update(const ContextBase *context, const EffectSlot *slot,
- const EffectProps *props, const EffectTarget target)
+ const EffectProps *props_, const EffectTarget target)
{
+ auto &props = std::get<EchoProps>(*props_);
const DeviceBase *device{context->mDevice};
const auto frequency = static_cast<float>(device->Frequency);
- mTap[0].delay = maxu(float2uint(props->Echo.Delay*frequency + 0.5f), 1);
- mTap[1].delay = float2uint(props->Echo.LRDelay*frequency + 0.5f) + mTap[0].delay;
+ mDelayTap[0] = maxu(float2uint(props.Delay*frequency + 0.5f), 1);
+ mDelayTap[1] = float2uint(props.LRDelay*frequency + 0.5f) + mDelayTap[0];
- const float gainhf{maxf(1.0f - props->Echo.Damping, 0.0625f)}; /* Limit -24dB */
+ const float gainhf{maxf(1.0f - props.Damping, 0.0625f)}; /* Limit -24dB */
mFilter.setParamsFromSlope(BiquadType::HighShelf, LowpassFreqRef/frequency, gainhf, 1.0f);
- mFeedGain = props->Echo.Feedback;
+ mFeedGain = props.Feedback;
/* Convert echo spread (where 0 = center, +/-1 = sides) to angle. */
- const float angle{std::asin(props->Echo.Spread)};
+ const float angle{std::asin(props.Spread)};
const auto coeffs0 = CalcAngleCoeffs(-angle, 0.0f, 0.0f);
const auto coeffs1 = CalcAngleCoeffs( angle, 0.0f, 0.0f);
@@ -127,14 +125,13 @@ void EchoState::process(const size_t samplesToDo, const al::span<const FloatBuff
const size_t mask{mSampleBuffer.size()-1};
float *RESTRICT delaybuf{mSampleBuffer.data()};
size_t offset{mOffset};
- size_t tap1{offset - mTap[0].delay};
- size_t tap2{offset - mTap[1].delay};
- float z1, z2;
+ size_t tap1{offset - mDelayTap[0]};
+ size_t tap2{offset - mDelayTap[1]};
ASSUME(samplesToDo > 0);
const BiquadFilter filter{mFilter};
- std::tie(z1, z2) = mFilter.getComponents();
+ auto [z1, z2] = mFilter.getComponents();
for(size_t i{0u};i < samplesToDo;)
{
offset &= mask;
@@ -161,8 +158,8 @@ void EchoState::process(const size_t samplesToDo, const al::span<const FloatBuff
mOffset = offset;
for(size_t c{0};c < 2;c++)
- MixSamples({mTempBuffer[c], samplesToDo}, samplesOut, mGains[c].Current, mGains[c].Target,
- samplesToDo, 0);
+ MixSamples({mTempBuffer[c].data(), samplesToDo}, samplesOut, mGains[c].Current.data(),
+ mGains[c].Target.data(), samplesToDo, 0);
}
diff --git a/alc/effects/equalizer.cpp b/alc/effects/equalizer.cpp
index 50bec4ad..165d00f2 100644
--- a/alc/effects/equalizer.cpp
+++ b/alc/effects/equalizer.cpp
@@ -86,16 +86,17 @@ namespace {
struct EqualizerState final : public EffectState {
- struct {
+ struct OutParams {
uint mTargetChannel{InvalidChannelIndex};
/* Effect parameters */
- BiquadFilter mFilter[4];
+ std::array<BiquadFilter,4> mFilter;
/* Effect gains for each channel */
float mCurrentGain{};
float mTargetGain{};
- } mChans[MaxAmbiChannels];
+ };
+ std::array<OutParams,MaxAmbiChannels> mChans;
alignas(16) FloatBufferLine mSampleBuffer{};
@@ -105,8 +106,6 @@ struct EqualizerState final : public EffectState {
const EffectTarget target) override;
void process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn,
const al::span<FloatBufferLine> samplesOut) override;
-
- DEF_NEWDEL(EqualizerState)
};
void EqualizerState::deviceUpdate(const DeviceBase*, const BufferStorage*)
@@ -114,18 +113,17 @@ void EqualizerState::deviceUpdate(const DeviceBase*, const BufferStorage*)
for(auto &e : mChans)
{
e.mTargetChannel = InvalidChannelIndex;
- std::for_each(std::begin(e.mFilter), std::end(e.mFilter),
- std::mem_fn(&BiquadFilter::clear));
+ std::for_each(e.mFilter.begin(), e.mFilter.end(), std::mem_fn(&BiquadFilter::clear));
e.mCurrentGain = 0.0f;
}
}
void EqualizerState::update(const ContextBase *context, const EffectSlot *slot,
- const EffectProps *props, const EffectTarget target)
+ const EffectProps *props_, const EffectTarget target)
{
+ auto &props = std::get<EqualizerProps>(*props_);
const DeviceBase *device{context->mDevice};
auto frequency = static_cast<float>(device->Frequency);
- float gain, f0norm;
/* Calculate coefficients for the each type of filter. Note that the shelf
* and peaking filters' gain is for the centerpoint of the transition band,
@@ -133,22 +131,22 @@ void EqualizerState::update(const ContextBase *context, const EffectSlot *slot,
* property gains need their dB halved (sqrt of linear gain) for the
* shelf/peak to reach the provided gain.
*/
- gain = std::sqrt(props->Equalizer.LowGain);
- f0norm = props->Equalizer.LowCutoff / frequency;
+ float gain{std::sqrt(props.LowGain)};
+ float f0norm{props.LowCutoff / frequency};
mChans[0].mFilter[0].setParamsFromSlope(BiquadType::LowShelf, f0norm, gain, 0.75f);
- gain = std::sqrt(props->Equalizer.Mid1Gain);
- f0norm = props->Equalizer.Mid1Center / frequency;
+ gain = std::sqrt(props.Mid1Gain);
+ f0norm = props.Mid1Center / frequency;
mChans[0].mFilter[1].setParamsFromBandwidth(BiquadType::Peaking, f0norm, gain,
- props->Equalizer.Mid1Width);
+ props.Mid1Width);
- gain = std::sqrt(props->Equalizer.Mid2Gain);
- f0norm = props->Equalizer.Mid2Center / frequency;
+ gain = std::sqrt(props.Mid2Gain);
+ f0norm = props.Mid2Center / frequency;
mChans[0].mFilter[2].setParamsFromBandwidth(BiquadType::Peaking, f0norm, gain,
- props->Equalizer.Mid2Width);
+ props.Mid2Width);
- gain = std::sqrt(props->Equalizer.HighGain);
- f0norm = props->Equalizer.HighCutoff / frequency;
+ gain = std::sqrt(props.HighGain);
+ f0norm = props.HighCutoff / frequency;
mChans[0].mFilter[3].setParamsFromSlope(BiquadType::HighShelf, f0norm, gain, 0.75f);
/* Copy the filter coefficients for the other input channels. */
diff --git a/alc/effects/fshifter.cpp b/alc/effects/fshifter.cpp
index d3989e84..076661cf 100644
--- a/alc/effects/fshifter.cpp
+++ b/alc/effects/fshifter.cpp
@@ -57,7 +57,7 @@ constexpr size_t HilStep{HilSize / OversampleFactor};
/* Define a Hann window, used to filter the HIL input and output. */
struct Windower {
- alignas(16) std::array<double,HilSize> mData;
+ alignas(16) std::array<double,HilSize> mData{};
Windower()
{
@@ -91,10 +91,11 @@ struct FshifterState final : public EffectState {
alignas(16) FloatBufferLine mBufferOut{};
/* Effect gains for each output channel */
- struct {
- float Current[MaxAmbiChannels]{};
- float Target[MaxAmbiChannels]{};
- } mGains[2];
+ struct OutGains {
+ std::array<float,MaxAmbiChannels> Current{};
+ std::array<float,MaxAmbiChannels> Target{};
+ };
+ std::array<OutGains,2> mGains;
void deviceUpdate(const DeviceBase *device, const BufferStorage *buffer) override;
@@ -102,8 +103,6 @@ struct FshifterState final : public EffectState {
const EffectTarget target) override;
void process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn,
const al::span<FloatBufferLine> samplesOut) override;
-
- DEF_NEWDEL(FshifterState)
};
void FshifterState::deviceUpdate(const DeviceBase*, const BufferStorage*)
@@ -122,20 +121,21 @@ void FshifterState::deviceUpdate(const DeviceBase*, const BufferStorage*)
for(auto &gain : mGains)
{
- std::fill(std::begin(gain.Current), std::end(gain.Current), 0.0f);
- std::fill(std::begin(gain.Target), std::end(gain.Target), 0.0f);
+ gain.Current.fill(0.0f);
+ gain.Target.fill(0.0f);
}
}
void FshifterState::update(const ContextBase *context, const EffectSlot *slot,
- const EffectProps *props, const EffectTarget target)
+ const EffectProps *props_, const EffectTarget target)
{
+ auto &props = std::get<FshifterProps>(*props_);
const DeviceBase *device{context->mDevice};
- const float step{props->Fshifter.Frequency / static_cast<float>(device->Frequency)};
+ const float step{props.Frequency / static_cast<float>(device->Frequency)};
mPhaseStep[0] = mPhaseStep[1] = fastf2u(minf(step, 1.0f) * MixerFracOne);
- switch(props->Fshifter.LeftDirection)
+ switch(props.LeftDirection)
{
case FShifterDirection::Down:
mSign[0] = -1.0;
@@ -149,7 +149,7 @@ void FshifterState::update(const ContextBase *context, const EffectSlot *slot,
break;
}
- switch(props->Fshifter.RightDirection)
+ switch(props.RightDirection)
{
case FShifterDirection::Down:
mSign[1] = -1.0;
@@ -235,8 +235,8 @@ void FshifterState::process(const size_t samplesToDo, const al::span<const Float
mPhase[c] = phase_idx;
/* Now, mix the processed sound data to the output. */
- MixSamples({BufferOut, samplesToDo}, samplesOut, mGains[c].Current, mGains[c].Target,
- maxz(samplesToDo, 512), 0);
+ MixSamples({BufferOut, samplesToDo}, samplesOut, mGains[c].Current.data(),
+ mGains[c].Target.data(), maxz(samplesToDo, 512), 0);
}
}
diff --git a/alc/effects/modulator.cpp b/alc/effects/modulator.cpp
index f99ba19c..7350ca5a 100644
--- a/alc/effects/modulator.cpp
+++ b/alc/effects/modulator.cpp
@@ -52,7 +52,7 @@ inline float Saw(uint index, float scale)
{ return static_cast<float>(index)*scale - 1.0f; }
inline float Square(uint index, float scale)
-{ return (static_cast<float>(index)*scale < 0.5f)*2.0f - 1.0f; }
+{ return float(static_cast<float>(index)*scale < 0.5f)*2.0f - 1.0f; }
inline float One(uint, float)
{ return 1.0f; }
@@ -89,14 +89,15 @@ struct ModulatorState final : public EffectState {
alignas(16) FloatBufferLine mModSamples{};
alignas(16) FloatBufferLine mBuffer{};
- struct {
+ struct OutParams {
uint mTargetChannel{InvalidChannelIndex};
BiquadFilter mFilter;
float mCurrentGain{};
float mTargetGain{};
- } mChans[MaxAmbiChannels];
+ };
+ std::array<OutParams,MaxAmbiChannels> mChans;
void deviceUpdate(const DeviceBase *device, const BufferStorage *buffer) override;
@@ -104,8 +105,6 @@ struct ModulatorState final : public EffectState {
const EffectTarget target) override;
void process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn,
const al::span<FloatBufferLine> samplesOut) override;
-
- DEF_NEWDEL(ModulatorState)
};
template<>
@@ -126,8 +125,9 @@ void ModulatorState::deviceUpdate(const DeviceBase*, const BufferStorage*)
}
void ModulatorState::update(const ContextBase *context, const EffectSlot *slot,
- const EffectProps *props, const EffectTarget target)
+ const EffectProps *props_, const EffectTarget target)
{
+ auto &props = std::get<ModulatorProps>(*props_);
const DeviceBase *device{context->mDevice};
/* The effective frequency will be adjusted to have a whole number of
@@ -137,8 +137,8 @@ void ModulatorState::update(const ContextBase *context, const EffectSlot *slot,
* but that may need a more efficient sin function since it needs to do
* many iterations per sample.
*/
- const float samplesPerCycle{props->Modulator.Frequency > 0.0f
- ? static_cast<float>(device->Frequency)/props->Modulator.Frequency + 0.5f
+ const float samplesPerCycle{props.Frequency > 0.0f
+ ? static_cast<float>(device->Frequency)/props.Frequency + 0.5f
: 1.0f};
const uint range{static_cast<uint>(clampf(samplesPerCycle, 1.0f,
static_cast<float>(device->Frequency)))};
@@ -150,17 +150,17 @@ void ModulatorState::update(const ContextBase *context, const EffectSlot *slot,
mIndexScale = 0.0f;
mGenModSamples = &ModulatorState::Modulate<One>;
}
- else if(props->Modulator.Waveform == ModulatorWaveform::Sinusoid)
+ else if(props.Waveform == ModulatorWaveform::Sinusoid)
{
mIndexScale = al::numbers::pi_v<float>*2.0f / static_cast<float>(mRange);
mGenModSamples = &ModulatorState::Modulate<Sin>;
}
- else if(props->Modulator.Waveform == ModulatorWaveform::Sawtooth)
+ else if(props.Waveform == ModulatorWaveform::Sawtooth)
{
mIndexScale = 2.0f / static_cast<float>(mRange-1);
mGenModSamples = &ModulatorState::Modulate<Saw>;
}
- else /*if(props->Modulator.Waveform == ModulatorWaveform::Square)*/
+ else /*if(props.Waveform == ModulatorWaveform::Square)*/
{
/* For square wave, the range should be even (there should be an equal
* number of high and low samples). An odd number of samples per cycle
@@ -171,7 +171,7 @@ void ModulatorState::update(const ContextBase *context, const EffectSlot *slot,
mGenModSamples = &ModulatorState::Modulate<Square>;
}
- float f0norm{props->Modulator.HighPassCutoff / static_cast<float>(device->Frequency)};
+ float f0norm{props.HighPassCutoff / static_cast<float>(device->Frequency)};
f0norm = clampf(f0norm, 1.0f/512.0f, 0.49f);
/* Bandwidth value is constant in octaves. */
mChans[0].mFilter.setParamsFromBandwidth(BiquadType::HighPass, f0norm, 1.0f, 0.75f);
diff --git a/alc/effects/null.cpp b/alc/effects/null.cpp
index 1f9ae67b..964afe47 100644
--- a/alc/effects/null.cpp
+++ b/alc/effects/null.cpp
@@ -1,7 +1,7 @@
#include "config.h"
-#include <stddef.h>
+#include <cstddef>
#include "almalloc.h"
#include "alspan.h"
@@ -25,8 +25,6 @@ struct NullState final : public EffectState {
const EffectTarget target) override;
void process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn,
const al::span<FloatBufferLine> samplesOut) override;
-
- DEF_NEWDEL(NullState)
};
/* This constructs the effect state. It's called when the object is first
diff --git a/alc/effects/pshifter.cpp b/alc/effects/pshifter.cpp
index 0c27be30..1cc1a18c 100644
--- a/alc/effects/pshifter.cpp
+++ b/alc/effects/pshifter.cpp
@@ -58,7 +58,7 @@ constexpr size_t StftStep{StftSize / OversampleFactor};
/* Define a Hann window, used to filter the STFT input and output. */
struct Windower {
- alignas(16) std::array<float,StftSize> mData;
+ alignas(16) std::array<float,StftSize> mData{};
Windower()
{
@@ -74,12 +74,6 @@ struct Windower {
const Windower gWindow{};
-struct PFFFTSetupDeleter {
- void operator()(PFFFT_Setup *ptr) { pffft_destroy_setup(ptr); }
-};
-using PFFFTSetupPtr = std::unique_ptr<PFFFT_Setup,PFFFTSetupDeleter>;
-
-
struct FrequencyBin {
float Magnitude;
float FreqBin;
@@ -88,29 +82,29 @@ struct FrequencyBin {
struct PshifterState final : public EffectState {
/* Effect parameters */
- size_t mCount;
- size_t mPos;
- uint mPitchShiftI;
- float mPitchShift;
+ size_t mCount{};
+ size_t mPos{};
+ uint mPitchShiftI{};
+ float mPitchShift{};
/* Effects buffers */
- std::array<float,StftSize> mFIFO;
- std::array<float,StftHalfSize+1> mLastPhase;
- std::array<float,StftHalfSize+1> mSumPhase;
- std::array<float,StftSize> mOutputAccum;
+ std::array<float,StftSize> mFIFO{};
+ std::array<float,StftHalfSize+1> mLastPhase{};
+ std::array<float,StftHalfSize+1> mSumPhase{};
+ std::array<float,StftSize> mOutputAccum{};
- PFFFTSetupPtr mFft;
- alignas(16) std::array<float,StftSize> mFftBuffer;
- alignas(16) std::array<float,StftSize> mFftWorkBuffer;
+ PFFFTSetup mFft;
+ alignas(16) std::array<float,StftSize> mFftBuffer{};
+ alignas(16) std::array<float,StftSize> mFftWorkBuffer{};
- std::array<FrequencyBin,StftHalfSize+1> mAnalysisBuffer;
- std::array<FrequencyBin,StftHalfSize+1> mSynthesisBuffer;
+ std::array<FrequencyBin,StftHalfSize+1> mAnalysisBuffer{};
+ std::array<FrequencyBin,StftHalfSize+1> mSynthesisBuffer{};
- alignas(16) FloatBufferLine mBufferOut;
+ alignas(16) FloatBufferLine mBufferOut{};
/* Effect gains for each output channel */
- float mCurrentGains[MaxAmbiChannels];
- float mTargetGains[MaxAmbiChannels];
+ std::array<float,MaxAmbiChannels> mCurrentGains{};
+ std::array<float,MaxAmbiChannels> mTargetGains{};
void deviceUpdate(const DeviceBase *device, const BufferStorage *buffer) override;
@@ -118,8 +112,6 @@ struct PshifterState final : public EffectState {
const EffectTarget target) override;
void process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn,
const al::span<FloatBufferLine> samplesOut) override;
-
- DEF_NEWDEL(PshifterState)
};
void PshifterState::deviceUpdate(const DeviceBase*, const BufferStorage*)
@@ -138,17 +130,18 @@ void PshifterState::deviceUpdate(const DeviceBase*, const BufferStorage*)
mAnalysisBuffer.fill(FrequencyBin{});
mSynthesisBuffer.fill(FrequencyBin{});
- std::fill(std::begin(mCurrentGains), std::end(mCurrentGains), 0.0f);
- std::fill(std::begin(mTargetGains), std::end(mTargetGains), 0.0f);
+ mCurrentGains.fill(0.0f);
+ mTargetGains.fill(0.0f);
if(!mFft)
- mFft = PFFFTSetupPtr{pffft_new_setup(StftSize, PFFFT_REAL)};
+ mFft = PFFFTSetup{StftSize, PFFFT_REAL};
}
void PshifterState::update(const ContextBase*, const EffectSlot *slot,
- const EffectProps *props, const EffectTarget target)
+ const EffectProps *props_, const EffectTarget target)
{
- const int tune{props->Pshifter.CoarseTune*100 + props->Pshifter.FineTune};
+ auto &props = std::get<PshifterProps>(*props_);
+ const int tune{props.CoarseTune*100 + props.FineTune};
const float pitch{std::pow(2.0f, static_cast<float>(tune) / 1200.0f)};
mPitchShiftI = clampu(fastf2u(pitch*MixerFracOne), MixerFracHalf, MixerFracOne*2);
mPitchShift = static_cast<float>(mPitchShiftI) * float{1.0f/MixerFracOne};
@@ -197,8 +190,8 @@ void PshifterState::process(const size_t samplesToDo,
mFftBuffer[k] = mFIFO[src] * gWindow.mData[k];
for(size_t src{0u}, k{StftSize-mPos};src < mPos;++src,++k)
mFftBuffer[k] = mFIFO[src] * gWindow.mData[k];
- pffft_transform_ordered(mFft.get(), mFftBuffer.data(), mFftBuffer.data(),
- mFftWorkBuffer.data(), PFFFT_FORWARD);
+ mFft.transform_ordered(mFftBuffer.data(), mFftBuffer.data(), mFftWorkBuffer.data(),
+ PFFFT_FORWARD);
/* Analyze the obtained data. Since the real FFT is symmetric, only
* StftHalfSize+1 samples are needed.
@@ -296,8 +289,8 @@ void PshifterState::process(const size_t samplesToDo,
/* Apply an inverse FFT to get the time-domain signal, and accumulate
* for the output with windowing.
*/
- pffft_transform_ordered(mFft.get(), mFftBuffer.data(), mFftBuffer.data(),
- mFftWorkBuffer.data(), PFFFT_BACKWARD);
+ mFft.transform_ordered(mFftBuffer.data(), mFftBuffer.data(), mFftWorkBuffer.data(),
+ PFFFT_BACKWARD);
static constexpr float scale{3.0f / OversampleFactor / StftSize};
for(size_t dst{mPos}, k{0u};dst < StftSize;++dst,++k)
@@ -311,8 +304,8 @@ void PshifterState::process(const size_t samplesToDo,
}
/* Now, mix the processed sound data to the output. */
- MixSamples({mBufferOut.data(), samplesToDo}, samplesOut, mCurrentGains, mTargetGains,
- maxz(samplesToDo, 512), 0);
+ MixSamples({mBufferOut.data(), samplesToDo}, samplesOut, mCurrentGains.data(),
+ mTargetGains.data(), maxz(samplesToDo, 512), 0);
}
diff --git a/alc/effects/reverb.cpp b/alc/effects/reverb.cpp
index 0f1fcca1..45bfaf0f 100644
--- a/alc/effects/reverb.cpp
+++ b/alc/effects/reverb.cpp
@@ -22,11 +22,12 @@
#include <algorithm>
#include <array>
+#include <cassert>
+#include <cstdint>
#include <cstdio>
#include <functional>
#include <iterator>
#include <numeric>
-#include <stdint.h>
#include "alc/effects/base.h"
#include "almalloc.h"
@@ -48,11 +49,6 @@
#include "vecmat.h"
#include "vector.h"
-/* This is a user config option for modifying the overall output of the reverb
- * effect.
- */
-float ReverbBoost = 1.0f;
-
namespace {
using uint = unsigned int;
@@ -70,7 +66,7 @@ struct CubicFilter {
static constexpr size_t sTableSteps{1 << sTableBits};
static constexpr size_t sTableMask{sTableSteps - 1};
- float mFilter[sTableSteps*2 + 1]{};
+ std::array<float,sTableSteps*2 + 1> mFilter{};
constexpr CubicFilter()
{
@@ -90,10 +86,14 @@ struct CubicFilter {
}
}
- constexpr float getCoeff0(size_t i) const noexcept { return mFilter[sTableSteps+i]; }
- constexpr float getCoeff1(size_t i) const noexcept { return mFilter[i]; }
- constexpr float getCoeff2(size_t i) const noexcept { return mFilter[sTableSteps-i]; }
- constexpr float getCoeff3(size_t i) const noexcept { return mFilter[sTableSteps*2-i]; }
+ [[nodiscard]] constexpr auto getCoeff0(size_t i) const noexcept -> float
+ { return mFilter[sTableSteps+i]; }
+ [[nodiscard]] constexpr auto getCoeff1(size_t i) const noexcept -> float
+ { return mFilter[i]; }
+ [[nodiscard]] constexpr auto getCoeff2(size_t i) const noexcept -> float
+ { return mFilter[sTableSteps-i]; }
+ [[nodiscard]] constexpr auto getCoeff3(size_t i) const noexcept -> float
+ { return mFilter[sTableSteps*2-i]; }
};
constexpr CubicFilter gCubicTable;
@@ -124,12 +124,12 @@ constexpr float MODULATION_DEPTH_COEFF{0.05f};
* tetrahedral array of discrete signals (boosted by a factor of sqrt(3), to
* reduce the error introduced in the conversion).
*/
-alignas(16) constexpr float B2A[NUM_LINES][NUM_LINES]{
- { 0.5f, 0.5f, 0.5f, 0.5f },
- { 0.5f, -0.5f, -0.5f, 0.5f },
- { 0.5f, 0.5f, -0.5f, -0.5f },
- { 0.5f, -0.5f, 0.5f, -0.5f }
-};
+alignas(16) constexpr std::array<std::array<float,NUM_LINES>,NUM_LINES> B2A{{
+ {{ 0.5f, 0.5f, 0.5f, 0.5f }},
+ {{ 0.5f, -0.5f, -0.5f, 0.5f }},
+ {{ 0.5f, 0.5f, -0.5f, -0.5f }},
+ {{ 0.5f, -0.5f, 0.5f, -0.5f }}
+}};
/* Converts (W-normalized) A-Format to B-Format for early reflections (scaled
* by 1/sqrt(3) to compensate for the boost in the B2A matrix).
@@ -252,7 +252,7 @@ constexpr std::array<float,NUM_LINES> EARLY_ALLPASS_LENGTHS{{
* Using an average dimension of 1m, we get:
*/
constexpr std::array<float,NUM_LINES> EARLY_LINE_LENGTHS{{
- 5.9850400e-4f, 1.0913150e-3f, 1.5376658e-3f, 1.9419362e-3f
+ 0.0000000e+0f, 4.9281100e-4f, 9.3916180e-4f, 1.3434322e-3f
}};
/* The late all-pass filter lengths are based on the late line lengths:
@@ -290,20 +290,16 @@ struct DelayLineI {
* of 2 to allow the use of bit-masking instead of a modulus for wrapping.
*/
size_t Mask{0u};
- union {
- uintptr_t LineOffset{0u};
- std::array<float,NUM_LINES> *Line;
- };
+ std::array<float,NUM_LINES> *Line;
/* Given the allocated sample buffer, this function updates each delay line
* offset.
*/
void realizeLineOffset(std::array<float,NUM_LINES> *sampleBuffer) noexcept
- { Line = sampleBuffer + LineOffset; }
+ { Line = sampleBuffer; }
/* Calculate the length of a delay line and store its mask and offset. */
- uint calcLineLength(const float length, const uintptr_t offset, const float frequency,
- const uint extra)
+ size_t calcLineLength(const float length, const float frequency, const uint extra)
{
/* All line lengths are powers of 2, calculated from their lengths in
* seconds, rounded up.
@@ -313,7 +309,6 @@ struct DelayLineI {
/* All lines share a single sample buffer. */
Mask = samples - 1;
- LineOffset = offset;
/* Return the sample count for accumulation. */
return samples;
@@ -369,7 +364,7 @@ struct DelayLineI {
struct VecAllpass {
DelayLineI Delay;
float Coeff{0.0f};
- size_t Offset[NUM_LINES]{};
+ std::array<size_t,NUM_LINES> Offset{};
void process(const al::span<ReverbUpdateLine,NUM_LINES> samples, size_t offset,
const float xCoeff, const float yCoeff, const size_t todo);
@@ -402,12 +397,12 @@ struct EarlyReflections {
* reflections.
*/
DelayLineI Delay;
- size_t Offset[NUM_LINES]{};
- float Coeff[NUM_LINES]{};
+ std::array<size_t,NUM_LINES> Offset{};
+ std::array<float,NUM_LINES> Coeff{};
/* The gain for each output channel based on 3D panning. */
- float CurrentGains[NUM_LINES][MaxAmbiChannels]{};
- float TargetGains[NUM_LINES][MaxAmbiChannels]{};
+ std::array<std::array<float,MaxAmbiChannels>,NUM_LINES> CurrentGains{};
+ std::array<std::array<float,MaxAmbiChannels>,NUM_LINES> TargetGains{};
void updateLines(const float density_mult, const float diffusion, const float decayTime,
const float frequency);
@@ -418,12 +413,12 @@ struct Modulation {
/* The vibrato time is tracked with an index over a (MOD_FRACONE)
* normalized range.
*/
- uint Index, Step;
+ uint Index{}, Step{};
/* The depth of frequency change, in samples. */
- float Depth;
+ float Depth{};
- float ModDelays[MAX_UPDATE_SAMPLES];
+ std::array<float,MAX_UPDATE_SAMPLES> ModDelays{};
void updateModulator(float modTime, float modDepth, float frequency);
@@ -433,7 +428,7 @@ struct Modulation {
struct LateReverb {
/* A recursive delay line is used fill in the reverb tail. */
DelayLineI Delay;
- size_t Offset[NUM_LINES]{};
+ std::array<size_t,NUM_LINES> Offset{};
/* Attenuation to compensate for the modal density and decay rate of the
* late lines.
@@ -441,7 +436,7 @@ struct LateReverb {
float DensityGain{0.0f};
/* T60 decay filters are used to simulate absorption. */
- T60Filter T60[NUM_LINES];
+ std::array<T60Filter,NUM_LINES> T60;
Modulation Mod;
@@ -449,8 +444,8 @@ struct LateReverb {
VecAllpass VecAp;
/* The gain for each output channel based on 3D panning. */
- float CurrentGains[NUM_LINES][MaxAmbiChannels]{};
- float TargetGains[NUM_LINES][MaxAmbiChannels]{};
+ std::array<std::array<float,MaxAmbiChannels>,NUM_LINES> CurrentGains{};
+ std::array<std::array<float,MaxAmbiChannels>,NUM_LINES> TargetGains{};
void updateLines(const float density_mult, const float diffusion, const float lfDecayTime,
const float mfDecayTime, const float hfDecayTime, const float lf0norm,
@@ -465,21 +460,22 @@ struct LateReverb {
struct ReverbPipeline {
/* Master effect filters */
- struct {
+ struct FilterPair {
BiquadFilter Lp;
BiquadFilter Hp;
- } mFilter[NUM_LINES];
+ };
+ std::array<FilterPair,NUM_LINES> mFilter;
/* Core delay line (early reflections and late reverb tap from this). */
DelayLineI mEarlyDelayIn;
DelayLineI mLateDelayIn;
/* Tap points for early reflection delay. */
- size_t mEarlyDelayTap[NUM_LINES][2]{};
- float mEarlyDelayCoeff[NUM_LINES]{};
+ std::array<std::array<size_t,2>,NUM_LINES> mEarlyDelayTap{};
+ std::array<float,NUM_LINES> mEarlyDelayCoeff{};
/* Tap points for late reverb feed and delay. */
- size_t mLateDelayTap[NUM_LINES][2]{};
+ std::array<std::array<size_t,2>,NUM_LINES> mLateDelayTap{};
/* Coefficients for the all-pass and line scattering matrices. */
float mMixX{0.0f};
@@ -551,9 +547,9 @@ struct ReverbState final : public EffectState {
Normal,
};
PipelineState mPipelineState{DeviceClear};
- uint8_t mCurrentPipeline{0};
+ bool mCurrentPipeline{false};
- ReverbPipeline mPipelines[2];
+ std::array<ReverbPipeline,2> mPipelines;
/* The current write offset for all delay lines. */
size_t mOffset{};
@@ -582,14 +578,14 @@ struct ReverbState final : public EffectState {
for(size_t c{0u};c < NUM_LINES;c++)
{
const al::span<float> tmpspan{mEarlySamples[c].data(), todo};
- MixSamples(tmpspan, samplesOut, pipeline.mEarly.CurrentGains[c],
- pipeline.mEarly.TargetGains[c], todo, 0);
+ MixSamples(tmpspan, samplesOut, pipeline.mEarly.CurrentGains[c].data(),
+ pipeline.mEarly.TargetGains[c].data(), todo, 0);
}
for(size_t c{0u};c < NUM_LINES;c++)
{
const al::span<float> tmpspan{mLateSamples[c].data(), todo};
- MixSamples(tmpspan, samplesOut, pipeline.mLate.CurrentGains[c],
- pipeline.mLate.TargetGains[c], todo, 0);
+ MixSamples(tmpspan, samplesOut, pipeline.mLate.CurrentGains[c].data(),
+ pipeline.mLate.TargetGains[c].data(), todo, 0);
}
}
@@ -632,8 +628,8 @@ struct ReverbState final : public EffectState {
const float hfscale{(c==0) ? mOrderScales[0] : mOrderScales[1]};
pipeline.mAmbiSplitter[0][c].processHfScale(tmpspan, hfscale);
- MixSamples(tmpspan, samplesOut, pipeline.mEarly.CurrentGains[c],
- pipeline.mEarly.TargetGains[c], todo, 0);
+ MixSamples(tmpspan, samplesOut, pipeline.mEarly.CurrentGains[c].data(),
+ pipeline.mEarly.TargetGains[c].data(), todo, 0);
}
for(size_t c{0u};c < NUM_LINES;c++)
{
@@ -642,8 +638,8 @@ struct ReverbState final : public EffectState {
const float hfscale{(c==0) ? mOrderScales[0] : mOrderScales[1]};
pipeline.mAmbiSplitter[1][c].processHfScale(tmpspan, hfscale);
- MixSamples(tmpspan, samplesOut, pipeline.mLate.CurrentGains[c],
- pipeline.mLate.TargetGains[c], todo, 0);
+ MixSamples(tmpspan, samplesOut, pipeline.mLate.CurrentGains[c].data(),
+ pipeline.mLate.TargetGains[c].data(), todo, 0);
}
}
@@ -662,8 +658,6 @@ struct ReverbState final : public EffectState {
const EffectTarget target) override;
void process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn,
const al::span<FloatBufferLine> samplesOut) override;
-
- DEF_NEWDEL(ReverbState)
};
/**************************************
@@ -678,11 +672,6 @@ inline float CalcDelayLengthMult(float density)
*/
void ReverbState::allocLines(const float frequency)
{
- /* All delay line lengths are calculated to accommodate the full range of
- * lengths given their respective parameters.
- */
- size_t totalSamples{0u};
-
/* Multiplier for the maximum density value, i.e. density=1, which is
* actually the least density...
*/
@@ -692,8 +681,12 @@ void ReverbState::allocLines(const float frequency)
* time and depth coefficient, and halfed for the low-to-high frequency
* swing.
*/
- constexpr float max_mod_delay{MaxModulationTime*MODULATION_DEPTH_COEFF / 2.0f};
+ static constexpr float max_mod_delay{MaxModulationTime*MODULATION_DEPTH_COEFF / 2.0f};
+
+ std::array<size_t,12> lineoffsets{};
+ size_t oidx{0};
+ size_t totalSamples{0u};
for(auto &pipeline : mPipelines)
{
/* The main delay length includes the maximum early reflection delay,
@@ -702,37 +695,45 @@ void ReverbState::allocLines(const float frequency)
* update size (BufferLineSize) for block processing.
*/
float length{ReverbMaxReflectionsDelay + EARLY_TAP_LENGTHS.back()*multiplier};
- totalSamples += pipeline.mEarlyDelayIn.calcLineLength(length, totalSamples, frequency,
- BufferLineSize);
+ size_t count{pipeline.mEarlyDelayIn.calcLineLength(length, frequency, BufferLineSize)};
+ lineoffsets[oidx++] = totalSamples;
+ totalSamples += count;
- constexpr float LateLineDiffAvg{(LATE_LINE_LENGTHS.back()-LATE_LINE_LENGTHS.front()) /
+ static constexpr float LateDiffAvg{(LATE_LINE_LENGTHS.back()-LATE_LINE_LENGTHS.front()) /
float{NUM_LINES}};
- length = ReverbMaxLateReverbDelay + LateLineDiffAvg*multiplier;
- totalSamples += pipeline.mLateDelayIn.calcLineLength(length, totalSamples, frequency,
- BufferLineSize);
+ length = ReverbMaxLateReverbDelay + LateDiffAvg*multiplier;
+ count = pipeline.mLateDelayIn.calcLineLength(length, frequency, BufferLineSize);
+ lineoffsets[oidx++] = totalSamples;
+ totalSamples += count;
/* The early vector all-pass line. */
length = EARLY_ALLPASS_LENGTHS.back() * multiplier;
- totalSamples += pipeline.mEarly.VecAp.Delay.calcLineLength(length, totalSamples, frequency,
- 0);
+ count = pipeline.mEarly.VecAp.Delay.calcLineLength(length, frequency, 0);
+ lineoffsets[oidx++] = totalSamples;
+ totalSamples += count;
/* The early reflection line. */
length = EARLY_LINE_LENGTHS.back() * multiplier;
- totalSamples += pipeline.mEarly.Delay.calcLineLength(length, totalSamples, frequency,
- MAX_UPDATE_SAMPLES);
+ count = pipeline.mEarly.Delay.calcLineLength(length, frequency, MAX_UPDATE_SAMPLES);
+ lineoffsets[oidx++] = totalSamples;
+ totalSamples += count;
/* The late vector all-pass line. */
length = LATE_ALLPASS_LENGTHS.back() * multiplier;
- totalSamples += pipeline.mLate.VecAp.Delay.calcLineLength(length, totalSamples, frequency,
- 0);
+ count = pipeline.mLate.VecAp.Delay.calcLineLength(length, frequency, 0);
+ lineoffsets[oidx++] = totalSamples;
+ totalSamples += count;
/* The late delay lines are calculated from the largest maximum density
* line length, and the maximum modulation delay. Four additional
* samples are needed for resampling the modulator delay.
*/
length = LATE_LINE_LENGTHS.back()*multiplier + max_mod_delay;
- totalSamples += pipeline.mLate.Delay.calcLineLength(length, totalSamples, frequency, 4);
+ count = pipeline.mLate.Delay.calcLineLength(length, frequency, 4);
+ lineoffsets[oidx++] = totalSamples;
+ totalSamples += count;
}
+ assert(oidx == lineoffsets.size());
if(totalSamples != mSampleBuffer.size())
decltype(mSampleBuffer)(totalSamples).swap(mSampleBuffer);
@@ -741,14 +742,15 @@ void ReverbState::allocLines(const float frequency)
std::fill(mSampleBuffer.begin(), mSampleBuffer.end(), decltype(mSampleBuffer)::value_type{});
/* Update all delays to reflect the new sample buffer. */
+ oidx = 0;
for(auto &pipeline : mPipelines)
{
- pipeline.mEarlyDelayIn.realizeLineOffset(mSampleBuffer.data());
- pipeline.mLateDelayIn.realizeLineOffset(mSampleBuffer.data());
- pipeline.mEarly.VecAp.Delay.realizeLineOffset(mSampleBuffer.data());
- pipeline.mEarly.Delay.realizeLineOffset(mSampleBuffer.data());
- pipeline.mLate.VecAp.Delay.realizeLineOffset(mSampleBuffer.data());
- pipeline.mLate.Delay.realizeLineOffset(mSampleBuffer.data());
+ pipeline.mEarlyDelayIn.realizeLineOffset(mSampleBuffer.data() + lineoffsets[oidx++]);
+ pipeline.mLateDelayIn.realizeLineOffset(mSampleBuffer.data() + lineoffsets[oidx++]);
+ pipeline.mEarly.VecAp.Delay.realizeLineOffset(mSampleBuffer.data() + lineoffsets[oidx++]);
+ pipeline.mEarly.Delay.realizeLineOffset(mSampleBuffer.data() + lineoffsets[oidx++]);
+ pipeline.mLate.VecAp.Delay.realizeLineOffset(mSampleBuffer.data() + lineoffsets[oidx++]);
+ pipeline.mLate.Delay.realizeLineOffset(mSampleBuffer.data() + lineoffsets[oidx++]);
}
}
@@ -761,17 +763,16 @@ void ReverbState::deviceUpdate(const DeviceBase *device, const BufferStorage*)
for(auto &pipeline : mPipelines)
{
- /* Clear filters and gain coefficients since the delay lines were all just
- * cleared (if not reallocated).
- */
+ /* Clear filters and gain coefficients since the delay lines were all
+ * just cleared (if not reallocated).
+ */
for(auto &filter : pipeline.mFilter)
{
filter.Lp.clear();
filter.Hp.clear();
}
- std::fill(std::begin(pipeline.mEarlyDelayCoeff),std::end(pipeline.mEarlyDelayCoeff), 0.0f);
- std::fill(std::begin(pipeline.mEarlyDelayCoeff),std::end(pipeline.mEarlyDelayCoeff), 0.0f);
+ pipeline.mEarlyDelayCoeff.fill(0.0f);
pipeline.mLate.DensityGain = 0.0f;
for(auto &t60 : pipeline.mLate.T60)
@@ -786,13 +787,13 @@ void ReverbState::deviceUpdate(const DeviceBase *device, const BufferStorage*)
pipeline.mLate.Mod.Depth = 0.0f;
for(auto &gains : pipeline.mEarly.CurrentGains)
- std::fill(std::begin(gains), std::end(gains), 0.0f);
+ gains.fill(0.0f);
for(auto &gains : pipeline.mEarly.TargetGains)
- std::fill(std::begin(gains), std::end(gains), 0.0f);
+ gains.fill(0.0f);
for(auto &gains : pipeline.mLate.CurrentGains)
- std::fill(std::begin(gains), std::end(gains), 0.0f);
+ gains.fill(0.0f);
for(auto &gains : pipeline.mLate.TargetGains)
- std::fill(std::begin(gains), std::end(gains), 0.0f);
+ gains.fill(0.0f);
}
mPipelineState = DeviceClear;
@@ -1057,7 +1058,7 @@ void ReverbPipeline::updateDelayLine(const float earlyDelay, const float lateDel
* output.
*/
length = (LATE_LINE_LENGTHS[i] - LATE_LINE_LENGTHS.front())/float{NUM_LINES}*density_mult +
- std::max(lateDelay - EARLY_LINE_LENGTHS[0]*density_mult, 0.0f);
+ lateDelay;
mLateDelayTap[i][1] = float2uint(length * frequency);
}
}
@@ -1076,7 +1077,7 @@ std::array<std::array<float,4>,4> GetTransformFromVector(const al::span<const fl
* rest of OpenAL which use right-handed. This is fixed by negating Z,
* which cancels out with the B-Format Z negation.
*/
- float norm[3];
+ std::array<float,3> norm;
float mag{std::sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2])};
if(mag > 1.0f)
{
@@ -1185,75 +1186,73 @@ void ReverbPipeline::update3DPanning(const al::span<const float,3> ReflectionsPa
}
void ReverbState::update(const ContextBase *Context, const EffectSlot *Slot,
- const EffectProps *props, const EffectTarget target)
+ const EffectProps *props_, const EffectTarget target)
{
+ auto &props = std::get<ReverbProps>(*props_);
const DeviceBase *Device{Context->mDevice};
const auto frequency = static_cast<float>(Device->Frequency);
/* If the HF limit parameter is flagged, calculate an appropriate limit
* based on the air absorption parameter.
*/
- float hfRatio{props->Reverb.DecayHFRatio};
- if(props->Reverb.DecayHFLimit && props->Reverb.AirAbsorptionGainHF < 1.0f)
- hfRatio = CalcLimitedHfRatio(hfRatio, props->Reverb.AirAbsorptionGainHF,
- props->Reverb.DecayTime);
+ float hfRatio{props.DecayHFRatio};
+ if(props.DecayHFLimit && props.AirAbsorptionGainHF < 1.0f)
+ hfRatio = CalcLimitedHfRatio(hfRatio, props.AirAbsorptionGainHF, props.DecayTime);
/* Calculate the LF/HF decay times. */
constexpr float MinDecayTime{0.1f}, MaxDecayTime{20.0f};
- const float lfDecayTime{clampf(props->Reverb.DecayTime*props->Reverb.DecayLFRatio,
- MinDecayTime, MaxDecayTime)};
- const float hfDecayTime{clampf(props->Reverb.DecayTime*hfRatio, MinDecayTime, MaxDecayTime)};
+ const float lfDecayTime{clampf(props.DecayTime*props.DecayLFRatio, MinDecayTime,MaxDecayTime)};
+ const float hfDecayTime{clampf(props.DecayTime*hfRatio, MinDecayTime, MaxDecayTime)};
/* Determine if a full update is required. */
const bool fullUpdate{mPipelineState == DeviceClear ||
/* Density is essentially a master control for the feedback delays, so
* changes the offsets of many delay lines.
*/
- mParams.Density != props->Reverb.Density ||
+ mParams.Density != props.Density ||
/* Diffusion and decay times influences the decay rate (gain) of the
* late reverb T60 filter.
*/
- mParams.Diffusion != props->Reverb.Diffusion ||
- mParams.DecayTime != props->Reverb.DecayTime ||
+ mParams.Diffusion != props.Diffusion ||
+ mParams.DecayTime != props.DecayTime ||
mParams.HFDecayTime != hfDecayTime ||
mParams.LFDecayTime != lfDecayTime ||
/* Modulation time and depth both require fading the modulation delay. */
- mParams.ModulationTime != props->Reverb.ModulationTime ||
- mParams.ModulationDepth != props->Reverb.ModulationDepth ||
+ mParams.ModulationTime != props.ModulationTime ||
+ mParams.ModulationDepth != props.ModulationDepth ||
/* HF/LF References control the weighting used to calculate the density
* gain.
*/
- mParams.HFReference != props->Reverb.HFReference ||
- mParams.LFReference != props->Reverb.LFReference};
+ mParams.HFReference != props.HFReference ||
+ mParams.LFReference != props.LFReference};
if(fullUpdate)
{
- mParams.Density = props->Reverb.Density;
- mParams.Diffusion = props->Reverb.Diffusion;
- mParams.DecayTime = props->Reverb.DecayTime;
+ mParams.Density = props.Density;
+ mParams.Diffusion = props.Diffusion;
+ mParams.DecayTime = props.DecayTime;
mParams.HFDecayTime = hfDecayTime;
mParams.LFDecayTime = lfDecayTime;
- mParams.ModulationTime = props->Reverb.ModulationTime;
- mParams.ModulationDepth = props->Reverb.ModulationDepth;
- mParams.HFReference = props->Reverb.HFReference;
- mParams.LFReference = props->Reverb.LFReference;
+ mParams.ModulationTime = props.ModulationTime;
+ mParams.ModulationDepth = props.ModulationDepth;
+ mParams.HFReference = props.HFReference;
+ mParams.LFReference = props.LFReference;
mPipelineState = (mPipelineState != DeviceClear) ? StartFade : Normal;
- mCurrentPipeline ^= 1;
+ mCurrentPipeline = !mCurrentPipeline;
}
auto &pipeline = mPipelines[mCurrentPipeline];
/* Update early and late 3D panning. */
mOutTarget = target.Main->Buffer;
- const float gain{props->Reverb.Gain * Slot->Gain * ReverbBoost};
- pipeline.update3DPanning(props->Reverb.ReflectionsPan, props->Reverb.LateReverbPan,
- props->Reverb.ReflectionsGain*gain, props->Reverb.LateReverbGain*gain, mUpmixOutput,
- target.Main);
+ const float gain{props.Gain * Slot->Gain * ReverbBoost};
+ pipeline.update3DPanning(props.ReflectionsPan, props.LateReverbPan, props.ReflectionsGain*gain,
+ props.LateReverbGain*gain, mUpmixOutput, target.Main);
/* Calculate the master filters */
- float hf0norm{minf(props->Reverb.HFReference/frequency, 0.49f)};
- pipeline.mFilter[0].Lp.setParamsFromSlope(BiquadType::HighShelf, hf0norm, props->Reverb.GainHF, 1.0f);
- float lf0norm{minf(props->Reverb.LFReference/frequency, 0.49f)};
- pipeline.mFilter[0].Hp.setParamsFromSlope(BiquadType::LowShelf, lf0norm, props->Reverb.GainLF, 1.0f);
+ float hf0norm{minf(props.HFReference/frequency, 0.49f)};
+ pipeline.mFilter[0].Lp.setParamsFromSlope(BiquadType::HighShelf, hf0norm, props.GainHF, 1.0f);
+ float lf0norm{minf(props.LFReference/frequency, 0.49f)};
+ pipeline.mFilter[0].Hp.setParamsFromSlope(BiquadType::LowShelf, lf0norm, props.GainLF, 1.0f);
for(size_t i{1u};i < NUM_LINES;i++)
{
pipeline.mFilter[i].Lp.copyParamsFrom(pipeline.mFilter[0].Lp);
@@ -1261,34 +1260,32 @@ void ReverbState::update(const ContextBase *Context, const EffectSlot *Slot,
}
/* The density-based room size (delay length) multiplier. */
- const float density_mult{CalcDelayLengthMult(props->Reverb.Density)};
+ const float density_mult{CalcDelayLengthMult(props.Density)};
/* Update the main effect delay and associated taps. */
- pipeline.updateDelayLine(props->Reverb.ReflectionsDelay, props->Reverb.LateReverbDelay,
- density_mult, props->Reverb.DecayTime, frequency);
+ pipeline.updateDelayLine(props.ReflectionsDelay, props.LateReverbDelay, density_mult,
+ props.DecayTime, frequency);
if(fullUpdate)
{
/* Update the early lines. */
- pipeline.mEarly.updateLines(density_mult, props->Reverb.Diffusion, props->Reverb.DecayTime,
- frequency);
+ pipeline.mEarly.updateLines(density_mult, props.Diffusion, props.DecayTime, frequency);
/* Get the mixing matrix coefficients. */
- CalcMatrixCoeffs(props->Reverb.Diffusion, &pipeline.mMixX, &pipeline.mMixY);
+ CalcMatrixCoeffs(props.Diffusion, &pipeline.mMixX, &pipeline.mMixY);
/* Update the modulator rate and depth. */
- pipeline.mLate.Mod.updateModulator(props->Reverb.ModulationTime,
- props->Reverb.ModulationDepth, frequency);
+ pipeline.mLate.Mod.updateModulator(props.ModulationTime, props.ModulationDepth, frequency);
/* Update the late lines. */
- pipeline.mLate.updateLines(density_mult, props->Reverb.Diffusion, lfDecayTime,
- props->Reverb.DecayTime, hfDecayTime, lf0norm, hf0norm, frequency);
+ pipeline.mLate.updateLines(density_mult, props.Diffusion, lfDecayTime, props.DecayTime,
+ hfDecayTime, lf0norm, hf0norm, frequency);
}
/* Calculate the gain at the start of the late reverb stage, and the gain
* difference from the decay target (0.001, or -60dB).
*/
- const float decayBase{props->Reverb.ReflectionsGain * props->Reverb.LateReverbGain};
+ const float decayBase{props.ReflectionsGain * props.LateReverbGain};
const float decayDiff{ReverbDecayGain / decayBase};
if(decayDiff < 1.0f)
@@ -1297,10 +1294,10 @@ void ReverbState::update(const ContextBase *Context, const EffectSlot *Slot,
* by -60dB), calculate the time to decay to -60dB from the start of
* the late reverb.
*/
- const float diffTime{std::log10(decayDiff)*(20.0f / -60.0f) * props->Reverb.DecayTime};
+ const float diffTime{std::log10(decayDiff)*(20.0f / -60.0f) * props.DecayTime};
- const float decaySamples{(props->Reverb.ReflectionsDelay + props->Reverb.LateReverbDelay
- + diffTime) * frequency};
+ const float decaySamples{(props.ReflectionsDelay+props.LateReverbDelay+diffTime)
+ * frequency};
/* Limit to 100,000 samples (a touch over 2 seconds at 48khz) to
* avoid excessive double-processing.
*/
@@ -1311,8 +1308,7 @@ void ReverbState::update(const ContextBase *Context, const EffectSlot *Slot,
/* Otherwise, if the late reverb already starts at -60dB or less, only
* include the time to get to the late reverb.
*/
- const float decaySamples{(props->Reverb.ReflectionsDelay + props->Reverb.LateReverbDelay)
- * frequency};
+ const float decaySamples{(props.ReflectionsDelay+props.LateReverbDelay) * frequency};
pipeline.mFadeSampleCount = static_cast<size_t>(minf(decaySamples, 100'000.0f));
}
}
@@ -1413,7 +1409,7 @@ void VecAllpass::process(const al::span<ReverbUpdateLine,NUM_LINES> samples, siz
ASSUME(todo > 0);
- size_t vap_offset[NUM_LINES];
+ std::array<size_t,NUM_LINES> vap_offset;
for(size_t j{0u};j < NUM_LINES;j++)
vap_offset[j] = offset - Offset[j];
for(size_t i{0u};i < todo;)
@@ -1504,10 +1500,11 @@ void ReverbPipeline::processEarly(size_t offset, const size_t samplesToDo,
mEarlyDelayTap[j][0] = mEarlyDelayTap[j][1];
}
- /* Apply a vector all-pass, to help color the initial reflections based
- * on the diffusion strength.
+ /* Apply a vector all-pass, to help color the initial reflections.
+ * Don't apply diffusion-based scattering since these are still the
+ * first reflections.
*/
- mEarly.VecAp.process(tempSamples, offset, mixX, mixY, todo);
+ mEarly.VecAp.process(tempSamples, offset, 1.0f, 0.0f, todo);
/* Apply a delay and bounce to generate secondary reflections, combine
* with the primary reflections and write out the result for mixing.
@@ -1594,17 +1591,52 @@ void ReverbPipeline::processLate(size_t offset, const size_t samplesToDo,
/* First, calculate the modulated delays for the late feedback. */
mLate.Mod.calcDelays(todo);
- /* Next, load decorrelated samples from the main and feedback delay
- * lines. Filter the signal to apply its frequency-dependent decay.
+ /* Now load samples from the feedback delay lines. Filter the signal to
+ * apply its frequency-dependent decay.
*/
+ for(size_t j{0u};j < NUM_LINES;++j)
+ {
+ size_t late_feedb_tap{offset - mLate.Offset[j]};
+ const float midGain{mLate.T60[j].MidGain};
+
+ for(size_t i{0u};i < todo;++i)
+ {
+ /* Calculate the read offset and offset between it and the next
+ * sample.
+ */
+ const float fdelay{mLate.Mod.ModDelays[i]};
+ const size_t idelay{float2uint(fdelay * float{gCubicTable.sTableSteps})};
+ const size_t delay{late_feedb_tap - (idelay>>gCubicTable.sTableBits)};
+ const size_t delayoffset{idelay & gCubicTable.sTableMask};
+ ++late_feedb_tap;
+
+ /* Get the samples around by the delayed offset. */
+ const float out0{late_delay.Line[(delay ) & late_delay.Mask][j]};
+ const float out1{late_delay.Line[(delay-1) & late_delay.Mask][j]};
+ const float out2{late_delay.Line[(delay-2) & late_delay.Mask][j]};
+ const float out3{late_delay.Line[(delay-3) & late_delay.Mask][j]};
+
+ /* The output is obtained by interpolating the four samples
+ * that were acquired above, and combined with the main delay
+ * tap.
+ */
+ const float out{out0*gCubicTable.getCoeff0(delayoffset)
+ + out1*gCubicTable.getCoeff1(delayoffset)
+ + out2*gCubicTable.getCoeff2(delayoffset)
+ + out3*gCubicTable.getCoeff3(delayoffset)};
+ tempSamples[j][i] = out * midGain;
+ }
+
+ mLate.T60[j].process({tempSamples[j].data(), todo});
+ }
+
+ /* Next load decorrelated samples from the main delay lines. */
const float fadeStep{1.0f / static_cast<float>(todo)};
- for(size_t j{0u};j < NUM_LINES;j++)
+ for(size_t j{0u};j < NUM_LINES;++j)
{
size_t late_delay_tap0{offset - mLateDelayTap[j][0]};
size_t late_delay_tap1{offset - mLateDelayTap[j][1]};
- size_t late_feedb_tap{offset - mLate.Offset[j]};
- const float midGain{mLate.T60[j].MidGain};
- const float densityGain{mLate.DensityGain * midGain};
+ const float densityGain{mLate.DensityGain};
const float densityStep{late_delay_tap0 != late_delay_tap1 ?
densityGain*fadeStep : 0.0f};
float fadeCount{0.0f};
@@ -1615,48 +1647,22 @@ void ReverbPipeline::processLate(size_t offset, const size_t samplesToDo,
late_delay_tap1 &= in_delay.Mask;
size_t td{minz(todo-i, in_delay.Mask+1 - maxz(late_delay_tap0, late_delay_tap1))};
do {
- /* Calculate the read offset and offset between it and the
- * next sample.
- */
- const float fdelay{mLate.Mod.ModDelays[i]};
- const size_t idelay{float2uint(fdelay * float{gCubicTable.sTableSteps})};
- const size_t delay{late_feedb_tap - (idelay>>gCubicTable.sTableBits)};
- const size_t delayoffset{idelay & gCubicTable.sTableMask};
- ++late_feedb_tap;
-
- /* Get the samples around by the delayed offset. */
- const float out0{late_delay.Line[(delay ) & late_delay.Mask][j]};
- const float out1{late_delay.Line[(delay-1) & late_delay.Mask][j]};
- const float out2{late_delay.Line[(delay-2) & late_delay.Mask][j]};
- const float out3{late_delay.Line[(delay-3) & late_delay.Mask][j]};
-
- /* The output is obtained by interpolating the four samples
- * that were acquired above, and combined with the main
- * delay tap.
- */
- const float out{out0*gCubicTable.getCoeff0(delayoffset)
- + out1*gCubicTable.getCoeff1(delayoffset)
- + out2*gCubicTable.getCoeff2(delayoffset)
- + out3*gCubicTable.getCoeff3(delayoffset)};
const float fade0{densityGain - densityStep*fadeCount};
const float fade1{densityStep*fadeCount};
fadeCount += 1.0f;
- tempSamples[j][i] = out*midGain +
- in_delay.Line[late_delay_tap0++][j]*fade0 +
+ tempSamples[j][i] += in_delay.Line[late_delay_tap0++][j]*fade0 +
in_delay.Line[late_delay_tap1++][j]*fade1;
++i;
} while(--td);
}
mLateDelayTap[j][0] = mLateDelayTap[j][1];
-
- mLate.T60[j].process({tempSamples[j].data(), todo});
}
/* Apply a vector all-pass to improve micro-surface diffusion, and
* write out the results for mixing.
*/
mLate.VecAp.process(tempSamples, offset, mixX, mixY, todo);
- for(size_t j{0u};j < NUM_LINES;j++)
+ for(size_t j{0u};j < NUM_LINES;++j)
std::copy_n(tempSamples[j].begin(), todo, outSamples[j].begin()+base);
/* Finally, scatter and bounce the results to refeed the feedback buffer. */
@@ -1673,7 +1679,7 @@ void ReverbState::process(const size_t samplesToDo, const al::span<const FloatBu
ASSUME(samplesToDo > 0);
- auto &oldpipeline = mPipelines[mCurrentPipeline^1];
+ auto &oldpipeline = mPipelines[!mCurrentPipeline];
auto &pipeline = mPipelines[mCurrentPipeline];
if(mPipelineState >= Fading)
@@ -1681,7 +1687,7 @@ void ReverbState::process(const size_t samplesToDo, const al::span<const FloatBu
/* Convert B-Format to A-Format for processing. */
const size_t numInput{minz(samplesIn.size(), NUM_LINES)};
const al::span<float> tmpspan{al::assume_aligned<16>(mTempLine.data()), samplesToDo};
- for(size_t c{0u};c < NUM_LINES;c++)
+ for(size_t c{0u};c < NUM_LINES;++c)
{
std::fill(tmpspan.begin(), tmpspan.end(), 0.0f);
for(size_t i{0};i < numInput;++i)
@@ -1722,7 +1728,7 @@ void ReverbState::process(const size_t samplesToDo, const al::span<const FloatBu
const al::span<float> tmpspan{al::assume_aligned<16>(mTempLine.data()), samplesToDo};
const float fadeStep{1.0f / static_cast<float>(samplesToDo)};
- for(size_t c{0u};c < NUM_LINES;c++)
+ for(size_t c{0u};c < NUM_LINES;++c)
{
std::fill(tmpspan.begin(), tmpspan.end(), 0.0f);
for(size_t i{0};i < numInput;++i)
@@ -1746,7 +1752,7 @@ void ReverbState::process(const size_t samplesToDo, const al::span<const FloatBu
filter.process(tmpspan, tmpspan.data());
pipeline.mEarlyDelayIn.write(offset, c, tmpspan.cbegin(), samplesToDo);
}
- for(size_t c{0u};c < NUM_LINES;c++)
+ for(size_t c{0u};c < NUM_LINES;++c)
{
std::fill(tmpspan.begin(), tmpspan.end(), 0.0f);
for(size_t i{0};i < numInput;++i)
@@ -1783,7 +1789,7 @@ void ReverbState::process(const size_t samplesToDo, const al::span<const FloatBu
if(mPipelineState == Cleanup)
{
size_t numSamples{mSampleBuffer.size()/2};
- size_t pipelineOffset{numSamples * (mCurrentPipeline^1)};
+ size_t pipelineOffset{numSamples * (!mCurrentPipeline)};
std::fill_n(mSampleBuffer.data()+pipelineOffset, numSamples,
decltype(mSampleBuffer)::value_type{});
diff --git a/alc/effects/vmorpher.cpp b/alc/effects/vmorpher.cpp
index 872c7add..eaf30d07 100644
--- a/alc/effects/vmorpher.cpp
+++ b/alc/effects/vmorpher.cpp
@@ -57,29 +57,30 @@ namespace {
using uint = unsigned int;
-#define MAX_UPDATE_SAMPLES 256
-#define NUM_FORMANTS 4
-#define NUM_FILTERS 2
-#define Q_FACTOR 5.0f
-
-#define VOWEL_A_INDEX 0
-#define VOWEL_B_INDEX 1
+constexpr size_t MaxUpdateSamples{256};
+constexpr size_t NumFormants{4};
+constexpr float QFactor{5.0f};
+enum : size_t {
+ VowelAIndex,
+ VowelBIndex,
+ NumFilters
+};
-#define WAVEFORM_FRACBITS 24
-#define WAVEFORM_FRACONE (1<<WAVEFORM_FRACBITS)
-#define WAVEFORM_FRACMASK (WAVEFORM_FRACONE-1)
+constexpr size_t WaveformFracBits{24};
+constexpr size_t WaveformFracOne{1<<WaveformFracBits};
+constexpr size_t WaveformFracMask{WaveformFracOne-1};
inline float Sin(uint index)
{
- constexpr float scale{al::numbers::pi_v<float>*2.0f / WAVEFORM_FRACONE};
+ constexpr float scale{al::numbers::pi_v<float>*2.0f / float{WaveformFracOne}};
return std::sin(static_cast<float>(index) * scale)*0.5f + 0.5f;
}
inline float Saw(uint index)
-{ return static_cast<float>(index) / float{WAVEFORM_FRACONE}; }
+{ return static_cast<float>(index) / float{WaveformFracOne}; }
inline float Triangle(uint index)
-{ return std::fabs(static_cast<float>(index)*(2.0f/WAVEFORM_FRACONE) - 1.0f); }
+{ return std::fabs(static_cast<float>(index)*(2.0f/WaveformFracOne) - 1.0f); }
inline float Half(uint) { return 0.5f; }
@@ -89,13 +90,12 @@ void Oscillate(float *RESTRICT dst, uint index, const uint step, size_t todo)
for(size_t i{0u};i < todo;i++)
{
index += step;
- index &= WAVEFORM_FRACMASK;
+ index &= WaveformFracMask;
dst[i] = func(index);
}
}
-struct FormantFilter
-{
+struct FormantFilter {
float mCoeff{0.0f};
float mGain{1.0f};
float mS1{0.0f};
@@ -106,20 +106,21 @@ struct FormantFilter
: mCoeff{std::tan(al::numbers::pi_v<float> * f0norm)}, mGain{gain}
{ }
- inline void process(const float *samplesIn, float *samplesOut, const size_t numInput)
+ void process(const float *samplesIn, float *samplesOut, const size_t numInput) noexcept
{
/* A state variable filter from a topology-preserving transform.
* Based on a talk given by Ivan Cohen: https://www.youtube.com/watch?v=esjHXGPyrhg
*/
const float g{mCoeff};
const float gain{mGain};
- const float h{1.0f / (1.0f + (g/Q_FACTOR) + (g*g))};
+ const float h{1.0f / (1.0f + (g/QFactor) + (g*g))};
+ const float coeff{1.0f/QFactor + g};
float s1{mS1};
float s2{mS2};
for(size_t i{0u};i < numInput;i++)
{
- const float H{(samplesIn[i] - (1.0f/Q_FACTOR + g)*s1 - s2)*h};
+ const float H{(samplesIn[i] - coeff*s1 - s2)*h};
const float B{g*H + s1};
const float L{g*B + s2};
@@ -133,7 +134,7 @@ struct FormantFilter
mS2 = s2;
}
- inline void clear()
+ void clear() noexcept
{
mS1 = 0.0f;
mS2 = 0.0f;
@@ -142,16 +143,17 @@ struct FormantFilter
struct VmorpherState final : public EffectState {
- struct {
+ struct OutParams {
uint mTargetChannel{InvalidChannelIndex};
/* Effect parameters */
- FormantFilter mFormants[NUM_FILTERS][NUM_FORMANTS];
+ std::array<std::array<FormantFilter,NumFormants>,NumFilters> mFormants;
/* Effect gains for each channel */
float mCurrentGain{};
float mTargetGain{};
- } mChans[MaxAmbiChannels];
+ };
+ std::array<OutParams,MaxAmbiChannels> mChans;
void (*mGetSamples)(float*RESTRICT, uint, const uint, size_t){};
@@ -159,9 +161,9 @@ struct VmorpherState final : public EffectState {
uint mStep{1};
/* Effects buffers */
- alignas(16) float mSampleBufferA[MAX_UPDATE_SAMPLES]{};
- alignas(16) float mSampleBufferB[MAX_UPDATE_SAMPLES]{};
- alignas(16) float mLfo[MAX_UPDATE_SAMPLES]{};
+ alignas(16) std::array<float,MaxUpdateSamples> mSampleBufferA{};
+ alignas(16) std::array<float,MaxUpdateSamples> mSampleBufferB{};
+ alignas(16) std::array<float,MaxUpdateSamples> mLfo{};
void deviceUpdate(const DeviceBase *device, const BufferStorage *buffer) override;
void update(const ContextBase *context, const EffectSlot *slot, const EffectProps *props,
@@ -169,14 +171,12 @@ struct VmorpherState final : public EffectState {
void process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn,
const al::span<FloatBufferLine> samplesOut) override;
- static std::array<FormantFilter,4> getFiltersByPhoneme(VMorpherPhenome phoneme,
- float frequency, float pitch);
-
- DEF_NEWDEL(VmorpherState)
+ static std::array<FormantFilter,NumFormants> getFiltersByPhoneme(VMorpherPhenome phoneme,
+ float frequency, float pitch) noexcept;
};
-std::array<FormantFilter,4> VmorpherState::getFiltersByPhoneme(VMorpherPhenome phoneme,
- float frequency, float pitch)
+std::array<FormantFilter,NumFormants> VmorpherState::getFiltersByPhoneme(VMorpherPhenome phoneme,
+ float frequency, float pitch) noexcept
{
/* Using soprano formant set of values to
* better match mid-range frequency space.
@@ -232,44 +232,43 @@ void VmorpherState::deviceUpdate(const DeviceBase*, const BufferStorage*)
for(auto &e : mChans)
{
e.mTargetChannel = InvalidChannelIndex;
- std::for_each(std::begin(e.mFormants[VOWEL_A_INDEX]), std::end(e.mFormants[VOWEL_A_INDEX]),
+ std::for_each(e.mFormants[VowelAIndex].begin(), e.mFormants[VowelAIndex].end(),
std::mem_fn(&FormantFilter::clear));
- std::for_each(std::begin(e.mFormants[VOWEL_B_INDEX]), std::end(e.mFormants[VOWEL_B_INDEX]),
+ std::for_each(e.mFormants[VowelBIndex].begin(), e.mFormants[VowelBIndex].end(),
std::mem_fn(&FormantFilter::clear));
e.mCurrentGain = 0.0f;
}
}
void VmorpherState::update(const ContextBase *context, const EffectSlot *slot,
- const EffectProps *props, const EffectTarget target)
+ const EffectProps *props_, const EffectTarget target)
{
+ auto &props = std::get<VmorpherProps>(*props_);
const DeviceBase *device{context->mDevice};
const float frequency{static_cast<float>(device->Frequency)};
- const float step{props->Vmorpher.Rate / frequency};
- mStep = fastf2u(clampf(step*WAVEFORM_FRACONE, 0.0f, float{WAVEFORM_FRACONE-1}));
+ const float step{props.Rate / frequency};
+ mStep = fastf2u(clampf(step*WaveformFracOne, 0.0f, float{WaveformFracOne}-1.0f));
if(mStep == 0)
mGetSamples = Oscillate<Half>;
- else if(props->Vmorpher.Waveform == VMorpherWaveform::Sinusoid)
+ else if(props.Waveform == VMorpherWaveform::Sinusoid)
mGetSamples = Oscillate<Sin>;
- else if(props->Vmorpher.Waveform == VMorpherWaveform::Triangle)
+ else if(props.Waveform == VMorpherWaveform::Triangle)
mGetSamples = Oscillate<Triangle>;
- else /*if(props->Vmorpher.Waveform == VMorpherWaveform::Sawtooth)*/
+ else /*if(props.Waveform == VMorpherWaveform::Sawtooth)*/
mGetSamples = Oscillate<Saw>;
- const float pitchA{std::pow(2.0f,
- static_cast<float>(props->Vmorpher.PhonemeACoarseTuning) / 12.0f)};
- const float pitchB{std::pow(2.0f,
- static_cast<float>(props->Vmorpher.PhonemeBCoarseTuning) / 12.0f)};
+ const float pitchA{std::pow(2.0f, static_cast<float>(props.PhonemeACoarseTuning) / 12.0f)};
+ const float pitchB{std::pow(2.0f, static_cast<float>(props.PhonemeBCoarseTuning) / 12.0f)};
- auto vowelA = getFiltersByPhoneme(props->Vmorpher.PhonemeA, frequency, pitchA);
- auto vowelB = getFiltersByPhoneme(props->Vmorpher.PhonemeB, frequency, pitchB);
+ auto vowelA = getFiltersByPhoneme(props.PhonemeA, frequency, pitchA);
+ auto vowelB = getFiltersByPhoneme(props.PhonemeB, frequency, pitchB);
/* Copy the filter coefficients to the input channels. */
for(size_t i{0u};i < slot->Wet.Buffer.size();++i)
{
- std::copy(vowelA.begin(), vowelA.end(), std::begin(mChans[i].mFormants[VOWEL_A_INDEX]));
- std::copy(vowelB.begin(), vowelB.end(), std::begin(mChans[i].mFormants[VOWEL_B_INDEX]));
+ std::copy(vowelA.begin(), vowelA.end(), mChans[i].mFormants[VowelAIndex].begin());
+ std::copy(vowelB.begin(), vowelB.end(), mChans[i].mFormants[VowelBIndex].begin());
}
mOutTarget = target.Main->Buffer;
@@ -288,11 +287,11 @@ void VmorpherState::process(const size_t samplesToDo, const al::span<const Float
*/
for(size_t base{0u};base < samplesToDo;)
{
- const size_t td{minz(MAX_UPDATE_SAMPLES, samplesToDo-base)};
+ const size_t td{minz(MaxUpdateSamples, samplesToDo-base)};
- mGetSamples(mLfo, mIndex, mStep, td);
+ mGetSamples(mLfo.data(), mIndex, mStep, td);
mIndex += static_cast<uint>(mStep * td);
- mIndex &= WAVEFORM_FRACMASK;
+ mIndex &= WaveformFracMask;
auto chandata = std::begin(mChans);
for(const auto &input : samplesIn)
@@ -304,30 +303,30 @@ void VmorpherState::process(const size_t samplesToDo, const al::span<const Float
continue;
}
- auto& vowelA = chandata->mFormants[VOWEL_A_INDEX];
- auto& vowelB = chandata->mFormants[VOWEL_B_INDEX];
+ const auto vowelA = al::span{chandata->mFormants[VowelAIndex]};
+ const auto vowelB = al::span{chandata->mFormants[VowelBIndex]};
/* Process first vowel. */
std::fill_n(std::begin(mSampleBufferA), td, 0.0f);
- vowelA[0].process(&input[base], mSampleBufferA, td);
- vowelA[1].process(&input[base], mSampleBufferA, td);
- vowelA[2].process(&input[base], mSampleBufferA, td);
- vowelA[3].process(&input[base], mSampleBufferA, td);
+ vowelA[0].process(&input[base], mSampleBufferA.data(), td);
+ vowelA[1].process(&input[base], mSampleBufferA.data(), td);
+ vowelA[2].process(&input[base], mSampleBufferA.data(), td);
+ vowelA[3].process(&input[base], mSampleBufferA.data(), td);
/* Process second vowel. */
std::fill_n(std::begin(mSampleBufferB), td, 0.0f);
- vowelB[0].process(&input[base], mSampleBufferB, td);
- vowelB[1].process(&input[base], mSampleBufferB, td);
- vowelB[2].process(&input[base], mSampleBufferB, td);
- vowelB[3].process(&input[base], mSampleBufferB, td);
+ vowelB[0].process(&input[base], mSampleBufferB.data(), td);
+ vowelB[1].process(&input[base], mSampleBufferB.data(), td);
+ vowelB[2].process(&input[base], mSampleBufferB.data(), td);
+ vowelB[3].process(&input[base], mSampleBufferB.data(), td);
- alignas(16) float blended[MAX_UPDATE_SAMPLES];
+ alignas(16) std::array<float,MaxUpdateSamples> blended;
for(size_t i{0u};i < td;i++)
blended[i] = lerpf(mSampleBufferA[i], mSampleBufferB[i], mLfo[i]);
/* Now, mix the processed sound data to the output. */
- MixSamples({blended, td}, samplesOut[outidx].data()+base, chandata->mCurrentGain,
- chandata->mTargetGain, samplesToDo-base);
+ MixSamples({blended.data(), td}, samplesOut[outidx].data()+base,
+ chandata->mCurrentGain, chandata->mTargetGain, samplesToDo-base);
++chandata;
}
diff --git a/alc/export_list.h b/alc/export_list.h
index c5af1ab0..7856bdc8 100644
--- a/alc/export_list.h
+++ b/alc/export_list.h
@@ -16,7 +16,8 @@ struct FuncExport {
const char *funcName;
void *address;
};
-#define DECL(x) { #x, reinterpret_cast<void*>(x) }
+#define DECL(x) FuncExport{#x, reinterpret_cast<void*>(x)}
+/* NOLINTNEXTLINE(*-avoid-c-arrays) Too large for std::array auto-deduction :( */
inline const FuncExport alcFunctions[]{
DECL(alcCreateContext),
DECL(alcMakeContextCurrent),
@@ -376,8 +377,9 @@ inline const FuncExport alcFunctions[]{
/* Extra functions */
DECL(alsoft_set_log_callback),
+};
#ifdef ALSOFT_EAX
-}, eaxFunctions[]{
+inline const std::array eaxFunctions{
DECL(EAXGet),
DECL(EAXSet),
DECL(EAXGetBufferMode),
@@ -387,15 +389,16 @@ inline const FuncExport alcFunctions[]{
DECL(EAXSetDirect),
DECL(EAXGetBufferModeDirect),
DECL(EAXSetBufferModeDirect),
-#endif
};
+#endif
#undef DECL
struct EnumExport {
const char *enumName;
int value;
};
-#define DECL(x) { #x, (x) }
+#define DECL(x) EnumExport{#x, (x)}
+/* NOLINTNEXTLINE(*-avoid-c-arrays) Too large for std::array auto-deduction :( */
inline const EnumExport alcEnumerations[]{
DECL(ALC_INVALID),
DECL(ALC_FALSE),
@@ -901,15 +904,16 @@ inline const EnumExport alcEnumerations[]{
DECL(AL_AUXILIARY_EFFECT_SLOT_EXT),
DECL(AL_STOP_SOURCES_ON_DISCONNECT_SOFT),
+};
#ifdef ALSOFT_EAX
-}, eaxEnumerations[]{
+inline const std::array eaxEnumerations{
DECL(AL_EAX_RAM_SIZE),
DECL(AL_EAX_RAM_FREE),
DECL(AL_STORAGE_AUTOMATIC),
DECL(AL_STORAGE_HARDWARE),
DECL(AL_STORAGE_ACCESSIBLE),
-#endif // ALSOFT_EAX
};
+#endif // ALSOFT_EAX
#undef DECL
#endif /* ALC_EXPORT_LIST_H */
diff --git a/alc/inprogext.h b/alc/inprogext.h
index c5b09f13..a150af86 100644
--- a/alc/inprogext.h
+++ b/alc/inprogext.h
@@ -1,6 +1,7 @@
#ifndef INPROGEXT_H
#define INPROGEXT_H
+/* NOLINTBEGIN */
#include "AL/al.h"
#include "AL/alc.h"
#include "AL/alext.h"
@@ -398,24 +399,24 @@ ALenum AL_APIENTRY EAXGetBufferModeDirect(ALCcontext *context, ALuint buffer, AL
#endif
#endif
-#ifndef AL_EXT_int32
-#define AL_EXT_int32
+#ifndef AL_EXT_32bit_formats
+#define AL_EXT_32bit_formats
#define AL_FORMAT_MONO_I32 0x1202 /* Same as AL_FORMAT_MONO32 */
#define AL_FORMAT_STEREO_I32 0x1203 /* Same as AL_FORMAT_STEREO32 */
#define AL_FORMAT_REAR_I32 0x19DB
-#define AL_FORMAT_QUAD_I32 0x19DC
-#define AL_FORMAT_51CHN_I32 0x19DD
-#define AL_FORMAT_61CHN_I32 0x19DE
-#define AL_FORMAT_71CHN_I32 0x19DF
-#define AL_FORMAT_UHJ2CHN_I32 0x19E0
-#define AL_FORMAT_UHJ3CHN_I32 0x19E1
-#define AL_FORMAT_UHJ4CHN_I32 0x19E2
-
-#define AL_FORMAT_REAR_FLOAT32 0x19E3
-#define AL_FORMAT_QUAD_FLOAT32 0x19E4
-#define AL_FORMAT_51CHN_FLOAT32 0x19E5
-#define AL_FORMAT_61CHN_FLOAT32 0x19E6
-#define AL_FORMAT_71CHN_FLOAT32 0x19E7
+#define AL_FORMAT_REAR_FLOAT32 0x19DC
+#define AL_FORMAT_QUAD_I32 0x19DD
+#define AL_FORMAT_QUAD_FLOAT32 0x19DE
+#define AL_FORMAT_51CHN_I32 0x19DF
+#define AL_FORMAT_51CHN_FLOAT32 0x19E0
+#define AL_FORMAT_61CHN_I32 0x19E1
+#define AL_FORMAT_61CHN_FLOAT32 0x19E2
+#define AL_FORMAT_71CHN_I32 0x19E3
+#define AL_FORMAT_71CHN_FLOAT32 0x19E4
+
+#define AL_FORMAT_UHJ2CHN_I32 0x19E5
+#define AL_FORMAT_UHJ3CHN_I32 0x19E6
+#define AL_FORMAT_UHJ4CHN_I32 0x19E7
#endif
/* Non-standard exports. Not part of any extension. */
@@ -436,5 +437,6 @@ void AL_APIENTRY alGetInteger64vDirectSOFT(ALCcontext *context, ALenum pname, AL
#ifdef __cplusplus
} /* extern "C" */
#endif
+/* NOLINTEND */
#endif /* INPROGEXT_H */
diff --git a/alc/panning.cpp b/alc/panning.cpp
index b512a42a..3b40687e 100644
--- a/alc/panning.cpp
+++ b/alc/panning.cpp
@@ -227,10 +227,10 @@ struct DecoderConfig<DualBand, 0> {
using DecoderView = DecoderConfig<DualBand, 0>;
-void InitNearFieldCtrl(ALCdevice *device, float ctrl_dist, uint order, bool is3d)
+void InitNearFieldCtrl(ALCdevice *device, const float ctrl_dist, const uint order, const bool is3d)
{
- static const uint chans_per_order2d[MaxAmbiOrder+1]{ 1, 2, 2, 2 };
- static const uint chans_per_order3d[MaxAmbiOrder+1]{ 1, 3, 5, 7 };
+ static const std::array<uint,MaxAmbiOrder+1> chans_per_order2d{{1, 2, 2, 2}};
+ static const std::array<uint,MaxAmbiOrder+1> chans_per_order3d{{1, 3, 5, 7}};
/* NFC is only used when AvgSpeakerDist is greater than 0. */
if(!device->getConfigValueBool("decoder", "nfc", false) || !(ctrl_dist > 0.0f))
@@ -243,13 +243,13 @@ void InitNearFieldCtrl(ALCdevice *device, float ctrl_dist, uint order, bool is3d
(device->AvgSpeakerDist * static_cast<float>(device->Frequency))};
device->mNFCtrlFilter.init(w1);
- auto iter = std::copy_n(is3d ? chans_per_order3d : chans_per_order2d, order+1u,
+ auto iter = std::copy_n(is3d ? chans_per_order3d.begin() : chans_per_order2d.begin(), order+1u,
std::begin(device->NumChannelsPerOrder));
std::fill(iter, std::end(device->NumChannelsPerOrder), 0u);
}
void InitDistanceComp(ALCdevice *device, const al::span<const Channel> channels,
- const al::span<const float,MAX_OUTPUT_CHANNELS> dists)
+ const al::span<const float,MaxOutputChannels> dists)
{
const float maxdist{std::accumulate(std::begin(dists), std::end(dists), 0.0f, maxf)};
@@ -329,7 +329,7 @@ constexpr auto GetAmbiLayout(DevAmbiLayout layouttype) noexcept
DecoderView MakeDecoderView(ALCdevice *device, const AmbDecConf *conf,
- DecoderConfig<DualBand, MAX_OUTPUT_CHANNELS> &decoder)
+ DecoderConfig<DualBand,MaxOutputChannels> &decoder)
{
DecoderView ret{};
@@ -361,8 +361,7 @@ DecoderView MakeDecoderView(ALCdevice *device, const AmbDecConf *conf,
const auto lfmatrix = conf->LFMatrix;
uint chan_count{0};
- using const_speaker_span = al::span<const AmbDecConf::SpeakerConf>;
- for(auto &speaker : const_speaker_span{conf->Speakers.get(), conf->NumSpeakers})
+ for(auto &speaker : al::span<const AmbDecConf::SpeakerConf>{conf->Speakers})
{
/* NOTE: AmbDec does not define any standard speaker names, however
* for this to work we have to by able to find the output channel
@@ -708,120 +707,126 @@ void InitPanning(ALCdevice *device, const bool hqdec=false, const bool stablize=
void InitHrtfPanning(ALCdevice *device)
{
- constexpr float Deg180{al::numbers::pi_v<float>};
- constexpr float Deg_90{Deg180 / 2.0f /* 90 degrees*/};
- constexpr float Deg_45{Deg_90 / 2.0f /* 45 degrees*/};
- constexpr float Deg135{Deg_45 * 3.0f /*135 degrees*/};
- constexpr float Deg_21{3.648638281e-01f /* 20~ 21 degrees*/};
- constexpr float Deg_32{5.535743589e-01f /* 31~ 32 degrees*/};
- constexpr float Deg_35{6.154797087e-01f /* 35~ 36 degrees*/};
- constexpr float Deg_58{1.017221968e+00f /* 58~ 59 degrees*/};
- constexpr float Deg_69{1.205932499e+00f /* 69~ 70 degrees*/};
- constexpr float Deg111{1.935660155e+00f /*110~111 degrees*/};
- constexpr float Deg122{2.124370686e+00f /*121~122 degrees*/};
- static const AngularPoint AmbiPoints1O[]{
- { EvRadians{ Deg_35}, AzRadians{-Deg_45} },
- { EvRadians{ Deg_35}, AzRadians{-Deg135} },
- { EvRadians{ Deg_35}, AzRadians{ Deg_45} },
- { EvRadians{ Deg_35}, AzRadians{ Deg135} },
- { EvRadians{-Deg_35}, AzRadians{-Deg_45} },
- { EvRadians{-Deg_35}, AzRadians{-Deg135} },
- { EvRadians{-Deg_35}, AzRadians{ Deg_45} },
- { EvRadians{-Deg_35}, AzRadians{ Deg135} },
- }, AmbiPoints2O[]{
- { EvRadians{-Deg_32}, AzRadians{ 0.0f} },
- { EvRadians{ 0.0f}, AzRadians{ Deg_58} },
- { EvRadians{ Deg_58}, AzRadians{ Deg_90} },
- { EvRadians{ Deg_32}, AzRadians{ 0.0f} },
- { EvRadians{ 0.0f}, AzRadians{ Deg122} },
- { EvRadians{-Deg_58}, AzRadians{-Deg_90} },
- { EvRadians{-Deg_32}, AzRadians{ Deg180} },
- { EvRadians{ 0.0f}, AzRadians{-Deg122} },
- { EvRadians{ Deg_58}, AzRadians{-Deg_90} },
- { EvRadians{ Deg_32}, AzRadians{ Deg180} },
- { EvRadians{ 0.0f}, AzRadians{-Deg_58} },
- { EvRadians{-Deg_58}, AzRadians{ Deg_90} },
- }, AmbiPoints3O[]{
- { EvRadians{ Deg_69}, AzRadians{-Deg_90} },
- { EvRadians{ Deg_69}, AzRadians{ Deg_90} },
- { EvRadians{-Deg_69}, AzRadians{-Deg_90} },
- { EvRadians{-Deg_69}, AzRadians{ Deg_90} },
- { EvRadians{ 0.0f}, AzRadians{-Deg_69} },
- { EvRadians{ 0.0f}, AzRadians{-Deg111} },
- { EvRadians{ 0.0f}, AzRadians{ Deg_69} },
- { EvRadians{ 0.0f}, AzRadians{ Deg111} },
- { EvRadians{ Deg_21}, AzRadians{ 0.0f} },
- { EvRadians{ Deg_21}, AzRadians{ Deg180} },
- { EvRadians{-Deg_21}, AzRadians{ 0.0f} },
- { EvRadians{-Deg_21}, AzRadians{ Deg180} },
- { EvRadians{ Deg_35}, AzRadians{-Deg_45} },
- { EvRadians{ Deg_35}, AzRadians{-Deg135} },
- { EvRadians{ Deg_35}, AzRadians{ Deg_45} },
- { EvRadians{ Deg_35}, AzRadians{ Deg135} },
- { EvRadians{-Deg_35}, AzRadians{-Deg_45} },
- { EvRadians{-Deg_35}, AzRadians{-Deg135} },
- { EvRadians{-Deg_35}, AzRadians{ Deg_45} },
- { EvRadians{-Deg_35}, AzRadians{ Deg135} },
+ static constexpr float Deg180{al::numbers::pi_v<float>};
+ static constexpr float Deg_90{Deg180 / 2.0f /* 90 degrees*/};
+ static constexpr float Deg_45{Deg_90 / 2.0f /* 45 degrees*/};
+ static constexpr float Deg135{Deg_45 * 3.0f /*135 degrees*/};
+ static constexpr float Deg_21{3.648638281e-01f /* 20~ 21 degrees*/};
+ static constexpr float Deg_32{5.535743589e-01f /* 31~ 32 degrees*/};
+ static constexpr float Deg_35{6.154797087e-01f /* 35~ 36 degrees*/};
+ static constexpr float Deg_58{1.017221968e+00f /* 58~ 59 degrees*/};
+ static constexpr float Deg_69{1.205932499e+00f /* 69~ 70 degrees*/};
+ static constexpr float Deg111{1.935660155e+00f /*110~111 degrees*/};
+ static constexpr float Deg122{2.124370686e+00f /*121~122 degrees*/};
+ static constexpr std::array AmbiPoints1O{
+ AngularPoint{EvRadians{ Deg_35}, AzRadians{-Deg_45}},
+ AngularPoint{EvRadians{ Deg_35}, AzRadians{-Deg135}},
+ AngularPoint{EvRadians{ Deg_35}, AzRadians{ Deg_45}},
+ AngularPoint{EvRadians{ Deg_35}, AzRadians{ Deg135}},
+ AngularPoint{EvRadians{-Deg_35}, AzRadians{-Deg_45}},
+ AngularPoint{EvRadians{-Deg_35}, AzRadians{-Deg135}},
+ AngularPoint{EvRadians{-Deg_35}, AzRadians{ Deg_45}},
+ AngularPoint{EvRadians{-Deg_35}, AzRadians{ Deg135}},
};
- static const float AmbiMatrix1O[][MaxAmbiChannels]{
- { 1.250000000e-01f, 1.250000000e-01f, 1.250000000e-01f, 1.250000000e-01f },
- { 1.250000000e-01f, 1.250000000e-01f, 1.250000000e-01f, -1.250000000e-01f },
- { 1.250000000e-01f, -1.250000000e-01f, 1.250000000e-01f, 1.250000000e-01f },
- { 1.250000000e-01f, -1.250000000e-01f, 1.250000000e-01f, -1.250000000e-01f },
- { 1.250000000e-01f, 1.250000000e-01f, -1.250000000e-01f, 1.250000000e-01f },
- { 1.250000000e-01f, 1.250000000e-01f, -1.250000000e-01f, -1.250000000e-01f },
- { 1.250000000e-01f, -1.250000000e-01f, -1.250000000e-01f, 1.250000000e-01f },
- { 1.250000000e-01f, -1.250000000e-01f, -1.250000000e-01f, -1.250000000e-01f },
- }, AmbiMatrix2O[][MaxAmbiChannels]{
- { 8.333333333e-02f, 0.000000000e+00f, -7.588274978e-02f, 1.227808683e-01f, 0.000000000e+00f, 0.000000000e+00f, -1.591525047e-02f, -1.443375673e-01f, 1.167715449e-01f, },
- { 8.333333333e-02f, -1.227808683e-01f, 0.000000000e+00f, 7.588274978e-02f, -1.443375673e-01f, 0.000000000e+00f, -9.316949906e-02f, 0.000000000e+00f, -7.216878365e-02f, },
- { 8.333333333e-02f, -7.588274978e-02f, 1.227808683e-01f, 0.000000000e+00f, 0.000000000e+00f, -1.443375673e-01f, 1.090847495e-01f, 0.000000000e+00f, -4.460276122e-02f, },
- { 8.333333333e-02f, 0.000000000e+00f, 7.588274978e-02f, 1.227808683e-01f, 0.000000000e+00f, 0.000000000e+00f, -1.591525047e-02f, 1.443375673e-01f, 1.167715449e-01f, },
- { 8.333333333e-02f, -1.227808683e-01f, 0.000000000e+00f, -7.588274978e-02f, 1.443375673e-01f, 0.000000000e+00f, -9.316949906e-02f, 0.000000000e+00f, -7.216878365e-02f, },
- { 8.333333333e-02f, 7.588274978e-02f, -1.227808683e-01f, 0.000000000e+00f, 0.000000000e+00f, -1.443375673e-01f, 1.090847495e-01f, 0.000000000e+00f, -4.460276122e-02f, },
- { 8.333333333e-02f, 0.000000000e+00f, -7.588274978e-02f, -1.227808683e-01f, 0.000000000e+00f, 0.000000000e+00f, -1.591525047e-02f, 1.443375673e-01f, 1.167715449e-01f, },
- { 8.333333333e-02f, 1.227808683e-01f, 0.000000000e+00f, -7.588274978e-02f, -1.443375673e-01f, 0.000000000e+00f, -9.316949906e-02f, 0.000000000e+00f, -7.216878365e-02f, },
- { 8.333333333e-02f, 7.588274978e-02f, 1.227808683e-01f, 0.000000000e+00f, 0.000000000e+00f, 1.443375673e-01f, 1.090847495e-01f, 0.000000000e+00f, -4.460276122e-02f, },
- { 8.333333333e-02f, 0.000000000e+00f, 7.588274978e-02f, -1.227808683e-01f, 0.000000000e+00f, 0.000000000e+00f, -1.591525047e-02f, -1.443375673e-01f, 1.167715449e-01f, },
- { 8.333333333e-02f, 1.227808683e-01f, 0.000000000e+00f, 7.588274978e-02f, 1.443375673e-01f, 0.000000000e+00f, -9.316949906e-02f, 0.000000000e+00f, -7.216878365e-02f, },
- { 8.333333333e-02f, -7.588274978e-02f, -1.227808683e-01f, 0.000000000e+00f, 0.000000000e+00f, 1.443375673e-01f, 1.090847495e-01f, 0.000000000e+00f, -4.460276122e-02f, },
- }, AmbiMatrix3O[][MaxAmbiChannels]{
- { 5.000000000e-02f, 3.090169944e-02f, 8.090169944e-02f, 0.000000000e+00f, 0.000000000e+00f, 6.454972244e-02f, 9.045084972e-02f, 0.000000000e+00f, -1.232790000e-02f, -1.256118221e-01f, 0.000000000e+00f, 1.126112056e-01f, 7.944389175e-02f, 0.000000000e+00f, 2.421151497e-02f, 0.000000000e+00f, },
- { 5.000000000e-02f, -3.090169944e-02f, 8.090169944e-02f, 0.000000000e+00f, 0.000000000e+00f, -6.454972244e-02f, 9.045084972e-02f, 0.000000000e+00f, -1.232790000e-02f, 1.256118221e-01f, 0.000000000e+00f, -1.126112056e-01f, 7.944389175e-02f, 0.000000000e+00f, 2.421151497e-02f, 0.000000000e+00f, },
- { 5.000000000e-02f, 3.090169944e-02f, -8.090169944e-02f, 0.000000000e+00f, 0.000000000e+00f, -6.454972244e-02f, 9.045084972e-02f, 0.000000000e+00f, -1.232790000e-02f, -1.256118221e-01f, 0.000000000e+00f, 1.126112056e-01f, -7.944389175e-02f, 0.000000000e+00f, -2.421151497e-02f, 0.000000000e+00f, },
- { 5.000000000e-02f, -3.090169944e-02f, -8.090169944e-02f, 0.000000000e+00f, 0.000000000e+00f, 6.454972244e-02f, 9.045084972e-02f, 0.000000000e+00f, -1.232790000e-02f, 1.256118221e-01f, 0.000000000e+00f, -1.126112056e-01f, -7.944389175e-02f, 0.000000000e+00f, -2.421151497e-02f, 0.000000000e+00f, },
- { 5.000000000e-02f, 8.090169944e-02f, 0.000000000e+00f, 3.090169944e-02f, 6.454972244e-02f, 0.000000000e+00f, -5.590169944e-02f, 0.000000000e+00f, -7.216878365e-02f, -7.763237543e-02f, 0.000000000e+00f, -2.950836627e-02f, 0.000000000e+00f, -1.497759251e-01f, 0.000000000e+00f, -7.763237543e-02f, },
- { 5.000000000e-02f, 8.090169944e-02f, 0.000000000e+00f, -3.090169944e-02f, -6.454972244e-02f, 0.000000000e+00f, -5.590169944e-02f, 0.000000000e+00f, -7.216878365e-02f, -7.763237543e-02f, 0.000000000e+00f, -2.950836627e-02f, 0.000000000e+00f, 1.497759251e-01f, 0.000000000e+00f, 7.763237543e-02f, },
- { 5.000000000e-02f, -8.090169944e-02f, 0.000000000e+00f, 3.090169944e-02f, -6.454972244e-02f, 0.000000000e+00f, -5.590169944e-02f, 0.000000000e+00f, -7.216878365e-02f, 7.763237543e-02f, 0.000000000e+00f, 2.950836627e-02f, 0.000000000e+00f, -1.497759251e-01f, 0.000000000e+00f, -7.763237543e-02f, },
- { 5.000000000e-02f, -8.090169944e-02f, 0.000000000e+00f, -3.090169944e-02f, 6.454972244e-02f, 0.000000000e+00f, -5.590169944e-02f, 0.000000000e+00f, -7.216878365e-02f, 7.763237543e-02f, 0.000000000e+00f, 2.950836627e-02f, 0.000000000e+00f, 1.497759251e-01f, 0.000000000e+00f, 7.763237543e-02f, },
- { 5.000000000e-02f, 0.000000000e+00f, 3.090169944e-02f, 8.090169944e-02f, 0.000000000e+00f, 0.000000000e+00f, -3.454915028e-02f, 6.454972244e-02f, 8.449668365e-02f, 0.000000000e+00f, 0.000000000e+00f, 0.000000000e+00f, 3.034486645e-02f, -6.779013272e-02f, 1.659481923e-01f, 4.797944664e-02f, },
- { 5.000000000e-02f, 0.000000000e+00f, 3.090169944e-02f, -8.090169944e-02f, 0.000000000e+00f, 0.000000000e+00f, -3.454915028e-02f, -6.454972244e-02f, 8.449668365e-02f, 0.000000000e+00f, 0.000000000e+00f, 0.000000000e+00f, 3.034486645e-02f, 6.779013272e-02f, 1.659481923e-01f, -4.797944664e-02f, },
- { 5.000000000e-02f, 0.000000000e+00f, -3.090169944e-02f, 8.090169944e-02f, 0.000000000e+00f, 0.000000000e+00f, -3.454915028e-02f, -6.454972244e-02f, 8.449668365e-02f, 0.000000000e+00f, 0.000000000e+00f, 0.000000000e+00f, -3.034486645e-02f, -6.779013272e-02f, -1.659481923e-01f, 4.797944664e-02f, },
- { 5.000000000e-02f, 0.000000000e+00f, -3.090169944e-02f, -8.090169944e-02f, 0.000000000e+00f, 0.000000000e+00f, -3.454915028e-02f, 6.454972244e-02f, 8.449668365e-02f, 0.000000000e+00f, 0.000000000e+00f, 0.000000000e+00f, -3.034486645e-02f, 6.779013272e-02f, -1.659481923e-01f, -4.797944664e-02f, },
- { 5.000000000e-02f, 5.000000000e-02f, 5.000000000e-02f, 5.000000000e-02f, 6.454972244e-02f, 6.454972244e-02f, 0.000000000e+00f, 6.454972244e-02f, 0.000000000e+00f, 1.016220987e-01f, 6.338656910e-02f, -1.092600649e-02f, -7.364853795e-02f, 1.011266756e-01f, -7.086833869e-02f, -1.482646439e-02f, },
- { 5.000000000e-02f, 5.000000000e-02f, 5.000000000e-02f, -5.000000000e-02f, -6.454972244e-02f, 6.454972244e-02f, 0.000000000e+00f, -6.454972244e-02f, 0.000000000e+00f, 1.016220987e-01f, -6.338656910e-02f, -1.092600649e-02f, -7.364853795e-02f, -1.011266756e-01f, -7.086833869e-02f, 1.482646439e-02f, },
- { 5.000000000e-02f, -5.000000000e-02f, 5.000000000e-02f, 5.000000000e-02f, -6.454972244e-02f, -6.454972244e-02f, 0.000000000e+00f, 6.454972244e-02f, 0.000000000e+00f, -1.016220987e-01f, -6.338656910e-02f, 1.092600649e-02f, -7.364853795e-02f, 1.011266756e-01f, -7.086833869e-02f, -1.482646439e-02f, },
- { 5.000000000e-02f, -5.000000000e-02f, 5.000000000e-02f, -5.000000000e-02f, 6.454972244e-02f, -6.454972244e-02f, 0.000000000e+00f, -6.454972244e-02f, 0.000000000e+00f, -1.016220987e-01f, 6.338656910e-02f, 1.092600649e-02f, -7.364853795e-02f, -1.011266756e-01f, -7.086833869e-02f, 1.482646439e-02f, },
- { 5.000000000e-02f, 5.000000000e-02f, -5.000000000e-02f, 5.000000000e-02f, 6.454972244e-02f, -6.454972244e-02f, 0.000000000e+00f, -6.454972244e-02f, 0.000000000e+00f, 1.016220987e-01f, -6.338656910e-02f, -1.092600649e-02f, 7.364853795e-02f, 1.011266756e-01f, 7.086833869e-02f, -1.482646439e-02f, },
- { 5.000000000e-02f, 5.000000000e-02f, -5.000000000e-02f, -5.000000000e-02f, -6.454972244e-02f, -6.454972244e-02f, 0.000000000e+00f, 6.454972244e-02f, 0.000000000e+00f, 1.016220987e-01f, 6.338656910e-02f, -1.092600649e-02f, 7.364853795e-02f, -1.011266756e-01f, 7.086833869e-02f, 1.482646439e-02f, },
- { 5.000000000e-02f, -5.000000000e-02f, -5.000000000e-02f, 5.000000000e-02f, -6.454972244e-02f, 6.454972244e-02f, 0.000000000e+00f, -6.454972244e-02f, 0.000000000e+00f, -1.016220987e-01f, 6.338656910e-02f, 1.092600649e-02f, 7.364853795e-02f, 1.011266756e-01f, 7.086833869e-02f, -1.482646439e-02f, },
- { 5.000000000e-02f, -5.000000000e-02f, -5.000000000e-02f, -5.000000000e-02f, 6.454972244e-02f, 6.454972244e-02f, 0.000000000e+00f, 6.454972244e-02f, 0.000000000e+00f, -1.016220987e-01f, -6.338656910e-02f, 1.092600649e-02f, 7.364853795e-02f, -1.011266756e-01f, 7.086833869e-02f, 1.482646439e-02f, },
+ static constexpr std::array AmbiPoints2O{
+ AngularPoint{EvRadians{-Deg_32}, AzRadians{ 0.0f}},
+ AngularPoint{EvRadians{ 0.0f}, AzRadians{ Deg_58}},
+ AngularPoint{EvRadians{ Deg_58}, AzRadians{ Deg_90}},
+ AngularPoint{EvRadians{ Deg_32}, AzRadians{ 0.0f}},
+ AngularPoint{EvRadians{ 0.0f}, AzRadians{ Deg122}},
+ AngularPoint{EvRadians{-Deg_58}, AzRadians{-Deg_90}},
+ AngularPoint{EvRadians{-Deg_32}, AzRadians{ Deg180}},
+ AngularPoint{EvRadians{ 0.0f}, AzRadians{-Deg122}},
+ AngularPoint{EvRadians{ Deg_58}, AzRadians{-Deg_90}},
+ AngularPoint{EvRadians{ Deg_32}, AzRadians{ Deg180}},
+ AngularPoint{EvRadians{ 0.0f}, AzRadians{-Deg_58}},
+ AngularPoint{EvRadians{-Deg_58}, AzRadians{ Deg_90}},
};
- static const float AmbiOrderHFGain1O[MaxAmbiOrder+1]{
+ static constexpr std::array AmbiPoints3O{
+ AngularPoint{EvRadians{ Deg_69}, AzRadians{-Deg_90}},
+ AngularPoint{EvRadians{ Deg_69}, AzRadians{ Deg_90}},
+ AngularPoint{EvRadians{-Deg_69}, AzRadians{-Deg_90}},
+ AngularPoint{EvRadians{-Deg_69}, AzRadians{ Deg_90}},
+ AngularPoint{EvRadians{ 0.0f}, AzRadians{-Deg_69}},
+ AngularPoint{EvRadians{ 0.0f}, AzRadians{-Deg111}},
+ AngularPoint{EvRadians{ 0.0f}, AzRadians{ Deg_69}},
+ AngularPoint{EvRadians{ 0.0f}, AzRadians{ Deg111}},
+ AngularPoint{EvRadians{ Deg_21}, AzRadians{ 0.0f}},
+ AngularPoint{EvRadians{ Deg_21}, AzRadians{ Deg180}},
+ AngularPoint{EvRadians{-Deg_21}, AzRadians{ 0.0f}},
+ AngularPoint{EvRadians{-Deg_21}, AzRadians{ Deg180}},
+ AngularPoint{EvRadians{ Deg_35}, AzRadians{-Deg_45}},
+ AngularPoint{EvRadians{ Deg_35}, AzRadians{-Deg135}},
+ AngularPoint{EvRadians{ Deg_35}, AzRadians{ Deg_45}},
+ AngularPoint{EvRadians{ Deg_35}, AzRadians{ Deg135}},
+ AngularPoint{EvRadians{-Deg_35}, AzRadians{-Deg_45}},
+ AngularPoint{EvRadians{-Deg_35}, AzRadians{-Deg135}},
+ AngularPoint{EvRadians{-Deg_35}, AzRadians{ Deg_45}},
+ AngularPoint{EvRadians{-Deg_35}, AzRadians{ Deg135}},
+ };
+ static constexpr std::array AmbiMatrix1O{
+ std::array<float,MaxAmbiChannels>{{1.250000000e-01f, 1.250000000e-01f, 1.250000000e-01f, 1.250000000e-01f}},
+ std::array<float,MaxAmbiChannels>{{1.250000000e-01f, 1.250000000e-01f, 1.250000000e-01f, -1.250000000e-01f}},
+ std::array<float,MaxAmbiChannels>{{1.250000000e-01f, -1.250000000e-01f, 1.250000000e-01f, 1.250000000e-01f}},
+ std::array<float,MaxAmbiChannels>{{1.250000000e-01f, -1.250000000e-01f, 1.250000000e-01f, -1.250000000e-01f}},
+ std::array<float,MaxAmbiChannels>{{1.250000000e-01f, 1.250000000e-01f, -1.250000000e-01f, 1.250000000e-01f}},
+ std::array<float,MaxAmbiChannels>{{1.250000000e-01f, 1.250000000e-01f, -1.250000000e-01f, -1.250000000e-01f}},
+ std::array<float,MaxAmbiChannels>{{1.250000000e-01f, -1.250000000e-01f, -1.250000000e-01f, 1.250000000e-01f}},
+ std::array<float,MaxAmbiChannels>{{1.250000000e-01f, -1.250000000e-01f, -1.250000000e-01f, -1.250000000e-01f}},
+ };
+ static constexpr std::array AmbiMatrix2O{
+ std::array<float,MaxAmbiChannels>{{8.333333333e-02f, 0.000000000e+00f, -7.588274978e-02f, 1.227808683e-01f, 0.000000000e+00f, 0.000000000e+00f, -1.591525047e-02f, -1.443375673e-01f, 1.167715449e-01f}},
+ std::array<float,MaxAmbiChannels>{{8.333333333e-02f, -1.227808683e-01f, 0.000000000e+00f, 7.588274978e-02f, -1.443375673e-01f, 0.000000000e+00f, -9.316949906e-02f, 0.000000000e+00f, -7.216878365e-02f}},
+ std::array<float,MaxAmbiChannels>{{8.333333333e-02f, -7.588274978e-02f, 1.227808683e-01f, 0.000000000e+00f, 0.000000000e+00f, -1.443375673e-01f, 1.090847495e-01f, 0.000000000e+00f, -4.460276122e-02f}},
+ std::array<float,MaxAmbiChannels>{{8.333333333e-02f, 0.000000000e+00f, 7.588274978e-02f, 1.227808683e-01f, 0.000000000e+00f, 0.000000000e+00f, -1.591525047e-02f, 1.443375673e-01f, 1.167715449e-01f}},
+ std::array<float,MaxAmbiChannels>{{8.333333333e-02f, -1.227808683e-01f, 0.000000000e+00f, -7.588274978e-02f, 1.443375673e-01f, 0.000000000e+00f, -9.316949906e-02f, 0.000000000e+00f, -7.216878365e-02f}},
+ std::array<float,MaxAmbiChannels>{{8.333333333e-02f, 7.588274978e-02f, -1.227808683e-01f, 0.000000000e+00f, 0.000000000e+00f, -1.443375673e-01f, 1.090847495e-01f, 0.000000000e+00f, -4.460276122e-02f}},
+ std::array<float,MaxAmbiChannels>{{8.333333333e-02f, 0.000000000e+00f, -7.588274978e-02f, -1.227808683e-01f, 0.000000000e+00f, 0.000000000e+00f, -1.591525047e-02f, 1.443375673e-01f, 1.167715449e-01f}},
+ std::array<float,MaxAmbiChannels>{{8.333333333e-02f, 1.227808683e-01f, 0.000000000e+00f, -7.588274978e-02f, -1.443375673e-01f, 0.000000000e+00f, -9.316949906e-02f, 0.000000000e+00f, -7.216878365e-02f}},
+ std::array<float,MaxAmbiChannels>{{8.333333333e-02f, 7.588274978e-02f, 1.227808683e-01f, 0.000000000e+00f, 0.000000000e+00f, 1.443375673e-01f, 1.090847495e-01f, 0.000000000e+00f, -4.460276122e-02f}},
+ std::array<float,MaxAmbiChannels>{{8.333333333e-02f, 0.000000000e+00f, 7.588274978e-02f, -1.227808683e-01f, 0.000000000e+00f, 0.000000000e+00f, -1.591525047e-02f, -1.443375673e-01f, 1.167715449e-01f}},
+ std::array<float,MaxAmbiChannels>{{8.333333333e-02f, 1.227808683e-01f, 0.000000000e+00f, 7.588274978e-02f, 1.443375673e-01f, 0.000000000e+00f, -9.316949906e-02f, 0.000000000e+00f, -7.216878365e-02f}},
+ std::array<float,MaxAmbiChannels>{{8.333333333e-02f, -7.588274978e-02f, -1.227808683e-01f, 0.000000000e+00f, 0.000000000e+00f, 1.443375673e-01f, 1.090847495e-01f, 0.000000000e+00f, -4.460276122e-02f}},
+ };
+ static constexpr std::array AmbiMatrix3O{
+ std::array<float,MaxAmbiChannels>{{5.000000000e-02f, 3.090169944e-02f, 8.090169944e-02f, 0.000000000e+00f, 0.000000000e+00f, 6.454972244e-02f, 9.045084972e-02f, 0.000000000e+00f, -1.232790000e-02f, -1.256118221e-01f, 0.000000000e+00f, 1.126112056e-01f, 7.944389175e-02f, 0.000000000e+00f, 2.421151497e-02f, 0.000000000e+00f}},
+ std::array<float,MaxAmbiChannels>{{5.000000000e-02f, -3.090169944e-02f, 8.090169944e-02f, 0.000000000e+00f, 0.000000000e+00f, -6.454972244e-02f, 9.045084972e-02f, 0.000000000e+00f, -1.232790000e-02f, 1.256118221e-01f, 0.000000000e+00f, -1.126112056e-01f, 7.944389175e-02f, 0.000000000e+00f, 2.421151497e-02f, 0.000000000e+00f}},
+ std::array<float,MaxAmbiChannels>{{5.000000000e-02f, 3.090169944e-02f, -8.090169944e-02f, 0.000000000e+00f, 0.000000000e+00f, -6.454972244e-02f, 9.045084972e-02f, 0.000000000e+00f, -1.232790000e-02f, -1.256118221e-01f, 0.000000000e+00f, 1.126112056e-01f, -7.944389175e-02f, 0.000000000e+00f, -2.421151497e-02f, 0.000000000e+00f}},
+ std::array<float,MaxAmbiChannels>{{5.000000000e-02f, -3.090169944e-02f, -8.090169944e-02f, 0.000000000e+00f, 0.000000000e+00f, 6.454972244e-02f, 9.045084972e-02f, 0.000000000e+00f, -1.232790000e-02f, 1.256118221e-01f, 0.000000000e+00f, -1.126112056e-01f, -7.944389175e-02f, 0.000000000e+00f, -2.421151497e-02f, 0.000000000e+00f}},
+ std::array<float,MaxAmbiChannels>{{5.000000000e-02f, 8.090169944e-02f, 0.000000000e+00f, 3.090169944e-02f, 6.454972244e-02f, 0.000000000e+00f, -5.590169944e-02f, 0.000000000e+00f, -7.216878365e-02f, -7.763237543e-02f, 0.000000000e+00f, -2.950836627e-02f, 0.000000000e+00f, -1.497759251e-01f, 0.000000000e+00f, -7.763237543e-02f}},
+ std::array<float,MaxAmbiChannels>{{5.000000000e-02f, 8.090169944e-02f, 0.000000000e+00f, -3.090169944e-02f, -6.454972244e-02f, 0.000000000e+00f, -5.590169944e-02f, 0.000000000e+00f, -7.216878365e-02f, -7.763237543e-02f, 0.000000000e+00f, -2.950836627e-02f, 0.000000000e+00f, 1.497759251e-01f, 0.000000000e+00f, 7.763237543e-02f}},
+ std::array<float,MaxAmbiChannels>{{5.000000000e-02f, -8.090169944e-02f, 0.000000000e+00f, 3.090169944e-02f, -6.454972244e-02f, 0.000000000e+00f, -5.590169944e-02f, 0.000000000e+00f, -7.216878365e-02f, 7.763237543e-02f, 0.000000000e+00f, 2.950836627e-02f, 0.000000000e+00f, -1.497759251e-01f, 0.000000000e+00f, -7.763237543e-02f}},
+ std::array<float,MaxAmbiChannels>{{5.000000000e-02f, -8.090169944e-02f, 0.000000000e+00f, -3.090169944e-02f, 6.454972244e-02f, 0.000000000e+00f, -5.590169944e-02f, 0.000000000e+00f, -7.216878365e-02f, 7.763237543e-02f, 0.000000000e+00f, 2.950836627e-02f, 0.000000000e+00f, 1.497759251e-01f, 0.000000000e+00f, 7.763237543e-02f}},
+ std::array<float,MaxAmbiChannels>{{5.000000000e-02f, 0.000000000e+00f, 3.090169944e-02f, 8.090169944e-02f, 0.000000000e+00f, 0.000000000e+00f, -3.454915028e-02f, 6.454972244e-02f, 8.449668365e-02f, 0.000000000e+00f, 0.000000000e+00f, 0.000000000e+00f, 3.034486645e-02f, -6.779013272e-02f, 1.659481923e-01f, 4.797944664e-02f}},
+ std::array<float,MaxAmbiChannels>{{5.000000000e-02f, 0.000000000e+00f, 3.090169944e-02f, -8.090169944e-02f, 0.000000000e+00f, 0.000000000e+00f, -3.454915028e-02f, -6.454972244e-02f, 8.449668365e-02f, 0.000000000e+00f, 0.000000000e+00f, 0.000000000e+00f, 3.034486645e-02f, 6.779013272e-02f, 1.659481923e-01f, -4.797944664e-02f}},
+ std::array<float,MaxAmbiChannels>{{5.000000000e-02f, 0.000000000e+00f, -3.090169944e-02f, 8.090169944e-02f, 0.000000000e+00f, 0.000000000e+00f, -3.454915028e-02f, -6.454972244e-02f, 8.449668365e-02f, 0.000000000e+00f, 0.000000000e+00f, 0.000000000e+00f, -3.034486645e-02f, -6.779013272e-02f, -1.659481923e-01f, 4.797944664e-02f}},
+ std::array<float,MaxAmbiChannels>{{5.000000000e-02f, 0.000000000e+00f, -3.090169944e-02f, -8.090169944e-02f, 0.000000000e+00f, 0.000000000e+00f, -3.454915028e-02f, 6.454972244e-02f, 8.449668365e-02f, 0.000000000e+00f, 0.000000000e+00f, 0.000000000e+00f, -3.034486645e-02f, 6.779013272e-02f, -1.659481923e-01f, -4.797944664e-02f}},
+ std::array<float,MaxAmbiChannels>{{5.000000000e-02f, 5.000000000e-02f, 5.000000000e-02f, 5.000000000e-02f, 6.454972244e-02f, 6.454972244e-02f, 0.000000000e+00f, 6.454972244e-02f, 0.000000000e+00f, 1.016220987e-01f, 6.338656910e-02f, -1.092600649e-02f, -7.364853795e-02f, 1.011266756e-01f, -7.086833869e-02f, -1.482646439e-02f}},
+ std::array<float,MaxAmbiChannels>{{5.000000000e-02f, 5.000000000e-02f, 5.000000000e-02f, -5.000000000e-02f, -6.454972244e-02f, 6.454972244e-02f, 0.000000000e+00f, -6.454972244e-02f, 0.000000000e+00f, 1.016220987e-01f, -6.338656910e-02f, -1.092600649e-02f, -7.364853795e-02f, -1.011266756e-01f, -7.086833869e-02f, 1.482646439e-02f}},
+ std::array<float,MaxAmbiChannels>{{5.000000000e-02f, -5.000000000e-02f, 5.000000000e-02f, 5.000000000e-02f, -6.454972244e-02f, -6.454972244e-02f, 0.000000000e+00f, 6.454972244e-02f, 0.000000000e+00f, -1.016220987e-01f, -6.338656910e-02f, 1.092600649e-02f, -7.364853795e-02f, 1.011266756e-01f, -7.086833869e-02f, -1.482646439e-02f}},
+ std::array<float,MaxAmbiChannels>{{5.000000000e-02f, -5.000000000e-02f, 5.000000000e-02f, -5.000000000e-02f, 6.454972244e-02f, -6.454972244e-02f, 0.000000000e+00f, -6.454972244e-02f, 0.000000000e+00f, -1.016220987e-01f, 6.338656910e-02f, 1.092600649e-02f, -7.364853795e-02f, -1.011266756e-01f, -7.086833869e-02f, 1.482646439e-02f}},
+ std::array<float,MaxAmbiChannels>{{5.000000000e-02f, 5.000000000e-02f, -5.000000000e-02f, 5.000000000e-02f, 6.454972244e-02f, -6.454972244e-02f, 0.000000000e+00f, -6.454972244e-02f, 0.000000000e+00f, 1.016220987e-01f, -6.338656910e-02f, -1.092600649e-02f, 7.364853795e-02f, 1.011266756e-01f, 7.086833869e-02f, -1.482646439e-02f}},
+ std::array<float,MaxAmbiChannels>{{5.000000000e-02f, 5.000000000e-02f, -5.000000000e-02f, -5.000000000e-02f, -6.454972244e-02f, -6.454972244e-02f, 0.000000000e+00f, 6.454972244e-02f, 0.000000000e+00f, 1.016220987e-01f, 6.338656910e-02f, -1.092600649e-02f, 7.364853795e-02f, -1.011266756e-01f, 7.086833869e-02f, 1.482646439e-02f}},
+ std::array<float,MaxAmbiChannels>{{5.000000000e-02f, -5.000000000e-02f, -5.000000000e-02f, 5.000000000e-02f, -6.454972244e-02f, 6.454972244e-02f, 0.000000000e+00f, -6.454972244e-02f, 0.000000000e+00f, -1.016220987e-01f, 6.338656910e-02f, 1.092600649e-02f, 7.364853795e-02f, 1.011266756e-01f, 7.086833869e-02f, -1.482646439e-02f}},
+ std::array<float,MaxAmbiChannels>{{5.000000000e-02f, -5.000000000e-02f, -5.000000000e-02f, -5.000000000e-02f, 6.454972244e-02f, 6.454972244e-02f, 0.000000000e+00f, 6.454972244e-02f, 0.000000000e+00f, -1.016220987e-01f, -6.338656910e-02f, 1.092600649e-02f, 7.364853795e-02f, -1.011266756e-01f, 7.086833869e-02f, 1.482646439e-02f}},
+ };
+ static constexpr std::array<float,MaxAmbiOrder+1> AmbiOrderHFGain1O{
/*ENRGY*/ 2.000000000e+00f, 1.154700538e+00f
- }, AmbiOrderHFGain2O[MaxAmbiOrder+1]{
+ };
+ static constexpr std::array<float,MaxAmbiOrder+1> AmbiOrderHFGain2O{
/*ENRGY*/ 1.825741858e+00f, 1.414213562e+00f, 7.302967433e-01f
/*AMP 1.000000000e+00f, 7.745966692e-01f, 4.000000000e-01f*/
/*RMS 9.128709292e-01f, 7.071067812e-01f, 3.651483717e-01f*/
- }, AmbiOrderHFGain3O[MaxAmbiOrder+1]{
+ };
+ static constexpr std::array<float,MaxAmbiOrder+1> AmbiOrderHFGain3O{
/*ENRGY 1.865086714e+00f, 1.606093894e+00f, 1.142055301e+00f, 5.683795528e-01f*/
/*AMP*/ 1.000000000e+00f, 8.611363116e-01f, 6.123336207e-01f, 3.047469850e-01f
/*RMS 8.340921354e-01f, 7.182670250e-01f, 5.107426573e-01f, 2.541870634e-01f*/
};
- static_assert(std::size(AmbiPoints1O) == std::size(AmbiMatrix1O), "First-Order Ambisonic HRTF mismatch");
- static_assert(std::size(AmbiPoints2O) == std::size(AmbiMatrix2O), "Second-Order Ambisonic HRTF mismatch");
- static_assert(std::size(AmbiPoints3O) == std::size(AmbiMatrix3O), "Third-Order Ambisonic HRTF mismatch");
+ static_assert(AmbiPoints1O.size() == AmbiMatrix1O.size(), "First-Order Ambisonic HRTF mismatch");
+ static_assert(AmbiPoints2O.size() == AmbiMatrix2O.size(), "Second-Order Ambisonic HRTF mismatch");
+ static_assert(AmbiPoints3O.size() == AmbiMatrix3O.size(), "Third-Order Ambisonic HRTF mismatch");
/* A 700hz crossover frequency provides tighter sound imaging at the sweet
* spot with ambisonic decoding, as the distance between the ears is closer
@@ -841,18 +846,18 @@ void InitHrtfPanning(ALCdevice *device)
*/
device->mRenderMode = RenderMode::Hrtf;
uint ambi_order{1};
- if(auto modeopt = device->configValue<std::string>(nullptr, "hrtf-mode"))
+ if(auto modeopt = device->configValue<std::string>({}, "hrtf-mode"))
{
struct HrtfModeEntry {
- char name[8];
+ char name[7]; /* NOLINT(*-avoid-c-arrays) */
RenderMode mode;
uint order;
};
- static const HrtfModeEntry hrtf_modes[]{
- { "full", RenderMode::Hrtf, 1 },
- { "ambi1", RenderMode::Normal, 1 },
- { "ambi2", RenderMode::Normal, 2 },
- { "ambi3", RenderMode::Normal, 3 },
+ static constexpr std::array hrtf_modes{
+ HrtfModeEntry{"full", RenderMode::Hrtf, 1},
+ HrtfModeEntry{"ambi1", RenderMode::Normal, 1},
+ HrtfModeEntry{"ambi2", RenderMode::Normal, 2},
+ HrtfModeEntry{"ambi3", RenderMode::Normal, 3},
};
const char *mode{modeopt->c_str()};
@@ -882,9 +887,9 @@ void InitHrtfPanning(ALCdevice *device)
device->mHrtfName.c_str());
bool perHrirMin{false};
- al::span<const AngularPoint> AmbiPoints{AmbiPoints1O};
- const float (*AmbiMatrix)[MaxAmbiChannels]{AmbiMatrix1O};
- al::span<const float,MaxAmbiOrder+1> AmbiOrderHFGain{AmbiOrderHFGain1O};
+ auto AmbiPoints = al::span{AmbiPoints1O}.subspan(0);
+ auto AmbiMatrix = al::span{AmbiMatrix1O}.subspan(0);
+ auto AmbiOrderHFGain = al::span{AmbiOrderHFGain1O};
if(ambi_order >= 3)
{
perHrirMin = true;
@@ -903,7 +908,7 @@ void InitHrtfPanning(ALCdevice *device)
const size_t count{AmbiChannelsFromOrder(ambi_order)};
std::transform(AmbiIndex::FromACN.begin(), AmbiIndex::FromACN.begin()+count,
- std::begin(device->Dry.AmbiMap),
+ device->Dry.AmbiMap.begin(),
[](const uint8_t &index) noexcept { return BFChannelConfig{1.0f, index}; }
);
AllocChannels(device, count, device->channelsFromFmt());
@@ -969,9 +974,9 @@ void aluInitRenderer(ALCdevice *device, int hrtf_id, std::optional<StereoEncodin
break;
}
- std::unique_ptr<DecoderConfig<DualBand,MAX_OUTPUT_CHANNELS>> decoder_store;
+ std::unique_ptr<DecoderConfig<DualBand,MaxOutputChannels>> decoder_store;
DecoderView decoder{};
- float speakerdists[MAX_OUTPUT_CHANNELS]{};
+ std::array<float,MaxOutputChannels> speakerdists{};
auto load_config = [device,&decoder_store,&decoder,&speakerdists](const char *config)
{
AmbDecConf conf{};
@@ -981,10 +986,10 @@ void aluInitRenderer(ALCdevice *device, int hrtf_id, std::optional<StereoEncodin
ERR(" %s\n", err->c_str());
return false;
}
- else if(conf.NumSpeakers > MAX_OUTPUT_CHANNELS)
+ else if(conf.Speakers.size() > MaxOutputChannels)
{
- ERR("Unsupported decoder speaker count %zu (max %d)\n", conf.NumSpeakers,
- MAX_OUTPUT_CHANNELS);
+ ERR("Unsupported decoder speaker count %zu (max %zu)\n", conf.Speakers.size(),
+ MaxOutputChannels);
return false;
}
else if(conf.ChanMask > Ambi3OrderMask)
@@ -998,7 +1003,7 @@ void aluInitRenderer(ALCdevice *device, int hrtf_id, std::optional<StereoEncodin
conf.Description.c_str());
device->mXOverFreq = clampf(conf.XOverFreq, 100.0f, 1000.0f);
- decoder_store = std::make_unique<DecoderConfig<DualBand,MAX_OUTPUT_CHANNELS>>();
+ decoder_store = std::make_unique<DecoderConfig<DualBand,MaxOutputChannels>>();
decoder = MakeDecoderView(device, &conf, *decoder_store);
for(size_t i{0};i < decoder.mChannels.size();++i)
speakerdists[i] = conf.Speakers[i].Distance;
@@ -1019,7 +1024,7 @@ void aluInitRenderer(ALCdevice *device, int hrtf_id, std::optional<StereoEncodin
const bool stablize{device->RealOut.ChannelIndex[FrontCenter] != InvalidChannelIndex
&& device->RealOut.ChannelIndex[FrontLeft] != InvalidChannelIndex
&& device->RealOut.ChannelIndex[FrontRight] != InvalidChannelIndex
- && device->getConfigValueBool(nullptr, "front-stablizer", false) != 0};
+ && device->getConfigValueBool({}, "front-stablizer", false) != 0};
const bool hqdec{device->getConfigValueBool("decoder", "hq-mode", true) != 0};
InitPanning(device, hqdec, stablize, decoder);
if(decoder)
@@ -1088,7 +1093,7 @@ void aluInitRenderer(ALCdevice *device, int hrtf_id, std::optional<StereoEncodin
HrtfStore *hrtf{device->mHrtf.get()};
device->mIrSize = hrtf->mIrSize;
- if(auto hrtfsizeopt = device->configValue<uint>(nullptr, "hrtf-size"))
+ if(auto hrtfsizeopt = device->configValue<uint>({}, "hrtf-size"))
{
if(*hrtfsizeopt > 0 && *hrtfsizeopt < device->mIrSize)
device->mIrSize = maxu(*hrtfsizeopt, MinIrLength);
@@ -1127,13 +1132,13 @@ void aluInitRenderer(ALCdevice *device, int hrtf_id, std::optional<StereoEncodin
device->mRenderMode = RenderMode::Pairwise;
if(device->Type != DeviceType::Loopback)
{
- if(auto cflevopt = device->configValue<int>(nullptr, "cf_level"))
+ if(auto cflevopt = device->configValue<int>({}, "cf_level"))
{
if(*cflevopt > 0 && *cflevopt <= 6)
{
- device->Bs2b = std::make_unique<bs2b>();
- bs2b_set_params(device->Bs2b.get(), *cflevopt,
- static_cast<int>(device->Frequency));
+ auto bs2b = std::make_unique<Bs2b::bs2b>();
+ bs2b->set_params(*cflevopt, static_cast<int>(device->Frequency));
+ device->Bs2b = std::move(bs2b);
TRACE("BS2B enabled\n");
InitPanning(device);
device->PostProcess = &ALCdevice::ProcessBs2b;